GCC(1)

Bestie, this is the GCC(1) manual page from the GNU crew ๐ŸŽ€ Let's get into it ๐Ÿ’…


๐ŸŽ€ 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...

Only the most useful options made the cut up here, so check below for the rest ๐Ÿ‘€ Also, g++ accepts mostly the same options as gcc โœจ


๐Ÿ“– DESCRIPTION

Okay so when you run GCC, it normally goes through the whole pipeline: preprocessing, compilation, assembly, and linking ๐Ÿ”ฅ The "overall options" let you stop the party early at an intermediate stage. For example, -c tells it not to run the linker, so what you get back is object files from the assembler ๐Ÿงš

Other options get passed along to one or more stages of processing. Some of them boss around the preprocessor, some of them boss around the compiler itself ๐Ÿ’… And yet other options control the assembler and linker. Most of those aren't documented here, since you rarely need to touch them ๐Ÿ™ˆ

Most of the command-line options you can use with GCC are built for C programs ๐Ÿ’– If an option is only useful with another language (usually C++), the explanation will say so out loud. If the description doesn't mention a source language, then you can use that option with all supported languages โœจ

The usual move is to run the executable called gcc, or machine-gcc when you're cross-compiling, or machine-gcc-version if you want one specific version of GCC ๐Ÿฆ‹ When you compile C++ programs, you should invoke GCC as g++ instead, no cap ๐Ÿซถ

The gcc program takes options and file names as operands. A lot of options have multi-letter names, so you can't squish single-letter options together. -dv is very different from -d -v, so don't be a menace about it ๐Ÿ˜ญ

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. For example, if you specify -L more than once, the directories get searched in the order you specified them. Also, where you put the -l option is significant ๐Ÿ‘‘

Lots of options have long names that start with -f or with -W---for example, -fmove-loop-invariants, -Wformat, and so on ๐ŸŒธ Most of these come in 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 isn't the default. Main character energy for the default ๐Ÿ‘‘

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

Arguments to options that set some sort of size threshold can be arbitrarily large decimal or hexadecimal integers, followed by a byte size suffix that designates a multiple of bytes. The suffixes are kB and KiB for kilobyte and kibibyte, MB and MiB for megabyte and mebibyte, GB and GiB for gigabyte and gigibyte, and so on ๐Ÿ’œ In the rest of this page these are called byte-size. If you want the full list and the real explanation of the binary and decimal byte size prefixes, go check the NIST, IEC, and other relevant national and international standards ๐Ÿค“


โœจ OPTIONS โœจ

๐Ÿฆ‹ Option Summary

Here's the whole options lineup, grouped by type ๐Ÿ’– The explanations live in the sections that follow.

๐ŸŒˆ 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  -aux-info filename
-fallow-parameterless-variadic-functions  -fno-asm -fno-builtin
-fno-builtin-function  -fcond-mismatch -ffreestanding  -fgimple
-fgnu-tm  -fgnu89-inline  -fhosted -flax-vector-conversions
-fms-extensions -foffload=arg  -foffload-options=arg -fopenacc
-fopenacc-dim=geom -fopenmp  -fopenmp-simd
-fpermitted-flt-eval-methods=standard -fplan9-extensions
-fsigned-bitfields  -funsigned-bitfields -fsigned-char
-funsigned-char  -fsso-struct=endianness

๐Ÿ’… 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  -Wno-deprecated-array-compare
-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 -Wmismatched-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
-fdiagnostics-escape-format=[unicode|bytes]

โœจ Warning Options โœจ

okay bestie, this is the warning buffet ๐Ÿ’… GCC has so many flags for complaining about your code that I'm not even kidding. Here's the whole menu, every single one, no cuts ๐Ÿซถ

-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  -Warray-compare -Wno-attributes
-Wattribute-alias=n -Wno-attribute-alias -Wno-attribute-warning
-Wbidi-chars=[none|unpaired|any|ucn] -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 -Wno-c++11-extensions
-Wno-c++14-extensions -Wno-c++17-extensions -Wno-c++20-extensions
-Wno-c++23-extensions -Wcast-align  -Wcast-align=strict
-Wcast-function-type  -Wcast-qual -Wchar-subscripts -Wclobbered
-Wcomment -Wconversion  -Wno-coverage-mismatch  -Wno-cpp
-Wdangling-else  -Wdangling-pointer  -Wdangling-pointer=n
-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 -Winfinite-recursion -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
-Wopenacc-parallelism -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 squad ๐Ÿ”ฎ These are the static analyzer flags, all lined up and ready to go ๐Ÿฆ‹

-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-exploded-paths -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-allocation-size
-Wno-analyzer-tainted-array-index -Wno-analyzer-tainted-divisor
-Wno-analyzer-tainted-offset -Wno-analyzer-tainted-size
-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 strictly for C and Objective-C, so keep them in your C/ObjC bag ๐Ÿ’œ

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

last stop on the tour, and it's a big one ๐ŸŒˆ Here's the full debugging lineup, every flag included ๐Ÿซถ

-g  -glevel  -gdwarf  -gdwarf-version -gbtf -gctf  -gctflevel -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 optimizer control panel ๐Ÿ’… and it's a LOT. Every single one is listed below, exactly as written.

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

๐ŸŒธ Program Instrumentation Options ๐ŸŒธ

Okay now the instrumentation crew ๐Ÿงš profiling, coverage, and sanitizers, all in one place, no cap.

  • -p ๐ŸŒธ
  • -pg ๐Ÿ’–
  • -fprofile-arcs โœจ
  • --coverage ๐Ÿ‘‘
  • -ftest-coverage ๐Ÿ’…
  • -fprofile-abs-path ๐ŸŒˆ
  • -fprofile-dir=path ๐ŸŽ€
  • -fprofile-generate ๐Ÿฆ‹
  • -fprofile-generate=path ๐Ÿ’œ
  • -fprofile-info-section โญ
  • -fprofile-info-section=name ๐Ÿซถ
  • -fprofile-note=path ๐ŸŒธ
  • -fprofile-prefix-path=path ๐Ÿ”ฅ
  • -fprofile-update=method ๐Ÿ’–
  • -fprofile-filter-files=regex โœจ
  • -fprofile-exclude-files=regex ๐Ÿ‘‘
  • -fprofile-reproducible=[multithreaded|parallel-runs|serial] ๐Ÿ’…
  • -fsanitize=style ๐ŸŒˆ
  • -fsanitize-recover ๐ŸŽ€
  • -fsanitize-recover=style ๐Ÿฆ‹
  • -fasan-shadow-offset=number ๐Ÿ’œ
  • -fsanitize-sections=s1,s2,... โญ
  • -fsanitize-undefined-trap-on-error ๐Ÿซถ
  • -fbounds-check ๐ŸŒธ
  • -fcf-protection=[full|branch|return|none|check] ๐Ÿ”ฅ
  • -fharden-compares ๐Ÿ’–
  • -fharden-conditional-branches โœจ
  • -fstack-protector ๐Ÿ‘‘
  • -fstack-protector-all ๐Ÿ’…
  • -fstack-protector-strong ๐ŸŒˆ
  • -fstack-protector-explicit ๐ŸŽ€
  • -fstack-check ๐Ÿฆ‹
  • -fstack-limit-register=reg ๐Ÿ’œ
  • -fstack-limit-symbol=sym โญ
  • -fno-stack-limit ๐Ÿซถ
  • -fsplit-stack ๐ŸŒธ
  • -fvtable-verify=[std|preinit|none] ๐Ÿ”ฅ
  • -fvtv-counts ๐Ÿ’–
  • -fvtv-debug โœจ
  • -finstrument-functions ๐Ÿ‘‘
  • -finstrument-functions-exclude-function-list=sym,sym,... ๐Ÿ’…
  • -finstrument-functions-exclude-file-list=file,file,... ๐ŸŒˆ
  • -fprofile-prefix-map=old=new ๐ŸŽ€

๐Ÿฆ‹ Preprocessor Options ๐Ÿฆ‹

Time for the preprocessor, where macros and includes get sorted out ๐Ÿ’–

  • -Aquestion=answer ๐Ÿฆ‹
  • -A-question[=answer] ๐Ÿ’œ
  • -C โญ
  • -CC ๐Ÿซถ
  • -Dmacro[=defn] ๐ŸŒธ
  • -dD ๐Ÿ”ฅ
  • -dI ๐Ÿ’–
  • -dM โœจ
  • -dN ๐Ÿ‘‘
  • -dU ๐Ÿ’…
  • -fdebug-cpp ๐ŸŒˆ
  • -fdirectives-only ๐ŸŽ€
  • -fdollars-in-identifiers ๐Ÿฆ‹
  • -fexec-charset=charset ๐Ÿ’œ
  • -fextended-identifiers โญ
  • -finput-charset=charset ๐Ÿซถ
  • -flarge-source-files ๐ŸŒธ
  • -fmacro-prefix-map=old=new ๐Ÿ”ฅ
  • -fmax-include-depth=depth ๐Ÿ’–
  • -fno-canonical-system-headers โœจ
  • -fpch-deps ๐Ÿ‘‘
  • -fpch-preprocess ๐Ÿ’…
  • -fpreprocessed ๐ŸŒˆ
  • -ftabstop=width ๐ŸŽ€
  • -ftrack-macro-expansion ๐Ÿฆ‹
  • -fwide-exec-charset=charset ๐Ÿ’œ
  • -fworking-directory โญ
  • -H ๐Ÿซถ
  • -imacros file ๐ŸŒธ
  • -include file ๐Ÿ”ฅ
  • -M ๐Ÿ’–
  • -MD โœจ
  • -MF ๐Ÿ‘‘
  • -MG ๐Ÿ’…
  • -MM ๐ŸŒˆ
  • -MMD ๐ŸŽ€
  • -MP ๐Ÿฆ‹
  • -MQ ๐Ÿ’œ
  • -MT โญ
  • -Mno-modules ๐Ÿซถ
  • -no-integrated-cpp ๐ŸŒธ
  • -P ๐Ÿ”ฅ
  • -pthread ๐Ÿ’–
  • -remap โœจ
  • -traditional ๐Ÿ‘‘
  • -traditional-cpp ๐Ÿ’…
  • -trigraphs ๐ŸŒˆ
  • -Umacro ๐ŸŽ€
  • -undef ๐Ÿฆ‹
  • -Wp,option ๐Ÿ’œ
  • -Xpreprocessor option โญ

๐Ÿงš Assembler Options ๐Ÿงš

Just two of these, but they're giving assembler energy ๐Ÿ’…

  • -Wa,option ๐Ÿงš
  • -Xassembler option ๐Ÿ’–

๐Ÿ“ Linker Options ๐Ÿ“

Linker time, bestie. Libraries, entry points, and static-vs-shared drama ๐Ÿ”ฅ

  • object-file-name ๐Ÿ“
  • -fuse-ld=linker ๐Ÿ’œ
  • -llibrary โœจ
  • -nostartfiles ๐Ÿ‘‘
  • -nodefaultlibs ๐Ÿ’…
  • -nolibc ๐ŸŒˆ
  • -nostdlib ๐ŸŽ€
  • -e entry ๐Ÿฆ‹
  • --entry=entry ๐Ÿ’œ
  • -pie โญ
  • -pthread ๐Ÿซถ
  • -r ๐ŸŒธ
  • -rdynamic ๐Ÿ”ฅ
  • -s ๐Ÿ’–
  • -static โœจ
  • -static-pie ๐Ÿ‘‘
  • -static-libgcc ๐Ÿ’…
  • -static-libstdc++ ๐ŸŒˆ
  • -static-libasan ๐ŸŽ€
  • -static-libtsan ๐Ÿฆ‹
  • -static-liblsan ๐Ÿ’œ
  • -static-libubsan โญ
  • -shared ๐Ÿซถ
  • -shared-libgcc ๐ŸŒธ
  • -symbolic ๐Ÿ”ฅ
  • -T script ๐Ÿ’–
  • -Wl,option โœจ
  • -Xlinker option ๐Ÿ‘‘
  • -u symbol ๐Ÿ’…
  • -z keyword ๐ŸŒˆ

๐Ÿ’… Directory Options ๐Ÿ’…

Where should the compiler look? These flags tell it the whole vibe ๐Ÿ—บ๏ธ

  • -Bprefix ๐Ÿ’…
  • -Idir ๐ŸŽ€
  • -I- ๐Ÿฆ‹
  • -idirafter dir ๐Ÿ’œ
  • -imacros file โญ
  • -imultilib dir ๐Ÿซถ
  • -iplugindir=dir ๐ŸŒธ
  • -iprefix file ๐Ÿ”ฅ
  • -iquote dir ๐Ÿ’–
  • -isysroot dir โœจ
  • -isystem dir ๐Ÿ‘‘
  • -iwithprefix dir ๐Ÿ’…
  • -iwithprefixbefore dir ๐ŸŒˆ
  • -Ldir ๐ŸŽ€
  • -no-canonical-prefixes ๐Ÿฆ‹
  • --no-sysroot-suffix ๐Ÿ’œ
  • -nostdinc โญ
  • -nostdinc++ ๐Ÿซถ
  • --sysroot=dir ๐ŸŒธ

๐Ÿ’– Code Generation Options ๐Ÿ’–

Now we're in the codegen zone, where the actual machine code gets shaped โœจ

  • -fcall-saved-reg ๐Ÿ’–
  • -fcall-used-reg ๐ŸŒˆ
  • -ffixed-reg ๐ŸŽ€
  • -fexceptions ๐Ÿฆ‹
  • -fnon-call-exceptions ๐Ÿ’œ
  • -fdelete-dead-exceptions โญ
  • -funwind-tables ๐Ÿซถ
  • -fasynchronous-unwind-tables ๐ŸŒธ
  • -fno-gnu-unique ๐Ÿ”ฅ
  • -finhibit-size-directive โœจ
  • -fcommon ๐Ÿ‘‘
  • -fno-ident ๐Ÿ’…
  • -fpcc-struct-return ๐ŸŒˆ
  • -fpic ๐ŸŽ€
  • -fPIC ๐Ÿฆ‹
  • -fpie ๐Ÿ’œ
  • -fPIE โญ
  • -fno-plt ๐Ÿซถ
  • -fno-jump-tables ๐ŸŒธ
  • -fno-bit-tests ๐Ÿ”ฅ
  • -frecord-gcc-switches ๐Ÿ’–
  • -freg-struct-return โœจ
  • -fshort-enums ๐Ÿ‘‘
  • -fshort-wchar ๐Ÿ’…
  • -fverbose-asm ๐ŸŒˆ
  • -fpack-struct[=n] ๐ŸŽ€
  • -fleading-underscore ๐Ÿฆ‹
  • -ftls-model=model ๐Ÿ’œ
  • -fstack-reuse=reuse_level โญ
  • -ftrampolines ๐Ÿซถ
  • -ftrapv ๐ŸŒธ
  • -fwrapv ๐Ÿ”ฅ
  • -fvisibility=[default|internal|hidden|protected] ๐Ÿ’–
  • -fstrict-volatile-bitfields โœจ
  • -fsync-libcalls ๐Ÿ‘‘

๐Ÿ‘‘ Developer Options ๐Ÿ‘‘

Developer mode, bestie ๐Ÿ› ๏ธ dumps, reports, and debug knobs for the people who really want to see under the hood ๐Ÿ’…

  • -dletters ๐Ÿ‘‘
  • -dumpspecs ๐Ÿ’…
  • -dumpmachine ๐ŸŒˆ
  • -dumpversion ๐ŸŽ€
  • -dumpfullversion ๐Ÿฆ‹
  • -fcallgraph-info[=su,da] ๐Ÿ’œ
  • -fchecking โญ
  • -fchecking=n ๐Ÿซถ
  • -fdbg-cnt-list ๐ŸŒธ
  • -fdbg-cnt=counter-value-list ๐Ÿ”ฅ
  • -fdisable-ipa-pass_name ๐Ÿ’–
  • -fdisable-rtl-pass_name โœจ
  • -fdisable-rtl-pass-name=range-list ๐Ÿ‘‘
  • -fdisable-tree-pass_name ๐Ÿ’…
  • -fdisable-tree-pass-name=range-list ๐ŸŒˆ
  • -fdump-debug ๐ŸŽ€
  • -fdump-earlydebug ๐Ÿฆ‹
  • -fdump-noaddr ๐Ÿ’œ
  • -fdump-unnumbered โญ
  • -fdump-unnumbered-links ๐Ÿซถ
  • -fdump-final-insns[=file] ๐ŸŒธ
  • -fdump-ipa-all ๐Ÿ”ฅ
  • -fdump-ipa-cgraph ๐Ÿ’–
  • -fdump-ipa-inline โœจ
  • -fdump-lang-all ๐Ÿ‘‘
  • -fdump-lang-switch ๐Ÿ’…
  • -fdump-lang-switch-options ๐ŸŒˆ
  • -fdump-lang-switch-options=filename ๐ŸŽ€
  • -fdump-passes ๐Ÿฆ‹
  • -fdump-rtl-pass ๐Ÿ’œ
  • -fdump-rtl-pass=filename โญ
  • -fdump-statistics ๐Ÿซถ
  • -fdump-tree-all ๐ŸŒธ
  • -fdump-tree-switch ๐Ÿ”ฅ
  • -fdump-tree-switch-options ๐Ÿ’–
  • -fdump-tree-switch-options=filename โœจ
  • -fcompare-debug[=opts] ๐Ÿ‘‘
  • -fcompare-debug-second ๐Ÿ’…
  • -fenable-kind-pass ๐ŸŒˆ
  • -fenable-kind-pass=range-list ๐ŸŽ€
  • -fira-verbose=n ๐Ÿฆ‹
  • -flto-report ๐Ÿ’œ
  • -flto-report-wpa โญ
  • -fmem-report-wpa ๐Ÿซถ
  • -fmem-report ๐ŸŒธ
  • -fpre-ipa-mem-report ๐Ÿ”ฅ
  • -fpost-ipa-mem-report ๐Ÿ’–
  • -fopt-info โœจ
  • -fopt-info-options[=file] ๐Ÿ‘‘
  • -fprofile-report ๐Ÿ’…
  • -frandom-seed=string ๐ŸŒˆ
  • -fsched-verbose=n ๐ŸŽ€
  • -fsel-sched-verbose ๐Ÿฆ‹
  • -fsel-sched-dump-cfg ๐Ÿ’œ
  • -fsel-sched-pipelining-verbose โญ
  • -fstats ๐Ÿซถ
  • -fstack-usage ๐ŸŒธ
  • -ftime-report ๐Ÿ”ฅ
  • -ftime-report-details ๐Ÿ’–
  • -fvar-tracking-assignments-toggle โœจ
  • -gtoggle ๐Ÿ‘‘
  • -print-file-name=library ๐Ÿ’…
  • -print-libgcc-file-name ๐ŸŒˆ
  • -print-multi-directory ๐ŸŽ€
  • -print-multi-lib ๐Ÿฆ‹
  • -print-multi-os-directory ๐Ÿ’œ
  • -print-prog-name=program โญ
  • -print-search-dirs ๐Ÿซถ
  • -Q ๐ŸŒธ
  • -print-sysroot ๐Ÿ”ฅ
  • -print-sysroot-headers-suffix ๐Ÿ’–
  • -save-temps โœจ
  • -save-temps=cwd ๐Ÿ‘‘
  • -save-temps=obj ๐Ÿ’…
  • -time[=file] ๐ŸŒˆ

๐Ÿ’œ Machine-Dependent Options ๐Ÿ’œ

Last stop, the target-specific flags ๐ŸŽฏ Here's the AArch64 crew, fully listed.

AArch64 Options

  • -mabi=name ๐Ÿ’œ
  • -mbig-endian โญ
  • -mlittle-endian ๐Ÿซถ
  • -mgeneral-regs-only ๐ŸŒธ
  • -mcmodel=tiny ๐Ÿ”ฅ
  • -mcmodel=small ๐Ÿ’–
  • -mcmodel=large โœจ
  • -mstrict-align ๐Ÿ‘‘
  • -mno-strict-align ๐Ÿ’…
  • -momit-leaf-frame-pointer ๐ŸŒˆ
  • -mtls-dialect=desc ๐ŸŽ€
  • -mtls-dialect=traditional ๐Ÿฆ‹
  • -mtls-size=size ๐Ÿ’œ
  • -mfix-cortex-a53-835769 โญ
  • -mfix-cortex-a53-843419 ๐Ÿซถ
  • -mlow-precision-recip-sqrt ๐ŸŒธ
  • -mlow-precision-sqrt ๐Ÿ”ฅ
  • -mlow-precision-div ๐Ÿ’–
  • -mpc-relative-literal-loads โœจ
  • -msign-return-address=scope ๐Ÿ‘‘
  • -mbranch-protection=none|standard|pac-ret[+leaf +b-key]|bti ๐Ÿ’…
  • -mharden-sls=opts ๐ŸŒˆ
  • -march=name ๐ŸŽ€
  • -mcpu=name ๐Ÿฆ‹
  • -mtune=name ๐Ÿ’œ
  • -moverride=string โญ
  • -mverbose-cost-dump ๐Ÿซถ
  • -mstack-protector-guard=guard ๐ŸŒธ
  • -mstack-protector-guard-reg=sysreg ๐Ÿ”ฅ
  • -mstack-protector-guard-offset=offset ๐Ÿ’–
  • -mtrack-speculation โœจ
  • -moutline-atomics ๐Ÿ‘‘

๐Ÿ’– Adapteva Epiphany Options ๐Ÿ’–

okay so the Epiphany chip gets its own little flag wardrobe ๐Ÿงš here's everything it's got:

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

the GCN one is short and sweet, no notes ๐Ÿ’…

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

๐ŸŒธ ARC Options ๐ŸŒธ

the ARC list is literally huge, bestie ๐Ÿ˜ญ it's giving whole buffet energy ๐Ÿ“

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

ARM is an entire universe of flags, so grab a snack first ๐Ÿฟ

-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 -mfix-cortex-a57-aes-1742098
-mfix-cortex-a72-aes-1655431 -munaligned-access -mneon-for-64bits
-mslow-flash-data -masm-syntax-unified -mrestrict-it
-mverbose-cost-dump -mpure-code -mcmse -mfix-cmse-cve-2021-35465
-mstack-protector-guard=guard -mstack-protector-guard-offset=offset
-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
-melinux-stacksize=n -metrax4  -metrax100  -mpdebug  -mcc-init
-mno-side-effects -mstack-align  -mdata-align  -mconst-align
-m32-bit  -m16-bit  -m8-bit  -mno-prologue-epilogue  -mno-gotplt
-melf  -maout  -melinux  -mlinux  -sim  -sim2 -mmul-bug-workaround
-mno-mul-bug-workaround

โญ CR16 Options โญ

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

๐Ÿซถ C-SKY Options ๐Ÿซถ

-march=arch  -mcpu=cpu -mbig-endian  -EB
-mlittle-endian  -EL -mhard-float  -msoft-float  -mfpu=fpu
-mdouble-float  -mfdivdu -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 ๐ŸŽ

Darwin has a lot of linker-y flags, so this one is extra long, bestie ๐Ÿ™ˆ

-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 -mco-re -mno-co-re -mjmpext -mjmp32
-malu32 -mcpu=version

๐ŸŽ€ FR30 Options ๐ŸŽ€

-msmall-model  -mno-lsim

๐Ÿฆ„ FT32 Options ๐Ÿฆ„

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

๐Ÿ’… FRV Options ๐Ÿ’…

FRV has a lot of flags too, so take a breath ๐Ÿ˜ฎโ€๐Ÿ’จ

-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 ๐Ÿง 

the IA-64 list is massive, so pace yourself ๐Ÿƒโ€โ™€๏ธ

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

๐ŸŒ™ LM32 Options ๐ŸŒ™

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

๐Ÿƒ M32R/D Options ๐Ÿƒ

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

๐Ÿซง M32C Options ๐Ÿซง

-mcpu=cpu  -msim  -memregs=number

๐Ÿ’– M680x0 Options ๐Ÿ’–

this is the M680x0 bunch, and they are a lot ๐Ÿฅน

-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 ๐Ÿญ

the last one in this batch, bestie, we're almost through the buffet โœจ

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

okay bestie, the MicroBlaze flags are up first and they're a whole lineup ๐Ÿ’–

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

the MIPS list is giant and iconic, so grab a snack ๐Ÿ“

  • -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
  • -munaligned-access
  • -mno-unaligned-access
  • -mmemcpy
  • -mno-memcpy
  • -mlong-calls
  • -mno-long-calls
  • -mmad
  • -mno-mad
  • -mimadd
  • -mno-imadd
  • -mfused-madd
  • -mno-fused-madd
  • -nocpp
  • -mfix-24k
  • -mno-fix-24k
  • -mfix-r4000
  • -mno-fix-r4000
  • -mfix-r4400
  • -mno-fix-r4400
  • -mfix-r5900
  • -mno-fix-r5900
  • -mfix-r10000
  • -mno-fix-r10000
  • -mfix-rm7000
  • -mno-fix-rm7000
  • -mfix-vr4120
  • -mno-fix-vr4120
  • -mfix-vr4130
  • -mno-fix-vr4130
  • -mfix-sb1
  • -mno-fix-sb1
  • -mflush-func=func
  • -mno-flush-func
  • -mbranch-cost=num
  • -mbranch-likely
  • -mno-branch-likely
  • -mcompact-branches=policy
  • -mfp-exceptions
  • -mno-fp-exceptions
  • -mvr4130-align
  • -mno-vr4130-align
  • -msynci
  • -mno-synci
  • -mlxc1-sxc1
  • -mno-lxc1-sxc1
  • -mmadd4
  • -mno-madd4
  • -mrelax-pic-calls
  • -mno-relax-pic-calls
  • -mmcount-ra-address
  • -mframe-header-opt
  • -mno-frame-header-opt

๐Ÿ’œ MMIX Options ๐Ÿ’œ

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

๐Ÿงš MN10300 Options ๐Ÿงš

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

๐ŸŽ€ Moxie Options ๐ŸŽ€

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

๐ŸŒˆ MSP430 Options ๐ŸŒˆ

  • -msim
  • -masm-hex
  • -mmcu=
  • -mcpu=
  • -mlarge
  • -msmall
  • -mrelax
  • -mwarn-mcu
  • -mcode-region=
  • -mdata-region=
  • -msilicon-errata=
  • -msilicon-errata-warn=
  • -mhwmult=
  • -minrt
  • -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
  • -mcmodel=code-model

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

PowerPC Options are a little plot twist, bestie. Look at the RS/6000 and PowerPC Options section instead โœจ


๐Ÿฆ‹ PRU Options ๐Ÿฆ‹

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

๐Ÿ’– RISC-V Options ๐Ÿ’–

the RISC-V list is loooong, but every single one is here ๐Ÿซถ

  • -mbranch-cost=N-instruction
  • -mplt
  • -mno-plt
  • -mabi=ABI-string
  • -mfdiv
  • -mno-fdiv
  • -mdiv
  • -mno-div
  • -misa-spec=ISA-spec-string
  • -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 absolutely massive, so we're going full send ๐Ÿ’…

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

Okay bestie, SPARC gets its own squad of flags ๐Ÿฆ‹. These are the ones you can throw at it:

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

Old-school vibes, no cap:

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

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

Tile-Gx has its own little set too โœจ:

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

๐Ÿงš TILEPro Options ๐Ÿงš

TILEPro keeps it short and sweet ๐Ÿ“:

-mcpu=cpu  -m32

๐Ÿฆ‹ V850 Options ๐Ÿฆ‹

V850 has a whole lot going on, so buckle up ๐Ÿซถ:

-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 ๐ŸŽ€

Quick and classic:

-mg  -mgnu  -munix  -mlra

๐ŸŒท Visium Options ๐ŸŒท

Visium's crew ๐Ÿ’œ:

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

๐Ÿ›ธ VMS Options ๐Ÿ›ธ

VMS brings its own flags to the party ๐Ÿ‘‘:

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

๐Ÿ“ VxWorks Options ๐Ÿ“

VxWorks, your flags are here ๐Ÿซถ:

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

๐Ÿ’– x86 Options ๐Ÿ’–

This is the big one bestie, the x86 list is absolutely massive ๐Ÿ˜ญ. Take a breath and scroll ๐ŸŒธ:

-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
-mmove-max=bits -mstore-max=bits -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 -mavx512fp16 -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  -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 -mrelax-cmpxchg-loop -mindirect-branch=choice
-mfunction-return=choice -mindirect-branch-register
-mharden-sls=choice -mindirect-branch-cs-prefix -mneeded
-mno-direct-extern-access

๐ŸชŸ x86 Windows Options ๐ŸชŸ

Windows folks, this one's for you ๐Ÿ’™:

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

โญ Xstormy16 Options โญ

Just one flag here, simple as that โœจ:

-msim

๐Ÿ”ฅ Xtensa Options ๐Ÿ”ฅ

Xtensa is giving main character energy ๐Ÿ’…:

-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 ๐ŸงŠ

zSeries doesn't have its own list here, it just points you over to the S/390 section ๐Ÿ™ˆ:

See S/390 and zSeries Options.

๐ŸŽ€ Options Controlling the Kind of Output ๐ŸŽ€

Okay so compiling can have up to four stages ๐Ÿ’…: preprocessing, compilation proper, assembly, and linking. They always happen in that order, no skipping the line! GCC can preprocess and compile several files into several assembler input files, or into just one assembler input file โœจ. Then each assembler input file makes an object file, and linking smooshes all the object files together (the ones you just compiled AND the ones you handed it) into one executable file ๐Ÿงš.

For any given input file, the file name suffix (the bit after the dot) decides what kind of compilation happens ๐Ÿฆ‹:

  • file.c โ€” C source code that must be preprocessed.
  • file.i โ€” C source code that should not be preprocessed.
  • file.ii โ€” C++ source code that should not be preprocessed.
  • file.m โ€” Objective-C source code. Note that you must link with the libobjc library to make an Objective-C program work ๐Ÿ”ฅ.
  • file.mi โ€” Objective-C source code 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. Note that .M refers to a literal capital M ๐Ÿ’….
  • file.mii โ€” Objective-C++ source code that should not be preprocessed.
  • file.h โ€” C, C++, Objective-C or Objective-C++ header file to be turned into a precompiled header (default), or C, C++ header file to be 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 code 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 code that must be preprocessed.
  • file.mii โ€” Objective-C++ source code that should not be preprocessed.
  • file.hh, file.H, file.hp, file.hxx, file.hpp, file.HPP, file.h++, file.tcc โ€” C++ header file to be turned into a precompiled header or Ada spec.
  • file.f, file.for, file.ftn โ€” Fixed form Fortran source code that should not be preprocessed.
  • file.F, file.FOR, file.fpp, file.FPP, file.FTN โ€” Fixed form Fortran source code that must be preprocessed (with the traditional preprocessor).
  • file.f90, file.f95, file.f03, file.f08 โ€” Free form Fortran source code that should not be preprocessed.
  • file.F90, file.F95, file.F03, file.F08 โ€” Free form Fortran source code that must be preprocessed (with the traditional preprocessor).
  • file.go โ€” Go source code ๐Ÿน.
  • file.d โ€” D source code.
  • file.di โ€” D interface file.
  • file.dd โ€” D documentation code (Ddoc).
  • file.ads โ€” Ada source code file that contains 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). Such files are also called specs.
  • file.adb โ€” Ada source code file containing a library unit body (a subprogram or package body). Such files 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 name the input language yourself with the -x option ๐Ÿ‘‘:

  • -x language โ€” Specify explicitly the language for the following input files (rather than letting the compiler pick a default based on the file name suffix). This option applies to all following input files until the next -x option. 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
  • -x none โ€” Turn off any language specification, so subsequent files get handled by their file name suffixes (same as if -x had never been used at all) ๐ŸŒˆ.

If you only want some stages of compilation, 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 though: some combinations (for example, -x cpp-output -E) instruct gcc to do absolutely nothing ๐Ÿ’€.

  • -c โ€” Compile or assemble the source files, but do not link. The linking stage just doesn't happen. The ultimate output is an object file for each source file.

By default, the object file name for a source file is made by replacing the suffix .c, .i, .s, etc., with .o.

Unrecognized input files, which don't need compiling or assembling, are ignored.

  • -S โ€” Stop after the stage of compilation proper; do not assemble. The output is an assembler code file for each non-assembler input file specified.

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

Input files that don't require compilation are ignored.

  • -E โ€” Stop after the preprocessing stage; do not run the compiler proper. The output is preprocessed source code, which gets sent to the standard output โœจ.

Input files that don't require preprocessing are ignored.

-o file

Okay bestie, this is the main output boss ๐Ÿ‘‘. -o file tells GCC where to put the primary output ๐Ÿ’–, and it doesn't care what kind of output that is. Executable, object file, assembler file, preprocessed C code, it's all the same to -o โœจ.

If you skip -o, GCC picks its own defaults ๐ŸŒธ. 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 gets printed to standard output.

Okay, so -o only names the primary output, but it also affects what the aux and dump outputs get called ๐Ÿฆ‹. Unless you override it, those land in the same directory as the primary output. For auxiliary outputs, the input file's suffix gets swapped for the suffix of the aux file type. For dump outputs, the dump file's suffix gets tacked onto the input file suffix. In compilation commands, the base name of both aux and dump outputs is the primary output's base name. In compile and link commands, the primary output name (minus the executable suffix) gets combined with the input file name. If both share the same base name (ignoring the suffix), the result is just that base name. Otherwise they get concatenated with a dash between them ๐Ÿงš

Here are the examples, iykyk ๐Ÿ’…

gcc -c foo.c ...

This will use foo.o as the primary output, and put aux outputs and dumps right next to it, e.g., aux file foo.dwo for -gsplit-dwarf, and dump file foo.c.???r.final for -fdump-rtl-final.

If a non-linker output file is explicitly specified, aux and dump files take the same base name by default ๐ŸŽ€

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

This will name aux outputs dir/foobar.* and dump outputs dir/foobar.c.*.

A linker output instead prefixes the aux and dump outputs ๐ŸŒˆ

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

This will generally name aux outputs dir/foobar-foo.* and dir/foobar-bar.*, and dump outputs dir/foobar-foo.c.* and dir/foobar-bar.c.*.

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

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

In this case aux outputs are named dir/foo.* and dump outputs are named dir/foo.c.*.

The location and names of aux and dump outputs can be adjusted with the options -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 change the name of the primary output file. Intermediate outputs, when preserved, 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 in foo.i, and then compiles to the (implied) output file foo.s.

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

This 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 take their names from the input file, or from the (non-linker) output file if one is explicitly given. Dump output files (like the ones requested by -fdump-* options) keep the input name suffix. Aux output files (the ones requested by 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 for an explicit -dumpbase basename.suf by also specifying -dumpbase-ext .suf ๐Ÿฆ‹

If dumpbase is explicitly given with any directory component, then any dumppfx setting (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.*, disregarding dir/ in -o, the ./ prefix implied by -save-temps=cwd, and pfx- in -dumpdir ๐Ÿ’€

When -dumpbase shows up in a command that compiles multiple inputs, or that compiles and then links, it can get combined with dumppfx, same as under -dumpdir. Then each input file gets compiled using the combined dumppfx, and default values for dumpbase and auxdropsuf get computed for each input file ๐Ÿงš

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

This creates foo.o and bar.o as primary outputs, and it avoids overwriting the aux and dump outputs by using the dumpbase as a prefix. The aux and dump outputs end up named main-foo.* and main-bar.*.

An empty string given as dumpbase keeps the output basename from influencing how aux and dump outputs get named during compilation. Default values get computed instead ๐Ÿซถ

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

This will name aux outputs dir/foo.* and dump outputs dir/foo.c.*. Their basenames come from the input name, but the directory still defaults to the one from the output.

An empty-string dumpbase does not stop the output basename from being used during linking ๐ŸŒธ

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

The compilation of the source files will name aux outputs dir/foo.* and dir/bar.*, and dump outputs dir/foo.c.* and dir/bar.c.*. LTO recompilation during linking will use dir/foobar. as the prefix for dumps and aux files.


-dumpbase-ext auxdropsuf

When forming the name of an auxiliary output file (but not a dump output), 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 suffix of the input file 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.*, taking the location of the primary output and dropping the .c suffix from the dumpbase. Dump outputs keep the suffix: dir/x-foo.c.*.

This option gets ignored if it doesn't match the suffix of a specified dumpbase. The one exception is when it's used as an alternative to the executable suffix while 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, and avoids overwriting the aux and dump outputs by using the executable name minus auxdropsuf as a prefix. It creates aux outputs main-foo.* and main-bar.*, and dump outputs main-foo.c.* and main-bar.c.* ๐Ÿฆ‹


-dumpdir dumppfx

When forming 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 and, in turn, from the input name. Dump outputs also take the input name suffix: 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 also take the input name suffix: dir/bar.c.*.

By default, dumppfx is 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 does. If you give 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 option. 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, the dumpbase (minus an auxdropsuf suffix) plus a dash gets appended to the explicit or defaulted dumppfx. If the dumpbase contains any directory components, it overrides dumppfx instead. This way each of the multiple compilations gets 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: dir/pfx-main-foo.c.* and dir/pfx-main-bar.c.*, respectively. Compare that with the single-input compilation:

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

Applying -dumpbase to a single source does not 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, an explicit or defaulted dumppfx also goes through the dumpbase- transformation above. That's the compilation of foo.c and bar.c from before, just without -c. If neither -dumpdir nor -dumpbase is given, the linker output base name (minus auxdropsuf if specified, or the executable suffix otherwise) plus a dash gets appended to the default dumppfx instead. Heads up though, unlike the earlier linking cases ๐Ÿ‘€

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

This does not append the output name main to dumppfx, because -dumpdir was explicitly specified. The goal is that an explicitly specified dumppfx can include the output name as part of its prefix, if you want that. Only an explicitly specified -dumpbase would get combined with it, so a meaningful option doesn't get discarded ๐ŸŒธ

When you compile and then 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 with an explicit -dumpdir that stops the combination, even if -save-temps=* overrides it later ๐Ÿ’–

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

Auxiliary outputs get named foo.*, and dump outputs get named foo.c.*, and they land in the current working directory when you ask for it with -save-temps=cwd ๐Ÿ“‚โœจ

Okay, here's the whole data flow, which is intuitive (though slightly imprecise, ngl) ๐Ÿง ๐Ÿ’– The primary output name gets split into a directory part and a basename part. dumppfx is set to the directory part, unless -dumpdir or -save-temps=* overrides it. dumpbase is set to the basename part, unless -dumpbase overrides it. If there are multiple inputs or you're linking, that dumpbase can get combined with dumppfx and taken from each input file ๐ŸŒธ Auxiliary output names for each input are formed by combining dumppfx, dumpbase minus its suffix, and the auxiliary output suffix. Dump output names are only different in that they keep the suffix from dumpbase ๐ŸŽ€

When it comes to auxiliary and dump outputs made during LTO recompilation ๐Ÿ”ฅ, a combo of dumppfx and dumpbase gets passed down to lto-wrapper as a -dumpdir option. That combo can be the one you gave, or one derived from the linker output name (but not from inputs), even in cases where it wouldn't normally get used that way. 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 lto-wrapper runs sub-compilers, it 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 โ€” Prints (on standard error) the commands that get run for each stage of compilation ๐Ÿ“ข It also prints the version number of the compiler driver, plus the preprocessor and the compiler proper ๐Ÿ‘‘
  • -### โ€” Basically -v, but nothing actually runs ๐Ÿ™…โ€โ™€๏ธ Arguments get quoted unless they only contain alphanumeric characters or ./-_. This is perfect for shell scripts that want to snag the command lines the driver generates ๐Ÿš
  • --help โ€” Prints (on stdout) a rundown of the command-line options gcc understands ๐Ÿ“š If -v is also on, --help gets passed along to all the processes gcc invokes, so they can show the options they accept too ๐Ÿซถ If -Wextra was specified as well (before --help), then options with no documentation also get displayed ๐Ÿฆ‹
  • --target-help โ€” Prints (on stdout) a description of the target-specific options for each tool ๐ŸŽฏ For some targets, extra target-specific info might get printed too โœจ
  • --help={class|[^]qualifier}[,...] โ€” Prints (on stdout) a description of the options the compiler understands that fit into all the classes and qualifiers you specify ๐Ÿ“ Here are the classes:
    • optimizers โ€” Shows every optimization option the compiler supports โšก
    • warnings โ€” Shows every option that controls the warning messages the compiler produces ๐Ÿšจ
    • target โ€” Shows target-specific options. Unlike --target-help, the target-specific options of the linker and assembler are not shown, because those tools don't support the extended --help= syntax yet ๐Ÿ™ƒ
    • params โ€” Shows the values --param recognizes ๐Ÿงช
    • language โ€” Shows the options supported for language, where language is one of the languages this GCC version supports ๐ŸŒˆ If an option is supported by all languages, you need to pick the common class instead
    • common โ€” Shows the options that are common to all languages ๐Ÿซง

And here are the qualifiers:

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

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

--help=target,undocumented

You can flip a qualifier by prefixing it with the ^ character ๐Ÿ”„ For example, to show all binary warning options (the ones that are either on or off and don't take an argument) that do have a description, use:

--help=warnings,^joined,^undocumented

The argument to --help= should not consist solely of inverted qualifiers ๐Ÿšซ

You can combine several classes, but that usually narrows the output so much there's nothing left to show ๐Ÿ˜ญ One case where it does work is when one of the classes is target. To show all the target-specific optimization options, use:

--help=target,optimizers

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

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

Here's a truncated example from the ARM port of gcc:

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

The output is sensitive to the effects of previous command-line options ๐Ÿงฉ So, for example, you can find out which optimizations are enabled at -O2 by using:

-Q -O2 --help=optimizers

Or you can discover which binary optimizations are enabled by -O3 by using:

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 gcc exits with the code of 1 if any phase of the compiler returns a non-success return code ๐Ÿ˜ญ If you specify -pass-exit-codes, gcc 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 to work on some systems where the assembler can't read from a pipe, but the GNU assembler has no trouble with it โš ๏ธ
  • -specs=file โ€” Processes file after the compiler reads in the standard specs file ๐Ÿ‘‘ This overrides 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 get processed in order, from left to right โžก๏ธ
  • -wrapper โ€” Invokes all subcommands under a wrapper program ๐ŸŽ The name of the wrapper program and its parameters get passed as a comma-separated list, like this:
gcc -c t.c -wrapper gdb,--args

This invokes all subprograms of gcc under gdb --args, so the invocation of cc1 is 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 is equivalent to specifying all the individual -f*-prefix-map options ๐Ÿง  It's handy for reproducible builds that don't depend on location ๐ŸŒˆ See also -fmacro-prefix-map, -fdebug-prefix-map and -fprofile-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 is used to identify 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 the 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 the 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 are inserted in place of the original @file option ๐Ÿ”„ If file doesn't exist or can't be read, then the option gets treated literally and is not removed ๐Ÿ™ˆ

Options in file are separated by whitespace. A whitespace character can be included 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 can 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 ๐ŸŒธ 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) ๐Ÿ‘‘ no cap, that's iconic ๐Ÿ”ฅ

However, here's the tea, bestie ๐Ÿ˜ญ using gcc does not add the C++ library. That's where g++ slides in ๐Ÿ’…. It's basically gcc with a glow-up: it calls GCC and automatically specifies linking against the C++ library โœจ. It also treats .c, .h and .i files as C++ source files instead of C source files, unless you use -x ๐Ÿฆ‹. It's handy for precompiling a C header file with a .h extension for use in C++ compilations ๐Ÿงš. On lots of systems, g++ is also installed as c++ ๐ŸŒธ.

When you're compiling C++ ๐Ÿ’–, you can use a bunch of the same command-line options you'd use for any language, or options meaningful for C and its relatives, or options that only matter for C++ programs. Mix and match, queen ๐Ÿ‘‘.


๐ŸŽ€ Options Controlling C Dialect

These options decide which flavour of C (or C-derived languages like C++, Objective-C and Objective-C++) the compiler is willing to accept ๐ŸŒˆ:

๐Ÿ’… -ansi

In C mode, it's basically the same as -std=c90 ๐ŸŽ€. In C++ mode, it's the same as -std=c++98.

This one is a lot ๐Ÿ™ˆ. It switches off GCC features that clash with ISO C90 (for C code) or standard C++ (for C++ code). That means no asm and typeof keywords, and no predefined macros like unix and vax that tell you what kind of system you're on ๐Ÿ’€. It also switches on the undesirable, rarely used ISO trigraph feature (nobody asked for that, bestie ๐Ÿ˜ญ). For the C compiler, it also disables // comments (the C++ style ones) and the inline keyword.

The alternate keywords __asm__, __extension__, __inline__ and __typeof__ keep working even with -ansi ๐Ÿฆ‹. You wouldn't use them in a strict ISO C program, obviously, but they're super handy in header files that might get included in -ansi builds ๐Ÿงš. The alternate predefined macros __unix__ and __vax__ are around too, with or without -ansi โœจ.

-ansi won't go around rejecting non-ISO programs for no reason ๐Ÿ™…. If you want that, you need -Wpedantic on top of -ansi, periodt.

When -ansi is on, the macro __STRICT_ANSI__ is predefined ๐Ÿ”ฅ. Some header files might notice it and skip declaring certain functions or defining macros the ISO standard doesn't ask for, so they don't mess with programs that use those names for other stuff ๐Ÿซถ.

Functions that are usually built in but don't have ISO C semantics (like alloca and ffs) stop being built-in functions under -ansi ๐Ÿ’€.

โœจ -std=

This one picks the language standard ๐Ÿ‘‘. Right now it only works when compiling C or C++.

The compiler can accept several base standards, like c90 or c++98, plus GNU dialects of those, like gnu90 or gnu++98. When you specify a base standard, the compiler accepts every program following that standard, plus any GNU extensions that don't contradict it. For example, -std=c90 turns off GCC features that clash with ISO C90, like the asm and typeof keywords, but it keeps other GNU extensions that don't mean anything in ISO C90, like leaving out the middle term of a ?: expression.

Now here's the twist ๐Ÿ‘€. When you pick a GNU dialect, every feature the compiler supports gets enabled, even if those features change the meaning of the base standard. So some strictly conforming programs might get rejected. The chosen standard is what -Wpedantic uses 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 doesn't.

You have to give this option a value ๐Ÿšจ. The 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 by amendment 1.
  • c99, c9x, iso9899:1999, iso9899:199x โ€” ISO C99 ๐ŸŒŸ. It's substantially, like, completely supported, minus bugs and floating-point drama (mostly with optional C99 features from Annexes F and G). Peep https://gcc.gnu.org/c99status.html for more info ๐Ÿ‘€. Heads up, 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, minus bugs, floating-point issues (mainly but not entirely about 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 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 is experimental and incomplete.
  • c++98, c++03 โ€” The 1998 ISO C++ standard plus the 2003 technical corrigendum and some extra 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 ๐Ÿ’€.

๐Ÿ“ -aux-info filename

This one dumps prototyped declarations for every function declared and/or defined in a translation unit (header files included ๐Ÿงš) into the file you name. It's silently ignored in any language that isn't C ๐Ÿคซ.

The file also has extra info tucked into comments ๐Ÿ“š. It tells you where each declaration came from (source file and line), and whether it 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). It also tells you whether the declaration came from a declaration or a definition (C or F, respectively, in the following character). For function definitions, you also get a K&R-style list of arguments followed by their declarations, also in comments, right after the declaration.

  • -fallow-parameterless-variadic-functions โ€” Lets you accept variadic functions with no named parameters ๐Ÿฆ‹. You can define one, but it's not super useful since you can't read the arguments ๐Ÿคท. This is only supported for C, because C++ already allows this construct.

๐Ÿ™… -fno-asm

This stops GCC from treating asm, inline or typeof as keywords ๐ŸŽ€, so your code can use those words as identifiers. Use __asm__, __inline__ and __typeof__ instead. In C, -ansi implies -fno-asm.

In C++, inline is a standard keyword, so this switch doesn't touch it ๐Ÿ™ƒ. You might want -fno-gnu-keywords instead, which disables typeof but leaves asm and inline alone. In C99 mode (-std=c99 or -std=gnu99), this switch only affects asm and typeof, since inline is a standard keyword in ISO C99.

๐Ÿ” -fno-builtin, -fno-builtin-function

This tells GCC to not recognize built-in functions that don't start with the __builtin_ prefix ๐Ÿ™….

Normally GCC has special tricks for certain built-in functions ๐Ÿง . For instance, alloca calls might become single instructions that adjust the stack directly, and memcpy calls might turn into inline copy loops. The code is often smaller and faster ๐ŸŽ๏ธ. But since those calls no longer show up as calls, you can't set a breakpoint on them, and you can't change what the functions do by linking against a different library ๐Ÿ’€.

Also, once something's recognized as a built-in, GCC may use what it knows about it to warn about bad calls, or to generate more efficient code, even if the result still contains calls to that function. For example, you get -Wformat warnings for bad calls to printf when printf is built in and strlen is known not to modify global memory ๐Ÿซถ.

With -fno-builtin-function, only the built-in version of function gets switched off ๐Ÿ’…. function can't begin with __builtin_ (that one's a hard rule ๐Ÿ™…โ€โ™€๏ธ). If the function you name isn't a built-in in your GCC version, the option just gets ignored, no drama โœจ. There's no -fbuiltin-function buddy to flip it back on, BUT if you want to pick and choose built-ins while using -fno-builtin or -ffreestanding, you can define your own macros, like:

#define abs(n)          __builtin_abs ((n))
#define strcpy(d, s)    __builtin_strcpy ((d), (s))
  • -fcond-mismatch โ€” Lets conditional expressions have mismatched types in the second and third arguments ๐Ÿฆ‹. When that happens, the value of the expression is void. This one isn't supported for C++, so keep it in C land, bestie ๐Ÿ’–.
  • -ffreestanding โ€” Tells GCC your compilation targets a freestanding environment ๐Ÿงš. This implies -fno-builtin. In a freestanding environment, the standard library might not exist, and program startup might not necessarily be at main. The most obvious example is an OS kernel ๐Ÿ’€. This is equivalent to -fno-hosted.
  • -fgimple โ€” Enables parsing of function definitions marked with __GIMPLE โœจ. It's experimental and lets you unit test GIMPLE passes ๐Ÿงช.
  • -fgnu-tm โ€” Makes the compiler generate code for the Linux variant of Intel's current Transactional Memory ABI specification document (Revision 1.1, May 6 2009) ๐Ÿ”ฅ. It's experimental, so the interface might change in future GCC versions as the official spec changes. Not every architecture is supported, so check before you commit to the vibe ๐Ÿซถ.

For more info on GCC's support for transactional memory,

Note: the transactional memory feature is not supported with non-call exceptions (-fnon-call-exceptions). ๐Ÿ™ˆ
  • -fgnu89-inline โ€” Tells GCC to use the traditional GNU semantics for inline functions when you're in C99 mode ๐Ÿ’œ. Using it is roughly the same as adding the gnu_inline function attribute to every inline function.
  • -fno-gnu89-inline โ€” Explicitly tells GCC to use C99 semantics for inline when you're in C99 or gnu99 mode (aka the default behavior ๐ŸŒธ). This option isn't supported in -std=c90 or -std=gnu90 mode.

Wanna check which inline semantics are active? The preprocessor macros __GNUC_GNU_INLINE__ and __GNUC_STDC_INLINE__ can help you check ๐Ÿ‘€.

  • -fhosted โ€” Asserts that compilation targets a hosted environment, which implies -fbuiltin ๐Ÿ“. A hosted environment has the entire standard library available, and main returns an int. Basically everything except a kernel. This is equivalent to -fno-freestanding.
  • -flax-vector-conversions โ€” Allows implicit conversions between vectors with differing numbers of elements and/or incompatible element types ๐ŸŒˆ. This option should not be used for new code, bestie, I mean it ๐Ÿ˜ญ.
  • -fms-extensions โ€” Accepts some non-standard constructs used in Microsoft header files ๐ŸชŸ. In C++ code, this allows member names in structures to be similar to previous type declarations:
typedef int UOW;
struct ABC {
  UOW UOW;
};

Some cases of unnamed fields in structures and unions are only accepted with this option. Also, this option is off for all targets except x86 targets using ms-abi โš ๏ธ.

  • -foffload=disable, -foffload=default, -foffload=target-list โ€” Picks which OpenMP and OpenACC offload targets get code generated ๐ŸŽฏ. The default behavior, same as -foffload=default, is to generate code for all supported offload targets. -foffload=disable generates code only for the host fallback, and -foffload=target-list generates code only for the comma-separated list of offload targets you specify.

Offload targets are written in GCC's internal target-triplet format. Run the compiler with -v to see the list of configured offload targets under "OFFLOAD_TARGET_NAMES" ๐Ÿ‘‘.

  • -foffload-options=options, -foffload-options=target-triplet-list=options โ€” With -foffload-options=options, GCC passes your options to the compilers for all enabled offloading targets ๐Ÿšš. For options that only apply to a specific target or targets, use the -foffload-options=target-list=options form. The target-list is a comma-separated list in the same format as the -foffload= option.

Typical command lines are:

-foffload-options=-lgfortran -foffload-options=-lm
-foffload-options="-lgfortran -lm" -foffload-options=nvptx-none=-latomic
-foffload-options=amdgcn-amdhsa=-march=gfx906 -foffload-options=-lm
  • -fopenacc โ€” Turns on handling of OpenACC directives: #pragma acc in C/C++ and !$acc in Fortran ๐Ÿš€. When you use it, the compiler generates accelerated code according to 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 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. You can leave a size out to use a target-specific default value.
  • -fopenmp โ€” Turns on handling of OpenMP directives: #pragma omp in C/C++ and !$omp in Fortran โœจ. When you use it, the compiler generates parallel code according to the OpenMP Application Program Interface v4.5 (https://www.openmp.org). This option implies -pthread, so it's only supported on targets with -pthread support. -fopenmp also implies -fopenmp-simd ๐Ÿซถ.
  • -fopenmp-simd โ€” Turns on handling of OpenMP's SIMD directives written with #pragma omp in C/C++ and !$omp in Fortran ๐Ÿฆ‹. Other OpenMP directives are ignored.
  • -fpermitted-flt-eval-methods=style โ€” Big brain energy ๐Ÿง . ISO/IEC TS 18661-3 defines new permissible values for FLT_EVAL_METHOD that say operations and constants with a semantic type that's an interchange or extended format should be evaluated at the precision and range of that type. These new values are a superset of the ones allowed under C99/C11, which doesn't specify what other positive values mean. So code that conforms to C11 may not have been written expecting the new values ๐Ÿค”.

-fpermitted-flt-eval-methods controls whether the compiler allows only the C99/C11 values, or the extended set from ISO/IEC TS 18661-3. style is either c11 or ts-18661-3, as appropriate.

The default in a standards-compliant mode (-std=c11 or similar) is -fpermitted-flt-eval-methods=c11. The default in a GNU dialect (-std=gnu11 or similar) is -fpermitted-flt-eval-methods=ts-18661-3.

  • -fplan9-extensions โ€” Accepts some non-standard constructs used in Plan 9 code ๐Ÿš. This enables -fms-extensions, permits passing pointers to structures with anonymous fields to functions that expect pointers to elements of the type of the field, and permits referring to anonymous fields declared using a typedef. It's only supported for C, not C++, sorry C++ girlies ๐Ÿ˜ญ.
  • -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: basic integer types like int are signed types.
  • -fsigned-char โ€” Lets the type char be signed, like signed char ๐Ÿ’–. This is equivalent to -fno-unsigned-char, which is the negative form of -funsigned-char. Likewise, -fno-signed-char is equivalent to -funsigned-char.
  • -funsigned-char โ€” Lets the type char be unsigned, like unsigned char ๐ŸŒˆ. Each kind of machine has a default for what char should be: it's either like unsigned char by default, or like signed char by default.

Ideally, a portable program should always use signed char or unsigned char when it depends on the signedness of an object. But lots of programs were written to use plain char and expect it to be signed, or expect it to be unsigned, depending on the machines they were written for. This option, and its inverse, lets you make those programs work with the opposite default ๐Ÿ”„.

The type char is always a distinct type from each of signed char or unsigned char, even though its behavior is always just like one of those two ๐Ÿงš.

  • -fsso-struct=endianness โ€” Sets the default scalar storage order of structures and unions to the endianness you specify ๐Ÿงฒ. The accepted values are big-endian, little-endian, and native (the native endianness of the target, which is 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. ๐Ÿ˜ฌ

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

This section covers the command-line options that are only meaningful for C++ programs ๐Ÿ’–. You can still 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. Therefore, the ABI obtained using version 0 will change in different versions of G++ as ABI bugs are fixed.
    • Version 1 is the version of the C++ ABI that first appeared in G++ 3.2.
    • Version 2 is the version of the C++ ABI that first appeared in G++ 3.4, and was the default through G++ 4.9.
    • Version 3 corrects an error in mangling a constant address as a template argument.

Version 4 first showed up in G++ 4.5 and gave vector types a standard mangling ๐Ÿ’œ

Version 5, first in G++ 4.6, fixed the mangling of attribute const/volatile on function pointer types, decltype of a plain decl, and using a function parameter in the declaration of another parameter ๐ŸŒธ

Version 6, first in G++ 4.7, fixed 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, first in G++ 4.8, treats nullptr_t as a builtin type and fixes the mangling of lambdas in default argument scope โœจ

Version 8, first in G++ 4.9, fixed the substitution behavior of function types with function-cv-qualifiers ๐ŸŽ€

Version 9, first in G++ 5.2, fixed the alignment of "nullptr_t" ๐Ÿ“

Version 10, first in G++ 6.1, added mangling for attributes that affect type identity, like ia32 calling convention attributes (e.g. stdcall) ๐Ÿงš

Version 11, first in G++ 7, fixed the mangling of sizeof... expressions and operator names ๐Ÿ”ฅ For multiple entities with the same name within a function that are declared in different scopes, the mangling changes starting with the twelfth occurrence. It also implies -fnew-inheriting-ctors ๐Ÿ’…

Version 12, first in G++ 8, fixed the calling conventions for empty classes on the x86_64 target and for classes with only deleted copy/move constructors ๐Ÿ‘‘ But it accidentally changed the calling convention for classes with a deleted copy constructor and a trivial move constructor ๐Ÿ˜ญ

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

Version 14, first in G++ 10, fixed the mangling of the nullptr expression ๐ŸŒˆ

Version 15, first in G++ 11, changes the mangling of __alignof__ so it's distinct from alignof, plus dependent operator names ๐Ÿฆ‹

See also -Wabi ๐Ÿ‘€


  • -fabi-compat-version=n โ€” On targets that support strong aliases, G++ works around mangling changes by making an alias with the correct mangled name whenever it defines a symbol with an incorrect mangled name. This switch picks which ABI version that alias uses ๐Ÿ”

With -fabi-version=0 (the default), this defaults to 11 (GCC 7 compatibility). If you explicitly pick another ABI version, it defaults to 0. For compatibility with GCC versions 3.2 through 4.9, use -fabi-compat-version=2 ๐Ÿงธ

If this option isn't given but -Wabi=n is, that version gets used for the compatibility aliases. If this option is given along with -Wabi (without the 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 ๐Ÿ› ๏ธ
  • -faligned-new โ€” Enables support for C++17 new of types that need more alignment than void* ::operator new(std::size_t) provides โœจ You can pass a number like -faligned-new=32 to say how much alignment (in bytes) that function provides, but few users will 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 support for char8_t, as adopted for C++20 ๐ŸŒ This adds a new char8_t fundamental type, changes the types of UTF-8 string and character literals, gives user-defined literals new signatures, comes with associated standard library updates, and adds the new __cpp_char8_t and __cpp_lib_char8_t feature test macros ๐Ÿ’…

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

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

And it 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, though ๐Ÿ˜ฌ 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 is 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 allocated ๐Ÿ” You usually don't need this, 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 all other cases, when operator new has a non-empty exception specification, memory exhaustion is 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 with -fconcepts-ts ๐Ÿฆ„

  • -fconstexpr-depth=n โ€” Sets the maximum nested evaluation depth for C++11 constexpr functions to n ๐ŸŒ€ A limit is needed so endless recursion can be detected 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 very large from highly recursive evaluations). The default is 8 ๐ŸŒธ

Very few users are likely to want to adjust it, but if your code does heavy constexpr calculations, you might want to experiment to find which value works best for you ๐Ÿ’…

  • -fconstexpr-fp-except โ€” Annex F of the C standard specifies that IEC559 floating point exceptions encountered at compile time should not stop compilation ๐Ÿค“ C++ compilers have historically not followed that guidance, instead treating floating point division by zero as non-constant even though it has a well-defined value ๐Ÿ˜ค This flag tells the compiler to give Annex F priority over other rules saying that a particular operation is undefined:
constexpr float inf = 1./0.; // OK with -fconstexpr-fp-except
  • -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, you can still get a too-long constexpr evaluation if there are several nested loops that each have lots of iterations (but are still under that limit), or if too many expressions need evaluating in the body of some loop or even outside of a loop. The default is 33554432 (1<<25) ๐Ÿซ 
  • -fcoroutines โ€” Enables support for the C++ coroutines extension (experimental) ๐Ÿงต
  • -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 โœ‚๏ธ This option disables that optimization and forces G++ to call the copy constructor in all cases. It also causes G++ to 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 ๐Ÿƒ
๐Ÿ’€ Heads up, bestie: This 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 โ€” โœจ okay so C++11 and OpenMP let thread_local and threadprivate variables do dynamic (runtime) initialization ๐Ÿงš. To make that work, every use of one of these variables goes through a wrapper function that handles the setup. When the use and the definition are in the same translation unit (TU), the overhead can get optimized away ๐Ÿ’…. But if the use is in a different TU, there's a lot of overhead even when the variable doesn't actually need dynamic initialization ๐Ÿ˜ญ. If you can be sure that no use in a non-defining TU needs to trigger dynamic initialization (because the variable is statically initialized, or a use in the defining TU always runs first), you can skip that overhead with -fno-extern-tls-init ๐Ÿซถ.

On targets that support symbol aliases, the default is -fextern-tls-init. On targets that do not support symbol aliases, the default is -fno-extern-tls-init ๐ŸŒธ.

  • -fno-gnu-keywords โ€” ๐ŸŽ€ Stops typeof from being treated as a keyword, so you can totally use it as a normal identifier. If you still want the keyword, use __typeof__ instead ๐Ÿ’–. This is already implied by the strict ISO C++ dialects, like -ansi, -std=c++98, -std=c++11, and so on.
  • -fimplicit-constexpr โ€” ๐Ÿฆ‹ Makes inline functions implicitly constexpr whenever they meet the requirements for a constexpr function. This only works in C++14 mode or later. It can flip initialization from dynamic to static, plus a few other optimizations pop off โœจ.
  • -fno-implicit-templates โ€” ๐Ÿ™ˆ Never emits code for non-inline templates that get instantiated implicitly (aka just by using them). Only explicit instantiations get code.
โš ๏ธ If you use this option, you have to structure your code so it includes all the explicit instantiations you need, or you'll get undefined symbols at link time. Be careful, bestie ๐Ÿ˜ญ.
  • -fno-implicit-inline-templates โ€” ๐ŸŒˆ Doesn't emit code for implicit instantiations of inline templates either. By default, inlines are handled differently so that compiles with and without optimization need the same set of explicit instantiations ๐Ÿง .
  • -fno-implement-inlines โ€” ๐Ÿ“ To save space, this skips emitting out-of-line copies of inline functions controlled by #pragma implementation.
๐Ÿ’€ This causes linker errors if those functions aren't inlined everywhere they're called. Not it.
  • -fmodules-ts, -fno-modules-ts โ€” ๐Ÿ’œ Enables support for C++20 modules. You usually don't need -fno-modules-ts, because that's already the default. Even though modules are a C++20 feature, selecting that standard version doesn't implicitly turn this on right now ๐Ÿ‘‘.
  • -fmodule-header, -fmodule-header=user, -fmodule-header=system โ€” ๐Ÿงš Compiles a header file into an importable header unit.
  • -fmodule-implicit-inline โ€” ๐Ÿ”ฅ Member functions defined inside their class definitions are not implicitly inline for modular code. This is different from traditional C++ behavior, and there are good reasons for it. It can cause a bit of trouble when porting code, though. This option makes those function definitions implicitly inline.
๐Ÿšจ It does generate an ABI incompatibility, so you have to use it everywhere or nowhere. (Definitions outside of a named module stay implicitly inline no matter what.)
  • -fno-module-lazy โ€” ๐Ÿฆ‹ Disables lazy module importing and module mapper creation.
  • -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] โ€” ๐Ÿ”ฎ This is an oracle that answers questions about module name to filename mappings. If you don't specify one, the CXX_MODULE_MAPPER environment variable gets used. If that's unset too, you get an in-process default โœจ.
  • -fmodule-only โ€” ๐ŸŒธ Only emits the Compiled Module Interface, and blocks any object file from being made ๐Ÿ™…โ€โ™€๏ธ.
  • -fms-extensions โ€” ๐Ÿ‘‘ Turns off Wpedantic warnings about constructs used in MFC, like implicit int and grabbing a pointer to a member function with non-standard syntax. It's giving legacy codebase energy ๐Ÿ’….
  • -fnew-inheriting-ctors โ€” ๐ŸŒŸ Enables the P0136 adjustment to the semantics of C++11 constructor inheritance. It's part of C++17, but it's also considered a Defect Report against C++11 and C++14. This flag is on by default, unless you specify -fabi-version=10 or lower ๐ŸŽ€.
  • -fnew-ttp-matching โ€” ๐Ÿ’– Enables the P0522 resolution to Core issue 150. This covers template template parameters and default arguments, and it lets a template with default template arguments be used as an argument for a template template parameter that has fewer template parameters. This flag is on by default for -std=c++17 โœจ.
  • -fno-nonansi-builtins โ€” ๐Ÿงน Disables built-in declarations of functions that aren't mandated by ANSI/ISO C. That includes ffs, alloca, _exit, index, bzero, conjf, and other related functions ๐Ÿ™ˆ.
  • -fnothrow-opt โ€” ๐Ÿญ Treats a throw() exception specification as if it were a noexcept specification. This can reduce or eliminate 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 can actually make the function smaller, because the EH cleanups for those variables can be optimized away ๐Ÿง .

The semantic effect is that an exception thrown out of a function with this exception specification results in a call to terminate instead of unexpected ๐Ÿ˜ญ.

  • -fno-operator-names โ€” ๐Ÿฆ‹ Stops the operator name keywords and, bitand, bitor, compl, not, or, and xor from being treated as synonyms for keywords. Bye-bye, operator name vibes ๐Ÿ‘‹.
  • -fno-optional-diags โ€” ๐ŸŒท Disables diagnostics that the standard says a compiler doesn't need to issue. Right now, the only one G++ issues like that is the one for a name that has multiple meanings within a class ๐Ÿคทโ€โ™€๏ธ.
  • -fpermissive โ€” ๐ŸŽ€ Downgrades some diagnostics about nonconformant code from errors to warnings. So using -fpermissive lets some nonconforming code compile. Bold choice, but it's your call ๐Ÿ’….
  • -fno-pretty-templates โ€” ๐Ÿ’… When an error message refers to a specialization of a function template, the compiler normally prints the template's signature, followed by the template arguments and any typedefs or typenames in the signature. For example, you'd see void f(T) [with T = int] instead of void f(int), so it's clear which template is involved ๐Ÿ‘€. When an error message refers to a specialization of a class template, the compiler leaves out any template arguments that match the default template arguments for that template. If either of those behaviors makes the error harder to read instead of easier, you can use -fno-pretty-templates to turn them off ๐Ÿซถ.
  • -fno-rtti โ€” ๐Ÿงƒ Disables generation of information about every class with virtual functions. That info is used by the C++ run-time type identification features (dynamic_cast and typeid). If you don't use those parts of the language, you can save some space with this flag โœจ. Exception handling uses the same information, but G++ generates it only as needed. The dynamic_cast operator can still be used for casts that don't require run-time type information, like casts to void * or to unambiguous base classes ๐Ÿ’–.
โš ๏ธ Mixing code compiled with -frtti and code compiled with -fno-rtti may not work. For example, programs may fail to link if a class compiled with -fno-rtti is used as a base for a class compiled with -frtti ๐Ÿ’€.
  • -fsized-deallocation โ€” ๐Ÿ”ฅ Enables the built-in global declarations below, as 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, say, use the size of the object to make deallocation faster ๐ŸŽ๏ธ. It's enabled by default under -std=c++14 and above. The flag -Wsized-deallocation warns you about places that might want to add a definition ๐Ÿ‘€.

  • -fstrict-enums โ€” ๐Ÿ“ Lets the compiler optimize using the assumption that a value of an enumerated type can only be one of the enumeration's values. (As the C++ standard defines it, that's 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 turn an arbitrary integer value into the enumerated type, so be careful with casts ๐Ÿซฃ.
  • -fstrong-eval-order โ€” ๐Ÿงš Evaluates member access, array subscripting, and shift expressions in left-to-right order, and evaluates assignment in right-to-left order, as adopted for C++17. It's enabled by default with -std=c++17. -fstrong-eval-order=some only enables the ordering of member access and shift expressions, and it's the default without -std=c++17 ๐Ÿฆ‹.
  • -ftemplate-backtrace-limit=n โ€” ๐ŸŒธ Sets the maximum number of template instantiation notes shown for a single warning or error to n. The default is 10 ๐Ÿ“.
  • -ftemplate-depth=n โ€” ๐ŸŒŠ Sets the maximum instantiation depth for template classes to n. You need a limit like this to catch endless recursions during template class instantiation ๐Ÿ”. ANSI/ISO C++ conforming programs must not rely on a maximum depth greater than 17 (which changed to 1024 in C++11). The default is 900, because the compiler can run out of stack space before it hits 1024 in some situations ๐Ÿ˜ญ.
  • -fno-threadsafe-statics โ€” ๐Ÿงต Doesn't emit the extra code that uses the C++ ABI routines for thread-safe initialization of local statics. If your code doesn't need to be thread-safe, this option can shave off a bit of code size ๐Ÿƒ.
  • -fuse-cxa-atexit โ€” ๐ŸŒ… Registers destructors for objects with static storage duration with the __cxa_atexit function, instead of the atexit function. This option is required for fully standards-compliant handling of static destructors.
๐Ÿฅบ It only works if your C library supports __cxa_atexit.
  • -fno-use-cxa-get-exception-ptr โ€” ๐Ÿ™…โ€โ™€๏ธ Doesn't use the __cxa_get_exception_ptr runtime routine. This makes std::uncaught_exception incorrect, but it's necessary if that runtime routine isn't available ๐Ÿ’”.
  • -fvisibility-inlines-hidden โ€” ๐Ÿ”’ Declares that the user doesn't try to compare pointers to inline functions or methods where the addresses of the two functions are taken in different shared objects.
๐Ÿซฃ This is a promise you're making to the compiler, so make sure it's true!

The effect of all this is that GCC can, effectively, mark inline methods with __attribute__ ((visibility ("hidden"))) ๐Ÿซถ So they stay out of the export table of a DSO and don't need a PLT indirection when they're used inside that 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 hard on templates ๐Ÿ˜ญโœจ

This switch doesn't behave exactly like marking the methods as hidden directly ๐Ÿ’€ It doesn't affect static variables local to the function, and it doesn't make the compiler deduce that the function is defined in only one shared object.

You can give a method an explicit visibility to negate the effect of the switch for that method ๐ŸŽ€ For example, if you do want to compare pointers to a particular inline method, you might mark it as having default visibility. Marking the enclosing class with explicit visibility has no effect ๐Ÿ™ˆ

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

  • -fvisibility-ms-compat โ€” This flag tries to use visibility settings to make GCC's C++ linkage model match Microsoft Visual Studio's ๐Ÿ’œ

The flag 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 are permitted when this option is not 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 can end up relying on the Visual Studio behavior, perhaps accidentally ๐Ÿ˜ญ

Among the consequences of these changes: static data members of the same type, with the same name, but defined in different shared objects are different, so changing one doesn't change the other. Pointers to function members defined in different shared objects may also not compare equal. When this flag is given, it's a violation of the ODR (the One Definition Rule) to define types with the same name differently โš ๏ธ

  • -fno-weak โ€” Skip weak symbol support, even if the linker provides it. By default, G++ uses weak symbols if they're available. This option exists only for testing and should not be used by end-users ๐Ÿ™… It results in inferior code and has no benefits. This option may be removed in a future release of G++ ๐Ÿ’€
  • -fext-numeric-literals (C++ and Objective-C++ only) โ€” Accepts imaginary, fixed-point, or machine-defined literal number suffixes as GNU extensions. When this option is turned off, these suffixes are treated as C++11 user-defined literal numeric suffixes. It's on by default for all pre-C++11 dialects and all GNU dialects: -std=c++98, -std=gnu++98, -std=gnu++11, -std=gnu++14. It's off by default for ISO C++11 onwards (-std=c++11, ...) ๐Ÿ“
  • -nostdinc++ โ€” Don't search for header files in the standard directories specific to C++, but still search the other standard directories. (This option is used when building the C++ library ๐Ÿง)
  • -flang-info-include-translate, -flang-info-include-translate-not, -flang-info-include-translate=header โ€” Informs you of include translation events ๐Ÿ‘€ The first one notes accepted include translations, and the second notes declined include translations. The =header form informs you of include translations relating to that specific header. If header is of the form "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 โ€” Informs you of Compiled Module Interface pathnames ๐Ÿ“‚ The first one notes all read CMI pathnames. The =module form will not reading a specific module's CMI. module may be a named module or a header-unit. The latter is indicated by either being a pathname containing directory separators, or by being enclosed in "<>" or "".
  • -stdlib=libstdc++,libc++ โ€” When G++ is configured to support this option, you can pick alternate C++ runtime libraries ๐Ÿ”„ There are two options: 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). The option switches G++ to use the headers from the specified library, and to emit -lstdc++ or -lc++ respectively, when a C++ runtime is required for linking.

On top of that, these warning options only mean something for C++ programs ๐Ÿ’œ

  • -Wabi-tag (C++ and Objective-C++ only) โ€” Warns when a type with an ABI tag is used in a context that doesn't have that ABI tag. See C++ Attributes for more information about ABI tags ๐Ÿท๏ธ
  • -Wcomma-subscript (C++ and Objective-C++ only) โ€” Warns about uses of a comma expression within a subscripting expression. This usage was deprecated in C++20 and is going to be removed in C++23 ๐Ÿ˜ฌ However, a comma expression wrapped in ( ) is not deprecated. Example:
void f(int *a, int b, int c) {
    a[b,c];     // deprecated in C++20, invalid in C++23
    a[(b,c)];   // OK
}

In C++23, it's valid to have comma separated expressions in a subscript when an overloaded subscript operator is found and supports the right number and types of arguments. G++ will accept the formerly valid syntax for code that isn't valid in C++23, but used to be valid (though deprecated) in C++20, with a pedantic warning that can be disabled with -Wno-comma-subscript ๐Ÿ™ƒ

This is enabled by default with -std=c++20 unless -Wno-deprecated is given, and with -std=c++23 regardless of -Wno-deprecated.

  • -Wctad-maybe-unsupported (C++ and Objective-C++ only) โ€” Warns when performing class template argument deduction (CTAD) on a type with no explicitly written deduction guides ๐Ÿ” This warning points out cases where CTAD only succeeded because the compiler synthesized the implicit deduction guides, which might not be what the programmer intended. Certain style guides only allow CTAD on types that specifically "opt-in" (that is, types designed to support CTAD). This warning can be suppressed with the following pattern:
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 neither friends nor public static member functions ๐Ÿ”’ It also warns if there are no non-private methods, and there's at least one private member function that isn't a constructor or destructor.
  • -Wdelete-non-virtual-dtor (C++ and Objective-C++ only) โ€” 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. 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 also flags the implicit declaration as deprecated if the class has a user-provided destructor.
  • -Wno-deprecated-enum-enum-conversion (C++ and Objective-C++ only) โ€” Disables the warning about the case when the usual arithmetic conversions are 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, this warning can be enabled by -Wenum-conversion.

  • -Wno-deprecated-enum-float-conversion (C++ and Objective-C++ only) โ€” Disables the warning about the case when the usual arithmetic conversions are 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, this warning can be enabled by -Wenum-conversion.

  • -Wno-init-list-lifetime (C++ and Objective-C++ only) โ€” Don't warn about uses of std::initializer_list that are likely to result in dangling pointers ๐Ÿซ  The underlying array for an initializer_list is handled like a normal C++ temporary object, so it's super easy to accidentally keep a pointer to the array past the end of its lifetime. For example:
  • If a function returns a temporary initializer_list, or a local initializer_list variable, the array's lifetime ends at the end of the return statement, so the returned value 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 on the heap has a dangling pointer.
  • When an initializer_list variable is assigned from a brace-enclosed initializer list, the temporary array created for the right side of the assignment only lives until the end of the full-expression. So at the next statement, the initializer_list variable has a dangling pointer.
// li's initial underlying array lives as long as li
std::initializer_list<int> li = { 1,2,3 };
// assignment changes li to point to a temporary array
li = { 4, 5 };
// now the temporary is gone and li has a dangling pointer
int i = li.begin()[0] // undefined behavior

Undefined behavior alert, bestie ๐Ÿ’€ Don't let your code hit that last line!

  • When a list constructor stores the "begin" pointer from the "initializer_list" argument, this doesn't extend the lifetime of the array, so if a class variable is constructed from a temporary "initializer_list", the pointer is left dangling by the end of the variable declaration statement. ๐Ÿ’€
  • -Winvalid-imported-macros โ€” okay so this one double-checks that all imported macro definitions are still valid once compilation wraps up โœจ It's not on by default because figuring that out takes extra processing ๐Ÿ™ˆ But it's super handy when you're putting together sets of header-units and need your macros to stay consistent ๐Ÿ’–
  • -Wno-literal-suffix (C++ and Objective-C++ only) โ€” don't warn when a string or character literal is followed by a ud-suffix that doesn't begin with an underscore ๐ŸŽ€ GCC is being nice here. As a conforming extension, it treats those suffixes as separate preprocessing tokens so older code using the 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 gets treated as its own separate preprocessing token. Iconic behavior, honestly ๐Ÿ’…

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 GCC is watching out for that ๐Ÿ‘€

These warnings are enabled by default โœ…

  • -Wno-narrowing (C++ and Objective-C++ only) โ€” for C++11 and later, narrowing conversions get diagnosed by default, just like the standard requires ๐Ÿ“ A narrowing conversion from a constant gives an error, and a narrowing conversion from a non-constant gives a warning. This flag suppresses that diagnostic ๐Ÿ™…โ€โ™€๏ธ Just know it doesn't change the meaning of well-formed code, and narrowing conversions are still ill-formed in SFINAE contexts, so don't get too comfy ๐Ÿ˜ค

With -Wnarrowing in C++98, GCC warns when a narrowing conversion that C++11 prohibits happens inside { }, for example:

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 (throw() or noexcept), even though the compiler knows it never actually 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 ๐Ÿ”ฅ It's enabled by -Wabi and -Wc++17-compat. Here's the plot twist:
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>. The noexcept sneaks right into the type ๐Ÿซฃ

  • -Wclass-memaccess (C++ and Objective-C++ only) โ€” warns when the destination of a call to a raw memory function such as memset or memcpy is an object of class type, and writing into that object might bypass a non-trivial or deleted constructor or copy assignment, break const-correctness or encapsulation, or corrupt virtual table pointers ๐Ÿ’” Messing with the representation of these objects can break invariants that the class's member functions rely on. For example, this memset is undefined because it modifies a non-trivial class object, so GCC flags it:
std::string str = "abc";
memset (&str, 0, sizeof str);

The safe move is to initialize or clear these objects using the appropriate constructor or assignment operator, if one is available ๐Ÿซถ The -Wclass-memaccess option is enabled by -Wall. And if you explicitly cast the pointer to the class object to void *, or to a type that the raw memory function can safely access, the warning goes quiet ๐Ÿคซ

  • -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 itself or its 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 ๐Ÿ™ƒ The register keyword 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 must actually 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 about it. 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 ๐Ÿ™…โ€โ™€๏ธ A typical scenario where copy elision can happen is returning from a function with a class return type, when the expression being returned is the name of a non-volatile automatic object, that object is not a function parameter, and it has the same type as the function's return type. Like this:
struct T {
...
};
T fn()
{
  T t;
  ...
  return std::move (t);
}

But in this example, the std::move call is what blocks copy elision, so the vibe is off ๐Ÿ“ฆ This warning is enabled by -Wall.

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

Here, the std::move call is redundant, no cap ๐Ÿ™…โ€โ™€๏ธ Because G++ implements Core Issue 1579, here's another example:

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 expression being returned and the function's return type differ. Even so, G++ treats the return value as if it were designated by an rvalue anyway ๐ŸŒ€

This warning is enabled by -Wextra ๐Ÿงก

  • -Wrange-loop-construct (C++ and Objective-C++ only) โ€” warns when a C++ range-based for-loop is making an unnecessary copy ๐Ÿ›๏ธ This can happen when the range declaration isn't a reference, but 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 goes off when a loop variable in a range-based for-loop is initialized with a value of a different type, resulting in 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 & gets 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:

struct foo;
void foo ();   // "hides" struct foo
void bar (struct foo&);  // no warning, keyword struct is necessary

Here the function foo hides the struct, so the struct keyword is actually needed ๐Ÿง 

  • -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. GCC doesn't warn 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 the following 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 ๐ŸŒˆ


Okay so when you turn this one on, bestie, heads up ๐Ÿ’…: the standard library headers don't follow all of these guidelines, so they'll throw warnings too. Use grep -v to filter those out ๐Ÿซถ

  • -Wno-exceptions (C++ and Objective-C++ only) โ€” Silences the warning for when one exception handler is shadowed by another one ๐Ÿ™ˆ. It can be a sign that your exception handlers are in the wrong order.
  • -Wstrict-null-sentinel (C++ and Objective-C++ only) โ€” Warns you about using an uncasted NULL as a sentinel ๐Ÿ‘€. If you're only compiling with GCC, it actually works, since NULL is defined as __null. It's a null pointer constant rather than a null pointer, but it's guaranteed to be the same size as a pointer. Just know this isn't portable across different compilers, so it's not it ๐Ÿ’€.
  • -Wno-non-template-friend (C++ and Objective-C++ only) โ€” Turns off warnings for non-template friend functions declared inside a template ๐Ÿฆ‹. Super old GCC versions, from before the ISO standard existed, could read something like friend int foo(int) as a specific template specialization, when the name of the friend is an unqualified-id. This warning exists to catch those compatibility problems, and it's on by default.
  • -Wold-style-cast (C++ and Objective-C++ only) โ€” Warns you when a C-style cast to a non-void type shows up in a C++ program ๐ŸŽ€. The new-style casts (dynamic_cast, static_cast, reinterpret_cast, and const_cast) are way less vulnerable to unintended effects and much easier to search for, so they're the move โœจ.
  • -Woverloaded-virtual (C++ and Objective-C++ only) โ€” Warns when a function declaration hides virtual functions from a base class ๐Ÿ˜ญ. Check out this drama:
struct A {
  virtual void f();
};

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

The A class version of f gets 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 into 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, instead of a conversion to an unsigned type of the same size ๐Ÿงš. Older G++ versions tried to keep the unsignedness, but the standard requires the current behavior, so this is just how it is.
  • -Wtemplates (C++ and Objective-C++ only) โ€” Warns when a primary template declaration shows up ๐ŸŒˆ. Some coding rules ban templates, and this option can help enforce that rule. It's inactive inside system header files, like the STL, so you can still use the STL ๐Ÿ’–. You're also still allowed to instantiate or specialize templates.
  • -Wmismatched-new-delete (C++ and Objective-C++ only) โ€” Warns about mismatches between calls to operator new or operator delete and the matching allocation or deallocation function ๐Ÿ”ฅ. That covers C++ operator delete being called on pointers that came from mismatched forms of operator new, or from other functions that allocate objects where operator delete isn't a suitable deallocator. It also covers other deallocation functions being called on pointers from operator new when that deallocation function isn't suitable.

In the function below, the delete expression gets flagged because it doesn't match the array form of the new expression that the pointer came from. The call to free 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 included in -Wall.

  • -Wmismatched-tags (C++ and Objective-C++ only) โ€” Warns when you declare structs, classes, or class templates (and their specializations) with a class-key that doesn't match the definition, or the first declaration if there's no definition ๐ŸŽ€. In the example below, the struct Object in the argument list of draw triggers the warning. To avoid it, either drop the redundant struct class-key or swap it for class to match the definition:
class Object {
public:
  virtual ~Object () = 0;
};
void draw (struct Object*);

Using the struct class-key here isn't wrong, and this option is really about keeping your class declarations stylistically consistent ๐Ÿซถ. If you're writing code that's meant to be portable to Windows-based compilers, the warning helps stop unresolved references, since symbols declared with different class-keys get mangled differently. You can use this option on its own or alongside -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, and this can enforce that. It's inactive inside system header files, like the STL, so the STL is still good to go. You can also define classes that indirectly use multiple inheritance.
  • -Wvirtual-inheritance โ€” Warns when a class is defined with a virtual direct base class ๐Ÿฆ‹. Some coding rules ban multiple inheritance, and this can help enforce that rule. It's inactive inside system header files, like the STL, so you can still use the STL. You can also define classes that indirectly use virtual inheritance.
  • -Wno-virtual-move-assign โ€” Suppresses warnings about inheriting from a virtual base that has a non-trivial C++11 move assignment operator ๐Ÿ™ƒ. This one is dangerous ๐Ÿšจ. If the virtual base can be reached along more than one path, it gets moved multiple times, which can leave both objects in the moved-from state. If your move assignment operator is written to avoid moving from an already moved-from object, you can safely disable this warning.
  • -Wnamespaces โ€” Warns when a namespace definition is opened ๐ŸŒธ. Some coding rules ban namespaces, and this helps enforce that. It's inactive inside system header files, like the STL, so the STL is still fair game. You can also use using directives and qualified names.
  • -Wno-terminate (C++ and Objective-C++ only) โ€” Turns off 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, which is a syntactic ambiguity in C++ ๐Ÿ™ˆ. 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 will suggest ways to deal with the ambiguity, for example, removing the parentheses or using braces instead โœจ. This warning is enabled by default.

  • -Wno-class-conversion (C++ and Objective-C++ only) โ€” Stops the warning for when a conversion function converts an object to the same type, to a base class of that type, or to void ๐Ÿงš. These conversion functions will never be called, so the warning doesn't really help you here.
  • -Wvolatile (C++ and Objective-C++ only) โ€” Warns about deprecated uses of the volatile qualifier ๐Ÿ˜ญ. That includes postfix and prefix ++ and -- expressions on volatile-qualified types, simple assignments where the left operand is a volatile-qualified non-class type (for their value), and compound assignments where the left operand is a volatile-qualified non-class type. It also covers volatile-qualified function return types, volatile-qualified parameter types, and structured bindings of a volatile-qualified type. This usage was deprecated in C++20.

This is 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 useful for making the switch 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 ๐Ÿ˜ณ. One example is constructing an object in a buffer that's smaller than the object's type. 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 for -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]();

Okay so, level 2 of -Wplacement-new=2 is where it gets spicy ๐ŸŒถ๏ธ On top of everything level 1 catches, GCC also flags placement new expressions that build an object in the last member of a struct whose array has just one element, when that member's size is smaller than the object being built ๐Ÿ˜ญ The previous example would get flagged, but the flexible array member extension lets you dodge 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) โ€” Bestie, this one warns you when a catch handler doesn't catch by reference ๐Ÿซถ With -Wcatch-value=1 (or just -Wcatch-value), you get warned about polymorphic class types that get caught by value. -Wcatch-value=2 extends that to every class type caught by value, and -Wcatch-value=3 goes further and warns about all types that aren't caught by reference ๐Ÿ’… -Wcatch-value is turned on by -Wall, so you're already covered ๐ŸŽ€
  • -Wconditionally-supported (C++ and Objective-C++ only) โ€” Warns you about conditionally-supported constructs, as defined by C++11 [intro.defs] ๐Ÿงš
  • -Wno-delete-incomplete (C++ and Objective-C++ only) โ€” Turns off the warning for deleting a pointer to an incomplete type. That can cause undefined behavior at runtime ๐Ÿ’€ This warning is on by default, so this flag is how you silence it ๐Ÿ™ˆ
  • -Wextra-semi (C++, Objective-C++ only) โ€” Catches redundant semicolons after in-class function definitions ๐Ÿ“
  • -Wno-inaccessible-base (C++, Objective-C++ only) โ€” Controls the warning for when a base class can't be reached from a derived class because of ambiguity. It's on by default โœจ The warning for ambiguous virtual bases is actually turned on by -Wextra, not by this one ๐ŸŒˆ Check out this drama:
struct A { int a; };

struct B : A { };

struct C : B, A { };
  • -Wno-inherited-variadic-ctor โ€” Hushes the warnings about C++11 inheriting constructors when the base class has a C variadic constructor. This warning is on by default because the ellipsis doesn't get inherited ๐ŸŒธ
  • -Wno-invalid-offsetof (C++ and Objective-C++ only) โ€” Mutes warnings for using the offsetof macro on a non-POD type. The 2014 ISO C++ standard says that's undefined when the type isn't standard-layout ๐Ÿ˜ฌ In real C++ implementations, offsetof usually still gives you meaningful results, so this flag is for people who know their code isn't portable and have decided to ignore the warning on purpose ๐Ÿ’œ The rules around offsetof might get relaxed in a future version of the C++ standard, so keep an eye out โญ
  • -Wsized-deallocation (C++ and Objective-C++ only) โ€” Warns when you define an unsized deallocation function without the matching sized one, or the other way around. Here's the unsized pair:
void operator delete (void *) noexcept;
void operator delete[] (void *) noexcept;

And here's the sized pair:

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

This is turned on by -Wextra along with -fsized-deallocation ๐Ÿ”ฅ

  • -Wsuggest-final-types โ€” Warns about types with virtual methods where the code would be better if the type were declared final in C++11, or, if that's possible, declared inside an anonymous namespace ๐Ÿ‘‘ That lets GCC devirtualize polymorphic calls more aggressively. It works best with link-time optimization, since that gives the compiler a more complete picture of the class hierarchy ๐Ÿฆ‹
  • -Wsuggest-final-methods โ€” Warns about virtual methods that would benefit from the C++11 final specifier, or, if possible, from having their type declared in an anonymous namespace or with final ๐Ÿ’… Like the one above, this is more useful with link-time optimization, when the class hierarchy graph is more complete. The recommended move is to look at the -Wsuggest-final-types suggestions first, then rebuild with the new annotations ๐Ÿซถ
  • -Wsuggest-override โ€” Warns when you override virtual functions without marking them with the override keyword ๐ŸŽ€
  • -Wuse-after-free, -Wuse-after-free=n โ€” Warns about uses of pointers to dynamically allocated objects that a deallocation function has made indeterminate ๐Ÿ˜ญ It's enabled at every optimization level, but the results can differ between optimized and unoptimized builds ๐ŸŒˆ
    • -Wuse-after-free=1 โ€” At level 1, the warning only tries to catch unconditional uses of pointers that a deallocation call or a successful realloc has made indeterminate. That's true whether or not the call actually moved the memory ๐Ÿงš It includes double free calls and uses in arithmetic and relational expressions. Uses of indeterminate pointers in equality (or inequality) expressions aren't diagnosed at this level, even though they're still undefined ๐Ÿ™ˆ
    • -Wuse-after-free=2 โ€” At level 2, the warning also catches conditional uses of pointers made indeterminate by a deallocation call, on top of the unconditional ones. Equality (or inequality) expressions still aren't diagnosed here either ๐Ÿ’€ In this function, the second free is the one that gets flagged at this level:
struct A { int refcount; void *data; };

void release (struct A *p)
{
  int refcount = --p->refcount;
  free (p);
  if (refcount == 0)
    free (p->data);   // warning: p may be used after free
}
  • -Wuse-after-free=3 โ€” At level 3, the warning also catches uses of indeterminate pointers in equality expressions ๐Ÿ“ Every use of an indeterminate pointer is undefined, but equality tests sometimes show up after realloc calls, as a way to check whether the object got moved to a new address ๐Ÿ‘€ Those get their own level so legacy code can move over to safe alternatives gradually. In the function below, the equality test is the one flagged at this level:
void adjust_pointers (int**, int);

void grow (int **p, int n)
{
  int **q = (int**)realloc (p, n *= 2);
  if (q == p)
    return;
  adjust_pointers ((int**)q, n);
}

To dodge the warning at this level, store offsets into the allocated memory instead of raw pointers. That way you never have to fix up stored pointers after a reallocation โœจ

-Wuse-after-free=2 is included in -Wall ๐Ÿ’–

  • -Wuseless-cast (C++ and Objective-C++ only) โ€” Warns when an expression gets cast to its own type. Totally pointless, honestly ๐Ÿ’…
  • -Wno-conversion-null (C++ and Objective-C++ only) โ€” Doesn't warn about conversions between NULL and non-pointer types. -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 ๐Ÿ™ˆ

This section is all 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, you might compile a file called some_class.m like this:

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

Here, -fgnu-runtime only applies to Objective-C and Objective-C++ programs. You can use the other options with any language GCC supports ๐ŸŒˆ

Since Objective-C is an extension of C, Objective-C compilations can also use options specific to the C front end (like -Wtraditional). Likewise, Objective-C++ compilations 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 โ€” Uses class-name as the class to instantiate for each literal string written as @"...". The default class name is NXConstantString when the GNU runtime is in use, and NSConstantString when the NeXT runtime is in use (see below) ๐ŸŽ€ If -fconstant-cfstrings is also present, it overrides -fconstant-string-class and makes @"..." literals get laid out as constant CoreFoundation strings โœจ
  • -fgnu-runtime โ€” Generates object code that's compatible with the standard GNU Objective-C runtime. This is the default on most systems ๐Ÿฆ‹
  • -fnext-runtime โ€” Generates output compatible with the NeXT runtime. This is the default on NeXT-based systems, including Darwin and Mac OS X ๐ŸŽ When this option is used, the macro __NEXT_RUNTIME__ is predefined, and only then ๐Ÿซถ
  • -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 option only works together with the NeXT runtime and ABI version 0 or 1 โญ
  • -fobjc-abi-version=n โ€” Uses version n of the Objective-C ABI for the selected runtime. Right now this is only supported for the NeXT runtime ๐ŸŒธ In that case, version 0 is the traditional (32-bit) ABI without support for properties or other Objective-C 2.0 additions. Version 1 is the traditional (32-bit) ABI with support for 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 โ€” okay so this one is giving main character energy ๐Ÿ’… For every Objective-C class, GCC checks whether any instance variable is a C++ object with a non-trivial default constructor. If one is, it synthesizes a special - (id) .cxx_construct instance method that runs those constructors on the instance variables, in order, then returns self. It does the same check for destructors. If an instance variable is a C++ object with a non-trivial destructor, it synthesizes - (void) .cxx_destruct, which runs all those default destructors in reverse order ๐Ÿ”ฅ
    • The - (id) .cxx_construct and - (void) .cxx_destruct methods it generates only handle instance variables declared in the current Objective-C class. Anything inherited from superclasses is not included ๐Ÿ™…โ€โ™€๏ธ
    • It's the Objective-C runtime's job to call all of these methods throughout an object's inheritance hierarchy.
    • The runtime invokes - (id) .cxx_construct immediately after a new object instance is allocated, and it invokes - (void) .cxx_destruct immediately before it deallocates an object instance.
    • As of this writing, only the NeXT runtime on Mac OS X 10.4 and later can actually invoke - (id) .cxx_construct and - (void) .cxx_destruct ๐Ÿ™ˆ
  • -fobjc-direct-dispatch โ€” lowkey a speed boost โœจ It lets the compiler take fast jumps straight to the message dispatcher. On Darwin, this is handled through the comm page ๐Ÿฆ‹
  • -fobjc-exceptions โ€” bestie, this one unlocks structured exception handling in Objective-C, kind of like what C++ has ๐ŸŽ€ You need it 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 โ€” this turns on garbage collection (GC) for Objective-C and Objective-C++ programs ๐Ÿงน It's only available with the NeXT runtime. The GNU runtime has its own, different garbage collection setup that doesn't need any special compiler flags, so no cap, you don't need this one there ๐ŸŒˆ
  • -fobjc-nilcheck โ€” for the NeXT runtime with version 2 of the ABI, this checks for a nil receiver in method invocations before the actual method call happens โœจ It's 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 โ€” this makes you conform to the syntax of Objective-C 1.0, the language GCC 4.0 understood ๐Ÿ“ It only affects 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 the Objective-C or Objective-C++ compiler, any Objective-C syntax GCC 4.0 wouldn't recognize gets rejected. This is super useful if you need to be sure your Objective-C code still compiles with older versions of GCC ๐Ÿ‘‘
  • -freplace-objc-classes โ€” this emits a special marker that tells ld(1) not to statically link the resulting object file in, and lets dyld(1) load it at run time instead ๐Ÿงš It's paired with the Fix-and-Continue debugging mode, where the object file might get recompiled and dynamically reloaded while the program is running, so you don't have to restart the whole thing ๐Ÿ” 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, GCC normally swaps calls to objc_getClass("...") (when the class name is known at compile time) for static class references that get set up at load time, which is faster โšก This flag stops that and keeps the objc_getClass("...") calls around. It's useful in Zero-Link debugging mode, since it lets you modify individual class implementations while the program runs ๐Ÿซถ The GNU runtime always keeps calls to objc_get_class("...") no matter which command-line options you use ๐Ÿคทโ€โ™€๏ธ
  • -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, whether they're declared locally in a class method or globally with the same name ๐Ÿ˜ญ Using -fno-local-ivars turns that behavior off, so you avoid the shadowing drama ๐Ÿซ 
  • -fivar-visibility=[public|protected|private|package] โ€” this sets the default instance variable visibility to whichever option you pick ๐ŸŒธ Instance variables declared outside the scope of any access modifier directive then default to that visibility.
  • -gen-decls โ€” this dumps interface declarations for every class seen in the source file into a file named sourcename.decl ๐Ÿ“
  • -Wassign-intercept (Objective-C and Objective-C++ only) โ€” warns you whenever an Objective-C assignment is getting intercepted by the garbage collector ๐Ÿšจ
  • -Wno-property-assign-default (Objective-C and Objective-C++ only) โ€” this stops the warning you'd get when a property for an Objective-C object has no assign semantics specified ๐Ÿ™ˆ
  • -Wno-protocol (Objective-C and Objective-C++ only) โ€” okay so if a class says it implements a protocol, you normally get a warning for every method in that protocol the class doesn't implement. By default, you also get a warning for methods that aren't explicitly implemented in the class, even when the implementation is inherited from the superclass. With -Wno-protocol, inherited methods count as implemented, and no warning is issued for them ๐Ÿซถ
  • -Wobjc-root-class (Objective-C and Objective-C++ only) โ€” warns if a class interface doesn't have a superclass. Most classes inherit from NSObject (or Object), for example ๐ŸŒณ If you're making a class that's meant to be a root class, you can silence 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 for the same selector show up during compilation ๐Ÿ” It also checks each selector that appears in a @selector(...) expression, and warns if a matching method for that selector was found during compilation. These checks scan the method table only at the very end of compilation, so the warnings won't show up if the final stage never gets reached. That happens if an error stops compilation partway, or if you're using -fsyntax-only ๐Ÿฅฒ
  • -Wstrict-selector-match (Objective-C and Objective-C++ only) โ€” warns if multiple methods with different argument and/or return types exist for a selector when you're sending a message with it to a receiver of type id or Class ๐Ÿ‘€ This flag is off by default. With it off, the compiler skips these warnings when the differences are confined to types that have the same size and alignment ๐Ÿ’…
  • -Wundeclared-selector (Objective-C and Objective-C++ only) โ€” warns if 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 as soon as it finds a @selector(...) expression, while -Wselector only checks in the final stage of compilation. 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

Okay, this section is all about how your error messages look ๐ŸŽ€ Traditionally, diagnostic messages were formatted without caring about the output device (its width and stuff). With the options below, you can control the formatting algorithm, like how many characters go on a line or how often source location info gets reported. Heads up that 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 every error message stays on one line. This is the default for all front ends.
Note: this option also affects how #error and #warning pre-processor directives display, plus the deprecated function/type/variable attribute. It does NOT 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 utilities that parse diagnostics output and need it to stay more stable over time. Right now, -fdiagnostics-plain-output is equivalent to: -fno-diagnostics-show-caret -fno-diagnostics-show-line-numbers -fdiagnostics-color=never -fdiagnostics-urls=never -fdiagnostics-path-format=separate-events. If GCC ever 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 diagnostic reporter to emit source location info once. So if a message is too long for one physical line and gets wrapped, the source location isn't repeated as a prefix on every continuation line. This is the default behavior โœจ
  • -fdiagnostics-show-location=every-line โ€” also only matters in line-wrapping mode ๐ŸŒˆ This one tells the diagnostic reporter to emit the same source location info as a prefix on every physical line that results from breaking up a message that's too long to fit on a single line ๐Ÿซถ
  • -fdiagnostics-color[=WHEN], -fno-diagnostics-color โ€” okay bestie, this one is all about color ๐ŸŒˆ WHEN can be never, always, or auto. The default depends on how your compiler was set up ๐Ÿ’…. It can be any of those WHEN options, or never if the GCC_COLORS environment variable isn't present in the environment, and auto otherwise. auto only lets GCC get colorful when standard error is a terminal and it's not running in an emacs shell ๐Ÿ™ˆ. -fdiagnostics-color and -fno-diagnostics-color are just shortcuts for -fdiagnostics-color=always and -fdiagnostics-color=never, respectively โœจ.

The colors are controlled by the environment variable GCC_COLORS ๐ŸŽ€. Its value is a colon-separated list of capabilities and Select Graphic Rendition (SGR) substrings. The terminal or terminal emulator is the one that actually interprets SGR commands (check the section in your text terminal's docs for the permitted values and what they mean as character attributes ๐Ÿ“–). These substring values are decimal integers that can be concatenated with semicolons. Common values to concatenate include:

  • 1 for bold
  • 4 for underline
  • 5 for blink
  • 7 for inverse
  • 39 for default foreground color
  • 30 to 37 for foreground colors
  • 90 to 97 for 16-color mode foreground colors
  • 38;5;0 to 38;5;255 for 88-color and 256-color modes foreground colors
  • 49 for default background color
  • 40 to 47 for background colors
  • 100 to 107 for 16-color mode background colors
  • 48;5;0 to 48;5;255 for 88-color and 256-color modes background colors

The default GCC_COLORS is:

error=01;31:warning=01;35:note=01;36:range1=32:range2=34:locus=01:\
quote=01: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 ๐Ÿ™…โ€โ™€๏ธ. These are the supported capabilities:

  • "error=" โ€” SGR substring for error: markers.
  • "warning=" โ€” SGR substring for warning: markers.
  • "note=" โ€” SGR substring for note: markers.
  • "path=" โ€” SGR substring for coloring 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=" โ€” SGR substring for the first additional range.
  • "range2=" โ€” SGR substring for the second additional range.
  • "locus=" โ€” SGR substring for location info, like file:line or file:line:column etc.
  • "quote=" โ€” SGR substring for info printed within quotes.
  • "fixit-insert=" โ€” SGR substring for fix-it hints suggesting text to be inserted or replaced.
  • "fixit-delete=" โ€” SGR substring for fix-it hints suggesting text to be deleted.
  • "diff-filename=" โ€” SGR substring for filename headers within generated patches.
  • "diff-hunk=" โ€” SGR substring for the starts of hunks within generated patches.
  • "diff-delete=" โ€” SGR substring for deleted lines within generated patches.
  • "diff-insert=" โ€” SGR substring for inserted lines within generated patches.
  • "type-diff=" โ€” SGR substring for highlighting mismatching types within template arguments in the C++ frontend.
  • -fdiagnostics-urls[=WHEN] โ€” okay this one is so cute ๐Ÿฆ‹. It uses escape sequences to embed URLs in diagnostics. For example, when -fdiagnostics-show-option prints the text showing the command-line option that controls a diagnostic, it can embed 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 in any graphical terminal known to be incompatible with this feature (see below) ๐Ÿ™ˆ.

The default depends on how the compiler was configured, and 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 setup, GCC defaults to auto if either the GCC_URLS or TERM_URLS environment variables are present and non-empty in the compiler's environment, or to never if neither is.

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 is not set, TERM_URLS is used as a fallback. Note: ST is an ANSI escape sequence with the string terminator ESC \, and BEL is an ASCII character, CTRL-G, that usually sounds like a beep ๐Ÿ””.

GCC tries to detect a few terminals that are known to not implement the URL feature, and that have bugs (or at least had bugs in some versions still in use) where URL escapes are likely to misbehave, i.e., print garbage on the screen ๐Ÿ’€. That list is currently xfce4-terminal, certain known buggy gnome-terminal versions, the linux console, and mingw. This check can be skipped with -fdiagnostics-urls=always.


  • -fno-diagnostics-show-option โ€” by default, each diagnostic emitted includes text indicating the command-line option that directly controls it (if that option is known to the diagnostic machinery) ๐Ÿ”. Specifying -fno-diagnostics-show-option suppresses that behavior.
  • -fno-diagnostics-show-caret โ€” by default, each diagnostic includes the original source line and a caret ^ pointing at the column ๐ŸŽฏ. This option suppresses that info. If -fmessage-length=n is given, the source line is truncated to n characters. When the output goes to the terminal, the width is limited to the width given by the COLUMNS environment variable or, if it's not set, to the terminal width ๐Ÿ“.
  • -fno-diagnostics-show-labels โ€” by default, when printing source code (via -fdiagnostics-show-caret), diagnostics can label ranges of source code with pertinent info, like the types of expressions ๐Ÿท๏ธ:
printf ("foo %s bar", long_i + long_j);
             ~^       ~~~~~~~~~~~~~~~
              |              |
              char *         long int

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

  • -fno-diagnostics-show-cwe โ€” diagnostic messages can optionally have an associated CWE identifier (https://cwe.mitre.org/index.html) ๐Ÿงพ. GCC itself only provides this metadata for some of the -fanalyzer diagnostics. GCC plugins may also provide diagnostics with this metadata. By default, if this info is present, it gets printed with the diagnostic. This option suppresses the printing of this metadata.
  • -fno-diagnostics-show-line-numbers โ€” by default, when printing source code (via -fdiagnostics-show-caret), a left margin is printed showing line numbers ๐Ÿ”ข. This option suppresses that left margin.
  • -fdiagnostics-minimum-margin-width=width โ€” this one controls the minimum width of the left margin printed by -fdiagnostics-show-line-numbers ๐Ÿ“. It defaults to 6.
  • -fdiagnostics-parseable-fixits โ€” emits fix-it hints in a machine-parseable format, perfect for IDEs ๐Ÿค–. For each fix-it, a line gets printed after the relevant diagnostic, starting with the string "fix-it:". For example:
fix-it:"test.c":{45:3-45:21}:"gtk_widget_show_all"

The location is written as a half-open range, expressed as a count of bytes, starting at byte 1 for the initial column. In the example above, bytes 3 through 20 of line 45 of "test.c" are 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 printing diagnostics that show mismatching template types, like this ๐ŸŒณ:
could not convert 'std::map<int, std::vector<double> >()'
  from 'map<[...],vector<double>>' to 'map<[...],vector<float>>

the -fdiagnostics-show-template-tree flag enables printing a tree-like structure showing the common and differing parts of the types, like this:

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

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

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

Specifying the -fno-elide-type flag suppresses that behavior ๐Ÿ™…โ€โ™€๏ธ. This flag also affects the output of the -fdiagnostics-show-template-tree flag ๐Ÿ’….

  • -fdiagnostics-path-format=KIND โ€” okay so this one decides how the control-flow paths for diagnostics get shown ๐Ÿ›ค๏ธ (only for diagnostics that actually have a path attached, obvi) โœจ

KIND can be none, separate-events, or inline-events, and inline-events is the default ๐Ÿ’…

none means no diagnostic paths get printed at all, bestie ๐Ÿ™ˆ

separate-events gives every event its own "note" diagnostic. It looks like this ๐ŸŽ€:

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 prints the events right inside the source code ๐Ÿง. It tries to squish together events that are close enough to each other into runs and shows them as labelled ranges. Same events as above, but served inline:

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

When the path hops between functions (that's interprocedural control flow ๐Ÿง ), the events get grouped by stack frame, and the indentation shows how frames get nested, pushed, and popped. 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 โ€” this one adds extra info to the control-flow paths attached to a diagnostic ๐Ÿ”

If this option is provided, the stack depth gets printed for each run of events inside -fdiagnostics-path-format=separate-events. It's mainly for GCC developers and plugin developers who are debugging diagnostics that report interprocedural control flow, so unless you're in that headspace, it's not really your moment ๐Ÿ’œ

  • -fno-show-column โ€” no column numbers in diagnostics, bestie ๐Ÿ™…โ€โ™€๏ธ

This can be necessary if the diagnostics are being scanned by a program that doesn't understand column numbers, such as dejagnu. Lowkey a lifesaver for those tools ๐Ÿซถ

  • -fdiagnostics-column-unit=UNIT โ€” picks the units for the column number ๐Ÿ“. This affects traditional diagnostics (as long as -fno-show-column isn't in play) and also JSON format diagnostics if you've asked for them.

The default UNIT, display, counts how many display columns each character takes up ๐Ÿ’…. That can be bigger than the number of bytes needed to encode the character (hello, tab characters ๐Ÿ™ƒ), or smaller (hello, multibyte characters ๐ŸŒˆ). For example, "GREEK SMALL LETTER PI (U+03C0)" takes up one display column but needs two bytes in UTF-8, while "SLIGHTLY SMILING FACE (U+1F642)" takes up two display columns and needs four bytes in UTF-8.

Setting UNIT to byte makes the column number the raw byte count in all cases, which is how GCC used to output it before version 11.1.0 ๐Ÿ•ฐ๏ธ

  • -fdiagnostics-column-origin=ORIGIN โ€” decides which number the first column gets 1๏ธโƒฃ. The default value of 1 matches traditional GCC behaviour and the GNU style guide, so it's the vibe ๐ŸŒธ. Some utilities might work better with an origin of 0, and any non-negative value is allowed ๐Ÿงš
  • -fdiagnostics-escape-format=FORMAT โ€” how weird bytes get shown when GCC prints the source lines for a diagnostic ๐Ÿ”ค.

Normally GCC just prints the source bytes straight up. But some diagnostics are about encoding problems in the source file, like malformed UTF-8 or Unicode normalization issues. Those get flagged, so GCC escapes any bytes that aren't printable ASCII when it prints their source lines. This option controls how those bytes get escaped ๐Ÿซ .

The default FORMAT, unicode, shows non-printable-ASCII Unicode characters as <U+XXXX>, and bytes that aren't a valid UTF-8 encoded Unicode character get shown as hexadecimal in the form <XX> ๐Ÿ“. For example, a source line with the string before, then the Unicode character U+03C0 ("GREEK SMALL LETTER PI", UTF-8 encoding 0xCF 0x80), then the stray byte 0xBF (a UTF-8 trailing byte), then the string after, would be printed for such a diagnostic as:

before<U+03C0><BF>after

Setting FORMAT to bytes shows every non-printable-ASCII byte as <XX>, so you can see the underlying encoding of non-ASCII Unicode characters ๐Ÿ‘€. For the example above, this would print:

before<CF><80><BF>after
  • -fdiagnostics-format=FORMAT โ€” picks a different format for printing diagnostics ๐ŸŽจ. FORMAT is text or json, and the default is text.

The json format is a top-level JSON array full of JSON objects, each one representing a diagnostic ๐Ÿ’–. It's emitted as one line with zero formatting, so the examples below have been spruced up for clarity โœจ.

Diagnostics can have child diagnostics, too ๐Ÿ‘‘. For example, this warning 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 get 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
                        }
                    }
                ],
                "escape-source": false,
                "message": "...this statement, but the latter is ..."
            }
        ]
        "escape-source": false,
        "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, so you can always trace back which flag is responsible ๐Ÿ”ฅ.

A diagnostic can have zero or more locations ๐Ÿฆ‹ and each one can come with an optional "label" string, plus up to three positions: a "caret" position, and optional "start" and "finish" positions. A position is described by a "file" name, a "line" number, and three numbers for the column, which come in three flavors:

  • "display-column" โ€” counts display columns, so tabs and multibyte characters get accounted for ๐Ÿ’…
  • "byte-column" โ€” counts raw bytes ๐ŸŒธ
  • "column" โ€” is equal to one of the previous two, depending on what -fdiagnostics-column-unit says ๐ŸŽ€

All three columns are relative to the origin set by -fdiagnostics-column-origin. That's usually 1, but it can be set to 0 for compatibility with other utilities that number columns from 0 ๐Ÿงš. The column origin gets recorded in the JSON output under the "column-origin" tag. In the examples below, the extra column number outputs are left out to keep things short ๐Ÿ™ˆ

Okay, so take 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}

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

{
    "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}"
        }
    ],
    "escape-source": false,
    "message": "invalid operands to binary + ..."
}

If a diagnostic has fix-it hints, it gets a "fixits" array made of half-open intervals, kind of like the output of -fdiagnostics-parseable-fixits โœจ For example, here's a 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

It might get printed in JSON form like this:

{
    "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
            }
        }
    ],
    "escape-source": false,
    "message": "\u2018struct s\u2019 has no member named ..."
}

So the fix-it hint basically says to swap out the text from "start" up to but not including "next" with the value of "string" ๐Ÿ’– Deletions are shown by an empty value for "string", and insertions are shown by having "start" equal "next".

If the diagnostic has a path of control-flow events attached, it gets a "path" array of event objects. Each event object has a "description" string, a "location" object, a "function" string, and a "depth" number, which is how interprocedural paths get represented ๐ŸŒˆ The "function" is the current function at that event, and the "depth" is the stack depth relative to some baseline. The higher the number, the more frames are on the stack.

For example, the intraprocedural example from -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
        }
    }
]

Diagnostics also have a boolean attribute "escape-source". It's a hint for whether non-ASCII bytes should be escaped when the relevant lines of source code get printed. It's "true" for diagnostics involving source encoding issues ๐Ÿง


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

Warnings are the "hmm, sus" messages of GCC ๐Ÿ‘€ They flag constructions that aren't outright wrong on their own, but that are risky or might mean you goofed somewhere.

These next options don't turn on any specific warnings by themselves. Instead, they control what kinds of diagnostics GCC produces, and they're language-independent ๐Ÿ’…

  • -fsyntax-only โ€” Checks the code for syntax errors, but doesn't do anything beyond that ๐Ÿง 
  • -fmax-errors=n โ€” Limits the maximum number of error messages to n. Once that's hit, GCC bails out instead of trying to keep processing the source code ๐Ÿ›‘ If n is 0 (the default), there's no limit on how many error messages get produced. If -Wfatal-errors is also specified, then -Wfatal-errors takes precedence over this option.
  • -w โ€” Inhibits all warning messages ๐Ÿ™ˆ
  • -Werror โ€” Makes all warnings into errors ๐Ÿ’€
  • -Werror= โ€” Makes the specified warning into an error. You append the warning's specifier, so for example -Werror=switch turns the warnings controlled by -Wswitch into errors. This switch also has a negative form, which negates -Werror for specific warnings. For example, -Wno-error=switch makes -Wswitch warnings not be errors, even when -Werror is in effect ๐Ÿ”ฅ

The warning message for each controllable warning includes the option that controls it. You can use that option with -Werror= and -Wno-error= as described above. (Printing of the option in the warning message can be disabled using the -fno-diagnostics-show-option flag.)

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

  • -Wfatal-errors โ€” Makes the compiler abort compilation on the first error it hits, instead of trying to keep going and printing more error messages ๐Ÿ›‘

You can request many specific warnings with options that begin with -W. For example, -Wimplicit requests warnings on implicit declarations. Each of these specific warning options also has a negative form that begins with -Wno- to turn the warnings off, like -Wno-implicit. This manual only lists one of the two forms, whichever one isn't 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, like -Wunused, which may turn on even more options, like -Wunused-value. The combined effect of positive and negative forms is that more specific options win over less specific ones, no matter where they sit on the command-line. For options of the same specificity, the last one takes effect. Options enabled or disabled via pragmas 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 saying the option isn't recognized. However, if the -Wno- form is used, the behavior is a little 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 will warn that an unrecognized option is present ๐Ÿงš

The warnings below get way more powerful when optimization is on too, bestie ๐Ÿงš For example, -Wsuggest-final-types works better with link-time optimization, and some instances of other warnings won't get issued at all unless optimization is enabled ๐Ÿ’… Optimization in general makes control and data flow sensitive warnings better โœจ but in some cases it can also cause false positives ๐Ÿ’€

-Wpedantic / -pedantic ๐ŸŽ€

Okay, this is the strict ISO C and ISO C++ vibe check ๐Ÿ’… It issues all the warnings that strict ISO C and ISO C++ demand, and it rejects programs that use forbidden extensions, plus some other programs that don't follow ISO C and ISO C++. For ISO C, it follows whichever version of the standard you picked with any -std option.

Valid ISO C and ISO C++ programs should compile properly with or without this option ๐Ÿซถ Though a rare few need -ansi or a -std option that specifies the version of ISO C they require. Without this option, certain GNU extensions and traditional C and C++ features are still supported. With this option, they get rejected ๐Ÿ™…โ€โ™€๏ธ

-Wpedantic doesn't cause warning messages for use of the alternate keywords whose names begin and end with __. That 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__". BUT only system header files should use these escape routes ๐Ÿšจ Application programs should avoid them, no cap.

Some users try to use -Wpedantic to check programs for strict ISO C conformance, and then they're shook ๐Ÿ˜ญ It doesn't do quite what they want. It finds some non-ISO practices, but not all. It only catches the ones ISO C requires a diagnostic for, plus some others that have had diagnostics added.

A feature that reports any failure to conform to ISO C might be useful in some instances, but it would take a ton of extra work and would be super different from -Wpedantic ๐Ÿฅฒ We don't have plans to support something like that in the near future.

Where the standard you specify with -std is a GNU extended dialect of C, such as gnu90 or gnu99, there's a corresponding base standard, which is the version of ISO C that the GNU extended dialect is based on. Warnings from -Wpedantic are given wherever the base standard requires them. It wouldn't make sense to only warn about features that aren't in the specified GNU C dialect, because by definition the GNU dialects include every feature the compiler supports with the given option, so there'd be nothing to warn about ๐Ÿคทโ€โ™€๏ธ

-pedantic-errors ๐Ÿ’€

This one is the upgraded version of the pedantic vibe. It gives an error whenever the base standard (see -Wpedantic) requires a diagnostic. It also errors in some cases where there's undefined behavior at compile-time, and in some other cases that don't stop compilation of programs that are valid according to the standard.

This is NOT the same as -Werror=pedantic, since there are errors enabled by this option that the latter doesn't enable, and vice versa. Don't mix them up, bestie ๐Ÿ™ˆ

-Wall ๐ŸŒˆ

This one turns on all the warnings about constructions that some users consider questionable, and that are easy to avoid (or easy to modify to prevent the warning), even in conjunction with macros. It also enables some language-specific warnings described in C++ Dialect Options and Objective-C and Objective-C++ Dialect Options โœจ

-Wall turns on the following warning flags:

-Waddress -Warray-bounds=1 (only with -O2) -Warray-compare
-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
-Wdangling-pointer=2 -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++) -Wmismatched-dealloc -Wmismatched-new-delete (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 -Wuse-after-free=3 -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 don't consider questionable, but that you might occasionally want to check for. Others warn about constructions that are necessary or hard to avoid in some cases, and there's no simple way to change the code to suppress the warning. Some of them are enabled by -Wextra, but many of them have to be enabled individually ๐Ÿฆ‹

-Wextra ๐ŸŒธ

This one enables some extra warning flags that are NOT enabled by -Wall. (Fun fact: this option used to be called -W. The older name is still supported, but -Wextra is more descriptive, and honestly it's the one I'd use ๐Ÿ’–)

-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++03 and in C99 and newer)
-Wunused-parameter (only with -Wunused or -Wall)
-Wunused-but-set-parameter (only with -Wunused or -Wall)

The option -Wextra also prints warning messages for the following 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 warns about code affected by ABI changes. That includes code that may not be compatible with the vendor-neutral C++ ABI, as well as the psABI for the particular target ๐Ÿงš

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

You can also use -Wabi with 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 an explicit version number is provided and -fabi-compat-version is not specified, the version number from this option is used for compatibility aliases. If no explicit version number is provided with this option, but -fabi-compat-version is specified, that version number is used for C++ ABI warnings.

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

If you're concerned that code generated by G++ may not be binary compatible with code generated by other compilers, you should rewrite your code to avoid 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 was fixed in -fabi-version=3.

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

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

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

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

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

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

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

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

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

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

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

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

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

  • Okay so target-specific attributes that change the identity of a type, like ia32 calling conventions on a function type (stdcall, regparm, etc.), were not affecting the mangled name ๐Ÿ’€. That caused name collisions whenever function pointers got used as template arguments ๐Ÿ˜ญ

This got fixed in -fabi-version=10, which is the default as of 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 get passed in memory the way the psABI specifies ๐Ÿง  Before GCC 4.4 that wasn't happening. For example:
union U {
  long double ld;
  int i;
};

union U is now always passed in memory ๐Ÿ’–

  • -Wchar-subscripts โ€” Heads up ๐Ÿ‘€ this warns when an array subscript has type char. It's a super common mistake because people forget that char is signed on some machines. Enabled by -Wall ๐Ÿ’…
  • -Wno-coverage-mismatch โ€” Warns if feedback profiles don't match when you're using -fprofile-use. If a source file changes between compiling with -fprofile-generate and -fprofile-use, the profile feedback files can fail to match the source, and GCC can't use the feedback info ๐Ÿ˜ฉ This warning is on by default and is treated as an error. You can turn the warning off with -Wno-coverage-mismatch, or turn off just the error with -Wno-error=coverage-mismatch. Skipping the error can lead to poorly optimized code, so it's only worth it for very minor changes like bug fixes to an existing code-base ๐ŸŒธ Totally disabling the warning is not recommended, bestie ๐Ÿ™…โ€โ™€๏ธ
  • -Wno-coverage-invalid-line-number โ€” Warns in case a function ends earlier than it begins because of invalid linenum macros ๐Ÿฆ‹ This warning only shows up with --coverage enabled.

By default this warning is on and is treated as an error. Use -Wno-coverage-invalid-line-number to disable the warning, or -Wno-error=coverage-invalid-line-number to disable just the error โœจ

  • -Wno-cpp (C, Objective-C, C++, Objective-C++ and Fortran only) โ€” Silences the warning messages that come from #warning directives ๐Ÿคซ
  • -Wdouble-promotion (C, C++, Objective-C and Objective-C++ only) โ€” Gives a warning when a float value gets implicitly promoted to double ๐Ÿ‘€ Some CPUs have a 32-bit single-precision floating-point unit that does float in hardware but fakes double in software. On those machines, doing math with double is way more expensive because of all that software emulation overhead ๐Ÿ˜ค

It's really easy to do double math by accident, because floating-point literals are implicitly double. For example:

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

The compiler does the whole calculation in double here, because that floating-point literal is a double ๐Ÿ™ˆ

  • -Wduplicate-decl-specifier (C and Objective-C only) โ€” Warns if a declaration has a duplicate const, volatile, restrict or _Atomic specifier ๐Ÿงน Enabled by -Wall.
  • -Wformat, -Wformat=n โ€” Checks calls to printf and scanf, etc., to make sure the arguments you pass have types that match the format string, and that the conversions in the format string actually make sense ๐ŸŽ€ This covers the standard functions plus anything else tagged with format attributes, in the printf, scanf, strftime and strfmon families (strfmon is an X/Open extension, not part of the C standard), or other target-specific families. Which functions get checked without format attributes depends on the standard version you pick. Those checks are turned off by -ffreestanding or -fno-builtin ๐ŸŒˆ

The formats get 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 won't warn about features that go beyond a particular library's limits ๐Ÿคทโ€โ™€๏ธ BUT if you use -Wpedantic together with -Wformat, you'll get warnings about format features that aren't in the selected standard version (not for strfmon formats, though, since those aren't in any version of the C standard).

  • -Wformat=1, -Wformat โ€” -Wformat is the same as -Wformat=1, and -Wno-format is the same as -Wformat=0 ๐Ÿ’– Since -Wformat also checks for null format arguments in several functions, it also implies -Wnonnull โœจ Some parts of this level of checking can be switched off with -Wno-format-contains-nul, -Wno-format-extra-args, and -Wno-format-zero-length. -Wformat is enabled by -Wall.
  • -Wformat=2 โ€” Enables -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 extra arguments passed to a printf or scanf format function. The C standard says those arguments get ignored, so no biggie ๐Ÿ’…

If the unused arguments sit between used arguments that have $ operand number specifications, warnings still show up, because the implementation couldn't know what type to hand to va_arg to skip the unused ones ๐Ÿค” With scanf formats, though, this option suppresses that warning when all the unused arguments are pointers, since the Single Unix Specification says those unused arguments are allowed ๐Ÿฆ‹

  • -Wformat-overflow, -Wformat-overflow=level โ€” Warns 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, 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 ๐Ÿ™ƒ
    • -Wformat-overflow, -Wformat-overflow=1 โ€” Level 1, which -Wformat turns on, is the cautious option. It only warns about calls that most likely overflow the buffer ๐Ÿงธ At this level, numeric arguments to format directives with unknown values are assumed to be one, and strings of unknown length are assumed to be empty. Numeric arguments known to be bounded to a subrange of their type, or string arguments whose output is bounded by their directive's precision or by a finite set of string literals, are assumed to take whatever value in that range produces the most bytes of output ๐Ÿง 

For example, this sprintf call gets diagnosed, because even when both a and b are zero, the terminating NUL character ('\0') that the function appends to the destination buffer gets written past its end ๐Ÿ’€ Making the buffer one byte bigger is enough to dodge the warning, though it might not be enough to avoid the overflow itself.

void f (int a, int b)
{
  char buf [13];
  sprintf (buf, "a = %i, b = %i\n", a, b);
}
  • -Wformat-overflow=2 โ€” Level 2 warns about calls that might overflow the destination buffer when an argument has a big enough length or magnitude ๐Ÿ“ At level 2, unknown numeric arguments are assumed to be the minimum representable value for signed types with a precision greater than 1, and the maximum representable value otherwise. Unknown string arguments whose length can't be assumed to be bounded (by the directive's precision, by a finite set of string literals they might evaluate to, or by the character array they might point to) are assumed to be 1 character long.

At level 2, the call in the example above gets diagnosed again, but this time it's because with a equal to a 32-bit INT_MIN, the first %i directive will write some of its digits past the end of the destination buffer ๐Ÿ˜ญ To make the call safe no matter what the two variables hold, the destination buffer has to be at least 34 bytes. GCC includes the minimum buffer size in an informational note right after the warning ๐Ÿ“

Instead of making the buffer bigger, you can also limit the range of the formatted values ๐ŸŒธ The maximum length of string arguments can be capped by putting a precision in the format directive. When 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 will shrink the buffer size you need. For example, if a and b in the example above can be assumed to fit in the short int type, then using either the %hi format directive or casting the argument to short brings the maximum required buffer 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 specified, don't warn about zero-length formats. The C standard allows zero-length formats, so it's all good ๐Ÿซง
  • -Wformat-nonliteral โ€” If -Wformat is specified, also warn if the format string isn't a string literal and therefore can't be checked ๐Ÿ” The exception is when the format function takes its format arguments as a va_list.
  • -Wformat-security โ€” ๐Ÿ” okay so if -Wformat is on, this one tags along and also flags format function uses that could be security problems ๐Ÿšจ. Right now it's catching printf and scanf calls where the format string isn't a string literal and there are no format arguments, like printf (foo);. That can be a real hole if the format string came from untrusted input and contains %n ๐Ÿ’€. (It's currently a subset of what -Wformat-nonliteral warns about, but future -Wformat-security warnings might cover things -Wformat-nonliteral doesn't โœจ.)
  • -Wformat-signedness โ€” ๐Ÿ”„ if -Wformat is specified, this one also warns when the format string wants an unsigned argument and you hand it a signed one, and vice versa ๐Ÿซถ.
  • -Wformat-truncation, -Wformat-truncation=level โ€” โœ‚๏ธ bestie, this one keeps an eye on formatted I/O calls like snprintf and vsnprintf that might cut your output short (aka truncation) ๐Ÿ˜ญ. When GCC can't figure out the exact number of bytes a format directive writes at compile time, it estimates using heuristics that depend on the level argument and on optimization. Turning on optimization usually makes the warning more accurate, but it can also cause false positives ๐Ÿ™ƒ. Except where noted, it uses the same logic as -Wformat-overflow.
    • -Wformat-truncation, -Wformat-truncation=1 โ€” level 1 (enabled by -Wformat) is the cautious queen ๐Ÿ‘‘. It only warns about bounded functions whose return value is unused and that will most likely truncate output.
    • -Wformat-truncation=2 โ€” level 2 goes harder ๐Ÿ”ฅ. It also warns about bounded functions whose return value is used and that might truncate given an argument of sufficient length or magnitude.
  • -Wformat-y2k โ€” ๐Ÿ“… if -Wformat is specified, this also warns about strftime formats that may only give you a two-digit year. Y2K energy, and we are NOT doing that again ๐Ÿ’€.
  • -Wnonnull โ€” ๐Ÿšซ warns about passing a null pointer to arguments marked as needing a non-null value by the nonnull function attribute. It's included in -Wall and -Wformat, and you can switch 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 GCC detects paths that trigger erroneous or undefined behavior from dereferencing a null pointer. This option is only active when -fdelete-null-pointer-checks is active, which optimizations enable on most targets ๐ŸŒธ. How precise the warnings are depends on the optimization options you use.
  • -Winfinite-recursion โ€” ๐ŸŒ€ warns about infinitely recursive calls. It works at all optimization levels, but you need optimization to catch infinite recursion between two or more functions. It's included in -Wall โœจ.
  • -Winit-self (C, C++, Objective-C and Objective-C++ only) โ€” ๐Ÿชž warns about uninitialized variables that are initialized with themselves. Heads up: this option can only be used with the -Wuninitialized option.

For example, GCC warns about i being uninitialized in the following snippet only when -Winit-self has been 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 when a declaration doesn't specify a type. This warning is enabled by default in C99 and later dialects of C, and also by -Wall.
  • -Wno-implicit-function-declaration (C and Objective-C only) โ€” controls warnings when a function is used before it's declared ๐Ÿง. This warning is enabled by default in C99 and later dialects of C, and also by -Wall. Fair warning: -pedantic-errors turns it into an error โ—.
  • -Wimplicit (C and Objective-C only) โ€” same as -Wimplicit-int and -Wimplicit-function-declaration ๐Ÿ’–. Enabled by -Wall.
  • -Wimplicit-fallthrough โ€” same as -Wimplicit-fallthrough=3, and -Wno-implicit-fallthrough is the same as -Wimplicit-fallthrough=0 ๐Ÿซง.
  • -Wimplicit-fallthrough=n โ€” warns when a switch case falls through. Picture this, bestie ๐Ÿ‘€:
switch (cond)
  {
  case 1:
    a = 1;
    break;
  case 2:
    a = 2;
  case 3:
    a = 3;
    break;
  }

This warning does not fire when the last statement of a case can't fall through, e.g. when there's a return statement or a call to a function declared with the noreturn attribute ๐Ÿ™Œ. -Wimplicit-fallthrough= also takes control flow statements, like ifs, into account and only warns when it's appropriate. E.g.

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

Sometimes a switch case fall through is desirable, so GCC gives you an attribute, __attribute__ ((fallthrough)), to be used along with a null statement to suppress the warning that would normally show up ๐Ÿฆ‹:

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

C++17 has 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 should match the regular expressions listed below. The option argument n decides 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:
    • "-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 the following regular expressions:
    • "-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 a case or default keyword, or by a user label that precedes some case or default label ๐Ÿ’…:

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) โ€” controls whether warnings triggered by the warn_if_not_aligned attribute should be issued ๐Ÿ“. These warnings are enabled by default.
  • -Wignored-qualifiers (C and C++ only) โ€” warns if the return type of a function has a type qualifier such as const. For ISO C, a type qualifier like that has no effect, since the value returned by a function isn't an lvalue ๐Ÿซ . For C++, the warning is only emitted for scalar types or void. ISO C 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 is ignored. This is different from the -Wattributes option: it warns whenever the compiler decides to drop an attribute, not when the attribute is unknown, used in the wrong place, etc. ๐Ÿ—‘๏ธ This warning is enabled by default.
  • -Wmain โ€” โญ warns if the type of main is suspicious. 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 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. Main character energy: the indentation is lying.

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".  */

In the case of mixed tabs and spaces, the warning uses the -ftabstop= option to determine if the statements line up (defaulting to 8) ๐Ÿ“.

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

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

This one goes quiet after a #line directive, since that usually means autogenerated code, and nobody can assume anything about the layout of the file the directive points to. โœจ This warning is enabled by -Wall in C and C++. ๐ŸŒธ

  • -Wmissing-attributes โ€” Ooh, this one's a vibe check on function declarations ๐Ÿ” It warns when a declaration is missing one or more attributes that a related function was declared with, and when that absence could hurt the correctness or efficiency of the generated code. For example, it flags aliases that use attributes to set less strict requirements than their targets, which is typically a potential optimization opportunity ๐Ÿ’… The opposite situation is handled by -Wattribute-alias=2, which warns when the alias is more restrictive than the target, since that could lead to incorrect code generation ๐Ÿ˜ญ Attributes considered include "alloc_align", "alloc_size", "cold", "const", "hot", "leaf", "malloc", "nonnull", "noreturn", "nothrow", "pure", "returns_nonnull", and "returns_twice".

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

You can use the "copy" attribute to apply the same set of attributes to a declaration as another declaration has, without typing them all out again ๐Ÿซถ It works on declarations of functions, variables, or types.

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

Here's the tea. Since the declaration of the primary function template below uses both "malloc" and "alloc_size", the explicit specialization gets diagnosed because it's missing one of them ๐Ÿ’€

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

template <>
void* __attribute__ ((malloc))   // missing alloc_size
allocate<void> (size_t);
  • -Wmissing-braces โ€” Warns if an aggregate or union initializer isn't fully bracketed. In the example below, the initializer for a isn't fully bracketed, but the one for b is ๐Ÿงš
int a[2][2] = { 0, 1, 2, 3 };
int b[2][2] = { { 0, 1 }, { 2, 3 } };

This warning is enabled by -Wall. โœจ

  • -Wmissing-include-dirs (C, C++, Objective-C, Objective-C++ and Fortran only) โ€” Warns if a user-supplied include directory doesn't exist ๐Ÿ“‚ This option is disabled by default for C, C++, Objective-C, and Objective-C++. For Fortran, it's partially enabled by default, and only warns for -I and -J ๐Ÿฆ‹
  • -Wno-missing-profile โ€” This one controls warnings about missing feedback profiles when you use -fprofile-use ๐Ÿ“Š It's the diagnosis for when a new function or a new file gets added between -fprofile-generate and -fprofile-use without regenerating the profiles. The profile feedback data files then have no profile info 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, you'll get warnings reminding you that a profile generation step is due. Ignoring them can result in poorly optimized code. You can use -Wno-missing-profile to turn the warning off, but that's not recommended and should only be done when non-existent profile data is justified ๐Ÿ™…โ€โ™€๏ธ
  • -Wmismatched-dealloc โ€” Warns about calls to deallocation functions that get pointer arguments returned from allocation functions the former isn't a suitable deallocator for ๐Ÿ—‘๏ธ A pair of functions can be linked as matching allocators and deallocators using the attribute "malloc". Unless the -fno-builtin option disables it, the standard functions "calloc", "malloc", "realloc", and "free", plus the matching forms of C++ "operator new" and "operator delete", are implicitly treated as matching allocators and deallocators ๐Ÿค In the example below, "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 included in -Wall. ๐Ÿ’–

  • -Wmultistatement-macros โ€” Warns about unsafe multiple-statement macros that look guarded by a clause like "if", "else", "for", "switch", or "while", but where only the first statement is actually guarded after the macro is expanded ๐Ÿšจ
#define DOIT x++; y++
if (c)
  DOIT;

The code above 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, like when there's an assignment where a truth value is expected, or when operators are nested in ways people often get confused about ๐Ÿค“

It also warns if a comparison like x<=y<=z shows up. That's equivalent to (x<=y ? 1 : 0) <= z, which is a different interpretation from ordinary mathematical notation ๐Ÿ™ƒ

It also warns about dangerous uses of the GNU extension to ?: with an 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 about some cases of unnecessary parentheses in declarations, which can signal 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 โ€” Okay, bestie, this one is a whole saga ๐ŸŽฌ It warns about code that may have undefined semantics because of violations of the sequence point rules in the C and C++ standards.

The standards define the order in which expressions get evaluated in terms of sequence points, which are a partial ordering between parts of the program: the stuff executed before a sequence point, and the stuff executed after it. These show up after the evaluation of a full expression (one that isn't part of a larger expression), after the evaluation of the first operand of a "&&", "||", "? :", or "," (comma) operator, before a function is called (but after its arguments and the expression denoting the called function are evaluated), and in certain other places. Apart from what the sequence point rules say, the order of evaluation of subexpressions isn't specified. These rules only give a partial order, not a total one. For example, if two functions get called within one expression with no sequence point between them, the order of those calls isn't specified. However, the standards committee has ruled that function calls do not overlap ๐Ÿซ 

It's not specified when, between sequence points, modifications to object values take effect. Programs whose behavior depends on this have undefined behavior. The C and C++ 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 ๐Ÿ’€

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 fairly effective at detecting this sort of problem ๐Ÿ”

The C++17 standard will define the order of evaluation of operands in more cases. In particular, it requires that the right-hand side of an assignment be 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 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 https://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, so yes, that gets flagged too ๐Ÿซถ)

For C only, warn about a return statement with an expression in a function whose return type is void ๐Ÿซถ, unless the expression type is also void. As a GNU extension, that second case gets a pass with no warning unless -Wpedantic is used ๐Ÿงš. Trying to use the return value of a non-void function other than main that just flows off the end (aka reaching the closing curly brace that ends the function) is undefined ๐Ÿ’€.

๐Ÿ’€ Heads up, bestie: in C++, flowing off the end of a non-void function other than main results in undefined behavior even when the value of the function is not used. Unlike C, C++ is not chill about this one ๐Ÿ˜ญ

This warning is enabled by default in C++ and by -Wall otherwise โœจ.

  • -Wno-shift-count-negative โ€” okay so this one controls warnings if a shift count is negative ๐ŸŒธ. It's enabled by default, so you get it for free ๐Ÿ’….
  • -Wno-shift-count-overflow โ€” controls warnings if a shift count is greater than or equal to the bit width of the type ๐Ÿฆ‹. Also enabled by default โœจ.
  • -Wshift-negative-value โ€” warns if you left shift a negative value ๐Ÿ™ˆ. This warning is enabled by -Wextra in C99 and C++11 modes (and newer) ๐ŸŒˆ.
  • -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 it's enabled by default in C99 and C++11 modes (and newer) ๐Ÿ’–. This level does not warn about left-shifting 1 into the sign bit. (However, in C, such an overflow is still rejected in contexts where an integer constant expression is required.) No warning is emitted in C++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 provoke 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 โ€” same energy as -Wswitch: warns on a switch with an enum index that's missing a case for one or more named codes, and case labels outside the enum range also get warnings ๐Ÿ’…. The only difference 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 a boolean index 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 outside of its respective type range ๐Ÿฆ‹. 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 does not warn if the statement between the controlling expression and the first case label is just a declaration ๐Ÿง :

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

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

  • -Wsync-nand (C and C++ only) โ€” 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, so watch out ๐Ÿซถ.
  • -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 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) ๐Ÿ’œ. Enabled by -Wall. To suppress it, use the unused attribute. This is 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 ๐Ÿงš. Enabled by -Wall.
  • -Wunused-label โ€” warns whenever a label is declared but not used ๐Ÿท๏ธ. Enabled by -Wall. To suppress this warning, use the unused attribute.
  • -Wunused-local-typedefs (C, Objective-C, C++ and Objective-C++ only) โ€” warns when a typedef locally defined in a function is not used ๐Ÿ“. 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++. 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's not an error, since const variables take the place of #defines ๐Ÿค“. To suppress this warning, use the unused attribute.
    • -Wunused-const-variable=1 โ€” this is the warning level that's enabled by -Wunused-variable for C ๐Ÿ’–. It only warns about unused static const variables defined in the main compilation unit, but not about static const variables declared in any header that's included.
    • -Wunused-const-variable=2 โ€” this level also warns for unused constant static variables in headers (excluding system headers) ๐Ÿ”. This is the warning level of -Wunused-const-variable and it must be explicitly requested, since in C++ it isn't an error and in C it might be harder to clean up all the headers included.

  • -Wunused-value โ€” warns whenever a statement computes a result that is explicitly not used ๐Ÿ™ƒ. To suppress this warning, cast the unused expression to void. This includes an expression-statement or the left-hand side of a comma expression that contains no side effects. For example, an expression such as x[i,j] causes a warning, while x[(void)i,j] does not. Enabled by -Wall.
  • -Wunused โ€” all the above -Wunused options combined ๐Ÿง . To get a warning about an unused function parameter, you must either specify -Wextra -Wunused (note that -Wall implies -Wunused), or separately specify -Wunused-parameter ๐Ÿ‘‘.
  • -Wuninitialized โ€” warns if an object with automatic or allocated storage duration is used without having been initialized ๐Ÿ˜ญ. In C++, it also warns if a non-static reference or non-static const member appears in a class without constructors.

In addition, passing a pointer (or in C++, a reference) to an uninitialized object to a const-qualified argument of a built-in function known to read the object is also diagnosed by this warning. (-Wmaybe-uninitialized is issued for ordinary functions.)

If you want to warn about code that uses the uninitialized value of the variable in its own initializer, use the -Winit-self option ๐Ÿ”.

These warnings occur 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 version of GCC used ๐ŸŽข.

Note that there may be no warning about a variable that is used only to compute a value that itself is never used, because such computations may be deleted by data flow analysis before the warnings are printed ๐Ÿซ .

In C++, this warning also warns about using uninitialized objects in member-initializer-lists. For example, GCC warns about b being uninitialized in the following snippet:

struct A {
  int a;
  int b;
  A() : a(b) { }
};
  • -Wno-invalid-memory-model โ€” controls warnings for invocations of __atomic built-ins, __sync built-ins, and the C11 atomic generic functions with a memory consistency argument that is either invalid for the operation or outside the range of values of the memory_order enumeration ๐Ÿงช. For example, since the __atomic_store and __atomic_store_n built-ins are only defined for the relaxed, release, and sequentially consistent memory orders, the following code is diagnosed:
void store (int *i)
{
  __atomic_store_n (i, 0, memory_order_consume);
}

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

  • -Wmaybe-uninitialized โ€” for an object with automatic or allocated storage duration, if there's a path from the function entry to a use of the object where it is initialized, but some other paths where it is not initialized, the compiler emits a warning if it can't prove those uninitialized paths aren't executed at run time ๐Ÿ”ฎ.

In addition, passing a pointer (or in C++, a reference) to an uninitialized object into a const-qualified function argument also gets flagged by this warning ๐Ÿซถ (-Wuninitialized is issued for built-in functions known to read the object). bestie, if you annotate the function with attribute access (none), you're telling GCC the argument isn't used to access the object, and the warning goes away โœจ

these warnings only show up in optimizing compilation, because otherwise GCC doesn't keep track of what's going on with variables ๐Ÿ’…

these warnings are optional because GCC can't always tell when the code is actually correct, even when it looks like there's an error ๐Ÿ™ˆ here's one example of how that happens:

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

if the value of y is always 1, 2 or 3, then x is always initialized, but GCC doesn't know that ๐Ÿ˜ญ to shut the warning up, you need a default case with assert(0) or similar code ๐ŸŒธ

this option also warns when a non-volatile automatic variable might get 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, honestly!). so you might get a warning even when there's no real problem, because longjmp can't actually be called at the spot that would cause trouble ๐Ÿ’€

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, you'll even get warnings for unknown pragmas in system header files. that's not the case if the warnings are only turned on by the -Wall command-line option ๐Ÿ’…
  • -Wno-pragmas โ€” ๐Ÿ™ˆ don't warn about misuses of pragmas, like incorrect parameters, invalid syntax, or conflicts between pragmas. see also -Wunknown-pragmas ๐ŸŽ€
  • -Wno-prio-ctor-dtor โ€” ๐ŸŒˆ skip the warning if a priority from 0 to 100 is used for a constructor or destructor. constructor and destructor attributes let you give a priority to control the order they run in, before main is called or after it returns โœจ but the priority values have to be greater than 100, because the compiler reserves 0--100 for itself ๐Ÿ’œ
  • -Wstrict-aliasing โ€” ๐Ÿฆ‹ 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 vibe, only active when -fstrict-aliasing is active. it warns about code that might break those strict aliasing rules. higher levels mean higher accuracy (fewer false positives), and they also take more effort, kinda like how -O works ๐Ÿง  -Wstrict-aliasing is equivalent to -Wstrict-aliasing=3 โœจ
    • Level 1: most aggressive, quick, least accurate ๐Ÿ”ฅ possibly useful when higher levels don't warn but -fstrict-aliasing still breaks the code, since it has very few false negatives. however, it has many false positives ๐Ÿ˜ญ it warns for all pointer conversions between possibly incompatible types, even if never dereferenced. runs in the front end only.
    • Level 2: aggressive, quick, not too precise ๐Ÿ’… may still have many false positives (not as many as level 1, though), and few false negatives (but possibly more than level 1). unlike level 1, it only warns when an address is taken. warns about incomplete types. runs in the front end only.
    • Level 3 (default for -Wstrict-aliasing): should have very few false positives and few false negatives ๐Ÿซถ slightly slower than levels 1 or 2 when optimization is enabled. it takes care of the common pun+dereference pattern in the front end: *(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. only warns when the converted pointer is dereferenced. does not warn about incomplete types.
  • -Wstrict-overflow, -Wstrict-overflow=n โ€” this option is only active when signed overflow is undefined ๐ŸŒธ it warns about cases where the compiler optimizes based on the assumption that signed overflow doesn't happen. it doesn't warn about every place the code might overflow, only where the compiler actually implements some optimization, so this warning depends on the optimization level ๐Ÿงš an optimization that assumes no signed overflow is perfectly safe if the variables involved never actually overflow, so this warning can easily give a false positive (a warning about code that isn't really a problem) ๐Ÿ™ˆ to help you focus on the important stuff, there are several warning levels. no warnings are issued for undefined signed overflow when estimating how many iterations a loop requires, in particular when figuring out whether a loop will be executed at all ๐Ÿ”
    • -Wstrict-overflow=1 โ€” warns about cases that are both questionable and easy to avoid ๐Ÿ’… for example, the compiler simplifies x + 1 > x to 1. this level of -Wstrict-overflow is enabled by -Wall; higher levels aren't, and must be explicitly requested.
    • -Wstrict-overflow=2 โ€” also warns about other cases where a comparison is simplified to a constant ๐Ÿฆ‹ for example: abs (x) >= 0. this can only be simplified when signed integer overflow is undefined, because abs (INT_MIN) overflows to INT_MIN, which is less than zero. -Wstrict-overflow (with no level) is the same as -Wstrict-overflow=2 ๐Ÿ‘‘
    • -Wstrict-overflow=3 โ€” also warns about other cases where a comparison is simplified ๐Ÿ’œ for example: x + 1 > 1 is simplified to x > 0.
    • -Wstrict-overflow=4 โ€” also warns about other simplifications not covered by the above cases โœจ for example: (x * 10) / 5 is simplified to x * 2.
    • -Wstrict-overflow=5 โ€” also warns about cases where the compiler reduces the magnitude of a constant involved in a comparison ๐Ÿ˜ญ for example: x + 2 > y is simplified to x + 1 >= y. this is reported only at the highest warning level, because this simplification applies to many comparisons, so this level gives a very large number of false positives ๐Ÿ’€
  • -Wstring-compare โ€” ๐Ÿ”ฅ warns for calls to strcmp and strncmp whose result is determined to be zero or non-zero in equality tests, because the length of one argument is greater than the size of the array the other argument is stored in (or the bound, for strncmp). those calls could be mistakes ๐Ÿ’… for example, the strcmp call below gets diagnosed 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 โ€” ๐Ÿง warns for calls to string manipulation functions like memcpy and strcpy that are determined to overflow the destination buffer. the optional argument is one greater than the type of Object Size Checking to perform to determine the size of the destination. the argument only matters for functions that operate on character arrays, not raw memory functions like memcpy, which always use Object Size type-0. the option also warns for calls that specify a size in excess of the largest possible object, or at most SIZE_MAX / 2 bytes. it gives the best results with optimization enabled, but can detect a small subset of simple buffer overflows even without optimization, in calls to GCC built-in functions like __builtin_memcpy that correspond to the standard functions. either way, it only warns about a subset of the buffer overflows detected by the corresponding overflow checking built-ins. for example, the option issues a warning for the strcpy call below because it copies at least 5 characters (the string "blue" including the terminating NUL) into a buffer of size 4:
enum Color { blue, purple, yellow };
const char* f (enum Color clr)
{
  static char buf [4];
  const char *str;
  switch (clr)
    {
      case blue: str = "blue"; break;
      case purple: str = "purple"; break;
      case yellow: str = "yellow"; break;
    }

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

Option -Wstringop-overflow=2 is enabled by default ๐Ÿ”ฅ

  • -Wstringop-overflow, -Wstringop-overflow=1 โ€” the -Wstringop-overflow=1 option uses type-zero Object Size Checking to determine the sizes of destination objects ๐ŸŒธ at this setting, the option doesn't warn for writes past the end of subobjects of larger objects accessed by pointers, unless the size of the largest surrounding object is known. when the destination may be one of several objects, it's assumed to be the largest one of them. on Linux systems, when optimization is enabled at this setting, the option warns for the same code as when the _FORTIFY_SOURCE macro is defined to a non-zero value ๐Ÿซถ
  • -Wstringop-overflow=2 ๐Ÿง okay so this one uses type-one Object Size Checking to figure out how big destination objects are. At this setting it warns about overflows when writing to members of the largest complete objects whose exact size is known. It does not warn for excessive writes to the same members of unknown objects referenced by pointers, since they might point to arrays with unknown numbers of elements. This is the default setting of the option ๐Ÿ’–
  • -Wstringop-overflow=3 ๐ŸŽ€ this one switches to type-two Object Size Checking for destination sizes. At this setting it warns about overflowing the smallest object or data member. It's the most restrictive setting that can still flag totally safe code, so be ready for some false alarms ๐Ÿ˜ญ
  • -Wstringop-overflow=4 ๐Ÿฆ‹ type-three Object Size Checking is in charge here. It warns about overflowing any data members. When the destination is one of several objects, it uses the size of the largest one to decide whether to warn. Like -Wstringop-overflow=3, this setting may warn on benign code ๐Ÿ’…
  • -Wno-stringop-overread ๐ŸŒธ warns for calls to string manipulation functions like memchr or strcpy that are determined to read past the end of the source sequence.

Option -Wstringop-overread is enabled by default โœจ

  • -Wno-stringop-truncation ๐Ÿ™ˆ this one tells GCC to not warn for calls to bounded string functions like strncat, strncpy, and stpncpy that might truncate the copied string or leave the destination unchanged.

Here's a sneaky example. In the following code, the call to strncat sets a bound that's smaller than the length of the source string. So the copy gets truncated, and the call is diagnosed. To avoid the warning, use bufsize - strlen (buf) - 1) as the bound.

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

Another one: this strncpy call copies only the characters before the terminating NUL into d, and doesn't add the NUL to the end. Assuming the result of strncpy is always a NUL-terminated string is a super common mistake, so this call gets diagnosed ๐Ÿ‘€ To dodge the warning when the result isn't supposed to be NUL-terminated, call memcpy instead.

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

Last one! Here the strncpy call uses the size of the destination buffer as the bound. If the source string's length is equal to or greater than that size, the copy won't be NUL-terminated, so yep, it 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 you've got a character array that's meant to hold a sequence of bytes with no terminating NUL, you can annotate it with the attribute nonstring to skip this warning ๐Ÿงš Just know that arrays like that aren't suitable for functions that expect NUL-terminated strings. To help catch accidental misuse, GCC still issues warnings unless it can prove the use is safe ๐Ÿ”ฅ

  • -Wsuggest-attribute=[pure|const|noreturn|format|cold|malloc] ๐Ÿ”ฎ warns for cases where adding an attribute might be beneficial. The attributes currently supported are listed below.
    • -Wsuggest-attribute=pure, -Wsuggest-attribute=const, -Wsuggest-attribute=noreturn, -Wmissing-noreturn, -Wsuggest-attribute=malloc โœจ these warn about functions that might be candidates for the attributes pure, const, noreturn, or malloc. The compiler 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 contain an infinite loop or return abnormally by throwing, calling abort, or trapping. This analysis requires option -fipa-pure-const, which is enabled by default at -O and higher. Higher optimization levels improve the accuracy of the analysis ๐Ÿ“ˆ
  • -Wsuggest-attribute=format, -Wmissing-format-attribute ๐Ÿ–จ๏ธ warns about function pointers that might be candidates for format attributes. Heads up, these are only possible candidates, not absolute ones.

GCC guesses that function pointers with format attributes that get used in assignment, initialization, parameter passing, or return statements should have a matching format attribute in the resulting type. In other words, the left-hand side of the assignment or initialization, the type of the parameter variable, or the return type of the containing function should also have a format attribute to avoid the warning.

GCC also warns about function definitions that might be candidates for format attributes. Again, these are just possible candidates. GCC guesses format attributes might be appropriate for any function that calls a function like vprintf or vscanf, but that might not always be the case, and some functions that really should have format attributes may not get detected ๐Ÿคทโ€โ™€๏ธ

  • -Wsuggest-attribute=cold ๐ŸงŠ warns about functions that might be candidates for the cold attribute. This is based on static detection, and it generally only warns about functions that always lead to a call to another cold function, like wrappers of C++ throw or fatal error reporting functions that lead to abort.
  • -Walloc-zero 0๏ธโƒฃ 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.
๐Ÿšจ Because the behavior of these functions with a zero size differs between implementations (and realloc has been deprecated for this), relying on it can cause subtle portability bugs. Avoid it!
  • -Walloc-size-larger-than=byte-size ๐Ÿ“ warns about calls to functions decorated with the attribute alloc_size that try to allocate objects larger than the specified number of bytes. It also warns when the result of the size computation, done in an integer type with infinite precision, would exceed the value of PTRDIFF_MAX on the target. -Walloc-size-larger-than=PTRDIFF_MAX is enabled by default. Warnings controlled by this option can be disabled either by specifying a byte-size of SIZE_MAX or more, or by -Wno-alloc-size-larger-than.
  • -Wno-alloc-size-larger-than ๐Ÿ™…โ€โ™€๏ธ disables -Walloc-size-larger-than= warnings. It's equivalent to -Walloc-size-larger-than=SIZE_MAX or larger.
  • -Walloca ๐Ÿซฃ warns on all uses of alloca in the source.
  • -Walloca-larger-than=byte-size ๐Ÿง  this one warns on calls to alloca with an integer argument whose value is either zero, or that isn't bounded by a controlling predicate limiting its value to at most byte-size. It also warns for calls to alloca where the bound value is unknown. Arguments of non-integer types are considered unbounded, even if they look like they're constrained to the expected range.

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

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

In the above example, passing -Walloca-larger-than=1000 would not issue a warning, because the call to alloca is known to be at most 1000 bytes. But if -Walloca-larger-than=500 were passed, the compiler would emit a warning ๐Ÿ‘€

Unbounded uses, on the other hand, are uses of alloca with no controlling predicate constraining its integer argument. For example:

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

If -Walloca-larger-than=500 were passed, the above would trigger a warning, but this time because of the lack of bounds checking ๐Ÿ™ƒ

Note that even seemingly correct code involving signed integers could cause a warning:

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

In the above example, n could be negative, causing a larger than expected argument to be implicitly cast into the alloca call. Plot twist! ๐ŸŒช๏ธ

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 effective when -ftree-vrp is active (the default for -O2 and above).

See also -Wvla-larger-than=byte-size. ๐Ÿซถ

  • -Wno-alloca-larger-than ๐Ÿ›‘ disables -Walloca-larger-than= warnings. It's equivalent to -Walloca-larger-than=SIZE_MAX or larger.
  • -Warith-conversion ๐Ÿงฎ do warn about implicit conversions from arithmetic operations, even when converting the operands to the same type can't change their values. This affects 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 ๐Ÿšง warns about out-of-bounds subscripts or offsets into arrays. This warning is enabled by -Wall. It's more effective when -ftree-vrp is active (the default for -O2 and above), but a subset of instances still get issued even without optimization ๐Ÿ’œ
  • -Warray-bounds=1 โ€” ๐ŸŽ€ This is the default level of -Warray-bounds, and -Wall switches it on for you. The higher levels aren't on by default, so you have to ask for them by name, bestie ๐Ÿ’…
  • -Warray-bounds=2 โ€” ๐Ÿ”ฅ This level goes further. It also flags out-of-bounds accesses to trailing struct members of one-element array types, and the intermediate results of pointer arithmetic that might come out of bounds. ngl it can throw a lot of false positives, so it's deactivated by default ๐Ÿ’€
  • -Warray-compare โ€” ๐Ÿฆ‹ Warns about equality and relational comparisons between two operands of array type. This comparison was deprecated in C++20, so it's not it ๐Ÿ™ˆ For example:
int arr1[5];
int arr2[5];
bool same = arr1 == arr2;

-Warray-compare is enabled by -Wall.

  • -Warray-parameter, -Warray-parameter=n โ€” ๐ŸŒธ Warns about redeclarations of functions with array or pointer arguments that don't match in kind or form. It also turns on detection of out-of-bounds accesses to those parameters by warnings like -Warray-bounds.

If the first function declaration uses the array form, the bound in the array is treated as the minimum number of elements callers must provide, and also the maximum number of elements the function accesses. Passing arguments that are too small, or accessing more than that maximum, may get flagged by warnings like -Warray-bounds. At level 1, the warning catches inconsistencies involving array parameters declared with the "T[static N]" form.

Here, the warning triggers on the redeclarations because the first one lets an array of any size be 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 on redeclarations with any other inconsistency in array or pointer argument forms that denote array sizes. Pointers and arrays of unspecified bound are treated as equivalent, so they 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 doesn't match the alias's type.
    • -Wattribute-alias=1 โ€” The default level diagnoses mismatches between the type of the alias declaration and the type of its target. These mismatches are usually a sign 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 can lead to incorrect code generation. In other cases they're harmless and could be fixed by just adding the missing attribute to the target. For comparison, -Wmissing-attributes controls diagnostics for when the alias declaration is less restrictive than the target, rather than more restrictive. 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 equivalent to -Wattribute-alias=1, and that's the default. You can turn these warnings off with either -Wno-attribute-alias or -Wattribute-alias=0 ๐Ÿ™…โ€โ™€๏ธ

  • -Wbidi-chars=[none|unpaired|any|ucn] โ€” ๐ŸŒˆ Warns about possibly misleading UTF-8 bidirectional control characters in comments, string literals, character constants, and identifiers. These characters can flip writing direction from left-to-right to right-to-left (and back), which can make the logical order and the visual order fight each other. This can be dangerous. For instance, a piece of code might look commented out when it actually isn't ๐Ÿ˜ฑ

GCC supports three warning levels here. The default is -Wbidi-chars=unpaired, which warns about improperly terminated bidi contexts. -Wbidi-chars=none turns the warning off, and -Wbidi-chars=any warns about any use of bidirectional control characters.

By default, this warning doesn't check UCNs. You can turn that checking on with -Wbidi-chars=unpaired,ucn or -Wbidi-chars=any,ucn. Using -Wbidi-chars=ucn is valid too, and it's equivalent to -Wbidi-chars=unpaired,ucn, as long as no earlier -Wbidi-chars=any was specified.

  • -Wbool-compare โ€” ๐Ÿงš Warns about a boolean expression being compared with an integer value other than "true"/"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 instance, bitwise negation of a boolean is very likely a bug in the program. For C, this warning also warns about incrementing or decrementing a boolean, which rarely makes sense. (In C++, decrementing a boolean is always invalid. Incrementing a boolean is invalid in C++17, and deprecated otherwise.)

This warning is enabled by -Wall.

  • -Wduplicated-branches โ€” ๐Ÿ“ Warns when an if-else has identical branches. This catches cases like:
if (p != NULL)
  return 0;
else
  return 0;

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

int i = x ? *p : *p;
  • -Wduplicated-cond โ€” ๐Ÿซถ Warns about duplicated conditions in an if-else-if chain. For instance, it warns for this code:
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 may return indeterminate values or crash the program. This warning is included in -Wall.
  • -Wno-discarded-qualifiers (C and Objective-C only) โ€” ๐ŸŒธ Stops the warning about type qualifiers on pointers being discarded. Usually the compiler warns if a "const char *" variable gets passed to a function that takes a "char *" parameter. Use this option to silence that warning.
  • -Wno-discarded-array-qualifiers (C and Objective-C only) โ€” ๐Ÿฆ‹ Stops the warning about type qualifiers on arrays that are pointer targets being discarded. Usually the compiler warns if a "const int (*)[]" variable gets passed to a function that takes an "int (*)[]" parameter. Use this option to suppress that warning.
  • -Wno-incompatible-pointer-types (C and Objective-C only) โ€” ๐Ÿ’… Stops the warning about conversions between pointers with incompatible types. This is for cases that -Wno-pointer-sign doesn't cover; that one handles pointer argument passing or assignment with different signedness.
  • -Wno-int-conversion (C and Objective-C only) โ€” โœจ Stops the warning about incompatible integer-to-pointer and pointer-to-integer conversions. This warning is about implicit conversions. For explicit conversions, 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

For example, the first two stores in function bad get flagged, because the array elements overlap the following members b and c. The third store is flagged by -Warray-bounds, because it's beyond 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
}

The option -Wzero-length-bounds is enabled by -Warray-bounds.

  • -Wno-div-by-zero โ€” ๐Ÿ”ข Stops the warning about compile-time integer division by zero. Floating-point division by zero doesn't get warned about, since it can be a legit way to get infinities and NaNs ๐ŸŒˆ
  • -Wsystem-headers โ€” ๐Ÿฐ Prints warning messages for constructs found in system header files. Warnings from system headers are normally suppressed, on the assumption that they usually aren't real problems and would just make the compiler output harder to read. This option tells GCC to show warnings from system headers as if they came from your own code. Heads up though: using -Wall alongside this option does not warn about unknown pragmas in system headers. For that, -Wunknown-pragmas has to be used too ๐Ÿง
  • -Wtautological-compare โ€” ๐Ÿ” Warns if a self-comparison always evaluates to true or false. This catches mistakes like:
int i = 1;
...
if (i > i) { ... }

It also warns about bitwise comparisons that always evaluate to true or false. For instance:

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

will always be false.

This warning is enabled by -Wall.

  • -Wtrampolines โ€” okay bestie, this one is about trampolines ๐ŸŽ€. These are tiny bits of data or code that get created at run time on the stack whenever you take the address of a nested function, and they're used to call that nested function indirectly ๐Ÿฆ‹. Some targets only use data, so they need no special treatment โœจ. But on most targets a trampoline is made of code ๐Ÿ’€, which means the stack has to be made executable for the program to work properly. This flag warns you about trampolines generated for pointers to nested functions.
  • -Wfloat-equal โ€” warns if floating-point values are used in equality comparisons ๐Ÿฆ‹. Here's the vibe: sometimes it's convenient to treat floats as approximations of infinitely precise real numbers ๐ŸŒธ. If you're doing that, you need to figure out (by analyzing the code or some other way) the maximum or likely maximum error the computation introduces, and account for it when comparing (and when producing output, but that's a whole different problem ๐Ÿ™ˆ). Instead of testing for equality, check whether the two values have ranges that overlap. You do that with the relational operators, so equality comparisons are probably a mistake ๐Ÿ’….
  • -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/or problematic constructs you should avoid ๐Ÿซถ. Here's the full list of what it catches:
    • Macro parameters that show up inside string literals in the macro body. Traditional C does macro replacement inside string literals, but ISO C does not ๐Ÿ˜ญ.
    • 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 you hide directives like #pragma, which traditional C doesn't understand, by indenting them. Some traditional implementations don't recognize #elif, so this option suggests avoiding it altogether ๐Ÿ™ˆ.
    • A function-like macro that appears without arguments.
    • The unary plus operator.
    • The U integer constant suffix, or the F or L floating-point constant suffixes. (Traditional C does support the L suffix on integer constants.) Heads up: these suffixes show up in macros defined in the system headers of most modern systems, like the _MIN/_MAX macros in <limits.h>. Using those macros in your own code might normally lead to 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 ๐Ÿ’€.
    • 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, so hexadecimal or octal values (which typically represent bit patterns) don't get warned about ๐ŸŒˆ.
    • ISO string concatenation usage 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 gets skipped. That's because the zero initializer in user code usually shows up conditioned on something like __STDC__ to avoid missing-initializer warnings, and it relies on default initialization to zero in the traditional C case ๐Ÿฆ‹.
    • Conversions by prototypes between fixed-point and floating-point values, and vice versa. Leaving out these prototypes when compiling with traditional C causes serious problems ๐Ÿ˜ญ. This is only a subset of the possible conversion warnings; for the full set, use -Wtraditional-conversion.
    • Use of ISO C style function definitions. This warning intentionally isn't 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 ๐Ÿ’…. This warning is also skipped for nested functions, since 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 ๐Ÿ”ฅ. That includes conversions of fixed-point to floating-point and vice versa, and conversions that change the width or signedness of a fixed-point argument, except when that 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 is known from C++, was introduced with ISO C99, and is allowed by default in GCC. It isn't 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, which means -Wno-shadow=local and -Wno-shadow=compatible-local get ignored when -Wshadow is used ๐Ÿ™ˆ. This is the same as -Wshadow=global.
  • -Wno-shadow-ivar (Objective-C only) โ€” skips the warning 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 type of the shadowing variable. In C++, type compatibility here means the shadowing variable's type can be converted to the shadowed variable's type ๐Ÿงš. The reason this flag exists (in addition to -Wshadow=local) is that when a local variable shadows another one of 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, enabling only -Wshadow=compatible-local does not emit a warning ๐Ÿฆ‹. Because their types are incompatible, if a programmer accidentally uses one in place of the other, type checking is expected to catch that and emit an error or warning ๐Ÿซถ. Using this flag instead of -Wshadow=local can possibly cut down on the number of warnings triggered by intentional shadowing ๐Ÿ’…. Also note that shadowing const char *i with 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 exceeds byte-size ๐Ÿ“. -Wlarger-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 by using -Wno-larger-than โœจ. It also warns for calls to bounded functions such as memchr or strnlen that specify a bound greater than the largest possible object, which is PTRDIFF_MAX bytes by default ๐Ÿ”ฅ. These particular warnings can only be disabled by -Wno-larger-than ๐Ÿ˜ญ.
  • -Wno-larger-than โ€” disables -Wlarger-than= warnings ๐ŸŒธ. It's equivalent to -Wlarger-than=SIZE_MAX or larger.
  • -Wframe-larger-than=byte-size โ€” warns if the size of a function frame exceeds byte-size ๐ŸŽ€. The computation done to figure out the stack frame size is approximate and not conservative, so the actual requirements may be somewhat greater than byte-size even if you don't get a warning ๐Ÿ™ˆ. Also, any space allocated via alloca, variable-length arrays, or related constructs is not counted by the compiler when it decides whether to issue a warning ๐Ÿ’€. -Wframe-larger-than=PTRDIFF_MAX is enabled by default. You can disable these warnings either by specifying a byte-size of SIZE_MAX or more, or by using -Wno-frame-larger-than ๐Ÿ‘‘.
  • -Wno-frame-larger-than โ€” disables -Wframe-larger-than= warnings ๐Ÿงš. It's equivalent to -Wframe-larger-than=SIZE_MAX or larger.
  • -Wfree-nonheap-object โ€” warns when you try to deallocate an object that was either not allocated on the heap, or using a pointer that wasn't returned from a prior call to the matching allocation function ๐Ÿ’…. Here's a sneaky example: because the call to stpcpy returns a pointer to the terminating nul character and not to the beginning of the object, the call to free below gets diagnosed ๐Ÿ˜ญ.
void f (char *p)
{
  p = stpcpy (p, "abc");
  // ...
  free (p);   // warning
}

-Wfree-nonheap-object is included in -Wall ๐Ÿซถ.

  • -Wstack-usage=byte-size โ€” warns if the stack usage of a function might exceed byte-size ๐ŸŒˆ. The computation done to determine stack usage is conservative, and any space allocated via alloca, variable-length arrays, or related constructs is included by the compiler when it decides whether to issue a warning ๐Ÿ’–. The message matches the output of -fstack-usage. If the stack usage is fully static but exceeds the specified amount, the message is warning: stack usage is 1120 bytes ๐Ÿ”ฅ. If the stack usage is (partly) dynamic but bounded, the message is warning: stack usage might be 1648 bytes โœจ.

okay so if the stack usage is (partly) dynamic and not bounded, the compiler spits out this message ๐Ÿ™ˆ:

warning: stack usage might be unbounded

-Wstack-usage=PTRDIFF_MAX is enabled by default ๐ŸŽ€. You can shut off the warnings this option controls in two ways: by giving it a byte-size of SIZE_MAX or more, or by using -Wno-stack-usage.

  • -Wno-stack-usage โ€” turns off all the -Wstack-usage= warnings ๐Ÿ™…โ€โ™€๏ธ. It's the same as -Wstack-usage=SIZE_MAX or larger.
  • -Wunsafe-loop-optimizations โ€” warns when 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 when 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, it silences the warnings about non-ISO printf / scanf format width specifiers I32, I64, and I on Windows targets ๐ŸชŸ. Those depend on the MS runtime, so the vibe is "it's fine, I know what I'm doing" ๐Ÿ’….
  • -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, which is handy for math with void * pointers and pointers to functions. In C++, it also warns when an arithmetic operation involves NULL. This warning is also enabled by -Wpedantic.
  • -Wno-pointer-compare โ€” doesn't warn if a pointer is compared with a zero character constant ๐Ÿ™ƒ. That 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 unsupported features in ThreadSanitizer ๐Ÿงต. TSan doesn't support std::atomic_thread_fence and can report false positives, so it's giving "double check your results" ๐Ÿซถ.

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 ๐Ÿค. Constant expressions are left alone. For example, it warns if an unsigned variable is compared against zero with < or >=. This warning is also enabled by -Wextra.
  • -Wabsolute-value (C and Objective-C only) โ€” warns about calls to standard functions that compute an absolute value when a better standard function exists ๐Ÿ“. For example, calling abs(3.14) triggers the warning, because the right function for a double argument is fabs. It also warns when the argument in a call to such a function has an unsigned type. You can suppress it with an explicit type cast, and it's also enabled 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 enabled by -Wall.
  • -Wtrigraphs โ€” warns if any trigraphs are found that might change the meaning of the program ๐Ÿ”. Trigraphs inside comments don't get flagged, except the ones that would form escaped newlines. This option is implied by -Wall. If you don't pass -Wall, it's still on unless trigraphs are enabled. Want trigraph conversion without the warnings but still get 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.
  • -Wexpansion-to-defined โ€” warns whenever defined shows up in the expansion of a macro, including when the macro gets expanded by an #if directive ๐Ÿ™…โ€โ™€๏ธ. That kind of usage isn't portable. This warning is also enabled 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 flagged.

Heads up: if a macro is actually used, but only inside skipped conditional blocks, the preprocessor still reports it as unused ๐Ÿ˜ญ. To dodge the warning, improve the scope of the macro's definition, like moving it into the first skipped block. Or you could add a dummy use, something like this:
#if defined the_macro_causing_the_warning
#endif
  • -Wno-endif-labels โ€” doesn't warn when an #else or an #endif is followed by text ๐Ÿท๏ธ. This sometimes happens in older programs with code like this:
#if FOO
...
#else FOO
...
#endif FOO

The second and third FOO should 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 non-matching type ๐ŸŽญ. 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 aren't in ISO C90 but are in ISO C99 ๐Ÿ“œ. For instance, it warns about variable length arrays, the long long type, the bool type, compound literals, designated initializers, and so on. This option doesn't care about the standards mode. Warnings are disabled in the expression that follows __extension__.
  • -Wc99-c11-compat (C and Objective-C only) โ€” warns about features that aren't in ISO C99 but are in ISO C11 ๐ŸŒˆ. For instance, it warns about 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 doesn't care about the standards mode. Warnings are disabled in the expression that follows __extension__.
  • -Wc11-c2x-compat (C and Objective-C only) โ€” warns about features that aren't in ISO C11 but are in ISO C2X ๐Ÿ”ฎ. For instance, it warns about leaving out the string in _Static_assert, using [[]] attribute syntax, using decimal floating-point types, and so on. This option doesn't care about the standards mode. Warnings are disabled in the expression that follows __extension__.
  • -Wc++-compat (C and Objective-C only) โ€” warns about ISO C constructs that live outside the common subset of ISO C and ISO C++ ๐Ÿค. For example, it warns about implicit conversion from void * to a pointer to a non-void type.
  • -Wc++11-compat (C++ and Objective-C++ only) โ€” warns about C++ constructs whose meaning changes between ISO C++ 1998 and ISO C++ 2011 ๐Ÿ”„. For example, identifiers in ISO C++ 1998 that 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 changes 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 changes 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 changes between ISO C++ 2017 and ISO C++ 2020 ๐Ÿ”„. This warning is enabled by -Wall.
  • -Wno-c++11-extensions (C++ and Objective-C++ only) โ€” doesn't warn about C++11 constructs in code being compiled with an older C++ standard ๐Ÿ™ˆ. Even without this option, some C++11 constructs only get diagnosed if you use -Wpedantic.
  • -Wno-c++14-extensions (C++ and Objective-C++ only) โ€” doesn't warn about C++14 constructs in code being compiled with an older C++ standard ๐Ÿ™ˆ. Even without this option, some C++14 constructs only get diagnosed if you use -Wpedantic.
  • -Wno-c++17-extensions (C++ and Objective-C++ only) โ€” doesn't warn about C++17 constructs in code being compiled with an older C++ standard ๐Ÿ™ˆ. Even without this option, some C++17 constructs only get diagnosed if you use -Wpedantic.
  • -Wno-c++20-extensions (C++ and Objective-C++ only) โ€” doesn't warn about C++20 constructs in code being compiled with an older C++ standard ๐Ÿ™ˆ. Even without this option, some C++20 constructs only get diagnosed if you use -Wpedantic.
  • -Wno-c++23-extensions (C++ and Objective-C++ only) โ€” doesn't warn about C++23 constructs in code being compiled with an older C++ standard ๐Ÿ™ˆ. Even without this option, some C++23 constructs only get diagnosed if you use -Wpedantic.
  • -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 * is cast to an ordinary char *.

It also warns when a cast introduces 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 in a way that increases the required alignment of the target ๐Ÿ“. For example, it warns if a char * is cast to an int * on machines where integers can only be accessed at two- or four-byte boundaries.
  • -Wcast-align=strict โ€” warns whenever a pointer gets cast in a way that increases the required alignment of the target, no matter what machine you're on ๐Ÿงฑ. For example, it warns if a char * is cast to an int * regardless of the target machine.
  • -Wcast-function-type โ€” warns when a function pointer gets cast to an incompatible function pointer ๐ŸŽ€. In a cast involving function types with a variable argument list, only the types of the initial arguments that are provided get considered. Any parameter of pointer-type matches any other pointer-type. Benign differences in integral types get ignored, like int vs. long on ILP32 targets. Type qualifiers get ignored too. The function type void (*) (void) is special and matches everything, so you can use it to suppress this warning ๐Ÿคซ. In a cast involving pointer to member types, this warning fires whenever the cast changes the pointer to member type. This warning is enabled by -Wextra.
  • -Wwrite-strings โ€” okay bestie, when you're compiling C this one gives string constants the type const char[length], so copying one's address into a non-const char * pointer gets you a warning ๐Ÿ’…. It helps you 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 it's just a nuisance ๐Ÿ˜ญ, which is exactly why -Wall doesn't ask for these warnings ๐Ÿซถ. When you're compiling C++, it warns about the deprecated conversion from string literals to char *, and this one is turned on by default for C++ programs โœจ.
  • -Wclobbered โ€” warns about variables that might get changed by longjmp or vfork ๐Ÿฆ‹. It's also switched on by -Wextra ๐ŸŒธ.
  • -Wconversion โ€” the main character of implicit conversions ๐Ÿ‘‘. It warns when an implicit conversion might alter a value, like abs (x) when x is double (real to integer), unsigned ui = -1 (signed to unsigned), or sqrtf (M_PI) (down to a smaller type) ๐Ÿ’€. It does NOT warn for explicit casts like abs ((int) x) and ui = (unsigned) -1, or when the value doesn't actually change, like abs (2.0) ๐Ÿ™ˆ. Signed/unsigned warnings can be silenced with -Wno-sign-conversion ๐ŸŽ€. For C++, it also warns about confusing overload resolution for user-defined conversions, plus conversions that never use a type conversion operator (to void, the same type, a base class, or a reference to them) ๐Ÿงš. Signed/unsigned conversion warnings are off by default in C++ unless you explicitly turn on -Wsign-conversion ๐Ÿ’œ. And warnings about arithmetic on a small type converting back to that same type only show up with -Warith-conversion ๐Ÿ“.
  • -Wdangling-else โ€” this one is for when an else could be confusing about which if it belongs to ๐Ÿ™ˆ. Check out this example:
{
  if (a)
    if (b)
      foo ();
  else
    bar ();
}

In C/C++, every else branch belongs to the innermost possible if statement, which here is if (b) ๐Ÿ’€. That's usually NOT what the programmer meant, even though the indentation suggests otherwise ๐Ÿ˜ญ. When this potential confusion exists, GCC warns when this flag is specified ๐Ÿšจ. To kill the warning, add explicit braces around the innermost if statement so the else can't possibly belong to the enclosing if โœจ. It ends up looking like this:

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

This warning is enabled by -Wparentheses ๐ŸŽ€.

  • -Wdangling-pointer, -Wdangling-pointer=n โ€” okay this is about using pointers (or C++ references) to objects with automatic storage duration AFTER their lifetime has ended ๐Ÿ’€. That includes local variables in nested blocks, compound literals, and other unnamed temporary objects ๐Ÿ“. It also warns about storing the address of those objects in escaped pointers ๐Ÿซฃ. It's enabled at all optimization levels, but it might give different results with optimization than without ๐ŸŒˆ.
    • -Wdangling-pointer=1 โ€” at level 1, only UNCONDITIONAL uses of dangling pointers get diagnosed ๐Ÿ”ฅ. For example:
int f (int c1, int c2, x)
{
  char *p = strchr ((char[]){ c1, c2 }, c3);
  return p ? *p : 'x';   // warning: dangling pointer to a compound literal
}

In the following function, storing the address of the local variable x in the escaped pointer *p also triggers the warning ๐Ÿ‘€.

void g (int **p)
{
  int x = 7;
  *p = &x;   // warning: storing the address of a local variable in *p
}
  • -Wdangling-pointer=2 โ€” at level 2, the warning also catches CONDITIONAL uses of dangling pointers, on top of the unconditional ones ๐Ÿงš. For example, the array a in the following function is out of scope when the pointer s that was set to point at it gets used, so the warning triggers at this level ๐Ÿฆ‹.
void f (char *s)
{
  if (!s)
    {
      char a[12] = "tmpname";
      s = a;
    }
  strcat (s, ".tmp");   // warning: dangling pointer to a may be used
  ...
}

-Wdangling-pointer=2 is included in -Wall ๐Ÿ’….

  • -Wdate-time โ€” warns when the macros __TIME__, __DATE__ or __TIMESTAMP__ show up, since they might stop your compiles from being bit-wise-identical and reproducible โฐ.
  • -Wempty-body โ€” warns if an empty body shows up in an if, else or do while statement ๐Ÿซง. It's also enabled by -Wextra ๐ŸŒธ.
  • -Wno-endif-labels โ€” don't warn about stray tokens after #else and #endif ๐Ÿ˜Œ.
  • -Wenum-compare โ€” warns about comparisons between values of different enumerated types ๐Ÿ“. In C++, enumerated type mismatches in conditional expressions get diagnosed too, and this one is on by default there โœจ. In C, it's enabled by -Wall ๐Ÿ’œ.
  • -Wenum-conversion โ€” warns when a value of one enumerated type gets implicitly converted to a DIFFERENT enumerated type ๐Ÿฆ‹. In C, this 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 already been initialized ๐Ÿงš. It only cares about variables that get initialized when they're declared ๐ŸŽ€. This one is only supported for C and Objective-C, because in C++ this sort of branch is an error anyway ๐Ÿ™…โ€โ™€๏ธ.
    • -Wjump-misses-init is included in -Wc++-compat ๐Ÿ‘‘. You can turn it off with the -Wno-jump-misses-init option ๐Ÿ’….
  • -Wsign-compare โ€” warns when a comparison between signed and unsigned values could give an incorrect result, because the signed value gets converted to unsigned ๐Ÿ”ฅ. In C++, this is also enabled by -Wall ๐Ÿซถ. In C, it's enabled by -Wextra ๐ŸŒธ.
  • -Wsign-conversion โ€” warns about implicit conversions that might change the sign of an integer value, like assigning a signed integer expression to an unsigned integer variable ๐Ÿ™ˆ. An explicit cast silences it ๐ŸŽ€. In C, this option is also enabled by -Wconversion ๐Ÿ’œ.
  • -Wfloat-conversion โ€” warns about implicit conversions that reduce the precision of a real value ๐ŸŒˆ. That includes real-to-integer conversions, and conversions from higher-precision real values to lower-precision ones ๐Ÿ“. This option is also enabled by -Wconversion โœจ.
  • -Wno-scalar-storage-order โ€” don't warn 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 what you actually wanted ๐Ÿ’€. This warns about things like:
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's size, but it won't work out correctly with pointers ๐Ÿ˜ญ. It warns e.g. 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 to certain string and memory built-in functions when the argument uses sizeof ๐ŸŽ€. It triggers for things like memset (ptr, 0, sizeof (ptr)); if ptr is a pointer and not an array, and it suggests a possible fix ๐Ÿฆ‹. It also triggers for stuff like memcpy (&foo, ptr, sizeof (&foo)); ๐Ÿงš. This one 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 example below, the call to strncat uses the size of the source string as its bound, which is 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 โ€” don't warn when the sizeof operator is applied to a parameter that's 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 if the first argument references an array, and the third argument is a number equal to the number of elements but NOT equal to the size of the array in memory ๐Ÿ“. That means you probably forgot to multiply by the element size ๐Ÿ’€. This warning is enabled by -Wall โœจ.
  • -Wmemset-transposed-args โ€” warns about suspicious memset calls where the second argument isn't zero and the third argument is zero ๐Ÿ™ˆ. For example, memset (buf, sizeof buf, 0) gets diagnosed because memset (buf, 0, sizeof buf) was what you meant ๐Ÿซถ. The diagnostic only shows up if the third argument is a literal zero ๐ŸŽ€. If it's an expression that folds to zero, or a cast of zero to some type, the arguments are far less likely to have been mistakenly transposed, so no warning is emitted ๐Ÿฆ‹. This warning is enabled by -Wall ๐Ÿ’….
  • -Waddress โ€” warns about suspicious uses of address expressions ๐Ÿ‘€. These include comparing the address of a function or a declared object to the null pointer constant, such as in
void f (void);
void g (void)
{
  if (!func)   // warning: expression evaluates to false
    abort ();
}

okay so GCC is literally side-eyeing this if (!func) ๐Ÿ‘€ because a function's address is basically always truthy ๐Ÿ’… (the only exception is weak symbols ๐Ÿซถ). so putting it in a condition is usually a sign you forgot the parentheses on a call or a dereference somewhere ๐Ÿ™ˆ

Comparing a pointer to a string literal is also flagged, like this โœจ

void f (const char *x)
{
  if (x == "abc")   // warning: expression evaluates to false
    puts ("equal");
}

and so is testing the result of pointer addition or subtraction for equality to null ๐Ÿ’€

void f (const int *p, int i)
{
  return p + i == NULL;
}

these almost always mean a programmer error, bestie ๐Ÿ˜ญ if it's the object-pointer part of the warning you're dealing with, you can shut it up by casting the pointer operand to an integer type, like inptr_t or uinptr_t. comparing against string literals is unspecified behavior and not portable, and it's giving "you meant strcmp" energy ๐ŸŽ€ the warning also goes quiet if the sketchy expression came out of a macro expansion. and -Waddress is turned on by -Wall ๐ŸŒธ

  • -Wno-address-of-packed-member โ€” don't warn when someone takes the address of a packed member of a struct or union, since that usually gives you an unaligned pointer value. this one is already on by default, so it's the main character ๐Ÿ‘‘
  • -Wlogical-op โ€” warns about suspicious logical operators in expressions, including when && or || shows up somewhere a bit-wise operator is probably what you wanted ๐Ÿงš it also calls out when both operands of a logical operator are the exact same thing:
extern int a;
if (a < 0 && a < 0) { ... }
  • -Wlogical-not-parentheses โ€” warns when a logical not is on the left-hand side of a comparison. it won't warn if the right operand counts as a boolean expression. the whole point is catching stuff like this ๐Ÿ™ƒ
int a;
...
if (!a > 1) { ... }

if you want to silence it, just wrap the left side in parentheses:

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

this warning is enabled by -Wall โœจ

  • -Waggregate-return โ€” warns if any functions that return structs or unions are defined or called. (in languages where you can return an array, this also gets a warning too ๐Ÿ“)
  • -Wno-aggressive-loop-optimizations โ€” warns if, in a loop with a constant number of iterations, the compiler detects undefined behavior in some statement during one or more of the iterations ๐Ÿ’€
  • -Wno-attributes โ€” don't warn if an unexpected __attribute__ shows up, like unrecognized attributes or function attributes slapped onto variables. this does not stop errors for incorrect use of supported attributes, so don't get it twisted ๐Ÿซถ

also, with -Wno-attributes=, you can hush warnings about unknown scoped attributes (in C++11 and C2X). for example, -Wno-attributes=vendor::attr disables the warning for this declaration:

[[vendor::attr]] void f();

you can mute every attribute warning in a namespace with -Wno-attributes=vendor::, which covers both of these at once ๐Ÿฆ‹

[[vendor::safe]] void f();
[[vendor::unsafe]] void f2();
heads up bestie: -Wno-attributes= does not imply -Wno-attributes ๐Ÿ˜ญ
  • -Wno-builtin-declaration-mismatch โ€” warns if a built-in function is declared with an incompatible signature or as a non-function, or when a built-in function declared with a type that doesn't include a prototype gets called with arguments 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 enabled by default โœจ to avoid it, include the appropriate header so the built-in function prototypes are in scope.

check out this memset call. it gets flagged because memset wants a value of type size_t as its argument, but the type of 32 is int ๐Ÿ’… with -Wextra, the declaration gets called out 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 silences 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 is allowed without a warning if it's preceded by a declaration that specifies the argument types ๐ŸŽ€)
  • -Wold-style-declaration (C and Objective-C only) โ€” 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 also gets turned on by -Wextra ๐Ÿงš
  • -Wold-style-definition (C and Objective-C only) โ€” warns if an old-style function definition is used, and it does this even if there's a previous prototype ๐Ÿ™ˆ a definition using () is not considered an old-style definition in C2X mode, because it's equivalent to (void) in that case. 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 ๐Ÿฆ‹
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 is issued 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 provide prototypes there, and a non-matching declaration declares an overload rather than conflicting with an earlier declaration. use -Wmissing-declarations to detect missing declarations in C++ instead.
  • -Wmissing-declarations โ€” warns if a global function is defined without a previous declaration, even if the definition itself provides a prototype. use it to catch global functions that aren't declared in header files โœจ in C, no warnings are issued for functions with previous non-prototype declarations, so use -Wmissing-prototypes for those. in C++, no warnings are issued for function templates, inline functions, or functions in anonymous namespaces ๐Ÿ‘‘
  • -Wmissing-field-initializers โ€” warns if a struct's initializer has some fields missing. for example, this causes such a warning, because x.h is implicitly zero ๐Ÿ“
struct s { int f, g, h; };
struct s x = { 3, 4 };

this option doesn't warn about designated initializers, so the following modification does not trigger a warning โœจ

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++ this option doesn't warn about the empty { } initializer, for example:

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-missing-requires โ€” by default, the compiler warns about a concept-id appearing as a C++20 simple-requirement ๐Ÿ‘€
bool satisfied = requires { C<T> };

here satisfied will be true if C<T> is a valid expression, which it is for all T. presumably the user meant to write this instead:

bool satisfied = requires { requires C<T> };

so satisfied is only true if concept C is satisfied for type T ๐ŸŒˆ this warning can be disabled with -Wno-missing-requires.

  • -Wno-missing-template-keyword โ€” the member access tokens ., -> and :: must be followed by the template keyword if the parent object is dependent and the member being named is a template ๐Ÿงš
template <class X>
void DoStuff (X x)
{
  x.template DoSomeOtherStuff<X>(); // Good.
  x.DoMoreStuff<X>(); // Warning, x is dependent.
}

in rare cases you can get false positives. to silence them, wrap the expression in parentheses. for example, the following is treated as a template, even where m and N are integers ๐Ÿ™ƒ

void NotATemplate (my_class t)
{
  int N = 5;

  bool test = t.m < N > (0); // Treated as a template.
  test = (t.m < N) > (0); // Same meaning, but not treated as a template.
}

this warning can be disabled with -Wno-missing-template-keyword ๐ŸŽ€

  • -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 shouldn't be used in portable code ๐Ÿ’€
  • -Wnormalized=[none|id|nfc|nfkc] โ€” in ISO C and ISO C++, two identifiers are different if they're different sequences of characters. but when characters outside the basic ASCII set are used, you can have two different character sequences that look exactly the same ๐Ÿ‘€ to avoid the confusion, the ISO 10646 standard sets out normalization rules that turn look-alike sequences into the same sequence when applied. GCC can warn you if you're using identifiers that haven't been normalized, and this option controls that warning ๐Ÿฆ‹

Okay so, bestie, GCC has four levels of warning for identifier normalization ๐Ÿซถโœจ The default is -Wnormalized=nfc, which yells about any identifier that isn't in the ISO 10646 "C" normalized form, NFC ๐Ÿ’… NFC is the recommended vibe for most uses, and it's the same thing as -Wnormalized.

Real talk though, ISO C and ISO C++ let some characters into identifiers that stop being allowed once they get turned into NFC ๐Ÿ˜ญ So there's no way to use those symbols in portable ISO C or C++ and still have every identifier in NFC. -Wnormalized=id silences the warning for just those characters ๐ŸŒธ The standards people are hoping future versions will fix this, which is why it isn't the default ๐Ÿ™ˆ

You can switch the warning off for every character with -Wnormalized=none or -Wno-normalized ๐Ÿฅบ But only do this if you're using some other normalization scheme (like "D") โœจ

Seriously, if you turn this off without a different normalization scheme, you can easily create bugs that are literally impossible to see ๐Ÿ’€

Some characters in ISO 10646 have totally different 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 shoved into a superscript ๐Ÿฆ‹ ISO 10646 also defines the NFKC normalization scheme to convert all of these into a standard form, and GCC warns if your code isn't in NFKC when you use -Wnormalized=nfkc ๐Ÿ”ฅ That warning is comparable to warning about every identifier with the letter O, since it might get mixed up with the digit 0, so it's not the default ๐Ÿ˜ญ It can still be a useful local coding convention if your programming environment can't be fixed to display these characters distinctly ๐Ÿ’œ

  • -Wno-attribute-warning โ€” stop warning about usage of functions declared with the "warning" attribute ๐Ÿ™…โ€โ™€๏ธ This one is on by default, so you only need this if it's bugging you. Use -Wno-attribute-warning to disable the warning, or -Wno-error=attribute-warning to disable the error when you're compiling with -Werror ๐ŸŽ€
  • -Wno-deprecated โ€” do not warn about usage of deprecated features ๐Ÿ“
  • -Wno-deprecated-declarations โ€” do not warn about uses of functions, variables, and types marked as deprecated with the "deprecated" attribute ๐Ÿงš
  • -Wno-overflow โ€” do not warn about compile-time overflow in constant expressions ๐ŸŒˆ
  • -Wno-odr โ€” warn about One Definition Rule violations during link-time optimization. This one is enabled by default โญ
  • -Wopenacc-parallelism โ€” warn about potentially suboptimal choices related to OpenACC parallelism ๐Ÿ”ฅ
  • -Wopenmp-simd โ€” warn if the vectorizer cost model overrides the OpenMP simd directive you set. If you want to loosen the cost model, you can use -fsimd-cost-model=unlimited ๐Ÿ’…
  • -Woverride-init (C and Objective-C only) โ€” warn if an initialized field without side effects gets overridden when you're using designated initializers ๐Ÿ‘‘ This one is included in -Wextra. If you want the other -Wextra warnings but not this one, use -Wextra -Wno-override-init ๐Ÿซถ
  • -Wno-override-init-side-effects (C and Objective-C only) โ€” do not warn if an initialized field with side effects gets overridden when using designated initializers. This is enabled by default โœจ
  • -Wpacked โ€” warn if a structure gets the packed attribute but the packed attribute has no effect on the layout or size of the structure. Those structs can end up misaligned for very little benefit ๐Ÿฅ€ For instance, in this code, the variable f.x in struct bar is misaligned, even though struct bar doesn't have the packed attribute itself:
struct foo {
  int x;
  char a, b, c, d;
} __attribute__((packed));
struct bar {
  char z;
  struct foo f;
};
  • -Wnopacked-bitfield-compat โ€” the 4.1, 4.2, and 4.3 series of GCC ignore the packed attribute on bit-fields of type char. That got fixed in GCC 4.4, but the change can lead to differences in structure layout ๐Ÿ˜ณ GCC tells you when the offset of such a field has changed in GCC 4.4. For example, there is no longer a 4-bit padding between field a and b in this structure:
struct foo
{
  char a:4;
  char b:8;
} __attribute__ ((packed));

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

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

This warning is enabled by -Wall ๐ŸŒธ

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

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

  • -Wnested-externs (C and Objective-C only) โ€” warn if an extern declaration is encountered within a function ๐Ÿ•ต๏ธ
  • -Winline โ€” warn if a function declared as inline cannot be inlined. Even with this option on, the compiler does not warn about failures to inline functions declared in system headers ๐Ÿ™…โ€โ™€๏ธ The compiler uses a bunch of heuristics to decide whether to inline a function, like the size of the function being inlined and how much inlining has already happened in the current function. So seemingly insignificant changes in your source can make the -Winline warnings show up or disappear ๐Ÿคทโ€โ™€๏ธ
  • -Winterference-size โ€” warn about use of the C++17 std::hardware_destructive_interference_size without specifying its value with --param destructive-interference-size. It also warns about questionable values for that option ๐Ÿง  This variable is meant for controlling class layout, to avoid false sharing in concurrent code:
struct independent_fields {
  alignas(std::hardware_destructive_interference_size) std::atomic<int> one;
  alignas(std::hardware_destructive_interference_size) std::atomic<int> two;
};

Here, one and two are meant to be far enough apart that stores to one won't require accesses to two to reload the cache line ๐Ÿฆ‹

By default, --param destructive-interference-size and --param constructive-interference-size are set based on the current -mtune option. That's typically the L1 cache line size for the particular target CPU, and sometimes a range if you're tuning for a generic target ๐ŸŒ So every translation unit that depends on ABI compatibility for these variables must be compiled with the same -mtune (or -mcpu) ๐Ÿšซ

If ABI stability matters, like if the use is in a header for a library, you should probably not use the hardware interference size variables at all. Alternatively, you can force a particular value with --param ๐Ÿซถ

If you're confident your use of the variable doesn't affect ABI outside a single build of your project, you can turn off the warning with -Wno-interference-size ๐Ÿ’…

  • -Wint-in-bool-context โ€” warn for suspicious use of integer values where boolean values are expected ๐Ÿคจ Examples include conditional expressions (?:) using non-boolean integer constants in a boolean context, like if (a <= b ? 2 : 3). It also covers left shifting of signed integers in a boolean context, like for (a = 0; 1 << a; a++);. Likewise for all kinds of multiplications, regardless of the data type. This warning is enabled by -Wall ๐ŸŽ€
  • -Wno-int-to-pointer-cast โ€” suppress warnings from casts to a pointer type of an integer of a different size. In C++, casting to a pointer type of smaller size is an error, so careful bestie ๐Ÿšซ Wint-to-pointer-cast is enabled by default ๐ŸŒท
  • -Wno-pointer-to-int-cast (C and Objective-C only) โ€” suppress warnings from casts from a pointer to an integer type of a different size ๐Ÿงšโ€โ™€๏ธ
  • -Winvalid-pch โ€” warn if a precompiled header is found in the search path but can't be used ๐Ÿ“‚
  • -Wlong-long โ€” warn if the long long type is used. This is enabled by either -Wpedantic or -Wtraditional in ISO C90 and C++98 modes. To inhibit the warning messages, use -Wno-long-long ๐Ÿญ
  • -Wvariadic-macros โ€” warn if variadic macros are used in ISO C90 mode, or if the GNU alternate syntax is used in ISO C99 mode. This is enabled by either -Wpedantic or -Wtraditional. To inhibit the warning messages, use -Wno-variadic-macros ๐ŸŒˆ
  • -Wno-varargs โ€” do not warn upon questionable usage of the macros used to handle variable arguments, like va_start. These warnings are enabled by default ๐Ÿฆ„

โš ๏ธ -Wvector-operation-performance ๐Ÿ’…

Okay so this one warns you if a vector operation isn't using the SIMD stuff your architecture actually has. It's mainly for performance tuning, bestie ๐ŸŽ๏ธ. A vector operation can get implemented three ways:

  • "piecewise": the scalar operation runs on every single vector element one by one ๐ŸŒ
  • "in parallel": the vector operation uses scalars of a wider type, which is normally more performance efficient ๐Ÿš€
  • "as a single scalar": the vector fits into a scalar type, so it's one scalar op ๐ŸŽฏ

๐Ÿ”Š -Wvla

Warns if a variable-length array shows up in your code. -Wno-vla stops the -Wpedantic warning about variable-length arrays, so you can keep the drama down ๐Ÿคซ

๐Ÿ“ -Wvla-larger-than=byte-size

If you use this, GCC will warn about variable-length array declarations whose size is either unbounded, or bounded by an argument that lets the array go past byte-size bytes. It's giving -Walloca-larger-than=byte-size energy, just for VLAs instead ๐Ÿซถ

Heads up: GCC might optimize small variable-length arrays with a known value into plain arrays, so this warning may not fire for those.

-Wvla-larger-than=PTRDIFF_MAX is turned on by default, but it's typically only actually effective when -ftree-vrp is active. That's on by default for -O2 and above ๐Ÿ’–

See also -Walloca-larger-than=byte-size.

๐Ÿ™…โ€โ™€๏ธ -Wno-vla-larger-than

Disables the -Wvla-larger-than= warnings. It's the same as -Wvla-larger-than=SIZE_MAX or larger ๐Ÿ’…

๐Ÿงฉ -Wvla-parameter

This one warns about function redeclarations where the arguments are variable-length array types of inconsistent kinds or forms. It also turns on 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 treated as the minimum number of elements expected to be passed to the function, and the maximum number of elements it accesses. Passing arguments that are too small, or accessing more than that max, may get diagnosed ๐Ÿ‘€

Here's the example, and why the warning triggers. The first declaration lets an array of any size be 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 bigger 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. And -Warray-parameter handles similar problems, but for ordinary array arguments ๐ŸŽ€

๐Ÿ”’ -Wvolatile-register-var

Warns if a register variable is declared volatile. Here's the tea: the volatile modifier doesn't stop every optimization that might eliminate reads and/or writes to register variables, so it's not the safety net you'd think ๐Ÿ’€ This warning is enabled by -Wall ๐ŸŒธ

๐Ÿข -Wdisabled-optimization

Warns if a requested optimization pass gets disabled. Not gonna lie, this doesn't usually mean your code is broken ๐Ÿ™ƒ It just means GCC's optimizers can't handle the code effectively. Often your code is too big or too complex, and GCC refuses to optimize programs when the optimization would probably take an absurd amount of time ๐Ÿ˜ฉ

โœ๏ธ -Wpointer-sign (C and Objective-C only)

Warns for pointer argument passing or assignment with different signedness. This 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 only does anything when -fstack-protector is active. It warns about functions that aren't protected against stack smashing ๐Ÿงฑ

๐Ÿ“œ -Woverlength-strings

Warns about string constants that are longer than the "minimum maximum" length the C standard specifies. Modern compilers are chill and allow string constants way longer than the standard's 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 set a normative minimum maximum, so GCC doesn't diagnose overlength strings in C++ ๐Ÿ™Œ

This option is implied by -Wpedantic, and you can disable it with -Wno-overlength-strings.

๐Ÿ”ข -Wunsuffixed-float-constants (C and Objective-C only)

Issues a warning for any floating constant that doesn't have a suffix ๐Ÿ’ซ When you combine it with -Wsystem-headers, it warns about those constants in system header files too. This is super useful 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, this stops GCC from warning about type mismatches in global declarations across 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 that's been marked with the "designated_init" attribute ๐Ÿ“


๐Ÿ” Options That Control Static Analysis

๐Ÿ•ต๏ธ -fanalyzer

This option turns on a static analysis of program flow. It hunts for "interesting" interprocedural paths through your code and issues warnings for problems it finds on them ๐Ÿ”Ž Fair warning, it's way more expensive than other GCC warnings, so it's not a fast bestie ๐ŸŒ

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-allocation-size -Wanalyzer-tainted-array-index
-Wanalyzer-tainted-divisor -Wanalyzer-tainted-offset
-Wanalyzer-tainted-size -Wanalyzer-unsafe-call-within-signal-handler
-Wanalyzer-use-after-free -Wanalyzer-use-of-uninitialized-value
-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. No analyzer, no vibes ๐Ÿ’”

๐Ÿงญ -Wanalyzer-too-complex

If -fanalyzer is enabled, the analyzer uses a bunch of heuristics to explore the control flow and data flow in the program ๐Ÿ—บ๏ธ But sufficiently complicated code can totally defeat them. By default, the analysis silently stops if the code is too complicated and it hits an internal limit. -Wanalyzer-too-complex makes it warn you when that happens ๐Ÿ“ข

๐Ÿ“‚ -Wno-analyzer-double-fclose

This warning requires -fanalyzer, which enables it. Use -Wno-analyzer-double-fclose to disable it ๐Ÿ™…โ€โ™€๏ธ

It warns for paths through the code where a FILE * can have fclose called on it more than once ๐Ÿ“

๐Ÿชฃ -Wno-analyzer-double-free

This warning requires -fanalyzer, which enables it. Use -Wno-analyzer-double-free to disable it.

It warns for paths through the code where a pointer can have a deallocator called on it more than once. That deallocator can be free, or a deallocator referenced by attribute "malloc" ๐Ÿงน

๐Ÿค -Wno-analyzer-exposure-through-output-file

This warning requires -fanalyzer, which enables it. Use -Wno-analyzer-exposure-through-output-file to disable it.

It warns for paths through the code where a security-sensitive value gets written to an output file, like writing a password to a log file ๐Ÿ” Yikes, don't do that bestie ๐Ÿ˜ญ

๐Ÿงพ -Wno-analyzer-file-leak

This warning requires -fanalyzer, which enables it. Use -Wno-analyzer-file-leak to disable it.

It warns for paths through the code where a <stdio.h> FILE * stream object gets leaked ๐Ÿ’ง

๐ŸŒฒ -Wno-analyzer-free-of-non-heap

This warning requires -fanalyzer, which enables it. Use -Wno-analyzer-free-of-non-heap to disable it.

It warns for paths through the code where free gets called on a non-heap pointer, like an on-stack buffer or a global ๐Ÿ™ˆ

๐Ÿง  -Wno-analyzer-malloc-leak

This warning requires -fanalyzer, which enables it. Use -Wno-analyzer-malloc-leak to disable it.

It warns for paths through the code where a pointer allocated via an allocator is leaked. That allocator can be malloc, or a function marked with attribute "malloc" ๐Ÿซ 

๐Ÿ”€ -Wno-analyzer-mismatching-deallocation

This warning requires -fanalyzer, which enables it. Use -Wno-analyzer-mismatching-deallocation to disable it.

It warns for paths through the code where the wrong deallocation function gets called on a pointer value, based on which function was used to allocate it. It'll flag mismatches between free, scalar delete and vector delete[], and those marked as allocator/deallocator pairs using attribute "malloc" ๐Ÿšซ

โ“ -Wno-analyzer-possible-null-argument

This warning requires -fanalyzer, which enables it. Use -Wno-analyzer-possible-null-argument to disable it.

It warns for paths through the code where a possibly-NULL value gets passed to a function argument marked with __attribute__((nonnull)), which requires a non-NULL value ๐Ÿ’œ

๐Ÿ‘ป -Wno-analyzer-possible-null-dereference

This warning requires -fanalyzer, which enables it. Use -Wno-analyzer-possible-null-dereference to disable it.

It warns for paths through the code where a possibly-NULL value gets dereferenced ๐Ÿ’€

๐Ÿซฅ -Wno-analyzer-null-argument

This warning requires -fanalyzer, which enables it. Use -Wno-analyzer-null-argument to disable it. โœจ

This one's about a value the analyzer knows is NULL getting handed to a function argument marked __attribute__((nonnull)), which means that argument really needs a non-NULL value ๐Ÿซถ bestie, that's a whole vibe check.

  • -Wno-analyzer-null-dereference โ€” needs -fanalyzer to turn it on, and you can switch it off with -Wno-analyzer-null-dereference ๐Ÿ’… It flags paths where something known to be NULL gets dereferenced ๐Ÿ’€
  • -Wno-analyzer-shift-count-negative โ€” needs -fanalyzer, and you disable it with -Wno-analyzer-shift-count-negative ๐ŸŒธ It catches paths where a shift happens with a negative count. It's the analyzer's cousin of -Wshift-count-negative from the C/C++ front ends, except this one follows interprocedural paths instead of just reading the syntax tree. The analyzer doesn't prioritize finding these, so false negatives are more likely than with other warnings ๐Ÿ™ˆ
  • -Wno-analyzer-shift-count-overflow โ€” needs -fanalyzer, and you turn it off with -Wno-analyzer-shift-count-overflow โœจ This one flags paths where the shift count is greater than or equal to the precision of the operand's type. Same energy as -Wshift-count-overflow in the front ends, but it's built on interprocedural paths rather than the syntax tree. Again, the analyzer doesn't prioritize these, so false negatives are more likely relative to other warnings ๐Ÿงš
  • -Wno-analyzer-stale-setjmp-buffer โ€” needs -fanalyzer, and disabling is -Wno-analyzer-stale-setjmp-buffer ๐Ÿฆ‹ It warns about paths where longjmp tries to rewind to a jmp_buf tied to a setjmp call inside a function that has already returned. When setjmp runs on a jmp_buf, it records the stack frame, and that frame goes invalid once the function returns. Rewinding to it means pointing at a stack frame that doesn't exist anymore, which can crash or get even worse ๐Ÿ˜ญ
  • -Wno-analyzer-tainted-allocation-size โ€” needs both -fanalyzer and -fanalyzer-checker=taint, and you turn it off with -Wno-analyzer-tainted-allocation-size ๐Ÿ”ฅ It flags paths where a value an attacker could control becomes the size of an allocation without being sanitized. That lets an attacker push in a huge allocation and cause a denial of service. See CWE-789: Memory Allocation with Excessive Size Value at https://cwe.mitre.org/data/definitions/789.html ๐Ÿ‘‘
  • -Wno-analyzer-tainted-array-index โ€” needs both -fanalyzer and -fanalyzer-checker=taint, and disabling it is -Wno-analyzer-tainted-array-index ๐ŸŽ€ It catches an attacker-controllable value used as an array index without sanitizing, which could sneak in an out-of-bounds access. See CWE-129: Improper Validation of Array Index at https://cwe.mitre.org/data/definitions/129.html ๐Ÿ’œ
  • -Wno-analyzer-tainted-divisor โ€” needs both -fanalyzer and -fanalyzer-checker=taint, and you switch it off with -Wno-analyzer-tainted-divisor ๐Ÿ“ It warns when an attacker-controllable value is the divisor in a division or modulus operation with no sanitizing, so an attacker could inject a division-by-zero ๐Ÿ’€
  • -Wno-analyzer-tainted-offset โ€” needs both -fanalyzer and -fanalyzer-checker=taint, and disabling it is -Wno-analyzer-tainted-offset ๐ŸŒˆ This one is for attacker-controllable values used as a pointer offset without sanitizing, which could inject an out-of-bounds access. See CWE-823: Use of Out-of-range Pointer Offset at https://cwe.mitre.org/data/definitions/823.html ๐Ÿซถ
  • -Wno-analyzer-tainted-size โ€” needs both -fanalyzer and -fanalyzer-checker=taint, and you turn it off with -Wno-analyzer-tainted-size ๐Ÿ’… It flags an attacker-controllable value used as the size of an operation like memset without sanitizing, which could inject an out-of-bounds access โœจ
  • -Wno-analyzer-unsafe-call-within-signal-handler โ€” needs -fanalyzer, and you disable it with -Wno-analyzer-unsafe-call-within-signal-handler ๐Ÿ™ˆ It catches paths where a function that's known to be async-signal-unsafe, like fprintf, gets called from inside a signal handler.
  • -Wno-analyzer-use-after-free โ€” needs -fanalyzer, and disabling is -Wno-analyzer-use-after-free ๐Ÿ’€ It warns about paths where a pointer gets used after a deallocator has been called on it. That deallocator is either free, or one referenced by the malloc attribute ๐Ÿ˜ญ
  • -Wno-analyzer-use-of-pointer-in-stale-stack-frame โ€” needs -fanalyzer, and you switch it off with -Wno-analyzer-use-of-pointer-in-stale-stack-frame ๐Ÿฆ‹ It flags paths where a pointer gets dereferenced and points to a variable living in a stale stack frame.
  • -Wno-analyzer-write-to-const โ€” needs -fanalyzer, and you disable it with -Wno-analyzer-write-to-const ๐ŸŒธ It warns when the analyzer detects someone trying to write through a pointer to a const object. The analyzer doesn't prioritize these paths, so false negatives are more likely than with other warnings ๐Ÿ™ˆ
  • -Wno-analyzer-write-to-string-literal โ€” needs -fanalyzer, and turning it off is -Wno-analyzer-write-to-string-literal ๐ŸŽ€ This one flags attempts 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 โœจ
  • -Wno-analyzer-use-of-uninitialized-value โ€” needs -fanalyzer, and you disable it with -Wno-analyzer-use-of-uninitialized-value ๐Ÿงš It warns about paths where an uninitialized value gets used.

Okay so, these are the knobs for steering the exploration ๐ŸŽ›๏ธ 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, and they're giving main character energy ๐Ÿ‘‘

  • -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 โ€” restricts the analyzer to running just the named checker, and turns that checker on ๐Ÿ’… Some checkers are disabled by default, even with -fanalyzer. The "taint" checker, which implements -Wanalyzer-tainted-array-index, is one of them, and this option is required to enable it ๐Ÿ”ฅ

  • -fno-analyzer-feasibility โ€” this one's 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 when you're debugging issues in this code ๐Ÿ™ˆ
  • -fanalyzer-fine-grained โ€” also for analyzer developers ๐Ÿฆ‹ Internally, the analyzer builds an "exploded graph" that combines control flow graphs with data flow information. By default, one edge in this graph can hold the effects of a run of multiple statements within a basic block. With -fanalyzer-fine-grained, every statement gets its own edge โœจ
  • -fanalyzer-show-duplicate-count โ€” another developer one ๐Ÿงš If several diagnostics are detected as duplicates of each other, this emits a note when reporting the best diagnostic, telling you how many additional diagnostics the deduplication logic suppressed ๐Ÿ“
  • -fno-analyzer-state-merge โ€” developer-only, babe ๐Ÿ’œ By default, the analyzer simplifies things by merging sufficiently similar states at each program point while it builds the "exploded graph". -fno-analyzer-state-merge suppresses that merging, which is handy for debugging state-handling issues ๐ŸŽ€
  • -fno-analyzer-state-purge โ€” developer-only too ๐ŸŒธ By default, the analyzer purges aspects of state at a program point that seem no longer relevant, like the values of locals that aren't accessed later in the function and don't matter for leak analysis. With -fno-analyzer-state-purge, that purging gets suppressed, again for debugging state-handling issues ๐Ÿ’…
  • -fanalyzer-transitivity โ€” turns on transitivity of constraints within the analyzer ๐ŸŒˆ
  • -fanalyzer-verbose-edges โ€” for analyzer developers ๐Ÿซถ It gives more verbose, lower-level detail in the descriptions of control flow within diagnostic paths ๐Ÿ”ฅ
  • -fanalyzer-verbose-state-changes โ€” developer-facing too ๐Ÿ‘‘ This one gives more verbose, lower-level detail in the descriptions of events related to state machines within diagnostic paths โœจ
  • -fanalyzer-verbosity=level โ€” controls how complex the control flow paths are that get emitted for analyzer diagnostics ๐Ÿงš

okay so the analyzer has five verbosity levels, and your level can be one of these ๐Ÿ’–

  • 0 โ€” the baseline ๐Ÿฆ‹ you get interprocedural call and return events (the stuff that jumps between functions), plus the most important state changes for a diagnostic. For example, for a double-free diagnostic, both calls to free get shown.
  • 1 โ€” everything from level 0, plus events for entering each function โœจ
  • 2 โ€” everything from level 1, plus control-flow events that matter for triggering the issue, like "true path taken" at a conditional ๐Ÿงš This level is the default. bestie, you don't have to do anything for this one.
  • 3 โ€” everything from level 2, but now you get all the control-flow events, not just the significant ones ๐ŸŒˆ
  • 4 โ€” this one is built for analyzer developers ๐Ÿ”ฅ It adds a bunch of extra events meant for debugging the analyzer itself.

  • -fdump-analyzer โ€” dumps internal details about what the analyzer is up to into file.analyzer.txt. Heads up, -fdump-analyzer-stderr overrides this one ๐Ÿ™ˆ
  • -fdump-analyzer-stderr โ€” same deal, but the dump goes to stderr instead ๐Ÿ’… This one overrides -fdump-analyzer.
  • -fdump-analyzer-callgraph โ€” dumps a call graph you can view with GraphViz, saved to file.callgraph.dot ๐ŸŒธ
  • -fdump-analyzer-exploded-graph โ€” dumps the "exploded graph" for GraphViz, saved to file.eg.dot. The nodes are color-coded by state-machine states so state changes pop ๐ŸŽ€
  • -fdump-analyzer-exploded-nodes โ€” emits diagnostics showing where the nodes in the "exploded graph" sit relative to your program's source โœจ
  • -fdump-analyzer-exploded-nodes-2 โ€” dumps a textual version of the "exploded graph" to file.eg.txt ๐Ÿ“
  • -fdump-analyzer-exploded-nodes-3 โ€” dumps a textual version of the "exploded graph," but one dump file per node, named file.eg-id.txt ๐Ÿ˜ญ Expect a lot of files.
  • -fdump-analyzer-exploded-paths โ€” dumps a textual "exploded path" for each diagnostic into file.idx.kind.epath.txt ๐Ÿฆ‹
  • -fdump-analyzer-feasibility โ€” dumps internal details about how the analyzer searches for feasible paths. It's written so you can view it with GraphViz, in files named file.*.fg.dot and file.*.tg.dot ๐Ÿงš
  • -fdump-analyzer-json โ€” dumps a compressed JSON version of the analyzer's internals to file.analyzer.json.gz ๐Ÿ’œ The precise format is subject to change, so don't build anything permanent on it yet.
  • -fdump-analyzer-state-purge โ€” same vibe as -fdump-analyzer-supergraph (it dumps a "supergraph" for GraphViz), but this one annotates the graph with what state gets purged at each node. It's written to file.state-purge.dot ๐Ÿ”ฅ
  • -fdump-analyzer-supergraph โ€” dumps representations of the "supergraph" for GraphViz, saved to file.supergraph.dot and file.supergraph-eg.dot. These show every control-flow graph in the program, with interprocedural edges for calls and returns ๐Ÿ‘‘ The second dump has annotations showing nodes in the "exploded graph" and any diagnostics tied to them.

โœจ Options for Debugging Your Program โœจ

okay bestie, if you want GCC to emit extra info for a debugger, you almost always just need to add -g to your other options ๐Ÿซถ Some debug formats can co-exist (like DWARF with CTF) as long as you enable each one explicitly with its own command-line option.

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

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

  • -g โ€” produces debugging info in the operating system's native format (stabs, COFF, XCOFF, or DWARF) ๐ŸŽ€ GDB can work with this info. On most systems that use stabs, -g turns on extra debugging info that only GDB can use. Those extras make debugging in GDB better, but they'll probably make other debuggers crash or refuse to read the program ๐Ÿ˜ญ If you want to be certain which extra info gets generated, use -gstabs+, -gstabs, -gxcoff+, -gxcoff, or -gvms (more on those below).
  • -ggdb โ€” produces debugging info for GDB ๐Ÿ”ฅ It uses the most expressive format available (DWARF, stabs, or the native format if neither of those is supported), including GDB extensions whenever possible.
  • -gdwarf, -gdwarf-version โ€” produces debugging info in DWARF format (if supported) ๐Ÿฆ‹ The version can be 2, 3, 4 or 5. The default is 5 for most targets, except VxWorks, TPF and Darwin/Mac OS X, which default to version 2, and AIX, which defaults to version 4.

Heads up: with DWARF Version 2, some ports require and always use some non-conflicting DWARF 3 extensions in the unwind tables. Version 4 may need GDB 7.0 and -fvar-tracking-assignments for maximum benefit, and version 5 needs 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 Version 2 in their names, but they apply to all currently supported versions of DWARF.
  • -gbtf โ€” requests BTF debug info ๐ŸŒธ BTF is the default debugging format for the eBPF target. On other targets, like x86, BTF info can be generated alongside DWARF when both formats are enabled explicitly through their own command-line options.
  • -gctf, -gctflevel โ€” requests CTF debug info, where level sets how much CTF info gets produced โœจ If you write -gctf without a value for level, the default level is 2. CTF info can be generated alongside DWARF when both are enabled explicitly through their own options.
    • Level 0 produces no CTF debug info at all, so -gctf0 negates -gctf ๐Ÿ™ˆ
    • Level 1 produces CTF info for tracebacks only. This includes callsite info but not type info.
    • Level 2 produces type info for entities (functions, data objects etc.) at file scope or global scope only.
  • -gstabs โ€” produces debugging info in stabs format (if 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 output that DBX doesn't understand. On System V Release 4 systems, this option requires the GNU assembler.
  • -gstabs+ โ€” produces debugging info in stabs format (if supported), using GNU extensions that only the GNU debugger (GDB) understands ๐Ÿ’œ Using these extensions will likely make other debuggers crash or refuse to read the program.
  • -gxcoff โ€” produces debugging info in XCOFF format (if supported) ๐Ÿ“ This is the format DBX uses on IBM RS/6000 systems.
  • -gxcoff+ โ€” produces debugging info in XCOFF format (if supported), using GNU extensions that only GDB understands ๐Ÿ”ฅ Using these extensions will likely 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 info in Alpha/VMS debug format (if supported) ๐ŸŒˆ This is the format DEBUG uses on Alpha/VMS systems.
  • -glevel, -ggdblevel, -gstabslevel, -gxcofflevel, -gvmslevel โ€” requests debugging info and uses level to set how much info you get ๐Ÿ’– The default level is 2.
    • Level 0 produces no debug info at all, so -g0 negates -g ๐Ÿ™ˆ
    • Level 1 produces minimal info, enough to make backtraces in parts of the program you don't plan to debug. This includes descriptions of functions and external variables, plus line number tables, but no info about local variables.
    • Level 3 includes extra info, like all the macro definitions 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 one 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 info is produced for symbols that aren't actually used. Use this option if you want debug info for all symbols ๐Ÿซถ
  • -femit-class-debug-always โ€” instead of emitting debugging info for a C++ class in only one object file, this emits it in every object file that uses the class ๐Ÿ’… Only use this with debuggers that can't handle how GCC normally emits class debug info. Using this option increases the size of the debugging info by as much as a factor of two, so it's a lot ๐Ÿ˜ญ
  • -fno-merge-debug-strings โ€” tells the linker not to merge strings in the debugging info that are identical across different object files ๐ŸŒธ Merging isn't supported by all assemblers or linkers. It shrinks the debug info in the output file but costs more link processing time. Merging is enabled by default, so you only need this if you want it off.
  • -fdebug-prefix-map=old=new ๐Ÿ—บ๏ธ โ€” okay so when you compile files living in directory old, GCC records their debug info as if they lived in new instead. This is perfect for swapping a build-time path for an install-time path in the debug info. You can also turn an absolute path into a relative one by using . for new. It can give you more reproducible, location-independent builds, but you might need an extra command to tell GDB where to find the source files. See also -ffile-prefix-map. ๐Ÿ’–
  • -fvar-tracking ๐Ÿ” โ€” runs the variable tracking pass, which works out where variables are stored at each position in the code. Better debug info gets generated (if your debug format supports it) โœจ
    • Lowkey on by default when you compile with optimization (-Os, -O, -O2, ...) and debug info (-g), as long as the debug info format supports it. ๐ŸŒธ
  • -fvar-tracking-assignments ๐Ÿ“ โ€” annotates assignments to user variables early in compilation, then tries to carry those annotations all the way to the end to improve debug info while optimizing. Using -gdwarf-4 alongside it is recommended ๐Ÿซถ
    • It can be enabled even when var-tracking is disabled. In that case the annotations get created and maintained, but thrown away at the end.
    • By default this rides along with -fvar-tracking, except when selective scheduling is enabled. ๐Ÿ’…
  • -gsplit-dwarf ๐Ÿงš โ€” if DWARF debug info is enabled, it separates as much of it as possible into a separate output file with the extension .dwo. This lets your build system skip linking files that carry debug info. To be useful, you need a debugger that can read .dwo files. ๐Ÿฆ‹
  • -gdwarf32, -gdwarf64 ๐ŸŽ€ โ€” if DWARF debug info is 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. 32-bit is smaller, but it can't handle more than 2GiB of debug info in any of the DWARF debug info sections. 64-bit allows bigger debug info, but not every consumer supports it well yet ๐Ÿ™ˆ
  • -gdescribe-dies ๐ŸŒˆ โ€” adds description attributes to some DWARF DIEs that have no name attribute, like artificial variables, external references, and call site parameter DIEs.
  • -gpubnames ๐Ÿ“š โ€” generates the DWARF .debug_pubnames and .debug_pubtypes sections.
  • -ggnu-pubnames ๐ŸŒŸ โ€” generates .debug_pubnames and .debug_pubtypes in a format that's suitable for converting into a GDB index. This is only useful with a linker that can produce GDB index version 7 ๐Ÿซง
  • -fdebug-types-section ๐Ÿง โ€” when you're using DWARF Version 4 or higher, type DIEs can get their own .debug_types section instead of living in .debug_info. It's more efficient in a separate comdat section, since the linker can then remove duplicates. BUT not all DWARF consumers support .debug_types yet, and on some objects it makes the debug info bigger instead of smaller ๐Ÿ˜ญ
  • -grecord-gcc-switches, -gno-record-gcc-switches ๐Ÿ“ โ€” makes the command-line options that might affect code generation get appended to the DW_AT_producer attribute in DWARF debug info. They're joined with spaces, separating them from each other and from the compiler version. It's enabled by default. See also -frecord-gcc-switches for another way to store compiler options in the object file. โœจ
  • -gstrict-dwarf ๐Ÿšซ โ€” disallows using extensions from a later DWARF standard version than the one you picked with -gdwarf-version. On most targets, using non-conflicting extensions from later versions is allowed anyway ๐Ÿ’œ
  • -gno-strict-dwarf ๐Ÿ•Š๏ธ โ€” allows using extensions from a later DWARF standard version than the one you picked with -gdwarf-version.
  • -gas-loc-support ๐Ÿ“ โ€” tells the compiler that the assembler supports .loc directives. The compiler can then use them so the assembler generates DWARF2+ line number tables. This is generally desirable, because assembler-generated line-number tables are way more compact than the ones the compiler makes itself. It's enabled by default if, at GCC configure time, the assembler was found to support those directives. ๐Ÿฆ‹
  • -gno-as-loc-support ๐Ÿ™… โ€” forces GCC to generate DWARF2+ line number tables internally, if DWARF2+ line number tables are going to be generated at all.
  • -gas-locview-support ๐Ÿ‘€ โ€” tells the compiler that the assembler supports "view" assignment and reset assertion checking in .loc directives. It's enabled by default if, at GCC configure time, the assembler was found to support them.
  • -gno-as-locview-support ๐Ÿ”ง โ€” forces GCC to assign view numbers internally, if -gvariable-location-views has been explicitly requested.
  • -gcolumn-info, -gno-column-info ๐Ÿ“ โ€” emits location column information into DWARF debug info, not just file and line. It's enabled by default. ๐Ÿซถ
  • -gstatement-frontiers, -gno-statement-frontiers ๐Ÿšฉ โ€” makes GCC create markers in the internal representation at the beginning of statements, and keep them roughly in place throughout compilation. Those markers guide the output of "is_stmt" markers in the line number table. It's enabled by default when you compile with optimization (-Os, -O1, -O2, ...) and output DWARF 2 debug info at the normal level ๐Ÿ”ฅ
  • -gvariable-location-views, -gvariable-location-views=incompat5, -gno-variable-location-views ๐ŸŒธ โ€” augments variable location lists with progressive view numbers implied from the line number table. This lets debug info consumers inspect state at certain points of the program, even when no instructions tied to those source locations exist there. If the assembler can't handle view numbers in line number tables, the compiler will emit the line number table itself, which makes it somewhat less compact. The augmented line number tables and location lists are fully backward-compatible, so consumers that don't know about these augmentations can still read them, but they won't get any benefit from them either.
    • Default: this is enabled when outputting DWARF 2 debug info at the normal level, as long as there's assembler support, -fvar-tracking-assignments is enabled, and -gstrict-dwarf is not. Without assembler support it may still be enabled, but that forces GCC to output internal line number tables. And if -ginternal-reset-location-views isn't enabled, that will most certainly lead to silently mismatching location views. ๐Ÿ˜ฑ
    • There's a proposed representation for view numbers that is not backward compatible with the location list format introduced in DWARF 5. You can enable it with -gvariable-location-views=incompat5. ๐Ÿงช
โš ๏ธ Heads up bestie: -gvariable-location-views=incompat5 may be removed in the future, and it's only provided as a reference implementation of the proposed representation. Debug info consumers aren't expected to support this extended format, and they'd be rendered unable to decode location lists that use it. ๐Ÿ’€
  • -ginternal-reset-location-views, -gno-internal-reset-location-views ๐Ÿงฉ โ€” attempts to determine which location views can be left out of location view lists. This requires the compiler to have very accurate insn length estimates, which isn't always the case. It may silently generate incorrect view lists when you're using an assembler that doesn't support location view lists. The GNU assembler will flag any such error as a "view number mismatch". This is only enabled on ports that define a reliable estimation function. ๐Ÿซ 
  • -ginline-points, -gno-inline-points โœจ โ€” generates extended debug info for inlined functions. Location view tracking markers get inserted at inlined entry points, so address and view numbers can be computed and output in the debug info. This can be enabled independently of location views, in which case the view numbers won't be output. It can only be enabled along with statement frontiers, and it's only enabled by default if location views are enabled. ๐Ÿงš
  • -gz[=type] ๐Ÿ—œ๏ธ โ€” produces compressed debug sections in DWARF format, if that's supported. If type isn't given, the default depends on what the assembler and linker can do. type may be one of:
    • none โ€” don't compress debug sections
    • zlib โ€” use zlib compression in ELF gABI format
    • zlib-gnu โ€” use zlib compression in traditional GNU format

If the linker doesn't support writing compressed debug sections, the option gets rejected. Otherwise, if the assembler doesn't support them, -gz is silently ignored when producing object files. ๐Ÿคทโ€โ™€๏ธ

  • -femit-struct-debug-baseonly ๐ŸŽฏ โ€” emits debug info for struct-like types only when the base name of the compilation source file matches the base name of the file where the struct is defined. This substantially reduces the size of debug info, but there's a significant potential loss in type information for the debugger. See -femit-struct-debug-reduced for a less aggressive option, and -femit-struct-debug-detailed for more detailed control. This option works only with DWARF debug output. ๐ŸŒท
  • -femit-struct-debug-reduced ๐ŸŒฟ โ€” emits debug info for struct-like types only when the base name of the compilation source file matches the base name of the file where the type is defined, unless the struct is a template or defined in a system header. It significantly reduces the size of debug info, with some potential loss in type information for the debugger. See -femit-struct-debug-baseonly for a more aggressive option, and -femit-struct-debug-detailed for more detailed control. This option works only with DWARF debug output. ๐Ÿƒ
  • -femit-struct-debug-detailed[=spec-list] ๐Ÿ’œ โ€” specifies the struct-like types that the compiler generates debug info for. The goal is to cut down on duplicate struct debug info between different object files within the same program. ๐Ÿซถ

okay so this one is literally the detailed version of -femit-struct-debug-reduced and -femit-struct-debug-baseonly ๐Ÿ’… those two handle most needs, but this is the extra-fancy control panel for when you want to fine-tune which structs get debug info โœจ

A specification has the syntax:

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

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

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

The third word says which source files the structs come from, so the compiler knows which ones should get debug info ๐ŸŽ€ none and any mean what you'd expect. base means the base name of the file where the type is declared has to match the base name of the main compilation file. In real life, that means when you compile foo.c, debug info is generated for types declared in that file and foo.h, but not other header files ๐Ÿ“ sys means those types satisfying base or declared in system or compiler headers.

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

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

This option works only with DWARF debug output โš ๏ธ
  • -fno-dwarf2-cfi-asm โ€” Emits DWARF unwind info as a compiler-generated ".eh_frame" section, instead of using GAS ".cfi_*" directives. Bestie, it's giving "do it the compiler's way" ๐Ÿ’…
  • -fno-eliminate-unused-debug-types โ€” 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 debugging info for every type declared in a compilation unit, even unused ones. For example, if you want to cast a value to a type that's declared but never actually used in your program, in the debugger ๐Ÿ” The catch? It often results in a significant amount of wasted 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: 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. Iconic behavior, honestly ๐Ÿ‘‘

Turning on optimization flags makes the compiler try to improve performance and/or code size, 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 of them ๐Ÿง 

Not every optimization is controlled directly by a flag. Only 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 individual optimization flags are specified ๐Ÿ™ˆ 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. To find out the exact set enabled at 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
-fmove-loop-stores -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 option increases both compilation time and the performance of the generated code ๐Ÿš€

-O2 turns on all optimization flags specified by -O1. 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-loop-vectorize
-ftree-pre -ftree-slp-vectorize -ftree-switch-conversion
-ftree-tail-merge -ftree-vrp -fvect-cost-model=very-cheap
Heads up: please note the warning under -fgcse about invoking -O2 on programs that use computed gotos โš ๏ธ

โœจ -O3 โœจ

Optimize yet more ๐Ÿ‘‘ -O3 turns on all optimizations specified by -O2, and 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-partial-pre -funswitch-loops -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 those that often increase code size:

-falign-functions  -falign-jumps -falign-labels  -falign-loops
-fprefetch-loop-arrays  -freorder-blocks-algorithm=stc

It also enables -finline-functions, makes the compiler tune for code size rather than execution speed, and performs further optimizations designed to 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.

Be careful with this one ๐Ÿ’€ 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. It turns off -fsemantic-interposition.

โœจ -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 those that may interfere with debugging:

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

โœจ -Oz โœจ

Optimize aggressively for size rather than speed ๐Ÿฆ‹ This may increase the number of instructions executed if those instructions require fewer bytes to encode. -Oz behaves similarly to -Os, including enabling most -O2 optimizations.

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

Options of the form -fflag specify machine-independent flags ๐ŸŒธ Most flags have both positive and negative forms; 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 these flags in the rare cases when "fine-tuning" of the optimizations to be performed is desired ๐Ÿ”ง

  • -fno-defer-pop โ€” For machines that must pop arguments after a function call, this always pops the arguments as soon as each function returns. At levels -O1 and higher, -fdefer-pop is the default, which lets the compiler let arguments pile up on the stack for several function calls and pop them all at once ๐Ÿฅž
  • -fforward-propagate โ€” Performs a forward propagation pass on RTL. The pass tries to combine two instructions and checks whether the result can be simplified. If loop unrolling is active, two passes are performed and the second is scheduled after loop unrolling ๐Ÿฆ‹

This option is enabled by default at optimization levels -O1, -O2, -O3, -Os.

  • -ffp-contract=style โ€” okay so this one decides whether the compiler is allowed to squish floating-point math together ๐Ÿงฎโœจ -ffp-contract=off flat out disables expression contraction ๐Ÿ™…โ€โ™€๏ธ -ffp-contract=fast turns it on so things like fused multiply-add operations can get formed, but only if the target has native support for them ๐Ÿ”ฅ -ffp-contract=on turns it on only if the language standard allows it ๐Ÿ“œ but bestie, this one isn't actually implemented yet ๐Ÿ’€ so it's treated exactly the same as -ffp-contract=off. The default is -ffp-contract=fast ๐Ÿ’–
  • -fomit-frame-pointer โ€” omit the frame pointer in functions that don't actually need one ๐Ÿฆ‹ this skips all the work of saving, setting up, and restoring the frame pointer, and on lots of targets it also frees up an extra register for you โœจ on some targets it does nothing, because the standard calling sequence always uses a frame pointer, so it can't be left out ๐Ÿ™ƒ also, -fno-omit-frame-pointer doesn't guarantee the frame pointer gets used in every function, since several targets always omit it in leaf functions ๐Ÿ‘€ enabled by default at -O1 and higher ๐Ÿ’…
  • -foptimize-sibling-calls โ€” optimizes sibling and tail recursive calls ๐Ÿ” enabled at levels -O2, -O3, -Os ๐ŸŒธ
  • -foptimize-strlen โ€” glow-up time ๐Ÿ’… this optimizes various standard C string functions (like "strlen", "strchr" or "strcpy") and their "_FORTIFY_SOURCE" counterparts into faster alternatives ๐Ÿš€ enabled at levels -O2, -O3 โญ
  • -fno-inline โ€” no inlining for you, unless the function has the always_inline attribute ๐Ÿ™… this is the default when you aren't optimizing ๐Ÿ“ and if you want to exempt a single function from inlining, just mark it 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, and this applies to all functions, even the ones not declared inline ๐Ÿ’œ enabled at levels -O2, -O3, -Os โœจ
  • -findirect-inlining โ€” inlines indirect calls that are discovered to be known at compile time, thanks to earlier inlining ๐Ÿช„ this only does anything 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 picks which ones are worth it ๐Ÿง  if every call to a given function gets integrated and the function is declared static, then it usually won't be output as assembler code on its own ๐Ÿซง enabled at levels -O2, -O3, -Os, and also enabled by -fprofile-use and -fauto-profile ๐Ÿ”ฅ
  • -finline-functions-called-once โ€” considers all static functions called exactly once for inlining into their caller, even if they aren't marked inline ๐ŸŽ€ if that call gets integrated, the function isn't output as assembler code by itself ๐Ÿฆ‹ enabled at levels -O1, -O2, -O3 and -Os, but not -Og ๐Ÿ™ˆ
  • -fearly-inlining โ€” inlines functions marked always_inline, plus any functions whose body seems smaller than the call overhead, early on, before the -fprofile-generate instrumentation and the real inlining pass ๐Ÿง doing it this way makes profiling way cheaper and usually makes inlining faster in programs with big chains of nested wrapper functions ๐Ÿ’… enabled by default ๐Ÿ‘‘
  • -fipa-sra โ€” does interprocedural scalar replacement of aggregates ๐Ÿงฉ it also removes unused parameters and swaps parameters passed by reference for parameters passed by value ๐Ÿ”„ enabled at levels -O2, -O3 and -Os ๐ŸŒธ
  • -finline-limit=n โ€” by default GCC limits how big a function can be and still get inlined, and this flag gives you coarse control over that limit ๐ŸŽš๏ธ n is the size of functions that can be inlined, measured in pseudo instructions ๐Ÿ“ inlining is actually controlled by a bunch of parameters, which you can set one at a time with --param name=value, and -finline-limit=n sets some of them like this:
    • max-inline-insns-single is set to n/2
    • max-inline-insns-auto is set to n/2

See below for documentation on the individual inlining parameters and their defaults ๐Ÿ“–

Note: there may be no value to -finline-limit that results in default behavior ๐Ÿคทโ€โ™€๏ธ Note: a pseudo instruction, in this context, is just an abstract measurement of a function's size ๐Ÿซ  it in no way represents a count of assembly instructions, and its exact meaning might change from one release to another ๐Ÿ’€
  • -fno-keep-inline-dllexport โ€” this is a more fine-grained version of -fkeep-inline-functions ๐Ÿ” it only applies to functions declared with the dllexport attribute or declspec ๐ŸŽฏ
  • -fkeep-inline-functions โ€” in C, it emits static functions that are declared inline into the object file, even if they've been inlined into all of their callers ๐Ÿ“ฆ this switch doesn't affect functions using the extern inline extension in GNU C90 ๐Ÿ™… in C++, it emits any and all inline functions into the object file ๐Ÿ’œ
  • -fkeep-static-functions โ€” emits static functions into the object file, even if they're never used ๐Ÿ—‚๏ธ no notes, just vibes ๐ŸŒท
  • -fkeep-static-consts โ€” emits variables declared static const when optimization isn't turned on, even if they aren't referenced ๐Ÿ’Ž GCC enables this by default ๐Ÿฅฐ if you want the compiler to check whether a variable is referenced no matter what optimization is doing, use the -fno-keep-static-consts option ๐Ÿซถ
  • -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 stop it ๐Ÿ™… enabled at levels -O1, -O2, -O3, -Os ๐ŸŒˆ
  • -fmerge-all-constants โ€” attempts to merge identical constants and identical variables ๐Ÿซจ this implies -fmerge-constants, and on top of that it considers things like constant initialized arrays or initialized constant variables with integral or floating-point types ๐Ÿงฎ
Warning, bestie ๐Ÿ’€ C and C++ require each variable, including multiple instances of the same variable in recursive calls, to have distinct locations, so using -fmerge-all-constants results in non-conforming behavior ๐Ÿšจ
  • -fmodulo-sched โ€” performs swing modulo scheduling right before the first scheduling pass ๐ŸŽข it looks at the innermost loops and reorders their instructions by overlapping different iterations ๐Ÿ”
  • -fmodulo-sched-allow-regmoves โ€” 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 ๐Ÿง  it's only effective when -fmodulo-sched is 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 sequences that decrement a register, compare it to zero, and then branch based on the result ๐Ÿ™… this only matters on architectures that support those instructions, which include x86, PowerPC, IA-64 and S/390 ๐Ÿ–ฅ๏ธ note that -fno-branch-count-reg doesn't remove decrement and branch instructions that other optimization passes already put in the instruction stream ๐Ÿซ  the default is -fbranch-count-reg at -O1 and higher, except for -Og ๐Ÿ’…
  • -fno-function-cse โ€” does not put function addresses in registers, so each instruction that calls a constant function contains the function's address explicitly ๐Ÿ“ this makes less efficient code, but some strange hacks that alter the assembler output can get confused by the optimizations you get when this option isn't used ๐Ÿ™ˆ the default is -ffunction-cse

  • -fno-zero-initialized-in-bss โ€” if the target supports a BSS section, GCC puts variables that are initialized to zero into BSS by default, which can save space in the resulting code ๐Ÿ’พ this option turns that off, because some programs explicitly rely on variables going into the data section ๐Ÿฅบ for example, so the executable can find the beginning of that section, 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 one is found ๐Ÿงต if so, the first branch gets redirected to either the destination of the second branch or a point right after it, depending on whether the condition is known to be true or false ๐Ÿฆ‹ enabled at levels -O1, -O2, -O3, -Os โœจ
  • -fsplit-wide-types โ€” when using a type that takes up multiple registers, like long long on a 32-bit system, this splits the registers apart and allocates them independently ๐Ÿงฉ this usually generates better code for those types, but it may make debugging more difficult ๐Ÿ™ƒ enabled at levels -O1, -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 โ€” during common subexpression elimination (CSE), scans through jump instructions when the target of the jump isn't reached by any other path ๐Ÿ•ต๏ธ for example, when CSE encounters an if statement with an else clause, it follows the jump when the tested condition is false ๐Ÿชž enabled at levels -O2, -O3, -Os ๐ŸŒท
  • -fcse-skip-blocks โ€” similar to -fcse-follow-jumps, but this one makes CSE follow jumps that conditionally skip over blocks ๐Ÿฆ˜ when CSE hits a simple if statement with no else clause, -fcse-skip-blocks makes it follow the jump around the body of the if ๐Ÿ’… enabled at levels -O2, -O3, -Os โœจ
  • -frerun-cse-after-loop โ€” re-runs common subexpression elimination after loop optimizations have been performed ๐Ÿ” enabled at levels -O2, -O3, -Os ๐Ÿ‘‘
  • -fgcse โ€” okay so this one runs a global common subexpression elimination pass ๐Ÿง โœจ. It also handles global constant and copy propagation, which is giving main character energy ๐Ÿ‘‘. It turns on at -O2, -O3, and -Os ๐Ÿ’….
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 common subexpression elimination pass by adding -fno-gcse to your command line. Bestie, test it and see ๐Ÿ’–.
  • -fgcse-lm โ€” when this is on, global common subexpression elimination tries to move loads that only get killed by stores back into themselves ๐ŸŒธ. That means a loop with a load/store sequence can become a load outside the loop and a copy/store inside it. Lowkey genius ๐Ÿงš. It's enabled by default whenever -fgcse is enabled.
  • -fgcse-sm โ€” this runs a store motion pass right after global common subexpression elimination ๐Ÿฆ‹. It tries to yeet stores out of loops. Team it up with -fgcse-lm and loops with a load/store sequence can turn into a load before the loop and a store after it ๐Ÿ”ฅ. Not enabled at any optimization level, so you have to ask for it ๐Ÿซถ.
  • -fgcse-las โ€” with this on, the global common subexpression elimination pass cleans up redundant loads that show up after stores to the same memory location, covering both partial and full redundancies โœจ. Also not enabled at any optimization level ๐Ÿ’€.
  • -fgcse-after-reload โ€” this one runs a redundant load elimination pass after reload ๐Ÿงน. Its whole purpose is cleaning up redundant spilling. It's enabled by -O3, -fprofile-use, and -fauto-profile ๐Ÿ‘‘.
  • -faggressive-loop-optimizations โ€” the loop optimizer uses language constraints to figure out bounds for how many times a loop runs ๐Ÿ”. It assumes your loop code won't trigger undefined behavior, like 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: because this assumes no undefined behavior, code that does hit signed integer overflow or out-of-bound array accesses in a loop is not what this option is built for ๐Ÿ’€.
  • -funconstrained-commons โ€” this tells the compiler that variables declared in common blocks (think Fortran ๐Ÿงš) might get overridden later with longer trailing arrays ๐ŸŒˆ. It stops certain optimizations that rely on knowing the array bounds, so it's a bit of a buzzkill but it keeps things safe ๐Ÿซถ.
  • -fcrossjumping โ€” this does a cross-jumping transformation ๐Ÿฆ‹. It merges equivalent code together to save code size. The result might run better, or it might not, so it's a vibe check ๐Ÿคทโ€โ™€๏ธ. It turns on at -O2, -O3, and -Os โœจ.
  • -fauto-inc-dec โ€” this combines increments or decrements of addresses with memory accesses ๐Ÿ’–. The pass is always skipped on architectures that don't have instructions to support it. It's enabled by default at -O1 and higher, but only on architectures that actually support it ๐ŸŒธ.
  • -fdce โ€” this performs dead code elimination (DCE) on RTL ๐Ÿ—‘๏ธ. Bye bye useless code ๐Ÿ’…. It's enabled by default at -O1 and higher.
  • -fdse โ€” this performs dead store elimination (DSE) on RTL ๐Ÿงน. Stores that nobody reads get tossed. It's enabled by default at -O1 and higher ๐Ÿ”ฅ.
  • -fif-conversion โ€” this attempts to turn conditional jumps into branch-less equivalents โœจ. It uses things like conditional moves, min, max, set flags, and abs instructions, plus some tricks you can do with standard arithmetic ๐Ÿง . On chips that have conditional execution, that part is handled by -fif-conversion2. It's enabled at -O1, -O2, -O3, and -Os, but not with -Og ๐Ÿ™…โ€โ™€๏ธ.
  • -fif-conversion2 โ€” this uses conditional execution (where your chip has it) to turn conditional jumps into branch-less equivalents ๐Ÿฆ‹. It's enabled at -O1, -O2, -O3, and -Os, but not with -Og ๐Ÿ’œ.
  • -fdeclone-ctor-dtor โ€” okay so the C++ ABI needs 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 ๐ŸŒˆ. With a hierarchy that has virtual bases, the base and complete variants end up as clones, which means two copies of the same function ๐Ÿ˜ญ. With this option, those variants become thunks that call one common implementation instead ๐Ÿ’…. It's enabled by -Os ๐Ÿ“.
  • -fdelete-null-pointer-checks โ€” this assumes programs can't safely dereference null pointers, and that no code or data lives at address zero ๐Ÿ™ˆ. It turns on simple constant folding optimizations at all optimization levels ๐Ÿ’–. Other GCC passes use this flag to run global dataflow analyses that delete useless null pointer checks. Those analyses assume that touching address zero always traps, so if a pointer gets checked after it's already been dereferenced, it can't be null ๐Ÿง .
Note however that in some environments this assumption is not true ๐Ÿ’€. If your program depends on that behavior, 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, it's completely disabled ๐Ÿšซ. Passes that use the dataflow information are enabled independently at different optimization levels ๐ŸŽ€.

  • -fdevirtualize โ€” this tries to convert calls to virtual functions into direct calls ๐Ÿฆ‹. It happens both within a procedure and across procedures, as part of indirect inlining (-findirect-inlining) and interprocedural constant propagation (-fipa-cp) โœจ. It's enabled at -O2, -O3, and -Os ๐Ÿ’….
  • -fdevirtualize-speculatively โ€” this tries to convert virtual function calls into speculative direct calls ๐Ÿ”ฎ. It looks at the type inheritance graph to figure out the set of likely targets for a call ๐Ÿง . If that set is small, ideally size 1, the call becomes a conditional that picks between a direct call and an indirect call ๐Ÿ’–. These speculative calls unlock more optimizations, like inlining ๐Ÿ”ฅ. If they stop being useful after further optimization, they get converted back to their original form ๐Ÿ™ƒ.
  • -fdevirtualize-at-ltrans โ€” this streams extra info needed for aggressive devirtualization when the link-time optimizer runs in local transformation mode ๐Ÿšš. You get more devirtualization, but the amount of streamed data goes up a lot ๐Ÿ˜ญ. Because of that, it's disabled by default ๐Ÿ’œ.
  • -fexpensive-optimizations โ€” this performs a bunch of minor optimizations that are relatively expensive to run ๐Ÿ’ธ. It's enabled at -O2, -O3, and -Os ๐ŸŒธ.
  • -free โ€” this tries to remove redundant extension instructions โœ‚๏ธ. It's especially helpful on the x86-64 architecture, which implicitly zero-extends 64-bit registers after writing to their lower 32-bit half ๐Ÿงš. It's enabled for Alpha, AArch64, and x86 at -O2, -O3, and -Os ๐ŸŽ€.
  • -fno-lifetime-dse โ€” in C++, an object's value is only affected by changes made during its lifetime ๐Ÿฆ‹. When the constructor begins, the object has an indeterminate value, and any changes made during its lifetime are dead once it's destroyed ๐Ÿ’€. Normally dead store elimination takes advantage of that. But if your code relies on the object's storage value sticking around after the lifetime ends, use this flag to turn that optimization off ๐Ÿซถ. If you want to keep stores made before the constructor starts (say your operator new clears the object storage) but still treat the object as dead after the destructor, use -flifetime-dse=1 ๐Ÿ’–. The default can be picked explicitly with -flifetime-dse=2 ๐Ÿ‘‘. -flifetime-dse=0 is the same as -fno-lifetime-dse ๐Ÿ™ˆ.
  • -flive-range-shrinkage โ€” this tries to cut down register pressure through register live range shrinkage ๐ŸŒˆ. It's especially helpful on fast processors with small or moderate-sized register sets ๐Ÿš€.
  • -fira-algorithm=algorithm โ€” this picks the coloring algorithm for the integrated register allocator ๐ŸŽจ. The algorithm 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 โ€” this picks which 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 value usually gives the best results in most cases and for most architectures ๐Ÿ’–. It's enabled by default when you compile with optimization for speed (-O, -O2, ...) ๐Ÿš€.
    • one โ€” uses all functions as a single region ๐Ÿงฉ. This typically gives the smallest code size, and it's enabled by default for -Os or -O0 ๐ŸŒธ.
  • -fira-hoist-pressure โ€” this uses IRA to evaluate register pressure in the code hoisting pass when deciding whether to hoist expressions ๐Ÿ—๏ธ. It usually gives smaller code, but it can slow the compiler down ๐Ÿข. It's enabled at -Os for all targets ๐Ÿ“.
  • -fira-loop-pressure โ€” this uses IRA to evaluate register pressure in loops when deciding whether to move loop invariants ๐Ÿ”. On machines with large register files (>= 32 registers), it usually makes code faster and smaller ๐Ÿš€. The catch is it can slow the compiler down too ๐Ÿซ . It's enabled at -O3 for some targets โœจ.
  • -fno-ira-share-save-slots โ€” this turns off sharing of stack slots used for saving call-used hard registers that live through a call ๐Ÿ™…โ€โ™€๏ธ. Every hard register gets its own stack slot, so function stack frames end up bigger ๐Ÿ“ฆ.
  • -fno-ira-share-spill-slots โ€” this turns off sharing of stack slots allocated for pseudo-registers ๐Ÿ™…โ€โ™€๏ธ. Each pseudo-register that doesn't get a hard register gets its own stack slot, so yep, function stack frames get bigger too ๐Ÿ“ฆ๐Ÿ’€.
  • -flra-remat โ€” this enables CFG-sensitive rematerialization in LRA ๐Ÿงช. Instead of loading the values of spilled pseudos, LRA tries to rematerialize (recalculate) them when that's profitable ๐Ÿง . It's enabled at -O2, -O3, and -Os ๐Ÿ’….
  • -fdelayed-branch โ€” if your target machine supports it, this tries to reorder instructions so they fill the instruction slots available after delayed branch instructions ๐Ÿฆ‹. It's enabled at -O1, -O2, -O3, and -Os, but not at -Og ๐Ÿ™…โ€โ™€๏ธ.
  • -fschedule-insns โ€” okay bestie, if the target machine supports it, GCC will try to reshuffle instructions so the CPU stops stalling while it waits for data ๐Ÿซถ this is a lifesaver on machines with slow floating point or memory load instructions, because other stuff can get issued while the load or float op is still cooking. Enabled at levels -O2, -O3 ๐Ÿ’…
  • -fschedule-insns2 โ€” this is giving -fschedule-insns but with an extra pass of instruction scheduling that runs after register allocation is done ๐Ÿ”ฅ it's especially iconic on machines with a relatively small number of registers where memory load instructions take more than one cycle. Enabled at levels -O2, -O3, -Os ๐Ÿฆ‹
  • -fno-sched-interblock โ€” the vibe here is no scheduling across basic blocks ๐Ÿ™…โ€โ™€๏ธ normally this is on when scheduling happens before register allocation, so basically with -fschedule-insns or at -O2 or higher.
  • -fno-sched-spec โ€” shutting down speculative motion of non-load instructions ๐Ÿšซ this is normally on when scheduling happens before register allocation, so with -fschedule-insns or at -O2 or higher.
  • -fsched-pressure โ€” main character energy ๐Ÿ‘‘ this turns on register pressure sensitive insn scheduling before register allocation. It only makes sense when that pre-allocation scheduling is on, so with -fschedule-insns or at -O2 or higher. It can make the generated code better and smaller by stopping register pressure from climbing above the number of available hard registers, which means fewer nasty spills during register allocation ๐ŸŒธ
  • -fsched-spec-load โ€” allows speculative motion of some load instructions ๐Ÿงš this only makes sense when scheduling before register allocation, so with -fschedule-insns or at -O2 or higher.
  • -fsched-spec-load-dangerous โ€” ngl this one is spicy ๐ŸŒถ๏ธ it allows speculative motion of more load instructions. Same deal, it only makes sense when scheduling before register allocation, so with -fschedule-insns or at -O2 or higher. ๐Ÿ’€
  • -fsched-stalled-insns, -fsched-stalled-insns=n โ€” this controls how many insns (if any) can get moved early from the queue of stalled insns into the ready list during the second scheduling pass ๐ŸŽ€ -fno-sched-stalled-insns means nothing gets moved early, -fsched-stalled-insns=0 means there's no limit on how many queued insns can jump the line, and -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 being pulled out early ๐Ÿ” it only has an effect during the second scheduling pass, and only if -fsched-stalled-insns is being used. -fno-sched-stalled-insns-dep is the same as -fsched-stalled-insns-dep=0, and -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 you faster schedules.
โš ๏ธ This one is experimental, because not all of the machine descriptions GCC uses model the CPU closely enough to avoid unreliable results from the algorithm. Be careful bestie ๐Ÿ™ˆ

It only makes sense when scheduling after register allocation, so with -fschedule-insns2 or at -O2 or higher.

  • -fsched-group-heuristic โ€” turns on the group heuristic in the scheduler ๐Ÿ’œ it favors the instruction that belongs to a schedule group. It's enabled by default whenever scheduling is on, so with -fschedule-insns or -fschedule-insns2 or at -O2 or higher.
  • -fsched-critical-path-heuristic โ€” enables the critical-path heuristic in the scheduler ๐Ÿ›ฃ๏ธ it favors instructions that sit on the critical path. Also on by default whenever scheduling is enabled, so with -fschedule-insns or -fschedule-insns2 or at -O2 or higher.
  • -fsched-spec-insn-heuristic โ€” enables the speculative instruction heuristic in the scheduler ๐Ÿ”ฎ it favors speculative instructions with greater dependency weakness. On by default whenever scheduling is enabled, so with -fschedule-insns or -fschedule-insns2 or at -O2 or higher.
  • -fsched-rank-heuristic โ€” enables the rank heuristic in the scheduler ๐Ÿ† it favors instructions that belong to a basic block with greater size or frequency. On by default whenever scheduling is enabled, so with -fschedule-insns or -fschedule-insns2 or at -O2 or higher.
  • -fsched-last-insn-heuristic โ€” enables the last-instruction heuristic in the scheduler ๐Ÿซ  it favors the instruction that is less dependent on the last instruction scheduled. On by default whenever scheduling is enabled, so with -fschedule-insns or -fschedule-insns2 or at -O2 or higher.
  • -fsched-dep-count-heuristic โ€” enables the dependent-count heuristic in the scheduler ๐Ÿ‘‘ it favors the instruction that has more instructions depending on it. On by default whenever scheduling is enabled, so 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 got modulo scheduled, later scheduling passes might change its schedule. Use this option to 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 option does nothing unless -fselective-scheduling or -fselective-scheduling2 is turned on.
  • -fsel-sched-pipelining-outer-loops โ€” when pipelining loops during selective scheduling, this also pipelines the outer loops ๐ŸŒŸ it does nothing unless -fsel-sched-pipelining is turned on.
  • -fsemantic-interposition โ€” okay this one is deep ๐Ÿซง some object formats, like ELF, let the dynamic linker interpose symbols. That means for symbols exported from the DSO, the compiler can't do interprocedural propagation, inlining, or other optimizations, since the function or variable might get swapped out. It's useful for things like rewriting memory allocation functions with a debugging implementation, but it's expensive for 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. Same vibe for variables: if interposition happens, the constructor of the variable will be the same. This flag has no effect on functions explicitly declared inline, where interposition is never allowed to change semantics, and it has no effect on symbols explicitly declared weak ๐Ÿฆ‹
  • -fshrink-wrap โ€” emits function prologues only before the parts of the function that actually need them, instead of at the top of the function ๐Ÿ“ this is enabled by default at -O and higher.
  • -fshrink-wrap-separate โ€” shrink-wraps the parts of the prologue and epilogue separately, so each part only runs when it's needed ๐ŸŒท this is on by default, but it does nothing unless -fshrink-wrap is also turned on and the target supports it.

  • -fcaller-saves โ€” enables allocation of values to registers that get clobbered by function calls ๐Ÿงบ GCC does this by emitting extra instructions to save and restore those registers around the calls. It only happens when it seems to give better code โœจ

This option is always enabled by default on certain machines, usually the ones with no call-preserved registers to use instead ๐Ÿ’– Enabled at levels -O2, -O3, -Os.

  • -fcombine-stack-adjustments โ€” tracks stack adjustments (pushes and pops) and stack memory references, then tries to find ways to combine them ๐Ÿง  enabled by default at -O1 and higher.
  • -fipa-ra โ€” uses caller save registers for allocation if those registers aren't used by any called function ๐Ÿง  that means there's no need to save and restore them around calls. This is only possible if the called functions are part of the same compilation unit as the current function and they're compiled before it ๐Ÿซถ enabled at levels -O2, -O3, -Os, but 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 (this happens on targets that don't expose prologues and epilogues in RTL) ๐Ÿ™ˆ
  • -fconserve-stack โ€” attempts to minimize stack usage, even if that makes the program slower ๐Ÿข it uses less stack space on purpose. 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 -O1 and higher.
  • -fcode-hoisting โ€” performs code hoisting ๐Ÿƒโ€โ™€๏ธ this tries to move the evaluation of expressions that run on all paths to the function exit as early as possible. It's especially useful as a code size optimization, but it often helps code speed too ๐Ÿš€ enabled by default at -O2 and higher.
  • -ftree-pre โ€” performs partial redundancy elimination (PRE) on trees ๐Ÿงน enabled at -O2 and -O3.
  • -ftree-partial-pre โ€” makes partial redundancy elimination (PRE) more aggressive ๐Ÿ˜ค enabled at -O3.
  • -ftree-forwprop โ€” performs forward propagation on trees โžก๏ธ enabled by default at -O1 and higher.
  • -ftree-fre โ€” performs full redundancy elimination (FRE) on trees ๐Ÿงฝ the difference between FRE and PRE is that FRE only considers expressions that are computed on all paths leading to the redundant computation. That makes the analysis faster than PRE, though it exposes fewer redundancies ๐Ÿฌ enabled by default at -O1 and higher.
  • -ftree-phiprop โ€” performs hoisting of loads from conditional pointers on trees ๐Ÿซง this pass is enabled by default at -O1 and higher. ๐Ÿ’…

-fhoist-adjacent-loads okay so this one speculatively hoists loads from both branches of an if-then-else ๐ŸŒธ but only when the loads grab adjacent locations in the same structure, and the target has a conditional move instruction โœจ it's enabled by default at -O2 and higher ๐Ÿ’…

-ftree-copy-prop bestie, this does copy propagation on trees ๐Ÿฆ‹ it gets rid of unnecessary copy operations (iconic behaviour, no cap) ๐Ÿซถ enabled by default at -O1 and higher

-fipa-pure-const this one discovers which functions are pure or constant ๐Ÿ”ฎ enabled by default at -O1 and higher

-fipa-reference this discovers which static variables do not escape the compilation unit ๐Ÿ‘‘ enabled by default at -O1 and higher

-fipa-reference-addressable this discovers read-only, write-only and non-addressable static variables ๐Ÿงš enabled by default at -O1 and higher

-fipa-stack-alignment it reduces stack alignment on call sites if possible ๐Ÿ’œ enabled by default

-fipa-pta okay this is the big one ๐Ÿ˜ญ it performs interprocedural pointer analysis and interprocedural modification and reference analysis ๐Ÿ”ฅ

heads up: this can cause excessive memory and compile-time usage on large compilation units ๐Ÿ’€

it is not enabled by default at any optimization level ๐Ÿ™ˆ

-fipa-profile this performs interprocedural profile propagation ๐ŸŒˆ functions called only from cold functions get marked as cold โ„๏ธ functions executed once (like "cold", "noreturn", static constructors or destructors) are identified too โœจ cold functions and loopless parts of functions executed once then get optimized for size ๐ŸŽ€ enabled by default at -O1 and higher

-fipa-modref this performs interprocedural mod/ref analysis ๐Ÿฆ‹ it looks at the side effects of functions (memory locations that are modified or referenced) and enables better optimization across the function call boundary ๐Ÿ’– enabled by default at -O1 and higher

-fipa-cp this performs interprocedural constant propagation ๐Ÿ“ it figures out when values passed to functions are constants and optimizes accordingly ๐Ÿซถ this can substantially increase performance if the app has constants passed to functions โญ enabled by default at -O2, -Os and -O3, and also enabled by -fprofile-use and -fauto-profile

-fipa-cp-clone this performs function cloning to make interprocedural constant propagation stronger ๐Ÿงฌ when enabled, it clones functions 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) ๐Ÿ™ˆ enabled by default at -O3, and also enabled by -fprofile-use and -fauto-profile

-fipa-bit-cp when enabled, this performs interprocedural bitwise constant propagation ๐ŸŒธ enabled by default at -O2 and by -fprofile-use and -fauto-profile ๐Ÿ’… it requires that -fipa-cp is enabled โš ๏ธ

-fipa-vrp when enabled, this performs interprocedural propagation of value ranges ๐Ÿ“ enabled by default at -O2 ๐ŸŽ€ it requires that -fipa-cp is enabled ๐Ÿซถ

-fipa-icf this performs Identical Code Folding for functions and read-only variables ๐Ÿชž it reduces code size but may disturb unwind stacks by swapping a function for an equivalent one with a different name ๐Ÿ˜ฌ it works more effectively with link-time optimization enabled โœจ

okay so the Gold Linker has its own ICF optimization too, and it's similar, but GCC's ICF works on different levels, so the optimizations aren't the same ๐Ÿ’… there are equivalences only GCC finds and equivalences only Gold finds ๐Ÿ‘‘

enabled by default at -O2 and -Os ๐Ÿ”ฅ

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

if the compiler's optimization uses a function's body (or info pulled from its body) to optimize or change another function, that latter function is called an impacted function of the former ๐Ÿซง if a function gets patched, its impacted functions should be patched too ๐Ÿ™

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

usually, the more IPA optimizations are enabled, the more impacted functions each function has ๐Ÿ“ˆ so to control that number (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 inlining and cloning optimizations are enabled, which includes inlining, cloning, interprocedural scalar replacement of aggregates and partial inlining ๐ŸŒท so when patching a function, all its callers and its clones' callers are impacted and need patching too ๐Ÿฉท

-flive-patching=inline-clone disables the following optimization flags: -fwhole-program -fipa-pta -fipa-reference -fipa-ra -fipa-icf -fipa-icf-functions -fipa-icf-variables -fipa-bit-cp -fipa-vrp -fipa-pure-const -fipa-reference-addressable -fipa-stack-alignment -fipa-modref ๐Ÿšซ

inline-only-static only inlining of static functions is enabled ๐Ÿช„ so when patching a static function, all its callers are impacted and need patching too ๐Ÿซถ

on top of everything -flive-patching=inline-clone disables, -flive-patching=inline-only-static also disables these: -fipa-cp-clone -fipa-sra -fpartial-inlining -fipa-cp ๐Ÿ™…โ€โ™€๏ธ

when -flive-patching is specified without any value, the default is inline-clone ๐Ÿ’–

this flag is disabled by default ๐Ÿ’ค

heads up: -flive-patching is not supported with link-time optimization (-flto) ๐Ÿšจ

-fisolate-erroneous-paths-dereference this detects paths that trigger erroneous or undefined behaviour from dereferencing a null pointer ๐Ÿ•ต๏ธโ€โ™€๏ธ it isolates those paths from the main control flow and turns the statement into a trap ๐Ÿชค enabled by default at -O2 and higher, and it depends on -fdelete-null-pointer-checks also being enabled ๐Ÿฅบ

-fisolate-erroneous-paths-attribute this detects paths that trigger erroneous or undefined behaviour 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 this performs forward store motion on trees ๐Ÿšš enabled by default at -O1 and higher ๐Ÿ’…

-ftree-bit-ccp this performs sparse conditional bit constant propagation on trees and propagates pointer alignment info ๐Ÿ“ it only operates on local scalar variables ๐ŸŽฏ enabled by default at -O1 and higher, except for -Og, and it requires that -ftree-ccp is enabled ๐Ÿซถ

-ftree-ccp this performs sparse conditional constant propagation (CCP) on trees ๐Ÿง  it only operates on local scalar variables ๐ŸŽ€ enabled by default at -O1 and higher ๐Ÿ’–

-fssa-backprop this propagates info about uses of a value up the definition chain to simplify the definitions ๐Ÿ”™ for example, it strips sign operations if the sign of a value never matters ๐Ÿงผ enabled by default at -O1 and higher โœจ

-fssa-phiopt this does pattern matching on SSA PHI nodes to optimize conditional code ๐Ÿงฉ enabled by default at -O1 and higher, except for -Og ๐ŸŒท

-ftree-switch-conversion this converts simple initializations in a switch into initializations from a scalar array ๐Ÿช… enabled by default at -O2 and higher ๐Ÿ’…

-ftree-tail-merge this looks for identical code sequences ๐Ÿ‘ฏโ€โ™€๏ธ when it finds them, it replaces one with a jump to the other ๐Ÿฆ˜ this is known as tail merging or cross jumping ๐Ÿ’œ enabled 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 this performs dead code elimination (DCE) on trees ๐Ÿงน enabled by default at -O1 and higher ๐Ÿ’…

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

-ffinite-loops this assumes that a loop with an exit will eventually take the exit and not loop forever ๐Ÿ” that lets the compiler remove loops that otherwise have no side effects, without treating endless looping as a side effect ๐Ÿซง

this option is enabled by default at -O2 for C++ with -std=c++11 or higher ๐Ÿ’…

-ftree-dominator-opts this does a bunch of simple scalar cleanups (constant/copy propagation, redundancy elimination, range propagation and expression simplification) based on a dominator tree traversal ๐ŸŒณ it also does jump threading (to reduce jumps to jumps) ๐Ÿฆ˜ enabled by default at -O1 and higher โœจ

-ftree-dse this performs dead store elimination (DSE) on trees ๐Ÿงฝ a dead store is a store into a memory location that gets overwritten by another store later, with no loads in between ๐Ÿ‘€ in that case the earlier store can be deleted ๐Ÿ—‘๏ธ enabled by default at -O1 and higher ๐Ÿ’–

-ftree-ch this performs loop header copying on trees ๐Ÿ” it's beneficial because it boosts the effectiveness of code motion optimizations ๐Ÿš€ it also saves one jump ๐Ÿฆ‹ enabled by default at -O1 and higher ๐ŸŒธ it is not enabled for -Os, since it usually increases code size ๐Ÿ™…โ€โ™€๏ธ

-ftree-loop-optimize this performs loop optimizations on trees ๐Ÿ”„ enabled by default at -O1 and higher ๐Ÿ’…

  • -ftree-loop-linear, -floop-strip-mine, -floop-block โ€” Okay, these three are all doing the same job ๐Ÿ’… They do loop nest optimizations, exactly like -floop-nest-optimize. To actually use this, GCC has to be configured with --with-isl so the Graphite loop transformation infrastructure is switched on โœจ
  • -fgraphite-identity โ€” This one is lowkey a tester ๐Ÿ” It turns on the identity transformation for Graphite. For every SCoP, GCC builds the polyhedral representation and then converts it back to GIMPLE. That lets you measure what the GIMPLE -> GRAPHITE -> GIMPLE round trip costs or gains you ๐Ÿง isl's code generator also does some minimal cleanup along the way, like index splitting and dead code elimination in loops.
  • -floop-nest-optimize โ€” The isl-based loop nest optimizer, and it's giving main character energy ๐Ÿ‘‘ It's a generic optimizer built on the Pluto algorithms, and it works out a loop structure tuned for data locality and parallelism ๐Ÿ”ฅ Heads up: this one is experimental โš ๏ธ
  • -floop-parallelize-all โ€” Graphite's data dependence analysis hunts down loops that can be parallelized ๐Ÿงš It parallelizes every loop it can analyze as free of loop-carried dependences, and it does not check whether parallelizing is actually profitable first ๐Ÿ’€
  • -ftree-coalesce-vars โ€” When GCC is leaving SSA form, this flag tries to cut down on copying by merging versions of different user-defined variables, not just compiler temporaries ๐Ÿฆ‹ Quick warning, bestie: this can seriously limit your ability to debug an optimized program compiled with -fno-var-tracking-assignments ๐Ÿ˜ญ The negated form, -fno-tree-coalesce-vars, stops SSA coalescing of user variables. It's on by default when optimization is on, and it barely does anything otherwise ๐ŸŽ€
  • -ftree-loop-if-convert โ€” This one takes conditional jumps in the innermost loops and turns them into branch-less equivalents ๐ŸŒธ The goal is to get rid of control flow so the vectorizer can handle those loops better. It's enabled by default whenever vectorization is enabled ๐Ÿ’–
  • -ftree-loop-distribution โ€” Loop distribution, which can help cache performance on big loop bodies and open the door for things like parallelization or vectorization โœจ Here's the Fortran glow-up:
        DO I = 1, N
          A(I) = B(I) + C
          D(I) = E(I) * F
        ENDDO

becomes:

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

This flag is enabled by default at -O3. It's also turned on by -fprofile-use and -fauto-profile ๐Ÿซถ

  • -ftree-loop-distribute-patterns โ€” This one distributes loops that can be code generated as calls into a library ๐ŸŒˆ It's enabled by default at -O2 and higher, and by -fprofile-use and -fauto-profile. It handles initialization loops and swaps them for a call to memset zero ๐Ÿงน Look at this:
        DO I = 1, N
          A(I) = 0
          B(I) = A(I) + I
        ENDDO

becomes:

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

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

  • -floop-interchange โ€” Loop interchange, happening outside of Graphite ๐Ÿ”„ It can boost cache performance on a loop nest and make room for stuff like vectorization โœจ Check out this C glow-up:
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];

becomes:

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];

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

  • -floop-unroll-and-jam โ€” Unroll and jam on the feasible loops ๐Ÿ“ In a loop nest, it unrolls the outer loop by some factor and fuses the resulting multiple inner loops together. Enabled by default at -O3, and also by -fprofile-use and -fauto-profile ๐ŸŒธ
  • -ftree-loop-im โ€” Loop invariant motion on trees ๐Ÿงš It only moves the invariants that are hard to handle at the RTL level, like function calls or operations that expand into nontrivial sequences of insns. With -funswitch-loops, it also moves the operands of invariant conditions out of the loop, so loop unswitching can get away with trivial invariance analysis ๐Ÿง  This pass also includes store motion ๐Ÿ’œ
  • -ftree-loop-ivcanon โ€” Creates a canonical counter for the number of iterations in loops where figuring out the count needs complicated analysis ๐ŸŽ€ Later optimizations can then work out the number easily. It's especially useful alongside unrolling โœจ
  • -ftree-scev-cprop โ€” Final value replacement, bestie ๐Ÿ’– If a variable changes in a loop in a way that its value on exit can be worked out from only its initial value and the number of iterations, GCC swaps uses of the final value for that computation, as long as it's cheap enough. That cuts down on data dependencies and can unlock more simplifications ๐Ÿซถ Enabled by default at -O1 and higher.
  • -fivopts โ€” Induction variable optimizations on trees, covering strength reduction, induction variable merging, and induction variable elimination ๐Ÿ”ฅ
  • -ftree-parallelize-loops=n โ€” This splits a loop's iteration space so it runs across n threads ๐Ÿงต It only works for loops whose iterations are independent and can be reordered however. It's only really worth it on multiprocessor machines, and for CPU-intensive loops rather than ones held back by something like memory bandwidth ๐Ÿ‘‘ This option implies -pthread, so it's only supported on targets that support -pthread โœจ
  • -ftree-pta โ€” Function-local points-to analysis on trees ๐Ÿ” It's enabled by default at -O1 and higher, except for -Og ๐Ÿ’…
  • -ftree-sra โ€” Scalar replacement of aggregates ๐Ÿฆ‹ It swaps structure references out 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 that hit consecutive memory addresses ๐Ÿงน It takes contiguous stores of immediate values that are narrower than a word and folds them into fewer, wider stores, so you get fewer instructions ๐Ÿ“ Enabled by default at -O2 and higher, and at -Os โœจ
  • -ftree-ter โ€” Temporary expression replacement during the SSA->normal phase ๐ŸŒˆ Single use/single def temporaries get replaced at their use location by their defining expression. This makes non-GIMPLE code, but it gives the expanders much more complex trees to chew on, which leads to better RTL generation ๐Ÿงš Enabled by default at -O1 and higher.
  • -ftree-slsr โ€” Straight-line strength reduction on trees ๐Ÿ’œ It spots related expressions involving multiplications and swaps them for cheaper calculations whenever it can ๐Ÿ’– Enabled by default at -O1 and higher.
  • -ftree-vectorize โ€” Vectorization on trees, bestie ๐Ÿ”ฅ This flag turns on -ftree-loop-vectorize and -ftree-slp-vectorize as well, unless you've explicitly specified them ๐Ÿซถ
  • -ftree-loop-vectorize โ€” Loop vectorization on trees โญ Enabled by default at -O2, and also by -ftree-vectorize, -fprofile-use, and -fauto-profile ๐ŸŽ€
  • -ftree-slp-vectorize โ€” Basic block vectorization on trees ๐ŸŒธ Enabled by default at -O2, and also by -ftree-vectorize, -fprofile-use, and -fauto-profile ๐Ÿ’…
  • -ftrivial-auto-var-init=choice โ€” This one is all about security and predictability ๐Ÿ”’ It initializes automatic variables with either a pattern or zeroes, which protects against uninitialized memory being disclosed or used ๐Ÿ˜ญ GCC still treats an automatic variable with no explicit initializer as uninitialized, so -Wuninitialized and -Wanalyzer-use-of-uninitialized-value will still warn about those ๐Ÿ™ˆ With this option, GCC also zeroes any padding in automatic variables of structure or union types โœจ

The three values of choice are:

  • uninitialized โ€” Doesn't initialize any automatic variables at all. This is the default for C and C++ ๐Ÿฅฑ
  • pattern โ€” Fills automatic variables with values that will likely turn logic bugs into crashes down the line ๐Ÿ’ฅ They're easy to spot in a crash dump and aren't values programmers can rely on for real program semantics ๐Ÿงฉ The pattern is a byte-repeatable one using byte 0xFE. The values used for pattern initialization might change in the future โš ๏ธ
  • zero โ€” Initializes automatic variables with zeroes ๐Ÿซง

The default is uninitialized ๐ŸŒท

You can control this behavior for a specific variable with the variable attribute uninitialized ๐ŸŽ€

  • -fvect-cost-model=model โ€” okay so this one lets you change the cost model for vectorization ๐Ÿ’… The model has to be unlimited, dynamic, cheap or very-cheap. With unlimited, the vectorized code path is just assumed to be profitable ๐Ÿ”ฅ With dynamic, a runtime check guards the vectorized path so it only kicks in for iteration counts that will likely run faster than the original scalar loop โœจ cheap is the "no drama" option: it turns off vectorization for loops where it would be cost prohibitive, like when it needs runtime checks for data dependence or alignment, but otherwise it's the same as dynamic ๐Ÿ™ˆ And very-cheap only vectorizes if the vector code would entirely replace the scalar code being vectorized. For example, if each vectorized iteration can only handle exactly four iterations of the scalar loop, very-cheap only allows it 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 โ€” this is the same vibe but for loops marked with the OpenMP simd directive ๐Ÿฆ‹ The model should be one of unlimited, dynamic, cheap. Every value means the same thing as it does in -fvect-cost-model, and by default, whatever cost model you set with -fvect-cost-model is used ๐Ÿซถ
  • -ftree-vrp โ€” Value Range Propagation on trees, bestie ๐ŸŒˆ It's kind of like constant propagation, except instead of tracking single values, it tracks ranges of values. This lets the optimizers remove unnecessary range checks, like array bound checks and null pointer checks ๐Ÿ’… It's enabled by default at -O2 and higher. Heads up though: null pointer check elimination only happens if -fdelete-null-pointer-checks is enabled ๐Ÿ™ˆ
  • -fsplit-paths โ€” splits paths that lead to loop backedges, which can glow up dead code elimination and common subexpression elimination โœจ Enabled by default at -O3 and above ๐Ÿ‘‘
  • -fsplit-ivs-in-unroller โ€” when a loop is unrolled, this lets the compiler express the values of induction variables in later iterations using the value from the first iteration ๐Ÿงš That breaks up long dependency chains, which makes the scheduling passes more efficient ๐Ÿ”ฅ

A combo of -fweb and CSE is often enough to get the same effect, ngl ๐Ÿ’… But it's not reliable when the loop body is more complicated than a single basic block, and on some architectures it doesn't work at all 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 end up giving you superior code ๐Ÿฆ‹

This one is enabled by default for PowerPC targets, but disabled by default everywhere else ๐ŸŒธ

  • -fpartial-inlining โ€” inlines parts of functions ๐ŸŽ€ This only does anything if inlining is already turned on by -finline-functions or -finline-small-functions. Enabled at levels -O2, -O3, -Os โœจ
  • -fpredictive-commoning โ€” the compiler reuses computations from previous iterations of loops, especially memory loads and stores ๐Ÿง โœจ Enabled at level -O3, and also turned on by -fprofile-use and -fauto-profile ๐ŸŒˆ
  • -fprefetch-loop-arrays โ€” if the target machine supports it, the compiler generates instructions to prefetch memory, which can help loops that access large arrays ๐Ÿ“ Heads up: this might make the code better or worse, and the results are super dependent on how the loops are structured in your source ๐Ÿ˜ญ Disabled at level -Os ๐Ÿ™ˆ
  • -fno-printf-return-value โ€” this stops the compiler from swapping in constants for the known return values of formatted output functions like "sprintf", "snprintf", "vsprintf", and "vsnprintf". ("printf" and "fprintf" are not included.) ๐Ÿ’… Normally this is a big win, because it lets GCC optimize or even eliminate branches based on those known return values, as long as the arguments are constant or known to be in a range where the exact return value can be figured out ๐Ÿ”ฅ For example, with -fprintf-return-value 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, so it gives the best results at -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 how they're implemented in the compiler: some targets use one, some use the other, and a few use both ๐ŸŒธ

-fpeephole is enabled by default. -fpeephole2 is enabled at levels -O2, -O3, -Os ๐Ÿ’–

  • -fno-guess-branch-probability โ€” tells GCC to stop guessing branch probabilities using heuristics ๐Ÿ™ˆ

Normally, if profiling feedback (-fprofile-arcs) doesn't provide branch probabilities, GCC uses heuristics based on the control flow graph to guess them ๐Ÿง  If some branch probabilities are specified by __builtin_expect, the heuristics guess the rest of the control flow graph while taking that __builtin_expect info into account. The interactions between the two can get complicated, so sometimes it helps to turn the heuristics off so the effects of __builtin_expect are easier to understand ๐Ÿ’…

You can also specify the expected probability of an expression with the __builtin_expect_with_probability built-in function ๐ŸŒˆ

The default is -fguess-branch-probability at levels -O, -O2, -O3, -Os โœจ

  • -freorder-blocks โ€” reorders basic blocks in the compiled function to reduce the number of taken branches and improve code locality ๐Ÿฆ‹ Enabled at levels -O1, -O2, -O3, -Os ๐Ÿ’œ
  • -freorder-blocks-algorithm=algorithm โ€” picks the algorithm used for basic block reordering ๐Ÿ“ The algorithm can be simple, which doesn't increase code size (except sometimes through secondary effects like alignment), or stc, the "software trace cache" algorithm, which puts all the often executed code together. It minimizes the number of branches executed by making extra copies of code, so it can get a little chunky ๐Ÿซ 

The default is simple at levels -O1 and -Os, and stc at levels -O2 and -O3 ๐Ÿ‘‘

  • -freorder-blocks-and-partition โ€” on top of reordering basic blocks to cut down taken branches, this one splits hot and cold basic blocks into separate sections of the assembly and .o files ๐ŸŒธ That helps paging and cache locality performance โœจ

This optimization is automatically turned off in a bunch of situations: when there's 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, it isn't enabled by default (to avoid linker errors), but you can still turn it on 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 works by putting the most frequently executed functions in the special .text.hot subsections and the unlikely ones in .text.unlikely ๐ŸŒˆ The linker does the reordering, so your object file format has to support named sections, and the linker has to place them somewhere reasonable ๐Ÿ’€

This option isn't effective unless you 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 โ€” lets the compiler assume the strictest aliasing rules that apply to the language being compiled ๐Ÿ’… For C (and C++), this turns on optimizations based on the type of expressions. An object of one type is assumed to never live at the same address as an object of a different type, unless the types are almost the same. For example, an "unsigned int" can alias an "int", but not a "void*" or a "double". A character type may alias any other type ๐Ÿฆ‹

Pay special attention to code like this:

union a_union {
  int i;
  double d;
};

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

Reading from a different union member than the one most recently written to (called "type-punning") is super common ๐Ÿ™ˆ Even with -fstrict-aliasing, type-punning is allowed, as long as 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 something by taking its address, casting the resulting pointer, and dereferencing it has undefined behavior, even if the cast uses a union type ๐Ÿ˜ญ 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 ๐Ÿ‘‘

  • -fipa-strict-aliasing โ€” controls whether the rules of -fstrict-aliasing get applied across function boundaries ๐Ÿ” Just a heads up: if multiple functions get inlined into a single function, the memory accesses are no longer considered to be crossing a function boundary ๐Ÿงš

The -fipa-strict-aliasing option is enabled by default, and it's only effective in combination with -fstrict-aliasing ๐Ÿ’–

  • -falign-functions, -falign-functions=n, -falign-functions=n:m, -falign-functions=n:m:n2, -falign-functions=n:m:n2:m2 โ€” bestie, this one is all about lining up function starts ๐Ÿฆ‹. It aligns the start of functions to the next power-of-two that's greater than or equal to n, skipping up to m-1 bytes โœจ. The point is that the CPU can grab at least the first m bytes of the function without crossing an n-byte alignment boundary ๐Ÿ’….
    • If m isn't specified, it defaults to n ๐ŸŒธ.
    • -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 gives you a secondary alignment ๐Ÿ‘‘. -falign-functions=64:7:32:3 aligns to the next 64-byte boundary if that can be done by skipping 6 bytes or less. Otherwise, it aligns to the next 32-byte boundary if that 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 they both mean functions are not aligned ๐Ÿ˜ญ.

If n isn't specified or is zero, the compiler uses a machine-dependent default. The maximum allowed n value is 65536 โœจ.

Enabled at levels -O2, -O3 ๐Ÿ”ฅ.

  • -flimit-function-alignment โ€” this one is the responsible friend ๐Ÿซถ. When it's enabled, the compiler tries not to overalign functions for no reason. It asks the assembler to align by the amount set by -falign-functions, but it won't skip more bytes than the size of the function itself ๐Ÿฆ‹.
  • -falign-labels, -falign-labels=n, -falign-labels=n:m, -falign-labels=n:m:n2, -falign-labels=n:m:n2:m2 โ€” aligns all branch targets to a power-of-two boundary ๐ŸŽ€. The parameters work just like -falign-functions ๐Ÿ’–.
    • -fno-align-labels and -falign-labels=1 are equivalent, and they mean labels are not aligned ๐Ÿ˜ญ.
    • If -falign-loops or -falign-jumps apply and their values are bigger than this one, their values win instead ๐Ÿ‘‘.
    • If n isn't specified or is zero, you get a machine-dependent default that is very likely to be 1, which means no alignment ๐Ÿฅฑ.
    • The maximum allowed n value is 65536 ๐Ÿ’….

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

  • -falign-loops, -falign-loops=n, -falign-loops=n:m, -falign-loops=n:m:n2, -falign-loops=n:m:n2:m2 โ€” aligns loops to a power-of-two boundary ๐ŸŒ€. If the loops run a lot of times, this makes up for the cost of running the dummy padding instructions ๐Ÿ’œ.
    • If -falign-labels is bigger than this value, its value gets used instead ๐ŸŒธ.
    • The parameters are analogous to -falign-functions ๐Ÿฆ‹.
    • -fno-align-loops and -falign-loops=1 are equivalent, and they mean loops are not aligned ๐Ÿ’€.
    • The maximum allowed n value is 65536 ๐Ÿ”ฅ.
    • If n isn't specified or is zero, the compiler uses a machine-dependent default ๐Ÿงš.

Enabled at levels -O2, -O3 ๐Ÿ‘‘.

  • -falign-jumps, -falign-jumps=n, -falign-jumps=n:m, -falign-jumps=n:m:n2, -falign-jumps=n:m:n2:m2 โ€” 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 need to run โœจ.
    • 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 the original page says they mean that loops are not aligned ๐Ÿ™ˆ.
    • If n isn't specified or is zero, the compiler uses a machine-dependent default ๐Ÿ“.
    • The maximum allowed n value is 65536 ๐Ÿ’–.

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

  • -fno-allocation-dce โ€” don't remove unused C++ allocations during dead code elimination ๐Ÿงน.
  • -fallow-store-data-races โ€” this one is a vibe with a warning label โš ๏ธ. It 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 doesn't touch optimization of local data ๐ŸŒธ. It's only safe to use if you already know global data won't be accessed by multiple threads ๐Ÿซถ.

Examples of optimizations this enables include hoisting, or if-conversions, that might cause a value already in memory to get rewritten with that same value ๐Ÿ”. That rewrite is fine in a single-threaded context, but it can be unsafe in a multi-threaded one ๐Ÿ’€. Also, on some processors, if-conversions may be required before vectorization can happen ๐Ÿง .

Enabled at level -Ofast ๐Ÿ”ฅ.

  • -funit-at-a-time โ€” kept around for compatibility only ๐Ÿ•ฐ๏ธ. It has no effect by itself. -fno-unit-at-a-time, though, implies -fno-toplevel-reorder and -fno-section-anchors ๐Ÿ™ƒ.

Enabled by default ๐Ÿ’….

  • -fno-toplevel-reorder โ€” don't reorder top-level functions, variables, and "asm" statements ๐Ÿ“œ. They get output in the same order they appear in the input file โœจ. With this 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 when possible ๐Ÿ’ก.

-ftoplevel-reorder is the default at -O1 and higher, and also at -O0 if -fsection-anchors is explicitly requested ๐Ÿฆ‹. On top of that, -fno-toplevel-reorder implies -fno-section-anchors ๐ŸŒธ.

  • -fweb โ€” this builds webs, the way they're commonly used for register allocation, and gives 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 ๐Ÿ’–. The catch? It can make debugging impossible, because variables no longer stay in a "home register" ๐Ÿ˜ญ.

Enabled by default with -funroll-loops โœจ.

  • -fwhole-program โ€” assume the current compilation unit is the whole program being compiled ๐ŸŒ. All public functions and variables become static functions, except for main and anything merged by the attribute "externally_visible" ๐Ÿ”’. Because of that, the interprocedural optimizers can get more aggressive ๐Ÿ”ฅ.
Don't use this together with -flto. Relying on a linker plugin instead should give you safer and more precise information ๐Ÿšจ.
  • -flto[=n] โ€” the standard link-time optimizer, and it's iconic ๐Ÿ‘‘. When you invoke it with source code, it generates GIMPLE (one of GCC's internal representations) and writes it to 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 ๐Ÿซถ.

To use the link-time optimizer, -flto and your optimization options should be specified at compile time and during the final link โœจ. It's recommended that you compile all the files in the same link with the same options, and then 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 that GIMPLE bytecode from foo.o and bar.o, merges the two files into a single internal image, and compiles the result as usual ๐Ÿ’–. Since both files get merged into one image, all the interprocedural analyses and optimizations work across the two files as if they were a single one ๐ŸŒˆ. For example, the inliner can inline functions in bar.o into functions in foo.o, and vice-versa ๐Ÿ”ฅ.

There's also a simpler way to turn on link-time optimization ๐ŸŒธ:

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 big thing to remember is that you need to use the GCC driver to perform the link step if you want link-time optimizations ๐Ÿš—. GCC automatically performs link-time optimization if any of the objects involved were compiled with the -flto command-line option ๐Ÿค–. You can always override that automatic decision by passing -fno-lto to the link command ๐Ÿ™…โ€โ™€๏ธ.

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

When a file is compiled with -flto and without -fuse-linker-plugin, the generated object file is larger than a regular one ๐Ÿ“ฆ. That's because it contains GIMPLE bytecodes and the usual final code (see -ffat-lto-objects) ๐Ÿ˜ญ. This means object files with LTO information can still be linked as normal object files. If -fno-lto is passed to the linker, though, no interprocedural optimizations get applied ๐Ÿ™ƒ. Also, when -fno-fat-lto-objects is enabled, the compile stage is faster, but you cannot perform a regular, non-LTO link on those objects ๐Ÿšซ.

When producing the final binary, GCC only applies link-time optimizations to the files that contain bytecode ๐ŸŽฏ. That means you can mix and match object files and libraries with GIMPLE bytecodes and final object code ๐Ÿงฆ. GCC automatically picks which files to optimize in LTO mode and which files to just link without any further processing ๐Ÿค.

Generally, options specified at link time override the ones specified at compile time ๐Ÿ‘‘. Sometimes, though, GCC tries to infer link-time options from the settings used to compile the input files ๐Ÿ”.

If you leave out the optimization level -O at link time, GCC just uses the highest level that was used when compiling the object files ๐Ÿ’…. But ngl, it's pretty ineffective to only set -O at link time and skip it at compile time ๐Ÿ™ˆ. There are two reasons. First, compiling without optimization skips the compiler passes that gather the info needed for good link-time optimization ๐Ÿ’€. Second, some early optimization passes can only happen at compile time, not link time. So set it at both steps, bestie ๐Ÿซถ.

Some code generation flags get preserved by GCC when it makes bytecode, because they need to be used during the final link โœจ. Right now those are -fcommon, -fexceptions, -fnon-call-exceptions, -fgnu-tm and all the -m target flags. Their settings get taken from the first object file that explicitly specifies them ๐Ÿงš.

The PIC and PIE flags (-fPIC, -fpic, -fpie and -fPIE) get combined using this scheme, and it's giving very precise vibes ๐ŸŽ€:

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

Certain ABI-changing flags have to match across every compilation unit. If you try to override one at link time with a conflicting value, it gets ignored ๐Ÿšซ. That includes stuff like -freg-struct-return and -fpcc-struct-return, so don't even try ๐Ÿ’….

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 when translation units conflict ๐Ÿฆ‹. Specifically, -fno-strict-overflow, -fwrapv and -fno-trapv take precedence. For example, -ffp-contract=off beats -ffp-contract=fast ๐Ÿ‘‘. You can still override them at link time.

Diagnostic options like -Wstringop-overflow get passed through to the link stage too, and their setting matches the compile step at function granularity ๐Ÿ”. This only matters for diagnostics that come out during optimization. Also, code transforms like inlining can make warnings get enabled or disabled for certain regions if the code isn't consistent with the compile-time setting ๐Ÿ˜ญ.

When you need to pass options to the assembler with -Wa or -Xassembler, make sure you either compile those translation units with -fno-lto, or use the same assembler options on every translation unit ๐Ÿšจ. You can also specify assembler options at LTO link time instead.

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 enabled, the link will turn on debug info generation too โœจ. Fancy debug info settings, like the DWARF level -gdwarf-5, need to be repeated explicitly on the linker command line. Mixing different settings across translation units is discouraged, so keep it consistent, babe ๐Ÿฅน.

If LTO runs into objects with C linkage that were declared with incompatible types across separate translation units being linked together, that's undefined behavior according to ISO C99 6.2.7 ๐Ÿ™ƒ. GCC might issue a non-fatal diagnostic, but the behavior is still undefined at run time. Similar diagnostics might show up for other languages too ๐Ÿ’€.

LTO also lets you apply interprocedural optimizations to files written in different languages, and this is the main character moment ๐Ÿ‘‘:

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

The final link is done with g++ so you get the C++ runtime libraries, and -lgfortran is added to get the Fortran runtime libraries ๐Ÿงš. In general, when you mix 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, like 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 work with LTO, use gcc-ar and gcc-ranlib instead of ar and ranlib. To show the symbols of object files with GIMPLE bytecode, use gcc-nm. Those commands require that ar, ranlib and nm were compiled with plugin support ๐Ÿ”ง. At link time, use the flag -fuse-linker-plugin so the library joins the LTO optimization process ๐Ÿฆ‹:

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

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

If you aren't 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 won't participate in the LTO optimization process ๐Ÿ˜”. To make a static library that works for both LTO optimization and regular linkage, compile its object files with -flto -ffat-lto-objects ๐Ÿซถ.

Link-time optimizations don't need the whole program to be present in order to work ๐ŸŒธ. If the program doesn't require any symbols to be exported, you can combine -flto and -fwhole-program. That lets the interprocedural optimizers use more aggressive assumptions, which can lead to better optimization opportunities โœจ. You don't need -fwhole-program when the linker plugin is active (see -fuse-linker-plugin) ๐Ÿ’….

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

Link-time optimization doesn't play well with debugging info on systems that aren't using a combo 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 using an installed make program ๐Ÿƒโ€โ™€๏ธ. The environment variable MAKE can override which program gets used ๐Ÿงš.

  • -flto-partition=alg โ€” Picks the partitioning algorithm the link-time optimizer uses ๐Ÿ“. The value is 1to1, which mirrors the original source files, or balanced, which splits things into equally sized chunks where possible, or max, which makes a new partition for every symbol where possible. Setting none as the algorithm turns off partitioning and streaming completely. The default is balanced. 1to1 can work as a workaround for various code ordering issues, but max partitioning is only meant for internal testing ๐Ÿงช. The value one uses exactly one partition, and the value none skips partitioning and runs the link-time optimization step straight from the WPA phase ๐ŸŒˆ.
  • -flto-compression-level=n โ€” Sets how much the intermediate language written to LTO object files gets compressed ๐Ÿ—œ๏ธ. It only matters when you're in LTO mode (-flto). GCC supports two LTO compression algorithms. For zstd, valid values are 0 (no compression) up to 19 (maximum compression), while zlib supports values from 0 to 9. Values outside the range get clamped to the minimum or maximum of the supported values. If you don't give the option, a default balanced compression setting is used ๐Ÿ’–.
  • -fuse-linker-plugin โ€” Turns on the use of a linker plugin during link-time optimization ๐Ÿ”Œ. This needs plugin support in the linker, which you get with gold or GNU ld 2.21 or newer ๐Ÿฆ‹.

This option lets GCC pull object files with GIMPLE bytecode out of library archives. That makes the optimization better by exposing more code to the link-time optimizer ๐Ÿ”ฅ. It also tells the optimizer which symbols can be accessed externally, meaning by a non-LTO object or during dynamic linking. The code quality improvements you get on binaries (and on shared libraries that use hidden visibility) are similar to -fwhole-program โœจ. See -flto for a description of what this flag does and how to use it ๐Ÿ’….

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

  • -ffat-lto-objects โ€” Fat LTO objects are object files that hold both the intermediate language and the object code ๐Ÿฑ. That makes them usable for both LTO linking and normal linking ๐Ÿ’œ. This option only works when you're compiling with -flto, and it gets ignored at link time ๐Ÿ™ˆ.

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

Modern binutils come with a plugin auto-load mechanism, and that's pretty iconic ๐Ÿ™Œ. 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 โ€” okay so after register allocation and post-register allocation instruction splitting, GCC hunts for arithmetic instructions that set processor flags like a comparison based on that same arithmetic ๐Ÿ‘€. If it's possible, it eliminates the explicit comparison operation โœจ.
    • This pass only applies to certain targets that can't explicitly represent the comparison operation before register allocation is complete ๐Ÿฆ‹.
    • Enabled at levels -O1, -O2, -O3, -Os ๐Ÿ’–.
  • -fcprop-registers โ€” after register allocation and post-register allocation instruction splitting, GCC runs a copy-propagation pass ๐Ÿ’…. It tries to reduce scheduling dependencies and occasionally eliminate the copy ๐Ÿซถ.
    • Enabled at levels -O1, -O2, -O3, -Os ๐ŸŒธ.
  • -fprofile-correction โ€” profiles collected with an instrumented binary for multi-threaded programs can be inconsistent because some counter updates got missed ๐Ÿ˜ญ. With this option, GCC uses heuristics to correct or smooth out those inconsistencies ๐Ÿฉน. By default, GCC emits an error message when it detects an inconsistent profile ๐Ÿ’€.
    • This option is enabled by -fauto-profile โœจ.
  • -fprofile-partial-training โ€” with -fprofile-use, every part of the program that didn't run during the train run gets optimized aggressively for size instead of speed ๐Ÿงš. Sometimes it isn't practical to train every possible hot path. For example, a program might have functions specific to some hardware, and training might not cover every hardware configuration the program runs on ๐Ÿ™ˆ. With -fprofile-partial-training, profile feedback is ignored for all functions that weren't executed during the train run, so they get optimized as if they were compiled without profile feedback ๐ŸŽ€. This gives better performance when the train run isn't representative, but it also leads to significantly bigger code ๐Ÿ“ฆ.
  • -fprofile-use, -fprofile-use=path โ€” enable profile feedback-directed optimizations, plus the following optimizations, many of which are generally only worth it when profile feedback is available ๐Ÿ‘‘:
-fbranch-probabilities  -fprofile-values -funroll-loops
-fpeel-loops  -ftracer  -fvpt -finline-functions  -fipa-cp
-fipa-cp-clone  -fipa-bit-cp -fpredictive-commoning  -fsplit-loops
-funswitch-loops -fgcse-after-reload  -ftree-loop-vectorize
-ftree-slp-vectorize -fvect-cost-model=dynamic
-ftree-loop-distribute-patterns -fprofile-reorder-functions

Before you can use this option, you must first generate profiling information ๐Ÿ”.

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

If path is specified, GCC looks in that path for the profile feedback data files. See -fprofile-dir ๐Ÿ“‚.

  • -fauto-profile, -fauto-profile=path โ€” enable sampling-based feedback-directed optimizations, plus the following optimizations, many of which are generally only worth it 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-correction

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

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/> ๐Ÿ”—.

E.g.

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

Next, use the create_gcov tool to convert the raw profile data into a format GCC can use ๐Ÿ› ๏ธ. You also have to hand this tool the unstripped binary for your program. See <https://github.com/google/autofdo> ๐Ÿ’œ.

E.g.

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

The following options control compiler behavior around floating-point arithmetic ๐Ÿฆ‹. They trade off between speed and correctness, so they all have to be specifically enabled ๐Ÿซง.

  • -ffloat-store โ€” don't store floating-point variables in registers, and inhibit other options that might change whether a floating-point value gets pulled from a register or from memory ๐Ÿ™…โ€โ™€๏ธ.
    • This prevents undesirable excess precision on machines like the 68000, where the floating registers (of the 68881) keep more precision than a "double" is supposed to have ๐Ÿค“. The same goes for the x86 architecture ๐Ÿ’ซ. For most programs, the excess precision only does good ๐Ÿ’–, but a few programs rely on the precise definition of IEEE floating point ๐Ÿง. For those, use -ffloat-store after modifying them to store all pertinent intermediate computations into variables ๐ŸŽ€.
  • -fexcess-precision=style โ€” gives you more control over excess precision on machines where floating-point operations happen in a format with more precision or range than the IEEE standard and interchange floating-point types ๐ŸŒˆ.
    • By default, -fexcess-precision=fast is in effect. That means operations may be carried out in a wider precision than the types in the source if that makes the code faster, and it's unpredictable when rounding to the source types actually happens ๐ŸŽข.
    • When compiling C, if -fexcess-precision=standard is specified, excess precision follows the rules in ISO C99. Specifically, both casts and assignments 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 isn't 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 ๐Ÿš€.
    • This option causes the preprocessor macro "__FAST_MATH__" to be defined โœจ.
    • This option isn't turned on by any -O option besides -Ofast ๐Ÿ™…. 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 those specifications ๐Ÿƒโ€โ™€๏ธ.
  • -fno-math-errno โ€” don't set errno after calling math functions that run with a single instruction, like sqrt ๐Ÿงฎ. A program that relies on IEEE exceptions for math error handling may want this flag for speed while keeping IEEE arithmetic compatibility ๐Ÿซถ.
    • This option isn't 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 those 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 the possibility that it might. That means -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 do other similar optimizations ๐Ÿ”ง.
    • This option isn't turned on by any -O option, for the same reason as before: it can give incorrect output for programs that depend on exact IEEE or ISO rules for math functions. It may, however, yield faster code for programs that don't need those guarantees ๐Ÿ.
    • 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. Because of that, 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 ๐Ÿค. Moreover, 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 โ€” allows the reciprocal of a value to 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 useful 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 isn't 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 those guarantees ๐Ÿข.
    • The default is -fno-finite-math-only ๐Ÿ’œ.
  • -fno-signed-zeros โ€” okay bestie, this one tells the optimizer it can ignore whether a zero is positive or negative ๐Ÿงš. IEEE arithmetic treats distinct +0.0 and -0.0 values as different, which is why stuff like x+0.0 or 0.0*x can't get simplified away, even with -ffinite-math-only ๐Ÿ˜ญ. This flag says the sign of a zero result isn't significant. The default is -fsigned-zeros ๐Ÿ’….
  • -fno-trapping-math โ€” this one assumes floating-point operations can't throw user-visible traps ๐Ÿฆ‹. Those traps are division by zero, overflow, underflow, inexact result, and invalid operation. It requires -fno-signaling-nans to be in effect โœจ. Turning it on can give faster code if your program relies on "non-stop" IEEE arithmetic, for example ๐ŸŒธ.
โš ๏ธ Never, ever turn this on through any -O option! It can produce incorrect output for programs that depend on an exact implementation of IEEE or ISO rules and specifications for math functions ๐Ÿ’€. The default is -ftrapping-math.
  • -frounding-math โ€” this turns off transformations and optimizations that assume the default floating-point rounding behavior ๐ŸŽ€. That default means round-to-zero for all floating-point to integer conversions, and round-to-nearest for all other arithmetic truncations. Use it if your program changes the FP rounding mode dynamically, or might run with a non-default rounding mode ๐ŸŒˆ. It also disables compile-time constant folding of floating-point expressions (since rounding mode can change those results) and arithmetic transformations that aren't safe with sign-dependent rounding modes ๐Ÿ™ˆ. The default is -fno-rounding-math.
๐Ÿงช This one is experimental! It doesn't currently guarantee that every GCC optimization affected by rounding mode gets disabled. Future versions of GCC might give finer control over this setting using C99's FENV_ACCESS pragma, and this command-line option will be used to set the default state for FENV_ACCESS ๐Ÿ”ฎ.
  • -fsignaling-nans โ€” this tells the compiler to assume IEEE signaling NaNs may cause user-visible traps during floating-point operations ๐Ÿ”ฅ. It disables optimizations that might change how many exceptions are visible with signaling NaNs. It also implies -ftrapping-math ๐Ÿ’œ. Turning it on defines the preprocessor macro __SUPPORT_SNAN__ โœจ. The default is -fno-signaling-nans.
๐Ÿงช Also experimental! It doesn't currently guarantee that every GCC optimization affecting signaling NaN behavior is disabled ๐Ÿ˜ญ.
  • -fno-fp-int-builtin-inexact โ€” this stops the built-in functions ceil, floor, round, and trunc (plus their float and long double variants) from generating code that raises the inexact floating-point exception for noninteger arguments ๐Ÿ“. ISO C99 and C11 let these raise inexact, but ISO/IEC TS 18661-1:2014 (the C bindings to IEEE 754-2008, as integrated into ISO C2X) doesn't allow it ๐Ÿ“š. The default is -ffp-int-builtin-inexact, so the exception is 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 these functions end up calling a library function, the inexact exception might still be raised if that library doesn't follow TS 18661 ๐Ÿ™ˆ.

  • -fsingle-precision-constant โ€” treats floating-point constants as single precision instead of quietly converting them to double-precision constants ๐ŸŒธ.
  • -fcx-limited-range โ€” when this is on, the compiler is told that a range reduction step isn't needed for complex division โœจ. It also skips checking whether a complex multiplication or division result is "NaN + I*NaN", and skips trying to rescue that situation ๐Ÿฆ‹. 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. It applies to all languages, though ๐Ÿ’….
  • -fcx-fortran-rules โ€” complex multiplication and division follow Fortran rules ๐Ÿงš. Range reduction happens as part of complex division, but there's no checking for a "NaN + I*NaN" result and no attempt to rescue it ๐Ÿ˜ญ. The default is -fno-cx-fortran-rules.

The following options control optimizations that may improve performance, but none of them are enabled by any -O options ๐ŸŒˆ. This section includes experimental options that may produce broken code ๐Ÿ’€, so proceed with caution, bestie!

  • -fbranch-probabilities โ€” okay this one is a whole glow-up arc โœจ. First you run a program compiled with -fprofile-arcs, and then you 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.cc. 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 this with -fprofile-arcs, it adds code that gathers some data about the values of expressions in your 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 orders those functions in ascending order โฐ. Enabled with -fprofile-use.
  • -fvpt โ€” if combined with -fprofile-arcs, this tells the compiler to add code that collects information about the values of expressions ๐Ÿ“Š. With -fbranch-probabilities, it reads that data back and actually performs optimizations based on it ๐Ÿ’…. Right now the optimizations include specializing division operations using what it knows about the value of the denominator โœจ. Enabled with -fprofile-use and -fauto-profile.
  • -frename-registers โ€” this tries to avoid false dependencies in scheduled code by using registers left over after register allocation ๐ŸŒธ. It helps the most on processors with lots of registers ๐Ÿ’–. Heads up though: depending on the debug information format the target uses, it can make debugging impossible, since variables no longer stay in a "home register" ๐Ÿ˜ญ. Enabled by default with -funroll-loops.
  • -fschedule-fusion โ€” a target-dependent pass over the instruction stream that schedules instructions of the same type together ๐Ÿงฉ. That's because the target machine can run them more efficiently when they're next to each other in the instruction flow ๐Ÿš€. Enabled at levels -O2, -O3, -Os.
  • -ftracer โ€” performs tail duplication to enlarge the superblock size ๐Ÿฆ‹. This simplifies the control flow of the function, which lets other optimizations do a better job ๐Ÿซถ. Enabled by -fprofile-use and -fauto-profile.
  • -funroll-loops โ€” unrolls loops whose number of iterations can be determined at compile time or upon entry to the loop ๐Ÿ”. -funroll-loops implies -frerun-cse-after-loop, -fweb, and -frename-registers ๐ŸŽ€. It also turns on complete loop peeling, which fully removes loops with a small constant number of iterations โœ‚๏ธ. 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 ๐Ÿข. -funroll-all-loops implies the same options as -funroll-loops.
  • -fpeel-loops โ€” peels loops that have enough information to show they won't roll much, either from profile feedback or static analysis ๐Ÿ‘. It also turns on complete loop peeling (fully removing loops with a small constant number of iterations) โœจ. 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.
  • -fmove-loop-stores โ€” enables the loop store motion pass in the GIMPLE loop optimizer ๐Ÿ“ฆ. It moves invariant stores to after the end of the loop, in exchange for carrying the stored value in a register across the iteration ๐Ÿง . For this option to have an effect, -ftree-loop-im has to be enabled too ๐Ÿซถ. 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 ๐Ÿ”€. You get duplicates of the loop on both branches, each modified according to the result of the condition ๐Ÿ‘ฏ. Enabled by -fprofile-use and -fauto-profile.
  • -fversion-loops-for-strides โ€” if a loop iterates over an array with a variable stride, GCC creates another version of the loop that assumes the stride is always one ๐Ÿง. For example, this loop:
                   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 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 โ€” okay so these tell GCC to tuck 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 decides what that section is called. ๐Ÿ’…

Use these on systems where the linker can do optimizations that improve locality of reference in the instruction space ๐Ÿฆ‹. Most systems using the ELF object format have linkers that can do this. On AIX, the linker rearranges sections (CSECTs) based on the call graph. The performance impact varies, so it's not guaranteed to be a glow-up ๐ŸŒธ.

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 files and debug info formats though, so keep that in mind ๐Ÿ™ˆ.

๐Ÿšจ Only use these options when there are significant benefits from doing so. When you specify these options, the assembler and linker create larger object and executable files, and they're also slower ๐Ÿ˜ญ. These options affect code generation. They prevent optimizations by the compiler and assembler from using relative locations inside a translation unit, since those locations aren't known until link time. An example of such an optimization is relaxing calls to short call instructions.

-fstdarg-opt โ€” optimize the prologue of variadic argument functions based on how those arguments get used ๐Ÿงš.

-fsection-anchors โ€” this one is a whole vibe โœจ. It tries to reduce the number of symbolic address calculations by using shared "anchor" symbols to address nearby objects. On some targets, that can cut down on GOT entries and GOT accesses ๐Ÿ‘‘.

For example, take the following function foo:

static int a, b, c;
int foo (void) { return a + b + c; }

Normally it calculates the addresses of all three variables, but if you compile it with -fsection-anchors, it grabs the variables from one common anchor point instead ๐Ÿ’œ. The effect is kinda like this pseudocode (which isn't valid C, sorry bestie ๐Ÿ™ˆ):

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

Not every target supports this option, so check before you commit ๐ŸŽ€.

-fzero-call-used-regs=choice โ€” main character energy for program security ๐Ÿ”ฅ. This zeroes call-used registers at function return, which can help mitigate Return-Oriented Programming (ROP) attacks or prevent information leakage through registers ๐Ÿ›ก๏ธ.

The possible values of choice are the same as for the zero_call_used_regs attribute. The default is skip ๐Ÿ’….

You can control this behavior for a specific function by using the function attribute zero_call_used_regs ๐Ÿฆ‹.

--param name=value โ€” okay this one is for the nerds who love tuning ๐Ÿค“. GCC uses various constants to control how much optimization happens. For example, GCC won't inline functions that contain more than a certain number of instructions ๐Ÿ™…โ€โ™€๏ธ. You can tweak some of these constants on the command line with --param.

โš ๏ธ The names of specific parameters, and what their values mean, are tied to the compiler's internals and can change without notice in future releases. So don't build your whole personality around them ๐Ÿ˜ญ.

To get the minimal, maximal, and default value of a parameter, use --help=param -Q options ๐Ÿง. In each case, the value is an integer. These are the names recognized for all targets:

  • predictable-branch-outcome โ€” when a branch is predicted to be taken with a probability lower than this threshold (in percent), it's considered 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 parameter sets the maximum number of instructions in a block that should be considered for if-conversion. The compiler also uses other heuristics to decide whether if-conversion is likely to be profitable ๐Ÿง .
  • max-rtl-if-conversion-predictable-cost โ€” RTL if-conversion will try to remove conditional branches around a block and replace them with conditionally executed instructions ๐Ÿ’ซ. These parameters set the maximum permissible cost for the sequence that if-conversion would generate, depending on whether the branch is statically determined to be predictable or not. The units are the same as those for the GCC internal seq_cost metric ๐Ÿ“. The compiler tries to provide a reasonable default for this parameter using the BRANCH_COST target macro ๐ŸŽฏ.
  • max-crossjump-edges โ€” the maximum number of incoming edges to consider for cross-jumping. The algorithm used by -fcrossjumping is O(N^2) in the number of edges incoming to each block ๐Ÿ˜ตโ€๐Ÿ’ซ. Higher values mean more aggressive optimization, which makes compilation time go up for probably a small improvement in executable size ๐Ÿข.
  • min-crossjump-insns โ€” the minimum number of instructions that must be matched at the end of two blocks before cross-jumping happens on them ๐Ÿ“. This value is ignored when all instructions in the block being cross-jumped from are matched ๐Ÿซ .
  • max-grow-copy-bb-insns โ€” the maximum code size expansion factor when copying basic blocks instead of jumping ๐Ÿงฉ. The expansion is relative to a jump instruction.
  • max-goto-duplication-insns โ€” the maximum 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 in compilation 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 maximum number of instructions to consider when looking for an instruction to fill a delay slot ๐Ÿ”. If more than this arbitrary number gets searched, the time saved by filling the delay slot is minimal, so GCC stops searching ๐Ÿ›‘. Higher values mean more aggressive optimization, making compilation take longer for probably a small improvement in execution time ๐ŸŒ.
  • max-delay-slot-live-search โ€” when filling delay slots, the maximum number of instructions to consider when searching for a block with valid live register information ๐Ÿ”Ž. Cranking this arbitrarily chosen value up means more aggressive optimization and longer compilation time ๐Ÿ•. This parameter should be removed once the delay slot code is rewritten to maintain the control-flow graph ๐Ÿšง.
  • max-gcse-memory โ€” the approximate maximum amount of memory in "kB" that can be allocated for the global common subexpression elimination optimization ๐Ÿ’พ. If more memory than specified is required, the optimization just doesn't happen ๐Ÿ™ƒ.
  • max-gcse-insertion-ratio โ€” if the ratio of expression insertions to deletions is larger than this value for any expression, RTL PRE inserts or removes the expression ๐Ÿ”„. Otherwise it leaves partially redundant computations in the instruction stream ๐Ÿซค.
  • max-pending-list-length โ€” the maximum number of pending dependencies the scheduler allows before it flushes the current state and starts over ๐Ÿงน. Big functions with few branches or calls can create excessively large lists that needlessly eat memory and resources ๐Ÿ”.
  • max-modulo-backtrack-attempts โ€” the maximum number of backtrack attempts the scheduler should make when modulo scheduling a loop ๐Ÿ”. Larger values can exponentially increase compilation time ๐Ÿ“ˆ๐Ÿ’€.
  • max-inline-functions-called-once-loop-depth โ€” the maximal loop depth of a call considered by the inline heuristics that try to inline all functions called once ๐ŸŽ€.
  • max-inline-functions-called-once-insns โ€” the maximal estimated size of functions produced while inlining functions called once ๐Ÿ“.
  • max-inline-insns-single โ€” several parameters control the tree inliner used in GCC ๐ŸŒณ. This number sets the maximum number of instructions (counted in GCC's internal representation) in a single function that the tree inliner considers 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 (included in -O3), a lot of functions that otherwise wouldn't be considered for inlining get investigated ๐Ÿ”ฌ. For those functions, a different, more restrictive limit than the one for functions declared inline can be applied (--param max-inline-insns-auto) ๐Ÿซถ.
  • max-inline-insns-small โ€” this is the bound applied to calls considered relevant with -finline-small-functions ๐Ÿงธ.
  • max-inline-insns-size โ€” this is the bound applied to calls that are optimized for size ๐Ÿ“ฆ. A small growth may be desirable to anticipate optimization opportunities exposed by inlining ๐ŸŒฑ.
  • 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's 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, 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 exceeds this threshold (in percent), the function can be inlined regardless of the limit on --param max-inline-insns-single and --param max-inline-insns-auto ๐Ÿš€๐Ÿ‘‘.
  • large-function-insns โ€” ๐Ÿ”๏ธ This is the cutoff for "really large" functions. Once a function is bigger than this after inlining, --param large-function-growth starts putting the brakes on inlining. It's mainly there to stop compile times from going totally off the rails because of the non-linear algorithms the back end uses. ๐Ÿ˜ญ
  • large-function-growth โ€” ๐Ÿ“ˆ This caps how much a large function can grow from inlining, measured in percent. So a value of 100 keeps growth to 2.0 times the original size. โœจ
  • large-unit-insns โ€” ๐Ÿ“ฆ This is the line for a large translation unit. Growth from inlining in units bigger than this gets limited by --param inline-unit-growth, and for small units that limit can be a bit too tight. Picture a unit with an inlineable function A and a function B that calls A three times. If B is small compared to A, the unit grows by 300%, and honestly that inlining is still very sane. ๐Ÿซถ But for really huge units packed with tiny inlineable functions, the overall unit growth limit is what stops an exponential explosion of code size. So for smaller units, the size gets bumped up to --param large-unit-insns before --param inline-unit-growth gets applied. ๐Ÿง 
  • lazy-modules โ€” ๐Ÿงฉ This is the maximum number of C++ module files that can be open at the same time when lazy loading is happening. ๐Ÿ’œ
  • inline-unit-growth โ€” ๐ŸŒฑ This sets the maximum overall growth of the compilation unit from inlining. A value of 20 limits unit growth to 1.2 times the original size. Also, cold functions (whether they're marked cold with an attribute or flagged cold by profile feedback) don't count toward the unit size. ๐ŸงŠ
  • ipa-cp-unit-growth โ€” ๐Ÿ”— This is the maximum overall growth of the compilation unit from interprocedural constant propagation. A value of 10 limits unit growth to 1.1 times the original size. ๐ŸŒธ
  • ipa-cp-large-unit-insns โ€” ๐Ÿ“ This is the size at which the IPA-CP pass decides a translation unit counts as large. ๐Ÿฆ‹
  • large-stack-frame โ€” ๐Ÿฅž This is the limit that defines large stack frames. While inlining, the algorithm tries really hard not to grow past this limit too much. ๐Ÿ™ˆ
  • large-stack-frame-growth โ€” ๐Ÿ—๏ธ This caps how much large stack frames can grow from inlining, in percent. A value of 1000 limits growth to 11 times the original size. Yes, that's a lot. ๐Ÿ’€
  • max-inline-insns-recursive, max-inline-insns-recursive-auto โ€” ๐Ÿ” These set the maximum number of instructions an out-of-line copy of a self-recursive inline function can grow into while doing recursive inlining. --param max-inline-insns-recursive is for functions that are declared inline. For functions that aren't declared inline, recursive inlining only happens when -finline-functions is enabled (it's included in -O3), and that's when --param max-inline-insns-recursive-auto takes over. ๐Ÿ’…
  • max-inline-recursive-depth, max-inline-recursive-depth-auto โ€” ๐ŸŒ€ These set the maximum recursion depth used for recursive inlining. Same deal as above: --param max-inline-recursive-depth applies to functions declared inline, while functions that aren't declared inline only get recursive inlining when -finline-functions (included in -O3) is enabled, and then --param max-inline-recursive-depth-auto applies instead. โœจ
  • min-inline-recursive-probability โ€” ๐ŸŽฏ Recursive inlining is only worth it for functions that recurse deeply on average. For functions with a shallow recursion depth, it can backfire by making the prologue bigger or making the function body more complicated for other optimizers. > Heads up: this one can genuinely hurt performance if you use it on the wrong functions. ๐Ÿ™ƒ When profile feedback is available (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 then limits inlining to call expressions whose probability is higher than the threshold, measured in percent. ๐Ÿ“
  • early-inlining-insns โ€” ๐Ÿš€ This sets how much growth the early inliner is allowed to make. Basically, it lets the early inliner do more inlining for code that has a large abstraction penalty. ๐Ÿ‘‘
  • max-early-inliner-iterations โ€” ๐Ÿ”„ This is the limit on how many iterations the early inliner runs. It's basically the bound on how many nested indirect calls the early inliner can resolve. Deeper chains still get handled later by late inlining. ๐Ÿงš
  • comdat-sharing-probability โ€” ๐Ÿค This is the probability, in percent, that C++ inline functions with comdat visibility get shared across multiple compilation units. ๐ŸŒˆ
  • modref-max-bases, modref-max-refs, modref-max-accesses โ€” ๐Ÿ—‚๏ธ These set the maximum number of base pointers, references, and accesses that get stored for a single function by mod/ref analysis. ๐Ÿซง
  • modref-max-tests โ€” ๐Ÿ” This is the maximum number of tests the alias oracle can run to tell memory locations apart using mod/ref information. It should be bigger than --param modref-max-bases and --param modref-max-refs. ๐Ÿ“š
  • modref-max-depth โ€” ๐Ÿ•ณ๏ธ This is the maximum depth of the DFS walk used by modref escape analysis. Setting it to 0 disables the analysis completely. ๐Ÿ™…โ€โ™€๏ธ
  • modref-max-escape-points โ€” ๐Ÿšช This is the maximum number of escape points that modref tracks per SSA-name. ๐Ÿ’œ
  • modref-max-adjustments โ€” ๐Ÿ“ This is the maximum amount the access range can get enlarged during modref dataflow analysis. ๐ŸŒŸ
  • profile-func-internal-id โ€” ๐Ÿชช This controls whether the function's internal id is 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 tolerant of source changes, like functions getting reordered. ๐Ÿฅน
  • min-vect-loop-bound โ€” ๐Ÿ”ข This is the minimum number of iterations a loop needs before it gets vectorized when -ftree-vectorize is used. The number of iterations after vectorization has to be greater than this value for vectorization to happen. ๐Ÿ’–
  • gcse-cost-distance-ratio โ€” ๐Ÿ“ This is a scaling factor in figuring out the maximum distance an expression can be moved by GCSE optimizations. It's only supported in the code hoisting pass. The bigger the ratio, the more aggressively simple expressions get hoisted, meaning expressions that cost less than gcse-unrestricted-cost. Setting it to 0 turns off hoisting of simple expressions completely. ๐Ÿ›‘
  • gcse-unrestricted-cost โ€” ๐Ÿ’ธ This is the cost, roughly measured as the cost of a single typical machine instruction, at which GCSE optimizations stop limiting how far an expression can travel. It's also only supported in the code hoisting pass. The lower the cost, the more aggressive the hoisting is, and setting it to 0 lets every expression travel unrestricted distances. ๐Ÿƒโ€โ™€๏ธ
  • max-hoist-depth โ€” ๐ŸŒณ This is how deep the search goes into the dominator tree looking for expressions to hoist. It exists to avoid quadratic behavior in the hoisting algorithm. A value of 0 means there's no limit on the search, but it might slow down compilation of huge functions. ๐ŸŒ
  • max-tail-merge-comparisons โ€” โš–๏ธ This is the maximum number of similar bbs that a bb gets compared against. It's there to avoid quadratic behavior in tree tail merging. ๐Ÿง
  • max-tail-merge-iterations โ€” ๐Ÿ”‚ This is the maximum number of iterations of the pass over the function. It limits compilation time in tree tail merging. โฑ๏ธ
  • store-merging-allow-unaligned โ€” ๐Ÿงท This lets the store merging pass introduce unaligned stores, but only if that's legal to do. ๐ŸŒท
  • max-stores-to-merge โ€” ๐Ÿงบ This is the maximum number of stores the store merging pass will try to merge into wider stores. ๐Ÿ’
  • max-store-chains-to-track โ€” ๐Ÿ”— This is the maximum number of store chains tracked at the same time while trying to merge them into wider stores in the store merging pass. ๐ŸŽ€
  • max-stores-to-track โ€” ๐Ÿ‘€ This is the maximum number of stores tracked at the same time while the store merging pass tries to merge them into wider stores. ๐Ÿซถ
  • max-unrolled-insns โ€” ๐Ÿ” This is the maximum number of instructions a loop can have and still be unrolled. If a loop does get unrolled, this parameter also decides how many times the loop code gets unrolled. ๐Ÿงถ
  • max-average-unrolled-insns โ€” ๐Ÿ“Š This is the maximum number of instructions a loop can have and still be unrolled, where the instructions are weighted by how likely they are to execute. If a loop is unrolled, this parameter also decides how many times the loop code is unrolled. ๐ŸŒŠ
  • max-unroll-times โ€” ๐Ÿ”ข This is the maximum number of unrollings a single loop can get. ๐Ÿ’…
  • max-peeled-insns โ€” ๐ŸŠ This is the maximum number of instructions a loop can have and still be peeled. If a loop gets peeled, this parameter also decides how many times the loop code is peeled. ๐Ÿง…
  • max-peel-times โ€” ๐Ÿ”ช This is the maximum number of peelings a single loop can get. ๐ŸŽˆ
  • max-peel-branches โ€” ๐ŸŒฟ This is the maximum number of branches on the hot path through the peeled sequence. ๐Ÿ”ฅ
  • max-completely-peeled-insns โ€” ๐Ÿงฎ This is the maximum number of insns a completely peeled loop can have. ๐ŸŒธ
  • max-completely-peel-times โ€” โณ This is the maximum number of iterations a loop can have and still be suitable for complete peeling. ๐Ÿฃ
  • max-completely-peel-loop-nest-depth โ€” ๐Ÿช† This is the maximum depth of a loop nest that's suitable for complete peeling. ๐Ÿงธ
  • max-unswitch-insns โ€” ๐Ÿ”€ This is the maximum number of insns an unswitched loop can have. ๐Ÿฆ„
  • max-unswitch-level โ€” ๐Ÿชœ This is the maximum number of branches that get unswitched in a single loop. โญ
  • lim-expensive โ€” ๐Ÿ’ฐ This is the minimum cost an expression needs to count as expensive in loop invariant motion. ๐Ÿ’Ž
  • min-loop-cond-split-prob โ€” โœ‚๏ธ When FDO profile information is available, this sets the minimum probability threshold a semi-invariant condition statement needs before it triggers a loop split. ๐Ÿง 
  • iv-consider-all-candidates-bound โ€” ๐Ÿงญ This is the bound on the number of candidates for induction variables. If there are this many candidates or fewer, all of them get considered for each use in induction variable optimizations. If there are more than that, only the most relevant ones get considered, so the time complexity doesn't go quadratic. ๐Ÿฅณ
  • iv-max-considered-uses โ€” okay so the induction variable optimizations literally give up ๐Ÿ˜ญ on any loop that has more induction variable uses than this. not a bug, just a vibe check ๐Ÿ’…
  • iv-always-prune-cand-set-bound โ€” if the set has fewer candidates than this value, the compiler always tries to clear out unnecessary ivs whenever it adds a new one. bestie, keep the set lean โœจ
  • avg-loop-niter โ€” the average number of iterations a loop is expected to run ๐Ÿ”
  • dse-max-object-size โ€” the biggest size (in bytes) of objects that dead store elimination tracks bytewise ๐Ÿงน. bigger numbers can mean longer compile times, so it's giving trade-off ๐Ÿซถ
  • dse-max-alias-queries-per-store โ€” the max number of questions dead store elimination can ask the alias oracle for each store ๐Ÿ”ฎ. more questions means slower compiles, but also possibly more dead stores getting cleaned up, so it's a whole vibe ๐Ÿ’œ
  • scev-max-expr-size โ€” caps how big the expressions can get in the scalar evolutions analyzer ๐Ÿ“. huge expressions make the analyzer slow, so keep it tidy bestie ๐Ÿงš
  • scev-max-expr-complexity โ€” caps how complex those scalar evolutions expressions are allowed to be ๐Ÿงฉ. complicated ones slow the analyzer down, obviously ๐Ÿ’€
  • max-tree-if-conversion-phi-args โ€” the max number of arguments a PHI can have and still get supported by TREE if conversion ๐ŸŒธ. this doesn't apply if the loop has a simd pragma, so iykyk ๐ŸŽ€
  • vect-max-version-for-alignment-checks โ€” the most run-time checks the vectorizer will do when it versions a loop for alignment ๐Ÿฆ‹
  • vect-max-version-for-alias-checks โ€” same energy, but for alias checks: the most run-time checks the vectorizer will do when it versions a loop for aliasing ๐ŸŒˆ
  • vect-max-peeling-for-alignment โ€” the max number of loop peels the vectorizer will do to make memory access aligned ๐Ÿ“. setting it to -1 means no limit at all, periodt ๐Ÿ‘‘
  • max-iterations-to-track โ€” how many iterations of a loop the brute-force algorithm will try to evaluate when it's figuring out how many times the loop runs ๐Ÿงฎ
  • hot-bb-count-fraction โ€” this is the denominator n in the fraction 1/n ๐Ÿฐ. a basic block needs an execution count above that fraction of the program's maximum block count to count as hot ๐Ÿ”ฅ. the default is 10000, so a block is hot when its count is more than 1/10000 of the max ๐ŸŒŸ. setting it to 0 means nothing is ever hot ๐Ÿฅ€. this only applies in non-LTO mode, so don't mix it up with the LTO one ๐Ÿ™ˆ
  • hot-bb-count-ws-permille โ€” the number of most-executed permilles (somewhere from 0 to 1000) of the whole program's profiled execution that a block's count has to belong to in order to be hot ๐Ÿ’–. the default is 990, which means a block is hot if its count is part of the top 990 permilles, aka 99.0%, of the profiled run ๐ŸŒท. 0 means nothing is ever hot. this one is used in LTO mode โœจ
  • hot-bb-frequency-fraction โ€” the denominator n in the fraction 1/n of the entry block's execution frequency in a function ๐ŸŽฏ. a block in that function needs to hit this to be hot ๐Ÿ”ฅ. the default is 1000, so a block is hot if it runs more often than 1/1000 of the entry block's frequency ๐Ÿ’…. 0 means it's never hot ๐Ÿ’€
  • unlikely-bb-count-fraction โ€” the denominator n in the fraction 1/n of the profiled runs of the whole program ๐ŸงŠ. if a block's execution count is below that fraction, it's considered unlikely to be executed. the default is 20, so a block is unlikely if it runs in fewer than 1/20, aka 5%, of the program's runs ๐Ÿ˜ด. 0 means it's always considered unlikely ๐Ÿ™ƒ
  • max-predicted-iterations โ€” the max number of loop iterations the compiler predicts statically ๐Ÿ”ข. this helps when a function has one loop with a known bound and another with an unknown one ๐Ÿง. the known count gets predicted right, but the unknown count averages out to about 10, so the unbounded loop looks artificially cold next to the other one ๐Ÿฅถ
  • builtin-expect-probability โ€” controls the probability that an expression has the value you specified ๐ŸŽฒ. it takes a percentage, so anything from 0 to 100 ๐Ÿ’ฏ
  • builtin-string-cmp-inline-length โ€” the max length of a constant string in a builtin string compare call that's allowed to get inlined ๐Ÿงต
  • align-threshold โ€” picks a fraction of the maximal execution frequency of a basic block in a function, and that's what decides whether the block gets aligned ๐Ÿ“
  • align-loop-iterations โ€” any loop that's expected to iterate at least this many times gets aligned ๐Ÿช„
  • tracer-dynamic-coverage, tracer-dynamic-coverage-feedback โ€” this value limits superblock formation once a given percentage of executed instructions is covered ๐Ÿงƒ. it stops code size from blowing up for no reason ๐Ÿ’…

The tracer-dynamic-coverage-feedback one is only used when profile feedback is available ๐Ÿ“Š. real profiles aren't as balanced as statically estimated ones, so the threshold can be set to a bigger value ๐ŸŒˆ

  • tracer-max-code-growth โ€” stops tail duplication once code growth hits this percentage ๐Ÿ“ˆ. honestly it's a pretty artificial limit, since most of the duplicates get cleaned up later in cross jumping, so it can be set way higher than the code growth you actually want ๐Ÿ™ˆ
  • tracer-min-branch-ratio โ€” stops reverse growth when the reverse probability of the best edge drops below this threshold (in percent) ๐Ÿ“‰
  • tracer-min-branch-probability, tracer-min-branch-probability-feedback โ€” stops forward growth if the best edge has a probability lower than this threshold ๐Ÿ›‘

These two work like the tracer-dynamic-coverage pair. tracer-min-branch-probability-feedback is for compiles with profile feedback, and tracer-min-branch-probability is for compiles without it ๐ŸŽ€. the feedback value needs to be more conservative (higher) to make the tracer effective ๐Ÿ’ช

  • stack-clash-protection-guard-size โ€” sets the size of the operating system's stack guard, as 2 raised to num bytes ๐Ÿ›ก๏ธ. higher values can mean fewer explicit probes, but if the value is bigger than the OS-provided guard, your code is left open to stack clash style attacks ๐Ÿšจ
  • stack-clash-protection-probe-interval โ€” stack clash protection probes the stack as it gets allocated ๐Ÿ”. this param sets the max distance between those probes, as 2 raised to num bytes ๐Ÿ“. higher values can mean fewer explicit probes, but a value bigger than the OS-provided guard leaves code open to stack clash style attacks ๐Ÿ˜ญ
  • max-cse-path-length โ€” the max number of basic blocks on a path that CSE looks at ๐Ÿ›ค๏ธ
  • max-cse-insns โ€” the max number of instructions CSE processes before it flushes ๐Ÿšฟ
  • ggc-min-expand โ€” GCC uses a garbage collector to manage its own memory ๐Ÿ—‘๏ธ. this sets the minimum percentage the collector's heap is allowed to grow between collections ๐Ÿ“ฆ. tuning it might speed up compilation, but it has zero effect on code generation ๐Ÿ™…โ€โ™€๏ธ

The default is 30% + 70% * (RAM/1GB), capped at 100% when RAM is at least 1GB ๐Ÿ’œ. if getrlimit is available, "RAM" means the smallest of actual RAM, RLIMIT_DATA, or RLIMIT_AS ๐Ÿง . if GCC can't work out RAM on a platform, it falls back to the 30% lower bound ๐Ÿฅบ. setting this and ggc-min-heapsize to zero makes a full collection happen 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 reach before it starts bothering to collect garbage ๐Ÿงบ. the first collection happens after the heap grows by ggc-min-expand% past ggc-min-heapsize ๐ŸŒฑ. again, tuning this may speed up compilation, and it has no effect on code generation โœจ

The default is the smallest of RAM/8, RLIMIT_RSS, or a limit that tries to make sure RLIMIT_DATA or RLIMIT_AS don't get exceeded ๐Ÿ“‰. but 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 is used ๐Ÿฅน. setting this really, really large basically turns garbage collection off ๐Ÿšซ. setting it and ggc-min-expand to zero makes a full collection happen at every opportunity ๐Ÿ”

  • max-reload-search-insns โ€” the max number of instructions reload will look backward through to find an equivalent register ๐Ÿ”™. higher values mean more aggressive optimization, which makes compile time go up with 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, which makes compile time go up with probably slightly better performance ๐Ÿš€
  • max-sched-ready-insns โ€” the max number of instructions that are ready to be issued the scheduler should consider 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 that's considered for interblock scheduling ๐Ÿงฑ
  • max-pipeline-region-blocks โ€” the max number of blocks in a region that's considered for pipelining in the selective scheduler ๐Ÿชˆ
  • max-sched-region-insns โ€” the max number of insns in a region that's considered for interblock scheduling ๐ŸŒท
  • max-pipeline-region-insns โ€” okay so this is the cap on how many insns a region can have before the selective scheduler even considers pipelining it ๐Ÿ’…
  • min-spec-prob โ€” the minimum probability (in percents) that a source block gets reached before interblock speculative scheduling will go for it ๐Ÿ”ฎ
  • max-sched-extend-regions-iters โ€” how many times the scheduler can loop through the CFG to extend regions ๐Ÿ” Set it to 0 and region extensions are switched off totally ๐Ÿ™…โ€โ™€๏ธ
  • max-sched-insn-conflict-delay โ€” the max conflict delay an insn can have and still be eligible for speculative motion ๐Ÿš€
  • sched-spec-prob-cutoff โ€” the lowest chance of speculation success (in percents) that still gets speculative insns scheduled ๐ŸŽฏ
  • sched-state-edge-prob-cutoff โ€” the minimum probability an edge needs before the scheduler bothers saving its state across it ๐Ÿช„
  • sched-mem-true-dep-cost โ€” the minimal distance, in CPU cycles, between a store and a load that target the same memory locations ๐Ÿง 
  • selsched-max-lookahead โ€” the max size of the lookahead window for selective scheduling. Basically, how deep it digs when hunting for available instructions ๐Ÿ”
  • selsched-max-sched-times โ€” how many times one instruction can get scheduled during selective scheduling. This is the cap on how many iterations it's allowed to be pipelined through ๐Ÿ”„
  • selsched-insns-to-rename โ€” the max number of best instructions in the ready list that get considered for renaming in the selective scheduler โœ๏ธ
  • sms-min-sc โ€” the smallest stage count the swing modulo scheduler will generate ๐ŸŽข
  • max-last-value-rtl โ€” the max size, counted in RTLs, that the combiner can record in an expression as a pseudo register's last known value ๐Ÿ“
  • max-combine-insns โ€” the max number of instructions the RTL combiner will try to combine together ๐Ÿงฉ
  • integer-share-limit โ€” small integer constants can share one data structure, which saves memory and makes things faster โšก This sets the biggest value a shared integer constant can have ๐Ÿ’œ
  • ssp-buffer-size โ€” the minimum size of buffers (aka arrays) that get stack smashing protection when -fstack-protector is on ๐Ÿ›ก๏ธ
  • min-size-for-stack-sharing โ€” the minimum size of variables that join in on stack slot sharing when you're not optimizing ๐Ÿ™ˆ
  • max-jump-thread-duplication-stmts โ€” the max number of statements allowed in a block that has to be duplicated when threading jumps ๐Ÿงต
  • max-fields-for-field-sensitive โ€” the max number of fields in a structure that get treated in a field sensitive way during pointer analysis ๐Ÿฆ‹
  • prefetch-latency โ€” an estimate of how many instructions, on average, run before a prefetch finishes โณ The distance prefetched ahead scales with this number ๐Ÿ“ Cranking it up might 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 โ€” this decides whether the loop array prefetch pass issues software prefetch hints for strides that aren't constant ๐ŸŒˆ Sometimes that's a win, but a non-constant stride can make it really hard to tell when the hints actually help ๐Ÿค”

Set it to 1 and hints get issued for non-constant strides โœ… Set it to 0 and hints only get issued for strides that are known to be constant and sit below prefetch-minimum-stride ๐Ÿ™…โ€โ™€๏ธ

  • prefetch-minimum-stride โ€” the minimum constant stride, in bytes, before prefetch hints start getting used ๐Ÿ“ If the stride is smaller than this threshold, no prefetch hints get issued ๐Ÿซฅ

This one is a lifesaver for processors with hardware prefetchers ๐Ÿซถ If both kinds of prefetcher are fighting each other, you can use this setting to keep them from clashing. If the hardware prefetchers have a maximum stride they can handle, put that number here so the software prefetchers get used better ๐Ÿงš

A value of -1 means there's no threshold at all, so prefetch hints can get issued for any constant stride โ™พ๏ธ

This setting only matters for strides that are known and constant ๐Ÿ’…

  • destructive-interference-size, constructive-interference-size โ€” these set the values for the C++17 variables "std::hardware_destructive_interference_size" and "std::hardware_constructive_interference_size" ๐Ÿ‘‘

The destructive interference size is the minimum recommended offset between two independent objects that are accessed concurrently, in bytes ๐Ÿ’ฅ The constructive interference size is the maximum recommended size of contiguous memory that gets accessed together ๐Ÿค Usually both match the size of an L1 cache line for the target, in bytes ๐Ÿซง For a generic target that covers a range of L1 cache line sizes, the constructive interference size is typically the small end of that range, and the destructive size is typically the large end ๐Ÿ“Š

The destructive interference size is meant for layout, so it has ABI impact โš ๏ธ Its default value isn't expected to stay stable, and on some targets it changes with -mtune ๐Ÿ˜ญ So using it somewhere ABI stability really matters, like the public interface of a library, is strongly discouraged ๐Ÿšซ If you do end up using it there, users can lock the value in place with this option ๐Ÿ”’

The constructive interference size is way less sensitive, since it's usually only used in a static_assert to make sure a type fits inside a cache line ๐Ÿ’–

See also -Winterference-size ๐Ÿ‘€

  • loop-interchange-max-num-stmts โ€” the max number of stmts in a loop that can be interchanged ๐Ÿ”
  • loop-interchange-stride-ratio โ€” the minimum ratio between the strides of two loops for an interchange to be profitable ๐Ÿ“ˆ
  • min-insn-to-prefetch-ratio โ€” the minimum ratio between the number of instructions and the number of prefetches needed to turn on prefetching in a loop ๐Ÿงฎ
  • prefetch-min-insn-to-mem-ratio โ€” the minimum ratio between the number of instructions and the number of memory references needed to turn on prefetching in a loop ๐Ÿ’œ
  • use-canonical-types โ€” whether the compiler uses the "canonical" type system ๐Ÿงฌ This should always be 1, since it uses a more efficient internal mechanism for comparing types in C++ and Objective-C++ โœจ But if bugs in the canonical type system are causing compilation failures, set it to 0 to turn canonical types off ๐Ÿซ 
  • switch-conversion-max-branch-ratio โ€” switch initialization conversion refuses to make arrays bigger than this value 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 kinds of source code, the enhanced PRE can run away and eat all the memory on the host machine ๐Ÿ˜ฑ This parameter caps how long those sets can get, so the runaway behavior can'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 gets hit, the innermost rpo-vn-max-loop-depth loops, plus the outermost loop in the loop nest, get value-numbered optimistically, and the remaining ones don't ๐Ÿช†
  • sccvn-max-alias-queries-per-access โ€” the max number of alias-oracle queries performed while looking for redundancies in loads and stores ๐Ÿ”Ž If this limit is hit, the search is aborted and the load or store is not considered redundant ๐Ÿ™ƒ The number of queries is algorithmically limited to the number of stores on all paths from the load to the function entry ๐Ÿงญ
  • ira-max-loops-num โ€” IRA uses regional register allocation by default ๐Ÿ—บ๏ธ If a function has more loops than the number given here, only that many of the most frequently executed loops form regions for regional register allocation ๐Ÿ‘‘
  • ira-max-conflict-table-size โ€” IRA uses a fancy algorithm to compress the conflict table, but for huge functions the table can still eat an excessive amount of memory ๐Ÿฅต If a function's conflict table could be bigger than the size in MB given here, the register allocator switches to a faster, simpler, lower-quality algorithm that doesn't need to build a pseudo-register conflict table ๐ŸŽ๏ธ
  • ira-loop-reserved-regs โ€” IRA can be used to evaluate more accurate register pressure in loops, which helps decide when to move loop invariants (see -O3) ๐ŸŽ€ This parameter gives the number of available registers reserved for other purposes ๐Ÿงธ The default is the best value found through lots of experiments ๐Ÿงช
  • ira-consider-dup-in-all-alts โ€” this makes IRA consider matching constraints (duplicated operand numbers) really heavily across all available alternatives for the preferred register class ๐Ÿฆ‹ If it's set to zero, IRA only respects the matching constraint when it's the only available alternative with an appropriate register class ๐Ÿ™ˆ Otherwise, IRA checks all available alternatives for the preferred register class, even after it's found a choice with an appropriate register class, and still respects the qualified matching constraint it found ๐Ÿ’…
  • lra-inheritance-ebb-probability-cutoff โ€” LRA tries to recycle values it already reloaded into registers for later insns, and that trick is called inheritance โœจ EBB is the region used for this optimization. This sets the minimal fall-through edge probability, in percent, for pulling a BB into the inheritance EBB in LRA. The default was picked after numerous runs of SPEC2000 on x86-64 ๐Ÿ’…
  • loop-invariant-max-bbs-in-loop โ€” Loop invariant motion can be super expensive, both in compile time and in how much compile-time memory it eats, especially with huge loops ๐Ÿ˜ญ Any loop with more basic blocks than this value just won't get loop invariant motion ๐Ÿ™…โ€โ™€๏ธ
  • loop-max-datarefs-for-datadeps โ€” Building data dependencies is pricey for very large loops ๐Ÿ’€ This caps how many data references in a loop get considered for data dependence analysis. Loops that are bigger than that aren't handled by the optimizations that rely on loop data dependencies ๐Ÿฆ‹
  • max-vartrack-size โ€” Sets a max number of hash table slots that can be used during variable tracking dataflow analysis for any function ๐Ÿ“Š If you go over that while variable tracking at assignments is on, the analysis gets retried without it, after all debug insns are removed from the function. If you're still over the limit without debug insns, var tracking analysis is totally disabled for that function ๐Ÿ˜ค Setting this to zero makes it unlimited โ™พ๏ธ
  • max-vartrack-expr-depth โ€” Sets a max number of recursion levels when mapping variable names or debug temporaries to value expressions ๐Ÿง  It's a trade-off: more compile time for more complete debug info โฑ๏ธ If it's set too low, value expressions that could show up in debug info might get skipped. Setting it higher lets the compiler find fancier debug expressions, but compile time and memory use can grow ๐Ÿ“ˆ
  • max-debug-marker-count โ€” A threshold on how many debug markers (like begin stmt markers) are allowed, so things don't blow up when inlining or 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 start at this value for nondebug insns ๐Ÿ”ข The range below it is reserved for debug insns created by -fvar-tracking-assignments. But if that reserved range runs out, debug insns can still get (non-overlapping) uids above it ๐Ÿซถ
  • ipa-sra-ptr-growth-factor โ€” IPA-SRA only swaps a pointer to an aggregate for one or more new parameters if their combined size is less than or equal to this factor times the size of the original pointer parameter ๐Ÿ“
  • ipa-sra-max-replacements โ€” The max pieces of an aggregate that IPA-SRA keeps track of ๐Ÿงฉ That also means it's the max number of replacements for a formal parameter ๐Ÿ”
  • sra-max-scalarization-size-Ospeed
  • sra-max-scalarization-size-Osize โ€” Both of these are for the two Scalar Reduction of Aggregates passes (SRA and IPA-SRA) ๐Ÿฐ They try to swap scalar parts of aggregates for uses of independent scalar variables โœจ These params set the max size, in storage units, of an aggregate that's even considered for replacement. sra-max-scalarization-size-Ospeed is for when you're compiling for speed ๐ŸŽ๏ธ, and sra-max-scalarization-size-Osize is for when you're compiling for size ๐Ÿ“ฆ
  • sra-max-propagations โ€” The max number of artificial accesses that Scalar Replacement of Aggregates (SRA) will track per local variable, so it can do copy propagation ๐Ÿ”
  • tm-max-aggregate-size โ€” When copying thread-local variables inside 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 only matters when you're using -fgnu-tm ๐ŸŽ€
  • graphite-max-nb-scop-params โ€” To avoid exponential chaos in the Graphite loop transforms, the number of parameters in a Static Control Part (SCoP) is capped ๐Ÿ™…โ€โ™€๏ธ Set it to zero to lift the cap ๐Ÿ”“ A variable whose value isn't known at compile time and is defined outside a SCoP counts as a parameter of that SCoP ๐Ÿงฎ
  • loop-block-tile-size โ€” Loop blocking and strip mining (turned on with -floop-block or -floop-strip-mine) strip mine each loop in the loop nest by a given number of iterations ๐Ÿฅž You can change the strip length with this param ๐ŸŽš๏ธ
  • ipa-jump-function-lookups โ€” The number of statements visited during jump function offset discovery ๐Ÿ‘€
  • ipa-cp-value-list-size โ€” IPA-CP tries to track every possible value and type passed to 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 of a function ๐Ÿ“‹
  • ipa-cp-eval-threshold โ€” IPA-CP calculates its own score for how profitable cloning is, based on heuristics ๐Ÿงฎ It goes ahead with the cloning opportunities whose scores beat ipa-cp-eval-threshold ๐Ÿ†
  • ipa-cp-max-recursive-depth โ€” The max depth of recursive cloning for a self-recursive function ๐Ÿ”„
  • ipa-cp-min-recursive-probability โ€” Recursive cloning only happens when the probability of the call being executed is higher than this param ๐ŸŽฒ
  • ipa-cp-profile-count-base โ€” When you use -fprofile-use, IPA-CP looks at the measured execution count of a call graph edge at this percentage position in its histogram ๐Ÿ“Š That number becomes the basis for its heuristics calculation ๐Ÿง 
  • ipa-cp-recursive-freq-factor โ€” How many times interprocedural copy propagation expects recursive functions to call themselves ๐Ÿ”
  • ipa-cp-recursion-penalty โ€” The percentage penalty that recursive functions get when they're evaluated for cloning ๐Ÿ˜ฌ
  • ipa-cp-single-call-penalty โ€” The percentage penalty that functions with a single call to another function get when they're evaluated for cloning ๐Ÿ“‰
  • ipa-max-agg-items โ€” IPA-CP can also propagate a bunch of scalar values passed in an aggregate ๐ŸŽ This controls the max number of those values for each parameter ๐Ÿ”ข
  • ipa-cp-loop-hint-bonus โ€” When IPA-CP figures out that a cloning candidate would make a loop's number of iterations known, it adds this bonus to the candidate's profitability score ๐ŸŽ‰
  • ipa-max-loop-predicates โ€” The max number of different predicates IPA will use to describe when loops in a function have known properties ๐Ÿ”ฎ
  • ipa-max-aa-steps โ€” While analyzing function bodies, IPA-CP uses alias analysis to track values pointed to by function parameters ๐Ÿ•ต๏ธโ€โ™€๏ธ To keep huge functions from taking forever, it gives up and treats all memory as clobbered after looking at ipa-max-aa-steps statements that modify memory ๐Ÿ›‘
  • ipa-max-switch-predicate-bounds โ€” The max number of boundary endpoints of case ranges in a switch statement ๐Ÿ”€ If a switch goes over this limit, IPA-CP won't build the cloning cost predicate (used to estimate cloning benefit) for the switch's default case ๐Ÿšซ
  • ipa-max-param-expr-ops โ€” IPA-CP will look at conditional statements 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 skipped by IPA analysis ๐Ÿ™…โ€โ™€๏ธ
  • lto-partitions โ€” The desired number of partitions made during WHOPR compilation ๐Ÿงฉ It should be more than the number of CPUs you're compiling with ๐Ÿ’ป
  • lto-min-partition โ€” The size of the minimal partition for WHOPR, in estimated instructions ๐Ÿฃ This stops tiny programs from getting split into way too many partitions ๐Ÿ™ˆ
  • lto-max-partition โ€” The size of the max partition for WHOPR, in estimated instructions ๐Ÿ“ It gives an upper bound on how big any single partition can get ๐Ÿงฑ This is only meant to be used with balanced partitioning โš–๏ธ
  • lto-max-streaming-parallelism โ€” The max number of parallel processes used for LTO streaming ๐ŸŒŠ
  • cxx-max-namespaces-for-diagnostic-help โ€” The max number of namespaces to 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 a statement's original block, that still allows that statement to be sunk ๐Ÿ“‰ Bigger numbers mean more aggressive statement sinking ๐Ÿ”ฅ Statements with memory operands get a small positive adjustment, since sinking those 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 turned off ๐Ÿšซ
  • case-values-threshold โ€” The smallest number of different values for which 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 โ€” ๐ŸŒธ okay so this one sets the max number of instructions that can run in parallel inside a reassociated tree. If you give it a non-zero value, it overrides the target-dependent heuristics that would otherwise be used by default โœจ
  • sched-pressure-algorithm โ€” ๐Ÿฆ‹ bestie, this picks between the two implementations of -fsched-pressure. Algorithm 1 is the OG version and is the more likely one to stop instructions from getting reordered. Algorithm 2 is the compromise between algorithm 1's cautious energy and the default scheduler's pretty aggressive approach. It leans harder on having a regular register file and accurate register pressure classes. For the deep dive, check out haifa-sched.cc in the GCC sources ๐Ÿ“š The default choice depends on the target ๐Ÿ’…
  • max-slsr-cand-scan โ€” ๐Ÿ’œ this caps how many existing candidates get looked at when the compiler is hunting for a basis for a new straight-line strength reduction candidate ๐Ÿ”
  • asan-globals โ€” ๐Ÿ›ก๏ธ turns on buffer overflow detection for global objects. This protection is on by default when you use -fsanitize=address. To turn off the global objects protection, use --param asan-globals=0 ๐Ÿ™…โ€โ™€๏ธ
  • asan-stack โ€” ๐Ÿงฑ same vibe, but for stack objects. It's on by default with -fsanitize=address. To skip stack protection, use --param asan-stack=0 ๐Ÿ’–
  • asan-instrument-reads โ€” ๐Ÿ‘€ enables buffer overflow detection for memory reads. Also on by default with -fsanitize=address. To disable the memory reads protection, use --param asan-instrument-reads=0 โœจ
  • asan-instrument-writes โ€” โœ๏ธ the writes version of the above. On by default with -fsanitize=address. To turn it off, use --param asan-instrument-writes=0 ๐Ÿซถ
  • asan-memintrin โ€” ๐Ÿงš enables detection for built-in functions. Enabled by default with -fsanitize=address. To disable built-in functions protection, use --param asan-memintrin=0 ๐ŸŒˆ
  • asan-use-after-return โ€” โฐ enables detection of use-after-return. It's on by default when you use -fsanitize=address. To disable it, use --param asan-use-after-return=0 ๐Ÿ™ˆ
โš ๏ธ Heads up: the check is disabled at run time by default! To turn it on, add "detect_stack_use_after_return=1" to the environment variable ASAN_OPTIONS ๐Ÿ˜ญ
  • asan-instrumentation-with-call-threshold โ€” ๐Ÿ“ž if a function being instrumented has memory accesses greater than or equal to this number, the compiler uses callbacks instead of inline checks. Want to skip the inline code entirely? 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 with -fsanitize=hwaddress and off by default with -fsanitize=kernel-hwaddress. To disable stack instrumentation, use --param hwasan-instrument-stack=0, and to turn it on, use --param hwasan-instrument-stack=1 ๐Ÿ”ฅ
  • hwasan-random-frame-tag โ€” ๐ŸŽฒ when stack instrumentation is running, tags for stack variables come from a deterministic sequence that starts at a random tag for each frame. If this param is left unset, the same sequence is used but starts at 1 instead. It's 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. On by default with -fsanitize=hwaddress, off by default with -fsanitize=kernel-hwaddress. To skip instrumenting these, use --param hwasan-instrument-allocas=0, and 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 โ€” ๐Ÿ“ enables hwasan checks on memory writes. Write instrumentation is on by default for both -fsanitize=hwaddress and -fsanitize=kernel-hwaddress. To stop checking memory writes, use --param hwasan-instrument-writes=0 ๐Ÿ’ซ
  • hwasan-instrument-mem-intrinsics โ€” ๐Ÿงฉ enables hwasan instrumentation of builtin functions. This is on by default for both -fsanitize=hwaddress and -fsanitize=kernel-hwaddress. To turn off instrumentation of builtin functions, use --param hwasan-instrument-mem-intrinsics=0 ๐ŸŒธ
  • use-after-scope-direct-emission-threshold โ€” ๐Ÿ“ if a local variable's size in bytes is smaller than or equal to this number, the compiler directly poisons (or unpoisons) shadow memory instead of making run-time callbacks ๐Ÿง 
  • tsan-distinguish-volatile โ€” ๐ŸŒ‹ emits special instrumentation for accesses to volatiles. Very specific, very iconic ๐Ÿ‘‘
  • tsan-instrument-func-entry-exit โ€” ๐Ÿšช emits instrumentation calls to __tsan_func_entry() and __tsan_func_exit() โœจ
  • max-fsm-thread-path-insns โ€” ๐Ÿงต the max number of instructions to copy when duplicating blocks on a finite state automaton jump thread path ๐Ÿ’œ
  • max-fsm-thread-length โ€” ๐Ÿ“ the max number of basic blocks on a jump thread path ๐Ÿ“
  • threader-debug โ€” ๐Ÿ› threader-debug=[none|all] turns on verbose dumping of the threader solver. Lots of tea spilled here ๐Ÿซ–
  • 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 of an innermost parallelized loop for which the parallelized version is preferred over the single-threaded one. Quick note: for a parallelized loop nest, the minimum number of iterations of the outermost loop per thread is two โœจ
  • max-ssa-name-query-depth โ€” ๐Ÿชœ the max recursion depth when querying properties of SSA names in things like fold routines. One level of recursion means following one use-def chain ๐Ÿ”—
  • max-speculative-devirt-maydefs โ€” ๐Ÿ•ต๏ธ the max number of may-defs analyzed while looking for a must-def that specifies the dynamic type of an object invoking a virtual call. That's the call we might be able to devirtualize speculatively ๐Ÿฆ‹
  • max-vrp-switch-assertions โ€” ๐Ÿ”€ the max number of assertions to add along the default edge of a switch statement during VRP ๐Ÿ’…
  • evrp-sparse-threshold โ€” ๐Ÿชถ the max number of basic blocks before EVRP switches over to a sparse cache ๐Ÿงบ
  • evrp-mode โ€” ๐ŸŽ›๏ธ specifies the mode Early VRP should operate in ๐ŸŒท
  • vrp1-mode โ€” ๐ŸŽš๏ธ specifies the mode VRP pass 1 should operate in ๐Ÿ“
  • vrp2-mode โ€” ๐ŸŽ›๏ธ specifies the mode VRP pass 2 should operate in ๐Ÿ’œ
  • ranger-debug โ€” ๐Ÿž specifies the type of debug output to be issued for ranges ๐ŸŒˆ
  • evrp-switch-limit โ€” ๐Ÿ›‘ the max number of switch cases before EVRP just ignores a switch altogether ๐Ÿ™…โ€โ™€๏ธ
  • unroll-jam-min-percent โ€” ๐Ÿ“‰ the min percentage of memory references that must be optimized away for the unroll-and-jam transformation to be considered profitable ๐Ÿ’ฐ
  • unroll-jam-max-unroll โ€” ๐Ÿ” the max number of times the outer loop gets unrolled by the unroll-and-jam transformation ๐Ÿงถ
  • max-rtl-if-conversion-unpredictable-cost โ€” ๐Ÿ’ธ the max permissible cost for the sequence the RTL if-conversion pass would generate for a branch that's considered unpredictable ๐Ÿซ 
  • max-variable-expansions-in-unroller โ€” ๐ŸŒ€ if -fvariable-expansion-in-unroller is used, this is the max number of times a single variable gets expanded during loop unrolling ๐Ÿงฉ
  • partial-inlining-entry-probability โ€” ๐ŸŽฏ the max probability of the entry BB of a split region (as a percent of the function's entry BB) that still lets partial inlining happen ๐Ÿงƒ
  • max-tracked-strlens โ€” ๐Ÿงต the max number of strings whose lengths the strlen optimization pass will track ๐Ÿ“
  • gcse-after-reload-partial-fraction โ€” ๐ŸŒ— the threshold ratio for performing partial redundancy elimination after reload ๐Ÿซถ
  • gcse-after-reload-critical-fraction โ€” ๐ŸŒ“ the threshold ratio of critical edges' execution count that permits redundancy elimination after reload ๐Ÿ’–
  • max-loop-header-insns โ€” ๐Ÿงพ the max number of insns in a loop header that the copy loop headers pass will duplicate ๐ŸŒธ
  • vect-epilogues-nomask โ€” ๐ŸŽ€ enables loop epilogue vectorization using a smaller vector size ๐Ÿฆ‹
  • vect-partial-vector-usage โ€” ๐Ÿงฉ controls when the loop vectorizer considers partial vector loads and stores instead of falling back to scalar code. This only matters on targets that support partial vector loads and stores. The levels are:
    • 0 โ€” the vectorizer never uses partial vector loads and stores ๐Ÿ™…โ€โ™€๏ธ
    • 1 โ€” partial vector loads and stores are allowed if vectorization removes the need for the code to iterate ๐Ÿ”
    • 2 โ€” partial vector loads and stores are allowed in all loops ๐Ÿ‘‘
  • vect-inner-loop-cost-factor โ€” ๐Ÿงฎ the max factor the loop vectorizer applies to the cost of statements in an inner loop, relative to the loop being vectorized. The factor used is the max of the estimated number of iterations of the inner loop and this parameter. The default value is 50 ๐Ÿ’œ
  • avoid-fma-max-bits โ€” ๐Ÿšซ the max number of bits for which we avoid creating FMAs โœจ
  • sms-loop-average-count-threshold โ€” ๐ŸŒŠ a threshold on the average loop count considered by the swing modulo scheduler ๐Ÿ”ฅ
  • sms-dfa-history โ€” okay so this one sets how many cycles the swing modulo scheduler looks at when it checks for conflicts using the DFA ๐Ÿ”ฅ
  • graphite-allow-codegen-errors โ€” decides whether codegen errors count as ICEs (internal compiler errors) when -fchecking is on ๐Ÿ’€
  • sms-max-ii-factor โ€” a tuning knob for the upper bound the swing modulo scheduler uses when it schedules a loop ๐ŸŽ€
  • lra-max-considered-reload-pseudos โ€” the max number of reload pseudos that get considered while spilling a non-reload pseudo ๐Ÿฆ‹
  • max-pow-sqrt-depth โ€” the max depth of sqrt chains allowed when synthesizing exponentiation by a real constant ๐ŸŒธ
  • max-dse-active-local-stores โ€” the max 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 โ€” sets a bound on how expensive an expression can be when GCC computes the number of iterations ๐Ÿ’œ
  • max-isl-operations โ€” the max number of isl operations, where 0 means no limit at all โœจ
  • graphite-max-arrays-per-scop โ€” the max number of arrays allowed per scop ๐Ÿ“
  • max-vartrack-reverse-op-size โ€” the max size of a loc list for which reverse ops are allowed to get added ๐ŸŒˆ
  • 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 โญ
  • uninit-control-dep-attempts โ€” the max number of nested calls allowed while hunting for control dependencies during uninitialized variable analysis ๐Ÿ‘‘
  • 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 sets how many lookahead cycles the model peeks into, and at ' ' it only turns on the instruction sorting heuristic ๐Ÿ”ฅ
  • loop-versioning-max-inner-insns โ€” the max 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 same idea for an outer loop, except any instructions in inner loops that directly benefit from versioning don't count toward the total ๐Ÿ’–
  • ssa-name-def-chain-limit โ€” the max number of SSA_NAME assignments GCC will follow when figuring out a property of a variable, like its value. It caps how many iterations or recursive calls GCC makes while optimizing certain statements or checking whether they're valid before issuing diagnostics ๐ŸŒŸ
  • store-merging-max-size โ€” the max size of a single store merging region, in bytes ๐ŸŽ€
  • hash-table-verification-limit โ€” the number of elements that get hash table verification done for each searched element ๐Ÿฆ‹
  • max-find-base-term-values โ€” the max number of VALUEs handled during a single find_base_term call ๐ŸŒธ
  • analyzer-max-enodes-per-program-point โ€” the max number of exploded nodes per program point in the analyzer. Once a point hits this, analysis of that point stops ๐Ÿงš
  • analyzer-max-constraints โ€” the max number of constraints per state ๐Ÿ’œ
  • analyzer-min-snodes-for-call-summary โ€” the minimum number of supernodes a function needs before the analyzer bothers summarizing its effects at call sites โœจ
  • analyzer-max-enodes-for-full-dump โ€” the max depth of exploded nodes that can show up in a dot dump before the output switches to a less verbose format ๐Ÿ“
  • analyzer-max-recursion-depth โ€” the max number of times a callsite can show up in a call stack inside the analyzer. Once that's reached, analysis of a call that would recurse deeper gets terminated ๐ŸŒˆ
  • analyzer-max-svalue-depth โ€” the max depth of a symbolic value. Anything deeper gets approximated as unknown โญ
  • analyzer-max-infeasible-edges โ€” the max number of infeasible edges the analyzer will reject before it declares a diagnostic infeasible ๐Ÿ‘‘
  • gimple-fe-computed-hot-bb-threshold โ€” the number of executions a basic block needs before it counts as hot. This one is only used in GIMPLE FE ๐Ÿ’…
  • analyzer-bb-explosion-factor โ€” the max number of 'after supernode' exploded nodes per supernode in the analyzer, before analysis gets terminated ๐Ÿ”ฅ
  • ranger-logical-depth โ€” the max depth of logical expression evaluation that ranger will look through when it evaluates outgoing edge ranges ๐Ÿซถ
  • relation-block-limit โ€” the max number of relations the oracle will register in a basic block ๐Ÿ’œ
  • openacc-kernels โ€” picks the mode for handling OpenACC kernels constructs. With --param=openacc-kernels=decompose, the constructs get split into parts, a sequence of compute constructs that each get handled on their own. This one is still work in progress. With --param=openacc-kernels=parloops, the constructs get handled en bloc by the parloops pass. This is the current default ๐Ÿ‘‘
  • openacc-privatization โ€” picks the mode for OpenACC privatization diagnostics, which show up with -fopt-info-omp-note and applicable -fdump-tree-*-details. With --param=openacc-privatization=quiet, nothing gets diagnosed, and this is the current default. With --param=openacc-privatization=noisy, the diagnostics do get printed ๐ŸŒธ

Heads up, these next ones are only available on AArch64 targets ๐Ÿ’…

  • aarch64-sve-compare-costs โ€” when vectorizing for SVE, GCC considers using "unpacked" vectors for smaller elements and uses the cost model to pick the cheapest approach. It also uses the cost model to choose between SVE and Advanced SIMD vectorization.
    • Using unpacked vectors 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 the float type. When division approximation is enabled, the precision of division scales with this param. The default value is 1.
  • aarch64-double-recp-precision โ€” the number of Newton iterations used to calculate the reciprocal for the double type. When division approximation is enabled, the precision of division scales with 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 โ€” uses the default heuristics.
    • 1 โ€” uses only Advanced SIMD for auto-vectorization.
    • 2 โ€” uses only SVE for auto-vectorization.
    • 3 โ€” uses both Advanced SIMD and SVE, and prefers Advanced SIMD when the costs are deemed equal.
    • 4 โ€” uses both Advanced SIMD and SVE, and prefers SVE when the costs are deemed equal.

The default value is 0.

  • aarch64-loop-vect-issue-rate-niters โ€” some AArch64 CPU tuning weighs both latencies and issue rates when deciding whether a loop should be vectorized with SVE, vectorized with Advanced SIMD, or not vectorized at all. If this param is set to n, GCC won't use this heuristic for loops known to execute in fewer than n Advanced SIMD iterations.

โœจ Program Instrumentation Options โœจ

GCC supports a bunch of command-line options that tack runtime instrumentation onto the code it normally generates. One reason to instrument is to collect profiling stats for finding hot spots, doing code coverage analysis, or running profile-guided optimizations. Another kind of instrumentation adds runtime checks that catch programming errors, like invalid pointer dereferences or out-of-bounds array accesses, plus deliberately hostile attacks like stack smashing or C++ vtable hijacking. There's also a general hook that can be used to build other kinds of tracing or function-level instrumentation for debugging or program analysis ๐Ÿ”

  • -p, -pg โ€” generates extra code that writes profile information for the analysis program prof (with -p) or gprof (with -pg). You have to use this option when compiling the source files you want data about, and you have to use it when linking too ๐Ÿ’–
    • 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. While the program runs, it records how many times each branch and call is executed, and how many times each one is 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 the 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 one is explicitly specified and it isn't the final executable. Otherwise, it's the basename of the source file. In both cases any suffix gets removed. For example, foo.gcda for input file dir/foo.c, or dir/foo.gcda for output file specified as -o dir/foo.o.
  • --coverage โ€” used to compile and link code that's instrumented for coverage analysis. It's a synonym for -fprofile-arcs -ftest-coverage when compiling, and for -lgcov when linking. Check out the docs for those options for more details ๐Ÿฆ‹
    • Compile the source files with -fprofile-arcs plus optimization and code generation options. For test coverage analysis, add the extra -ftest-coverage option. You don't need to profile every source file in a program ๐ŸŒˆ
    • Also compile the source files with -fprofile-abs-path to create absolute path names in the .gcno files. This helps gcov find the correct sources in projects where compilations happen from different working directories ๐Ÿซถ
  • Step three, the fun part ๐ŸŽ€: link your object files with -lgcov or -fprofile-arcs. The latter implies the former, so you're basically getting two for one โœจ.
  • Step four, run it ๐Ÿƒโ€โ™€๏ธ: run the program on a representative workload to generate the arc profile information. You can repeat this as many times as you want. You can even run concurrent instances of your program, and as long as the file system supports locking, your data files will be updated correctly ๐Ÿ’…. Unless a strict ISO C dialect option is in effect, fork calls are detected and handled correctly without double counting ๐Ÿซถ.

Moreover, an object file can be recompiled multiple times, and the matching .gcda file merges as long as the source file and the compiler options haven't changed. Iconic โœจ.

  • Step five, profile-directed optimizations ๐Ÿ”ฅ: compile the source files again with the same optimization and code generation options, plus -fbranch-probabilities.
  • Step six, test coverage ๐Ÿฆ‹: use gcov to turn the .gcno and .gcda files into human-readable info. Check the gcov documentation for more details, bestie ๐Ÿ“š.

So with -fprofile-arcs, GCC builds a program flow graph for each function in your program, then finds a spanning tree for that graph ๐ŸŒณ. Only the arcs that are not on the spanning tree need instrumenting. The compiler adds code to count how many times those arcs get executed. When an arc is the only exit or the only entrance to a block, the instrumentation code can go right into that block. Otherwise, a new basic block has to be created to hold it. Main character energy ๐Ÿ‘‘.


-ftest-coverage

Okay so this one makes a notes file that the gcov code-coverage utility can use to show your program's coverage ๐Ÿ“. Each source file's notes file is called auxname.gcno. For what auxname means and how to actually generate test coverage data, look at the -fprofile-arcs option above ๐ŸŒธ. Coverage data matches your source files more closely if you do not optimize ๐Ÿ™ˆ.

-fprofile-abs-path

This one is giving organization ๐Ÿ—‚๏ธ. It automatically converts relative source file names into absolute path names in the .gcno files. That lets gcov find the correct sources in projects where compilations happen from different working directories. No more lost files, bestie ๐Ÿงš.

-fprofile-dir=path

This sets the directory where profile data files get searched for, to path ๐Ÿ“. It only affects the profile data generated by -fprofile-generate, -ftest-coverage, and -fprofile-arcs, and the profile data used by -fprofile-use, -fbranch-probabilities, and their related options ๐Ÿ’–. Both absolute and relative paths work. By default, GCC uses the current directory as path, so the profile data file lives in the same directory as the object file. To avoid file name clashes, if the object file name isn't an absolute path, GCC mangles the absolute path of the sourcename.gcda file and uses that as the name of a .gcda file. See the similar option -fprofile-note ๐Ÿฆ‹.

When your executable runs in a massive parallel environment, it's recommended to save profiles into different folders ๐ŸŒˆ. You can do that with variables in path that get exported at run-time:

  • %p โ€” process ID.
  • %q{VAR} โ€” value of environment variable VAR

-fprofile-generate, -fprofile-generate=path

This one turns on the options usually used for instrumenting an application, so you get a profile that's useful for recompiling later with profile feedback based optimization ๐Ÿ”ฅ. You must use -fprofile-generate both when compiling and when linking your program, no skipping ๐Ÿ™…โ€โ™€๏ธ.

These options get enabled too: -fprofile-arcs, -fprofile-values, -finline-functions, and -fipa-bit-cp โญ.

If path is specified, GCC looks there for the profile feedback data files. See -fprofile-dir ๐Ÿ“‚.

To optimize your program based on the collected profile information, use -fprofile-use ๐Ÿ’….

-fprofile-info-section, -fprofile-info-section=name

This one puts the profile information into a specified section instead of using a constructor/destructor ๐Ÿงฉ. The section name is name if you give one. Otherwise it defaults to .gcov_info. A pointer to the profile information generated by -fprofile-arcs gets placed in that section for each translation unit. This option disables the profile information registration through a constructor, and it also disables the profile information processing through a destructor ๐Ÿ™ˆ.

This option isn't meant for hosted environments like GNU/Linux. It's for free-standing environments (like embedded systems) with limited resources, which don't support constructors/destructors or C library file I/O ๐Ÿงธ.

The linker can collect the input sections into one continuous memory block and define start and end symbols ๐Ÿง . Here's a GNU linker script example that defines a linker output section:

.gcov_info      :
{
  PROVIDE (__gcov_info_start = .);
  KEEP (*(.gcov_info))
  PROVIDE (__gcov_info_end = .);
}

Your program can then dump the profiling information registered in this linker set, like this ๐ŸŽ€:

#include <gcov.h>
#include <stdio.h>
#include <stdlib.h>

extern const struct gcov_info *__gcov_info_start[];
extern const struct gcov_info *__gcov_info_end[];

static void
filename (const char *f, void *arg)
{
  puts (f);
}

static void
dump (const void *d, unsigned n, void *arg)
{
  const unsigned char *c = d;

  for (unsigned i = 0; i < n; ++i)
    printf ("%02x", c[i]);
}

static void *
allocate (unsigned length, void *arg)
{
  return malloc (length);
}

static void
dump_gcov_info (void)
{
  const struct gcov_info **info = __gcov_info_start;
  const struct gcov_info **end = __gcov_info_end;

  /* Obfuscate variable to prevent compiler optimizations.  */
  __asm__ ("" : "+r" (info));

  while (info != end)
  {
    void *arg = NULL;
    __gcov_info_to_gcda (*info, filename, dump, allocate, arg);
    putchar ('\n');
    ++info;
  }
}

int
main()
{
  dump_gcov_info();
  return 0;
}

-fprofile-note=path

If path is specified, GCC saves the .gcno file into the path location ๐Ÿ“. Heads up, bestie: if you combine this with multiple source files, the .gcno file will get overwritten ๐Ÿ˜ญ.

-fprofile-prefix-path=path

This one works together with profile-generate=profile_dir and profile-use=profile_dir to tell GCC where the base directory of your built source tree is ๐Ÿ—บ๏ธ. By default, profile_dir holds files with mangled absolute paths of all object files in the built project. That's not ideal when the directory used to build the instrumented binary is different from the one used to build the binary optimized with profile feedback. Then the profile data won't be found during the optimized build ๐Ÿ’€. In that setup, -fprofile-prefix-path=path with path pointing at the base directory of the build strips the irrelevant part of the path and keeps every file name relative to the main build directory ๐ŸŒธ.

-fprofile-prefix-map=old=new

When compiling files that live in directory old, GCC records profiling information (with --coverage) describing them as if they lived in directory new instead ๐Ÿฆ‹. See also -ffile-prefix-map.

-fprofile-update=method

This alters the update method for an application instrumented for profile feedback based optimization ๐Ÿ”ง. The method argument should be one of single, atomic, or prefer-atomic. single is useful for single-threaded applications, while atomic prevents profile corruption by emitting thread-safe code ๐Ÿงต.

Warning: if an application doesn't properly join all threads (or creates a detached thread), a profile file can still get corrupted ๐Ÿšจ.

Using prefer-atomic gets transformed into atomic when a target supports it, or into single otherwise ๐ŸŒˆ. The GCC driver automatically selects prefer-atomic when -pthread is in the command line โœจ.

-fprofile-filter-files=regex

Only instruments functions from files whose name matches any of the regular expressions (separated by semi-colons) ๐Ÿ”.

For example, -fprofile-filter-files=main\.c;module.*\.c will instrument only main.c and all C files starting with 'module' ๐ŸŽ€.

-fprofile-exclude-files=regex

Only instruments functions from files whose name does not match any of the regular expressions (separated by semi-colons) ๐Ÿšซ.

For 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 ๐Ÿ”. That makes it possible to rebuild a program with the same outcome, which is super useful for things like distribution packages ๐Ÿ“ฆ.

With -fprofile-reproducible=serial, the gathered profile is reproducible, as long as the trained program behaves the same way on each invocation of the train run, it isn't multi-threaded, and profile data streaming always happens in the same order ๐Ÿซถ. Profile streaming happens at the end of the program run, but also before the fork function is invoked, so keep that in mind ๐Ÿง .

It's pretty common for execution counts in some parts of programs to depend on things like the length of temporary file names or memory space randomization (which can affect hash-table collision rate) ๐Ÿ™ˆ. Non-reproducible parts like that can be annotated with the no_instrument_function function attribute. You can use gcov-dump with -l to dump the gathered data and verify that it's actually reproducible ๐Ÿ”๐Ÿ’œ.

With -fprofile-reproducible=parallel-runs, the collected profile stays reproducible no matter what order the data gets streamed into the gcda files โœจ. This setting lets you run several instances of your instrumented program at once (like with make -j) ๐Ÿƒโ€โ™€๏ธ. Ngl there's a trade-off: it lowers the quality of the gathered data, especially for indirect call profiling ๐Ÿ˜ญ.

๐Ÿฆ‹ -fsanitize=address

Okay bestie, this one turns on AddressSanitizer, a fast memory error detector ๐Ÿ”ฅ. The memory access instructions get instrumented so it can catch out-of-bounds and use-after-free bugs. This option also turns on -fsanitize-address-use-after-scope. For more deets, check https://github.com/google/sanitizers/wiki/AddressSanitizer. You can tweak the run-time behavior with the ASAN_OPTIONS environment variable ๐Ÿ’…. When ASAN_OPTIONS is set to "help=1", the instrumented program shows you the available options at startup. The list of supported options lives at https://github.com/google/sanitizers/wiki/AddressSanitizerFlags#run-time-flags. This option can't be combined with -fsanitize=thread or -fsanitize=hwaddress ๐Ÿ™ˆ.

๐ŸŒธ -fsanitize=kernel-address

Enable AddressSanitizer for the Linux kernel ๐Ÿง. More details are at https://github.com/google/kasan.

๐Ÿงš -fsanitize=hwaddress

Enable Hardware-assisted AddressSanitizer, which is seriously iconic ๐Ÿคฏ. It uses a hardware ability to ignore the top byte of a pointer, so it can detect memory errors with a low memory overhead. The memory access instructions get instrumented to catch out-of-bounds and use-after-free bugs. This option also turns on -fsanitize-address-use-after-scope. See https://clang.llvm.org/docs/HardwareAssistedAddressSanitizerDesign.html for more details. The run-time behavior can be influenced with the HWASAN_OPTIONS environment variable. When it's set to "help=1", the available options show up at startup of the instrumented program. It can't be combined with -fsanitize=thread or -fsanitize=address, and it's currently only available on AArch64.

Note that the only target -fsanitize=hwaddress is currently supported on is AArch64.

๐Ÿ’œ -fsanitize=kernel-hwaddress

Enable Hardware-assisted AddressSanitizer for compiling the Linux kernel ๐Ÿง . It's similar to -fsanitize=kernel-address because it's kernel-focused, but it uses an alternate instrumentation method. It's also similar to -fsanitize=hwaddress, but with instrumentation differences that the kernel needs. 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 the -fsanitize=hwaddress. Instrumenting the stack and alloca calls is not 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 is not implemented for kernel instrumentation.

๐ŸŽ€ -fsanitize=pointer-compare

This instruments comparison operations (<, <=, >, >=) with pointer operands โœจ. It must be combined with either -fsanitize=kernel-address or -fsanitize=address, and it cannot be combined with -fsanitize=thread.

Note: By default the check is disabled at run time. To enable it, add "detect_invalid_pointer_pairs=2" to the environment variable ASAN_OPTIONS. Using "detect_invalid_pointer_pairs=1" only detects invalid operation when both pointers are non-null.

๐Ÿ“ -fsanitize=pointer-subtract

This instruments subtraction with pointer operands ๐Ÿฐ. It must be combined with either -fsanitize=kernel-address or -fsanitize=address, and it cannot be combined with -fsanitize=thread.

Note: By default the check is disabled at run time. To enable it, add "detect_invalid_pointer_pairs=2" to the environment variable ASAN_OPTIONS. Using "detect_invalid_pointer_pairs=1" only detects invalid operation when both pointers are non-null.

๐Ÿ›ก๏ธ -fsanitize=shadow-call-stack

Enable ShadowCallStack, a security glow-up that protects programs against return address overwrites (e.g. stack buffer overflows.) ๐Ÿ›ก๏ธ It works by saving a function's return address to a separately allocated shadow call stack in the function prologue, then restoring the return address from that shadow call stack in the function epilogue. Instrumentation only happens in functions that need to save the return address to the stack.

Right now it only supports the aarch64 platform ๐Ÿค. It's specifically designed for Linux kernels that enable the CONFIG_SHADOW_CALL_STACK option. For user space programs, runtime support is not currently provided in libc and libgcc. If you want this feature in user space, you need to provide your own runtime support. It should be noted that this may cause the ABI rules to be broken.

On aarch64, the instrumentation uses the platform register "x18". This generally means that any code that may run on the same thread as code compiled with ShadowCallStack must be compiled with -ffixed-x18. Otherwise, functions compiled without -ffixed-x18 might clobber "x18" and corrupt the shadow stack pointer ๐Ÿ˜ฑ.

Also, because there's no userspace runtime support, code compiled with ShadowCallStack cannot use exception handling. Use -fno-exceptions to turn off exceptions.

See https://clang.llvm.org/docs/ShadowCallStack.html for more details.

๐Ÿงต -fsanitize=thread

Enable ThreadSanitizer, a fast data race detector ๐ŸŽ๏ธ. Memory access instructions get instrumented to detect data race bugs. See https://github.com/google/sanitizers/wiki#threadsanitizer for more details. The run-time behavior can be influenced using the TSAN_OPTIONS environment variable. Check https://github.com/google/sanitizers/wiki/ThreadSanitizerFlags for a list of supported options. This option cannot 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

Enable LeakSanitizer, a memory leak detector ๐Ÿซง. This option only matters for linking executables, and only when the executable is linked against a library that overrides "malloc" and other allocator functions. See https://github.com/google/sanitizers/wiki/AddressSanitizerLeakSanitizer for more details. The run-time behavior can be influenced using the LSAN_OPTIONS environment variable. This option cannot be combined with -fsanitize=thread.

๐Ÿ‘‘ -fsanitize=undefined

Enable UndefinedBehaviorSanitizer, a fast undefined behavior detector ๐Ÿ‘‘. Various computations are instrumented to detect undefined behavior at runtime. See https://clang.llvm.org/docs/UndefinedBehaviorSanitizer.html for more details. The run-time behavior can be influenced using the UBSAN_OPTIONS environment variable. These are the current suboptions:

  • -fsanitize=shift โ€” This checks that the result of a shift operation is not undefined. What exactly counts as undefined differs slightly between C and C++, as well as between ISO C90 and C99, etc. This option has two suboptions, -fsanitize=shift-base and -fsanitize=shift-exponent.
  • -fsanitize=shift-exponent โ€” This checks that the second argument of a shift operation is not 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, this checks that the result of the shift operation is not undefined. Again, what exactly counts as undefined differs slightly between C and C++, as well as between ISO C90 and C99, etc.
  • -fsanitize=integer-divide-by-zero โ€” Detects integer division by zero ๐Ÿ™…โ€โ™€๏ธ.
  • -fsanitize=unreachable โ€” With this option, the compiler turns the "__builtin_unreachable" call into a diagnostics message call instead. When the program reaches the "__builtin_unreachable" call, the behavior is undefined ๐Ÿ’€.
  • -fsanitize=vla-bound โ€” This makes the compiler check that the size of a variable length array is positive.
  • -fsanitize=null โ€” This enables pointer checking. An application built with this turned on will issue an error message when it tries to dereference a NULL pointer, when a reference (possibly an rvalue reference) is bound to a NULL pointer, or when a method is invoked on an object pointed to by a NULL pointer.
  • -fsanitize=return โ€” This enables return statement checking. Programs built with this turned on will issue an error message when the end of a non-void function is reached without actually returning a value. This option works in C++ only.
  • -fsanitize=signed-integer-overflow โ€” This enables signed integer overflow checking. It checks that the result of +, *, and both unary and binary - does not overflow in signed arithmetic. It also detects INT_MIN / -1 signed division. Keep integer promotion rules in mind, because the following is not an overflow:
signed char a = SCHAR_MAX;
a++;
  • -fsanitize=bounds โ€” This enables instrumentation of array bounds, so various out-of-bounds accesses get detected. Flexible array members, flexible array member-like arrays, and initializers of variables with static storage are not instrumented ๐Ÿง.
  • -fsanitize=bounds-strict โ€” This enables strict instrumentation of array bounds. Most out-of-bounds accesses are detected, including flexible array members and flexible array member-like arrays. Initializers of variables with static storage are not instrumented.
  • -fsanitize=alignment โ€” This enables checking of pointer alignment when pointers are dereferenced, when a reference is bound to an insufficiently aligned target, or when a method or constructor is invoked on an insufficiently aligned object ๐Ÿ“.
  • -fsanitize=object-size โ€” This enables instrumentation of memory references using the "__builtin_object_size" function. Various out-of-bounds pointer accesses get detected ๐Ÿ”.
  • -fsanitize=float-divide-by-zero โ€” okay so this one catches floating-point division by zero ๐Ÿงฎ. Heads up though, it is not turned on by -fsanitize=undefined like the other similar options, because dividing floats by zero can be a legit way to get infinities and NaNs ๐ŸŒˆ not everything is a bug, bestie.
  • -fsanitize=float-cast-overflow โ€” this checks float-to-integer conversions and makes sure the result doesn't overflow ๐Ÿซถ. Also not included in -fsanitize=undefined.
โš ๏ธ This one doesn't vibe well with FE_INVALID exceptions enabled, so proceed with caution ๐Ÿ’€
  • -fsanitize=nonnull-attribute โ€” instruments calls to make sure you're not passing null values into arguments marked with 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 getting returned from them ๐Ÿ”
  • -fsanitize=bool โ€” instruments loads from bool. If something other than 0/1 gets loaded, you get a run-time error ๐Ÿšจ
  • -fsanitize=enum โ€” instruments loads from an enum type. If a value outside the enum's range gets loaded, that's a run-time error ๐Ÿšจ
  • -fsanitize=vptr โ€” this one is giving C++ energy ๐Ÿ‘‘. It instruments C++ member function calls, member accesses, and some conversions between pointers to base and derived classes, to verify the referenced object has the correct dynamic type.
  • -fsanitize=pointer-overflow โ€” instruments pointer arithmetic. If the pointer arithmetic overflows, that's a run-time error ๐Ÿšจ
  • -fsanitize=builtin โ€” instruments the arguments to selected builtin functions. If an invalid value gets passed in, you get a run-time error. For example, passing 0 to __builtin_ctz or __builtin_clz is undefined behavior, and this option will call it out ๐Ÿ™ˆ

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 the sanitizers you turned on before โœจ
-fsanitize=all is not allowed, since some sanitizers cannot be used together ๐Ÿ’€
  • -fasan-shadow-offset=number โ€” forces GCC to use a custom shadow offset in AddressSanitizer checks ๐Ÿงช super useful if you're experimenting with different shadow memory layouts in Kernel AddressSanitizer.
  • -fsanitize-sections=s1,s2,... โ€” sanitizes global variables in the user-defined sections you pick ๐ŸŽ€ si can have wildcards.
  • -fsanitize-recover[=opts] โ€” this controls error recovery for the sanitizers listed in the comma-separated opts list ๐Ÿ” When recovery is on, the sanitizer tries to keep the program running like nothing happened. That means you can get multiple runtime errors in one run, and the exit code might say success even though errors got reported ๐Ÿ™ƒ
    • -fno-sanitize-recover= flips that. Only the first 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 -fsanitize=unreachable and -fsanitize=return), -fsanitize=float-cast-overflow, -fsanitize=float-divide-by-zero, -fsanitize=bounds-strict, -fsanitize=kernel-address and -fsanitize=address.
    • For those sanitizers, recovery is turned on by default, except for -fsanitize=address, where it's still experimental ๐Ÿงช
    • -fsanitize-recover=all enables recovery for every sanitizer that supports it. -fno-sanitize-recover=all disables recovery for every sanitizer that supports it.

Even if recovery is turned on at compile time, the runtime library has to have it enabled too, or the failures are still fatal ๐Ÿ˜ญ The runtime library defaults to halt_on_error=0 for ThreadSanitizer and UndefinedBehaviorSanitizer, while AddressSanitizer defaults to 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 this opts list:
undefined,float-cast-overflow,float-divide-by-zero,bounds-strict
  • -fsanitize-address-use-after-scope โ€” enables sanitizing local variables so it can catch use-after-scope bugs ๐Ÿ‘€ This option sets -fstack-reuse to none.
  • -fsanitize-undefined-trap-on-error โ€” tells the compiler to report undefined behavior using __builtin_trap instead of a libubsan library routine ๐Ÿฆ‹ The perk is that libubsan isn't needed and doesn't get linked in, so this works even in freestanding environments.
  • -fsanitize-coverage=trace-pc โ€” enables coverage-guided fuzzing instrumentation ๐Ÿ› It inserts a call to __sanitizer_cov_trace_pc into every basic block.
  • -fsanitize-coverage=trace-cmp โ€” enables dataflow-guided fuzzing instrumentation ๐Ÿงš It inserts calls to:
    • __sanitizer_cov_trace_cmp1, __sanitizer_cov_trace_cmp2, __sanitizer_cov_trace_cmp4 or __sanitizer_cov_trace_cmp8 for integral comparisons where both operands are 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 with one constant operand
    • __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] โ€” this one is a security queen ๐Ÿ‘‘ It enables code instrumentation of control-flow transfers, checking that the target addresses of control-flow transfer instructions (like indirect function calls, function returns, and indirect jumps) are valid. That stops the flow of control from getting diverted to some unexpected target. It's meant to guard against threats like Return-oriented Programming (ROP), and similarly call/jmp-oriented programming (COP/JOP) ๐Ÿ›ก๏ธ
    • branch checks validity at indirect branch instructions, i.e. call/jmp instructions ๐ŸŒธ
    • return checks validity when returning from a function ๐ŸŒธ
    • full is an alias for both branch and return ๐Ÿ’–
    • none turns instrumentation off ๐Ÿ™…โ€โ™€๏ธ
    • check is for the final link with link-time optimization (LTO). An error gets issued if LTO object files were compiled with different -fcf-protection values. It's ignored at compile time ๐Ÿซ 
    • The macro __CET__ is defined when -fcf-protection is used. Its first bit is set to 1 for branch, and its second bit is set to 1 for return ๐Ÿง 
    • You can use the nocf_check attribute to mark which functions and calls should be skipped from instrumentation ๐Ÿ™ˆ
    • Currently, the x86 GNU/Linux target has an implementation based on Intel Control-flow Enforcement Technology (CET), which works for i686 processors or newer โšก
  • -fharden-compares โ€” for every logical test that survives gimple optimizations and is not the condition in a conditional branch (like conditions tested for conditional moves, or stored in boolean variables), it emits extra code to compute and verify the reversed condition. If the results don't match, it calls __builtin_trap ๐Ÿงฑ Use it with -fharden-conditional-branches to cover all conditionals.
  • -fharden-conditional-branches โ€” for every non-vectorized conditional branch that survives gimple optimizations, it emits extra code to compute and verify the reversed condition, and calls __builtin_trap if the result is unexpected ๐Ÿฐ Use it with -fharden-compares to cover all conditionals.
  • -fstack-protector โ€” emits extra code to check for buffer overflows, like stack smashing attacks ๐Ÿ›ก๏ธ It works by adding a guard variable to functions with vulnerable objects. That includes functions that call alloca, and functions with buffers 8 bytes or larger. The guards get initialized when a function is entered and checked when it exits. If a guard check fails, an error message gets printed and the program exits ๐Ÿ’€ Only variables that are actually allocated on the stack count. Optimized-away variables or variables allocated in registers don't.
  • -fstack-protector-all โ€” same energy as -fstack-protector, except all functions get protected ๐Ÿ’œ
  • -fstack-protector-strong โ€” like -fstack-protector, but it covers extra functions too: those with local array definitions, or those with references to local frame addresses ๐ŸŽ€ Same rule applies, only variables actually allocated on the stack are considered. Optimized-away variables or variables allocated in registers don't count.
  • -fstack-protector-explicit โ€” like -fstack-protector, but it only protects functions that have the stack_protect attribute ๐ŸŽฏ
  • -fstack-check โ€” generates code to verify that you don't go beyond the boundary of the stack ๐Ÿฅž You should specify this if you're running in an environment with multiple threads. You rarely need it in a single-threaded environment, since stack overflow is automatically detected on nearly all systems when there's only one stack ๐ŸŒ™
This switch doesn't actually cause checking to be done ๐Ÿ˜ญ The operating system or the language runtime has to do that. The switch just generates code that makes sure they see the stack being extended.

You can also tack on a string parameter ๐Ÿ’… no means no checking at all, generic forces the old-style checking, and specific picks the best checking method, which is the same as bare -fstack-check ๐ŸŽ€.

Old-style checking is a generic mechanism. It needs zero special target support in the compiler, but it comes with some major drawbacks ๐Ÿ™ˆ

  1. Modified allocation strategy for large objects: they always get allocated dynamically once their size goes over a fixed threshold. ngl this may change the semantics of some code ๐Ÿ˜ญ
  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, code performance takes a hit ๐Ÿ“‰

Also, old-style stack checking is the fallback method for specific if the compiler doesn't have target support added ๐Ÿงš

-fstack-check= was made for Ada's needs, to detect infinite recursion and stack overflows ๐ŸŒธ. specific is an excellent choice when compiling Ada code โœจ. It is not generally enough to protect against stack-clash attacks though, so if you want protection from those, you want -fstack-clash-protection ๐Ÿซถ.


  • -fstack-clash-protection โ€” Generates code to prevent stack clash style attacks ๐Ÿ›ก๏ธ. With this on, the compiler only allocates one page of stack space at a time, and each page gets accessed right after it's allocated. So allocations can't jump over a stack guard page the operating system provides ๐Ÿฆ‹.

Most targets don't fully support stack clash protection, lowkey sad ๐Ÿ˜ญ. But on the targets that do, -fstack-clash-protection protects dynamic stack allocations ๐Ÿ’–. It may also give limited protection for static stack allocations if the target supports -fstack-check=specific ๐ŸŒˆ.

  • -fstack-limit-register=reg, -fstack-limit-symbol=sym, -fno-stack-limit โ€” Generates code to make sure the stack doesn't grow past a certain value ๐Ÿšง. That value is either a register's value or the address of a symbol ๐Ÿ”ฅ. If a bigger stack is needed, a signal gets raised at run time. On most targets the signal goes up before the stack overruns the boundary, so you can catch it without taking any special precautions ๐Ÿ‘‘.

Here's an example vibe: if 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 โ€” Generates code to automatically split the stack before it overflows ๐Ÿงต. The resulting program has a discontiguous stack, which can only overflow if the program can't allocate any more memory ๐ŸŒŠ. This is most useful with threaded programs, because you no longer have to figure out a good stack size for each thread ๐Ÿ’œ. Right now it's only implemented for x86 targets running GNU/Linux ๐Ÿ’ป.

When code compiled with -fsplit-stack calls code compiled without -fsplit-stack, there might not be much stack space left for that second code to run in ๐Ÿ˜ฌ. If compiling all your code, library code included, with -fsplit-stack isn't an option, the linker can fix up those calls so the code compiled without -fsplit-stack always gets a large stack ๐Ÿซง. The gold linker in GNU binutils release 2.21 and later supports this โœจ.

  • -fvtable-verify=[std|preinit|none] โ€” This one is C++ only ๐Ÿ’…. It turns the security feature on, or off with -fvtable-verify=none. The feature checks at run time, 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 ๐Ÿ”. If an invalid vtable pointer shows up at run time, an error is reported and the program immediately halts ๐Ÿ›‘.

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 data structures get built, and in both cases it happens before execution reaches main โฐ. -fvtable-verify=std builds them after shared libraries have been loaded and initialized ๐Ÿ“š. -fvtable-verify=preinit builds them before shared libraries are loaded and initialized ๐ŸŒธ.

If you pass this option several times with different values, none takes the highest priority over both std and preinit, and preinit beats std ๐Ÿ‘‘.

  • -fvtv-debug โ€” Used together with -fvtable-verify=std or -fvtable-verify=preinit, this makes the debug versions of the runtime functions for vtable verification get called ๐Ÿ›. It also makes the compiler log which vtable pointers it finds for each class ๐Ÿ”. That info gets written to a file named vtv_set_ptr_data.log in the directory named by the environment variable VTV_LOGS_DIR if it's defined, or the current working directory otherwise ๐Ÿ“.
Note: this feature appends data to the log file ๐Ÿ™ˆ. If you want a fresh log file, delete any existing one first ๐Ÿงน.
  • -fvtv-counts โ€” This is a debugging flag ๐Ÿ”ง. Paired 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 how many calls to certain run-time library functions it inserts, and logs all of that for each compilation unit ๐Ÿ“Š. The compiler writes this info to a file named vtv_count_data.log in the directory named by VTV_LOGS_DIR if that's defined, or the current working directory otherwise ๐Ÿ—‚๏ธ. It also counts the size of the vtable pointer sets for each class and writes that to vtv_class_set_sizes.log in the same directory ๐Ÿฆ‹.
Note: this feature appends data to the log files ๐Ÿ™ˆ. To get fresh log files, delete any existing ones ๐Ÿงน.
  • -finstrument-functions โ€” Generates instrumentation calls for function entry and exit ๐Ÿ”ญ. Right after a function starts and right before it exits, the following profiling functions get called with the address of the current function and its call site ๐Ÿ’ซ. (On some platforms, __builtin_return_address doesn't work beyond the current function, so the call site info might not be available to the profiling functions otherwise ๐Ÿคทโ€โ™€๏ธ.)
void __cyg_profile_func_enter (void *this_fn,
                               void *call_site);
void __cyg_profile_func_exit  (void *this_fn,
                               void *call_site);

The first argument is the address of the start of the current function, which you can look up exactly in the symbol table ๐Ÿ”Ž.

This instrumentation also happens for functions expanded inline into other functions ๐ŸŒ€. The profiling calls show where, conceptually, the inline function gets entered and exited ๐Ÿšช. That means addressable versions of those functions must be available ๐Ÿ“. If all your uses of a function get expanded inline, this might add extra code size ๐Ÿ“ˆ. If you use extern inline in your C code, an addressable version of those functions has to be provided too ๐Ÿซถ. (This is normally 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 attribute no_instrument_function, and then this instrumentation isn't done for it ๐Ÿ™…โ€โ™€๏ธ. That's handy for the profiling functions above, high-priority interrupt routines, and any functions 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,... โ€” Sets the list of functions excluded from instrumentation (see -finstrument-functions) ๐Ÿšซ. If the file containing a function definition matches one of the file entries, that function doesn't get instrumented ๐Ÿ“. The match is done on substrings: if the file parameter is a substring of the file name, it counts as a match ๐Ÿ”ค.

For example:

-finstrument-functions-exclude-file-list=/bits/stl,include/sys

This excludes any inline function defined in files whose pathnames contain /bits/stl or include/sys ๐ŸŒธ.

If, for some reason, you want to include a comma in one of the sym entries, write ,, instead ๐Ÿง. For example, -finstrument-functions-exclude-file-list=',,tmp' (note the single quotes around the option) ๐Ÿ’œ.

  • -finstrument-functions-exclude-function-list=sym,sym,... โ€” This is like -finstrument-functions-exclude-file-list, but it sets the list of function names to exclude from instrumentation ๐ŸŽฏ. The name that gets matched is its user-visible name, like "vector<int> blah(const vector<int> &)", not the internal mangled name (like "_Z4blahRSt6vectorIiSaIiEE") ๐Ÿช„. The match is done on substrings: if the sym parameter is a substring of the function name, it's a match ๐Ÿ”. For C99 and C++ extended identifiers, the function name has to be given in UTF-8, not using universal character names ๐ŸŒˆ.
  • -fpatchable-function-entry=N[,M] โ€” Generates N NOPs right at the beginning of each function, with the function entry point sitting before the Mth NOP ๐Ÿงฉ. If M is omitted, it defaults to 0, so the function entry points to the address right at the first NOP ๐ŸŽ€. Those NOP instructions reserve extra space that you can use to patch in any instrumentation you want at run time, as long as the code segment is writable โœ๏ธ. The amount of space is controlled indirectly through the number of NOPs ๐Ÿ”ข. The NOP instruction used corresponds to the one emitted by the internal GCC back-end interface gen_nop โš™๏ธ. This behavior is target-specific and may also depend on the architecture variant and/or other compilation options ๐ŸŒ.

Okay so the starting addresses of these patch areas also get saved for run-time identification ๐Ÿ”. They're collected in the __patchable_function_entries section of the final binary ๐Ÿฆ‹, and each one is its function entry minus M. Very organized, very giving.

Heads up ๐Ÿšจ: a __attribute__ ((patchable_function_entry (N,M))) value beats the command-line -fpatchable-function-entry=N,M option, no cap. So you can bump the area size up, or wipe it entirely on one specific function ๐Ÿ’…. And if N=0, no pad location gets recorded at all ๐Ÿ’€.

The NOP instructions get tucked in at the function entry address ๐Ÿงš. Depending on M, they might even go in before that address, and yes, that includes before the prologue ๐Ÿ™ˆ.

The maximum value of N and M is 65535, so don't go past that ๐Ÿซถ.


โœจ Options Controlling the Preprocessor โœจ

These options are for the C preprocessor ๐ŸŒธ, which runs on every C source file before the actual compilation even starts.

If you use -E, the preprocessor just preprocesses and that's it ๐Ÿซง. A few of these options only make sense alongside -E, because they make the output unusable for real compilation ๐Ÿ’€.

There are also include search path options over in Directory Options, and the preprocessor diagnostic ones live in Warning Options ๐Ÿ—บ๏ธ.

  • -D name โ€” Predefine name as a macro, with the definition 1 ๐Ÿ“.
  • -D name=definition โ€” The definition gets tokenized and processed as if it showed up during translation phase three in a #define directive. Heads up: embedded newline characters cut the definition short โœ‚๏ธ.
    • If you're calling the preprocessor from a shell (or something shell-like), you may need the shell's quoting syntax to protect characters like spaces that mean something to the shell ๐Ÿš.
    • Want a function-like macro on the command line? Write its argument list with surrounding parentheses before the equals sign (if there is one). Parentheses mean stuff to most shells, so quote the option. With sh and csh, -D'name(args...)=definition' works โœจ.
    • -D and -U options get processed in the order they show up on the command line. All -imacros file and -include file options get processed after all the -D and -U ones ๐Ÿ”.
  • -U name โ€” Cancel any earlier definition of name, whether it was built in or came from a -D option ๐Ÿงน.
  • -include file โ€” Process file as if #include "file" showed up as the first line of the primary source file. The difference: the first directory searched for file is the preprocessor's working directory, not the directory with the main source file. If it's not found there, it gets searched for in the rest of the #include "..." search chain like normal.
    • With multiple -include options, the files get included in the order they appear on the command line.
  • -imacros file โ€” Exactly like -include, except any output from scanning file gets tossed. The macros it defines stay defined, so you can snag every macro from a header without processing its declarations ๐Ÿงฒ.
    • All files given with -imacros get processed before all the files given with -include.
  • -undef โ€” Don't predefine any system-specific or GCC-specific macros. The standard predefined macros still stay defined.
  • -pthread โ€” Defines the extra macros needed for the POSIX threads library ๐Ÿงต. Use it consistently for both compilation and linking. It's supported on GNU/Linux targets and most other Unix derivatives, plus x86 Cygwin and MinGW targets.
  • -M โ€” Instead of spitting out the preprocessed result, output a make rule describing the dependencies of the main source file ๐Ÿ“œ. That rule has the object file name for the source file, a colon, and the names of all the included files, including any coming from -include or -imacros command-line options.
    • Unless you specify it explicitly (with -MT or -MQ), the object file name is the source file name with any suffix swapped for the object file suffix, and any leading directory parts removed.
    • With lots of included files, the rule gets split into several lines using \-newline. The rule has no commands.
    • This option does not suppress the preprocessor's debug output, such as -dM. To keep that debug output from mixing with the dependency rules, specify the dependency output file with -MF, or use an environment variable like DEPENDENCIES_OUTPUT. Debug output still goes to the regular output stream as normal.
    • Passing -M to the driver implies -E, and suppresses warnings with an implicit -w.
  • -MM โ€” Like -M, but don't mention header files found in system header directories, or header files included (directly or indirectly) from such a header ๐Ÿ™….
    • This means the choice of angle brackets or double quotes in an #include directive doesn't, by itself, decide whether that header shows up 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 โ€” Used with an option like -M that requests 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 โ€” Disable dependency generation for compiled module interfaces.
  • -MP โ€” Tells 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 the errors make gives if you remove header files without updating the Makefile to match. This is typical output:
test.o: test.c test.h

test.h:
  • -MT target โ€” Changes the target of the rule emitted by dependency generation ๐ŸŽฏ. By default CPP takes the name of the main input file, deletes any directory components and any file suffix such as .c, and appends the platform's usual object suffix. That result is the target.
    • An -MT option sets the target to be exactly the string you specify.
    • If you want multiple targets, you can specify them as a single argument to -MT, or use multiple -MT options.

For example, -MT '$(objpfx)foo.o' might give:

$(objpfx)foo.o: foo.c
  • -MQ target โ€” Same as -MT, but it quotes any characters that are special to Make ๐Ÿ”. -MQ '$(objpfx)foo.o' gives:
$$(objpfx)foo.o: foo.c

The default target is automatically quoted, as if it were given with -MQ.

  • -MD โ€” -MD is equivalent to -M -MF file, except that -E is not implied ๐ŸŽ€. The driver figures out file based on whether an -o option is given. If it is, the driver uses its argument 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 together with -E, any -o switch is understood to specify the dependency output file. Without -E, each -o is understood to specify a target object file.
    • Since -E isn't implied, -MD can generate a dependency output file as a side effect of the compilation process ๐ŸŽ.
  • -MMD โ€” Like -MD, but only mention user header files, not system header files.
  • -fpreprocessed โ€” Tells the preprocessor that the input file has already been preprocessed ๐Ÿงƒ. This suppresses things like macro expansion, trigraph conversion, escaped newline splicing, and processing of most directives. The preprocessor still recognizes and removes comments, so you can pass a file preprocessed with -C to the compiler without problems. In this mode the integrated preprocessor is little more than a tokenizer for the front ends.
    • -fpreprocessed is implicit if the input file has one of the extensions .i, .ii or .mi. These are the extensions GCC uses for preprocessed files created by -save-temps.
  • -fdirectives-only โ€” When preprocessing, handle directives, but do not expand macros ๐Ÿงฉ. What it does depends on -E and -fpreprocessed:
    • With -E, preprocessing is limited to handling directives such as #define, #ifdef, and #error. Other preprocessor operations, such as macro expansion and trigraph conversion, are not performed. In addition, the -dD option is implicitly enabled.
    • With -fpreprocessed, predefinition of command-line and most builtin macros is disabled. Macros such as __LINE__, which are contextually dependent, are handled normally. This enables compilation of files previously preprocessed with -E -fdirectives-only.
    • With both -E and -fpreprocessed, the rules for -fpreprocessed take precedence. This enables full preprocessing of files previously preprocessed with -E -fdirectives-only.
  • -fdollars-in-identifiers โ€” Accept $ in identifiers ๐Ÿ’ต.
  • -fextended-identifiers โ€” Accept universal character names and extended characters in identifiers. This option is enabled by default for C99 (and later C standard versions) and C++ ๐ŸŒˆ.
  • -fno-canonical-system-headers โ€” When preprocessing, do not shorten system header paths with canonicalization.
  • -fmax-include-depth=depth โ€” Sets the maximum depth of nested #include. The default is 200 ๐Ÿ“.
  • -ftabstop=width โ€” Sets the distance between tab stops. This helps the preprocessor report correct column numbers in warnings or errors, even if tabs appear on the line ๐Ÿ“. If the value is less than 1 or greater than 100, the option is ignored. The default is 8.
  • -ftrack-macro-expansion[=level] โ€” okay so this one tracks where tokens come from across macro expansions ๐Ÿ”โœจ When a compile error shows up inside a macro, the compiler can show you the whole macro expansion stack, which is so helpful. The catch is that the preprocessor and compiler eat more memory with it on ๐Ÿ’€ The level argument lets you pick how precise the tracking is, so you can trade precision for memory if you need to. 0 turns it off. 1 is the degraded mode with minimal memory overhead, where every token that comes from expanding an argument of a function-like macro gets the same location. 2 tracks token locations fully, and it's the most memory-hungry option of the bunch. If you give the option with no argument, level defaults to 2.

Also, -ftrack-macro-expansion=2 is on by default ๐Ÿ’…

  • -fmacro-prefix-map=old=new โ€” when you're preprocessing files that live in directory old, this makes __FILE__ and __BASE_FILE__ act like the files live in directory new instead ๐Ÿ—บ๏ธ This is a fave for turning an absolute path into a relative one (use . for new), which can lead to more reproducible, location-independent builds ๐ŸŒธ It also affects __builtin_FILE() during compilation. See also -ffile-prefix-map.
  • -fexec-charset=charset โ€” sets the execution character set, which is what string and character constants get encoded in ๐ŸŒˆ The default is UTF-8, and charset can be any encoding your system's iconv library routine supports.
  • -fwide-exec-charset=charset โ€” same energy, but for wide string and wide character constants ๐Ÿ’– The default is UTF-32 or UTF-16, whichever matches the width of wchar_t. Just like -fexec-charset, charset can be any encoding iconv supports, but ngl you'll run into problems with encodings that don't fit exactly in wchar_t ๐Ÿ˜ญ
  • -finput-charset=charset โ€” this sets the input character set, which is used to translate your input file from its own character set into the source character set GCC uses ๐Ÿฆ‹ If the locale doesn't say what to use, or GCC can't read that info from the locale, the default is UTF-8. The locale or this command-line option can override that default, but if they clash, the command-line option wins. charset can be any encoding your system's iconv routine supports.
  • -fpch-deps โ€” when you're using precompiled headers, this makes the dependency-output flags also list the files the precompiled header depends on ๐Ÿงš Without it, only the precompiled header itself gets listed, not the files that were used to build it, since those aren't consulted once a PCH is in use.
  • -fpch-preprocess โ€” this lets you use a precompiled header together with -E ๐ŸŽ€ It drops a special #pragma, which looks like #pragma GCC pch_preprocess "filename", into the output to mark where the precompiled header was found, plus its filename. When -fpreprocessed is in use, GCC recognizes that #pragma and loads the PCH.

This option is off by default, because the preprocessed output is really only good as input to GCC ๐Ÿ™ˆ It gets switched on by -save-temps.

Don't write this #pragma in your own code, but it's 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 enabled, the preprocessor emits a second linemarker after the initial one, containing the current working directory followed by two slashes. GCC uses that directory, if it shows up in the preprocessed input, as the working directory in some debugging information formats. This is implicitly enabled when debugging info is on, but you can block it with the negated form -fno-working-directory. If -P is on 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 preferred over the older -A predicate(answer) form, which still works, because it doesn't use shell special characters.
  • -A -predicate=answer โ€” cancels an assertion with the predicate predicate and the answer answer ๐Ÿšซ
  • -C โ€” do not discard comments ๐Ÿ’ฌ All comments get passed through to the output file, except comments inside processed directives, which get deleted along with the directive.

Be prepared for side effects when you use -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 โ€” do not discard 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 โ€” inhibits linemarker generation in the preprocessor output ๐Ÿงน This can be handy when you're running the preprocessor on something that isn't C code, and the result is going to a program that might get confused by linemarkers.
  • -traditional, -traditional-cpp โ€” tries to imitate pre-standard C preprocessors instead of ISO C ones ๐Ÿ•ฐ๏ธ Check the GNU CPP manual for details.

GCC doesn't otherwise try to act like a pre-standard C compiler, 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, all starting with ??, that ISO C defines to stand for single characters. For example, ??/ stands for \, so '??/n' is a character constant for a newline.

The nine trigraphs and their replacements are:

Trigraph:       ??(  ??)  ??<  ??>  ??=  ??/  ??'  ??!  ??-
Replacement:      [    ]    {    }    #    \    ^    |    ~

By default GCC ignores trigraphs, but in standard-conforming modes it converts them. See the -std and -ansi options.

  • -remap โ€” enables special code to work around file systems that only allow super short file names, like MS-DOS ๐Ÿ’พ
  • -H โ€” prints the name of each header file used, along with everything else it normally does ๐Ÿ“œ Each name is indented to show how deep it sits in the #include stack. Precompiled header files get printed too, even if they turn out to be invalid. An invalid PCH gets printed with ...x, and a valid one gets printed with ...! โœจ
  • -dletters โ€” tells the compiler to make debugging dumps during compilation, as specified by letters ๐Ÿ”ฌ The flags documented here are the ones that matter to the preprocessor. Other letters are either read by the compiler proper, or reserved for future GCC versions, so they're silently ignored. If you pick letters whose behavior conflicts, the result is undefined, so maybe don't ๐Ÿ™ƒ
    • -dM โ€” instead of the normal output, you get a list of #define directives for all the macros defined during preprocessing, including predefined ones ๐Ÿงพ This is a great way to find out what's predefined in your version of the preprocessor. Assuming you have no file foo.h, this command:
touch foo.h; cpp -dM foo.h

shows all the predefined macros.

If you use -dM without -E, it's interpreted as a synonym for -fdump-rtl-mach ๐Ÿคฏ

  • -dD โ€” like -dM, except it does not include the predefined macros, and it outputs both the #define directives and the result of preprocessing. Both kinds of output go to the standard output file.
  • -dN โ€” like -dD, but it only emits the macro names, not their expansions ๐Ÿท๏ธ
  • -dI โ€” outputs #include directives in addition to the result of preprocessing ๐Ÿ“Ž
  • -dU โ€” like -dD, except only macros that get expanded, or whose definedness gets tested in preprocessor directives, are output ๐ŸŽฏ The output is delayed until the macro is used or tested, and #undef directives are also output for macros that were tested but undefined at that time.
  • -fdebug-cpp โ€” this one is only useful for debugging GCC ๐Ÿ› ๏ธ When used from CPP or with -E, it dumps debugging info about location maps. Every token in the output gets preceded by the dump of the map its location belongs to.

When used from GCC without -E, this option does nothing.

  • -Wp,option โ€” lets you bypass the compiler driver and pass option straight through to the preprocessor ๐Ÿšช If option contains commas, it gets split into multiple options at those commas. But lots of options get modified, translated, or interpreted by the compiler driver before they reach the preprocessor, and -Wp forcibly skips that step โš ๏ธ The preprocessor's direct interface is undocumented and subject to change, so whenever possible, avoid -Wp and let the driver handle the options instead.
  • -Xpreprocessor option โ€” passes option along as an option to the preprocessor ๐ŸŽ This is useful for system-specific preprocessor options that GCC doesn't recognize.

If you want to pass an option that takes an argument, you have to use -Xpreprocessor twice: once for the option, and once for the argument ๐Ÿ‘‘

๐ŸŽ€ OPTIONS ๐ŸŽ€ (continued) ๐ŸŽ€

  • -no-integrated-cpp โ€” okay so, by default GCC does preprocessing as part of tokenizing and parsing your input, all baked in together ๐Ÿ’… If you pass this one, the matching front end (cc1 for C, cc1plus for C++, or cc1obj for Objective-C) gets run twice instead. Once just for preprocessing, and once to actually compile the preprocessed input ๐Ÿซถ This is lowkey useful with -B or -wrapper if you want an alternate preprocessor, or extra processing of your source between normal preprocessing and compilation โœจ
  • -flarge-source-files โ€” for when your files are absolutely massive ๐Ÿ˜ This tells GCC to expect large source files, but the price is slower compilation and higher memory usage ๐Ÿ’€

Normally GCC tracks both column numbers and line numbers in your source, and it prints both in diagnostics. Once it has processed a certain number of source lines though, it stops tracking column numbers and only tracks line numbers ๐Ÿ˜ญ So diagnostics for later lines don't include column numbers. Options like -Wmisleading-indentation also 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, bestie ๐Ÿงš

  • -Wa,option โ€” pass option along as an option to the assembler. If option has commas in it, it gets split into multiple options at those commas ๐Ÿ“
  • -Xassembler option โ€” pass option along to the assembler too. You can use this to supply system-specific assembler options that GCC doesn't recognize ๐ŸŒˆ

If you want to pass an option that takes an argument, you must use -Xassembler twice: once for the option and once for the argument. No shortcuts here, it's giving strict ๐Ÿ’…


๐Ÿ”— Options for Linking ๐Ÿ”—

These options come into play when the compiler links object files into an executable output file. They're meaningless if the compiler isn't doing a link step, so don't waste your time on them otherwise ๐Ÿฅฒ

  • object-file-name โ€” a file name that doesn't end in a special recognized suffix is considered to name an object file or library. (The linker tells object files and libraries apart by the file contents, not the name ๐Ÿง) If linking happens, these object files are used as input to the linker.
  • -c, -S, -E โ€” if any of these is used, the linker doesn't run at all, so object file names should not be used as arguments ๐Ÿšซ
  • -flinker-output=type โ€” this one 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 you want incremental linking with a non-LTO object file, it can be useful to control the type manually ๐Ÿ› ๏ธ
    • exec โ€” code generation produces a static binary. In this case -fpic and -fpie are both disabled ๐Ÿ’€
    • dyn โ€” code generation produces a shared library. Here -fpic or -fPIC is preserved, but not enabled automatically. This lets you build shared libraries without position-independent code on architectures where that's possible, i.e. on x86 โœจ
    • pie โ€” code generation produces an -fpie executable. This gets similar optimizations to exec, except -fpie is not disabled if you specified it at compilation time ๐Ÿฆ‹
    • rel โ€” the compiler assumes incremental linking is happening. The sections holding intermediate code for link-time optimization get merged, pre-optimized, and output to the resulting object file. Also, if -ffat-lto-objects is specified, binary code is produced for future non-LTO linking. The object file from incremental linking is smaller than a static library made from the same object files, and at link time it also loads faster than a static library, as long as most of the objects in the library get 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 gets stripped. When multiple object files are linked together, the result is better optimized than with link-time optimizations disabled (cross-module inlining happens, yay!), 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, sadly, not possible to incrementally link LTO objects and non-LTO objects into a single mixed object file ๐Ÿ’” If any object file in an incremental link can't be used for link-time optimization, the linker plugin issues a warning and uses nolto-rel. To keep whole program optimization, it's recommended to link those objects into a static library instead. Alternatively, it's possible to use H.J. Lu's binutils, which support 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 โ€” search the library named library when linking. (The second alternative, with the library as a separate argument, is only there for POSIX compliance and isn't recommended ๐Ÿ™…โ€โ™€๏ธ)

The -l option 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. That includes several standard system directories, plus any you specify with -L ๐Ÿ—บ๏ธ

Static libraries are archives of object files, and they have file names like liblibrary.a. Some targets also support shared libraries, which typically have names like liblibrary.so. If both static and shared libraries are found, the linker gives preference to the shared library, unless the -static option is used ๐Ÿ‘‘

It makes a difference where in the command you write this option, because the linker searches and processes libraries and object files in the order they're specified. So foo.o -lz bar.o searches library z after file foo.o but before bar.o. If bar.o refers to functions in z, those functions may not be loaded ๐Ÿ˜ฑ

  • -lobjc โ€” you need this special case of the -l option in order to link an Objective-C or Objective-C++ program ๐ŸŒˆ
  • -nostartfiles โ€” don't use the standard system startup files when linking. The standard system libraries are still used normally, unless -nostdlib, -nolibc, or -nodefaultlibs is used ๐Ÿš€
  • -nodefaultlibs โ€” don't use the standard system libraries when linking. Only the libraries you specify get passed to the linker, and options that specify linkage of the system libraries, such as -static-libgcc or -shared-libgcc, are ignored. The standard startup files are still used normally, unless -nostartfiles is used ๐Ÿ“

The compiler may generate calls to "memcmp", "memset", "memcpy" and "memmove". These are usually resolved by entries in libc, so when this option is specified, those entry points should be supplied through some other mechanism ๐Ÿซ 

  • -nolibc โ€” don't use the C library, or the system libraries tightly coupled with it, when linking. You'll still link 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 the 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. It's intended for bare-board targets where there's genuinely 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 get passed to the linker. Options that specify 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 when this option is specified, those entry points should be supplied through some other mechanism ๐Ÿซ 

One of the standard libraries bypassed by -nostdlib and -nodefaultlibs is libgcc.a, a library of internal subroutines which GCC uses to overcome shortcomings of particular machines, or special needs for some languages ๐Ÿง 

In most cases you still need libgcc.a, even when you want to avoid the other standard libraries. In other words, when you specify -nostdlib or -nodefaultlibs, you should usually specify -lgcc as well ๐Ÿ’– This makes sure you have no unresolved references to internal GCC library subroutines. (An example of such an internal subroutine is "__main", used to make sure C++ constructors get called โœจ)

  • -e entry, --entry=entry โ€” specify that the program entry point is entry. The argument is interpreted by the linker. The GNU linker accepts either a symbol name or an address ๐ŸŽฏ
  • -pie โ€” produce a dynamically linked position independent executable on targets that support it. For predictable results, you must also specify the same set of options used for compilation (-fpie, -fPIE, or model suboptions) when you specify this linker option ๐Ÿฆ‹
  • -no-pie โ€” don't produce a dynamically linked position independent executable ๐Ÿ™…โ€โ™€๏ธ
  • -static-pie โ€” produce a static position independent executable on targets that support it. It's similar to a static executable, but it can be loaded at any address without a dynamic linker ๐ŸŒŒ For predictable results, you must also specify the same set of options used for compilation (-fpie, -fPIE, or model suboptions) when you specify this linker option ๐Ÿซถ

Okay bestie, we're still in the linker options ๐Ÿ”—๐Ÿ’–, so let's keep going!

  • -pthread โ€” Links your program with the POSIX threads library ๐Ÿงต. It's supported on GNU/Linux targets, most other Unix derivatives, and also on x86 Cygwin and MinGW targets. Heads up: on some targets it also sets flags for the preprocessor, so use it consistently for both compilation and linking โœจ.
  • -r โ€” Makes a relocatable object as 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, not only the used ones, to the dynamic symbol table ๐Ÿ‘‘. You need it for some uses of dlopen, or to get backtraces from inside a program ๐Ÿ™ˆ.
  • -s โ€” Removes all symbol table and relocation information from the executable ๐Ÿ’….
  • -static โ€” On systems that support dynamic linking, this overrides -pie and stops linking with the shared libraries ๐ŸงŠ. On other systems it does absolutely nothing.
  • -shared โ€” Produces a shared object that other objects can link with to form an executable ๐ŸŒˆ. Not every system supports it, so check first! For predictable results, you also need to specify the same set of options used for compilation (-fpic, -fPIC, or model suboptions) when you use this linker option.[1]
  • -shared-libgcc, -static-libgcc โ€” On systems that provide libgcc as a shared library, these force the use of the shared or static version, respectively ๐Ÿ’–. If no shared version of libgcc was built when the compiler was configured, these options have no effect.

There are a few situations where an app 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, each 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 usually use exceptions, so this is the right move โœจ.

If you use the GCC driver to create shared libraries instead, they might not always get 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 option --eh-frame-hdr, it links the shared version of libgcc into shared libraries by default. Otherwise, it takes advantage of the linker and optimizes away the linking with the shared version, so it links with the static version of libgcc by default. This lets exceptions propagate through those shared libraries without taking on relocation costs at library load time ๐Ÿฆ‹.

Heads up: if a library or main executable is supposed to throw or catch exceptions, you must link it using the G++ driver, or using the option -shared-libgcc, so it gets linked with the shared libgcc. Don't skip this one bestie ๐Ÿ˜ญ.
  • -static-libasan โ€” When the -fsanitize=address option is used to link a program, the GCC driver automatically links against libasan. If libasan is available as a shared library and the -static option isn't used, it links against the shared version. This option tells the GCC driver to link libasan statically, without necessarily linking other libraries statically ๐Ÿ”.
  • -static-libtsan โ€” When the -fsanitize=thread option is used to link a program, the GCC driver automatically links against libtsan. If libtsan is available as a shared library and the -static option isn't used, it links against the shared version. This option tells the GCC driver to link libtsan statically, without necessarily linking other libraries statically ๐Ÿงต.
  • -static-liblsan โ€” When the -fsanitize=leak option is used to link a program, the GCC driver automatically links against liblsan. If liblsan is available as a shared library and the -static option isn't used, it links against the shared version. This option tells the GCC driver to link liblsan statically, without necessarily linking other libraries statically ๐Ÿ’ง.
  • -static-libubsan โ€” When the -fsanitize=undefined option is used to link a program, the GCC driver automatically links against libubsan. If libubsan is available as a shared library and the -static option isn't used, it links against the shared version. 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 the -static option isn't used, it links against the shared version, and that's normally totally fine ๐Ÿ’…. But sometimes you want 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 overridden by the link editor option -Xlinker -z -Xlinker defs). Only a few systems support this one ๐Ÿซฃ.
  • -T script โ€” Uses script as the linker script ๐Ÿ“œ. This works on most systems using the GNU linker. On some targets, like bare-board targets without an operating system, you may need the -T option when linking to avoid references to undefined symbols.
  • -Xlinker option โ€” Passes option along to the linker as an option ๐ŸŽ€. Super handy for system-specific linker options that GCC doesn't recognize.

If you want to pass an option that takes a separate argument, you have to use -Xlinker twice: once for the option and once for the argument ๐Ÿงฉ. For example, to pass -assert definitions, you must write -Xlinker -assert -Xlinker definitions. Writing -Xlinker "-assert definitions" does not work, because it passes the whole string as a single argument, which isn't what the linker expects ๐Ÿ’€.

With the GNU linker, it's usually 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 rather than -Xlinker -Map -Xlinker output.map. Other linkers may not support this syntax for command-line options ๐Ÿคทโ€โ™€๏ธ.

  • -Wl,option โ€” Passes option to the linker as an option too ๐Ÿ”—. If option contains commas, it's split into multiple options at the commas. You can use this syntax to pass an argument to the option. For example, -Wl,-Map,output.map passes -Map output.map to the linker. With the GNU linker, you can also get the same effect with -Wl,-Map=output.map ๐Ÿ’–.
  • -u symbol โ€” Pretends the symbol 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 gets passed directly to the linker, along with the keyword keyword. Check the documentation for your linker to see 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.

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 the "#include "file"" and "#include <file>" directives ๐ŸŽ€.

You can mix and match any number or combination of these options on the command line to search for headers in several directories ๐ŸŒˆ. The lookup order goes like this:

  1. For the quote form of the include directive, the directory of the current file is searched first.
  2. For the quote form of the include directive, the directories specified by -iquote options are searched in left-to-right order, as they appear on the command line.
  3. Directories specified with -I options are scanned in left-to-right order.
  4. Directories specified with -isystem options are scanned in left-to-right order.
  5. Standard system directories are scanned.
  6. Directories specified with -idirafter options are scanned in left-to-right order.

You can use -I to override a system header file and swap in your own version, since these directories get searched before the standard system header file directories ๐Ÿ‘‘. But don't use this option to add directories that contain vendor-supplied system header files. Use -isystem for that ๐Ÿšซ.

The -isystem and -idirafter options also mark the directory as a system directory, so it gets the same special treatment as the standard system directories ๐Ÿซถ.

If a standard system include directory, or a directory specified with -isystem, is also specified with -I, the -I option gets ignored. The directory is still searched, but as a system directory at its normal position in the system include chain. This makes sure 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- โ€” Splits the include path ๐Ÿช“. This option has been deprecated.
Deprecated alert ๐Ÿšจ: please use -iquote instead for -I directories before the -I-, and remove the -I- option.

Any directories specified with -I options before -I- are searched only for headers requested with "#include "file"". They are not searched for "#include <file>". If additional directories are specified with -I options after the -I-, those directories are searched for all #include directives ๐Ÿ’….

In addition, -I- also stops the compiler from checking the current file's directory first when it hunts for #include "file" ๐Ÿ™ˆ and there is no way to override this effect of -I-. Bestie, choose wisely ๐Ÿ’…

  • -iprefix prefix โ€” ๐Ÿงš sets the prefix that any later -iwithprefix options will tack onto. If your prefix is an actual directory, you should include the final /.
  • -iwithprefix dir, -iwithprefixbefore dir โ€” ๐ŸŒธ glues dir onto whatever prefix you set earlier with -iprefix and adds the result to the include search path. -iwithprefixbefore drops it in the same spot -I would, while -iwithprefix puts it where -idirafter would.
  • -isysroot dir โ€” ๐Ÿ“š this one is basically --sysroot, but it only applies to header files. The exception is Darwin targets, where it covers both header files and libraries. Peep the --sysroot option for more info.
  • -imultilib dir โ€” uses dir as a subdirectory of the directory that holds the target-specific C++ headers.
  • -nostdinc โ€” ๐Ÿซถ skips the standard system directories when looking for header files. Only the stuff you explicitly point at with -I, -iquote, -isystem, and/or -idirafter gets searched, plus the directory of the current file if it applies.
  • -nostdinc++ โ€” skips the C++-specific standard directories when hunting for headers, but still checks the other standard ones. 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. You're not really meant to type this one yourself. Only the driver passes it along ๐Ÿ™…โ€โ™€๏ธ
  • -Ldir โ€” adds dir to the list of directories searched for -l ๐Ÿ—บ๏ธ
  • -Bprefix โ€” ๐Ÿ—‚๏ธ this tells the compiler where to find its own executables, libraries, include files, and data files.

The compiler driver runs one or more of the subprograms cpp, cc1, as and ld. It tries prefix as a prefix for every program it attempts to run, both with and without machine/version/ for the matching target machine and compiler version.

For each subprogram, the driver first tries the -B prefix, if you gave one. If that name isn't found, or if -B isn't specified at all, it tries two standard prefixes: /usr/lib/gcc/ and /usr/local/lib/gcc/. If neither of those produces a file that exists, the unmodified program name gets searched for through the directories in your PATH environment variable.

The compiler checks whether the path given by -B refers to a directory, and if necessary it adds a directory separator character to the end of the path.

-B prefixes that effectively specify directory names also apply to libraries in the linker, because the compiler translates these options into -L options for the linker. They also apply to include files in the preprocessor, because the compiler translates these options into -isystem options for the preprocessor. In this case, the compiler appends include to the prefix.

The runtime support file libgcc.a can also be searched for using the -B prefix, if needed. If it isn't found there, the two standard prefixes above are tried, and that is all. If it isn't found by those means either, the file is left out of the link.

Another way to specify a prefix much like the -B prefix is to use the environment variable GCC_EXEC_PREFIX.

As a special kludge, if the path provided by -B is [dir/]stageN/, where N is a number in the range 0 to 9, then it is replaced by [dir/]include. This is 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 โ€” ๐ŸŒ makes dir the logical root directory for headers and libraries. For example, if the compiler normally looks for headers in /usr/include and libraries in /usr/lib, it will instead look in dir/usr/include and dir/usr/lib.

If you use both this option and the -isysroot option, then --sysroot applies to libraries, but -isysroot applies to header files.

The GNU linker (beginning with version 2.16) has the necessary support for this option. If your linker doesn't support it, the header file side of --sysroot still works, but the library side does not.
  • --no-sysroot-suffix โ€” ๐Ÿ™…โ€โ™€๏ธ for some targets, a suffix gets added to the root directory given with --sysroot, depending on the other options used. So headers might be found in dir/suffix/usr/include instead of dir/usr/include. This option turns off adding that suffix.

โœจ Options for Code Generation Conventions โœจ

These machine-independent options are the boss of how the generated code handles its interface conventions ๐Ÿ’…

Most of them have both positive and negative forms, where the negative form of -ffoo is -fno-foo. In the list below, only one of the forms is shown, 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 โ€” ๐Ÿงน controls stack space reuse for user-declared local/auto variables and compiler-generated temporaries. reuse_level can be all, named_vars, or none. all enables stack reuse for all local variables and temporaries, named_vars enables reuse only for user-defined local variables with names, and none disables stack reuse completely. The default value is all.

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 a variable's lifetime ends and it lives in memory, the optimizing compiler is free to reuse its stack space for 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 a temporary's lifetime ends and it lives in memory, the optimizing compiler is free to reuse its stack space for other temporaries or scoped local variables whose live range does not overlap with it. However, some legacy code relies on the behavior of older compilers, in which 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 โ€” ๐Ÿšจ generates traps for signed overflow on addition, subtraction, and multiplication operations. -ftrapv and -fwrapv override each other, so -ftrapv -fwrapv on the command line results in -fwrapv being effective. Note that only active options override, so -ftrapv -fwrapv -fno-wrapv on the command line results in -ftrapv being effective.
  • -fwrapv โ€” ๐ŸŒ€ tells the compiler to assume that signed arithmetic overflow of addition, subtraction and multiplication wraps around using twos-complement representation. This flag enables some optimizations and disables others. The options -ftrapv and -fwrapv override each other, so -ftrapv -fwrapv on the command line results in -fwrapv being effective. Note that only active options override, so -ftrapv -fwrapv -fno-wrapv on the command line results in -ftrapv being effective.
  • -fwrapv-pointer โ€” ๐Ÿ‘‰ tells the compiler to assume that pointer arithmetic overflow on addition and subtraction wraps around using twos-complement representation. This flag disables some optimizations which assume pointer overflow is invalid.
  • -fstrict-overflow โ€” ๐Ÿง implies -fno-wrapv -fno-wrapv-pointer, and when negated, implies -fwrapv -fwrapv-pointer.
  • -fexceptions โ€” ๐Ÿ›Ÿ enables exception handling and generates the extra code needed to propagate exceptions. For some targets, this implies GCC generates frame unwind information for all functions.
That can produce significant data size overhead, although it does not affect execution.

If you don't specify this option, GCC enables it by default for languages like C++ that normally require exception handling, and disables it for languages like C that don't normally require it. However, you may need to enable this option when compiling C code that needs to interoperate properly with exception handlers written in C++. You may also wish to disable this option if you are compiling older C++ programs that don't use exception handling.

  • -fnon-call-exceptions โ€” ๐Ÿชค generates code that allows trapping instructions to throw exceptions.
This requires platform-specific runtime support that does not exist everywhere.

Moreover, it only allows trapping instructions to throw exceptions, i.e. memory references or floating-point instructions. It does not allow exceptions to be thrown from arbitrary signal handlers such as "SIGALRM". This enables -fexceptions.

  • -fdelete-dead-exceptions ๐Ÿ’… โ€” okay so this one is pure optimization drama. Instructions that could throw an exception but don't otherwise contribute to what the program does can get optimized away โœจ. It doesn't touch calls to functions unless they have the pure or const attributes. This is turned on by default for the Ada and C++ compilers, since the language specs allow it. Optimization passes that remove dead exceptions are enabled separately at different optimization levels ๐Ÿซถ.
  • -funwind-tables ๐Ÿฆ‹ โ€” similar to -fexceptions, except it only generates the static data that's needed and doesn't change the generated code in any other way. You usually don't have to turn this on yourself, because a language processor that needs this handling enables it for you ๐Ÿ’–.
  • -fasynchronous-unwind-tables ๐ŸŒˆ โ€” generates an unwind table in DWARF format, if the target machine supports it. The table is exact at every instruction boundary, so it can be used for stack unwinding from asynchronous events, like a debugger or a garbage collector ๐Ÿ”ฅ.
  • -fno-gnu-unique ๐Ÿ™ˆ โ€” okay, this one is a whole saga. With a recent GNU assembler and C library, C++ uses the STB_GNU_UNIQUE binding so that template static data members and static local variables in inline functions stay unique even with RTLD_LOCAL. That's needed to avoid problems where a library used by two different RTLD_LOCAL plugins depends on a definition in one of them and ends up disagreeing with the other about the binding of the symbol. BUT, this makes dlclose get ignored for affected DSOs ๐Ÿ’€. So if your program relies on reinitializing a DSO through dlclose and dlopen, you can use -fno-gnu-unique ๐Ÿ“.
  • -fpcc-struct-return ๐ŸŽ€ โ€” returns short struct and union values in memory, just like the 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 that of some integer type.

Warning: code compiled with -fpcc-struct-return is not binary compatible with code compiled with -freg-struct-return. Only use it to conform to a non-default application binary interface โš ๏ธ.
  • -freg-struct-return ๐Ÿงš โ€” returns struct and union values in registers when possible. This is more efficient for small structures than -fpcc-struct-return โญ.

If you specify neither -fpcc-struct-return nor -freg-struct-return, GCC defaults to whichever convention is standard for the target. If there isn't a standard convention, GCC defaults to -fpcc-struct-return, except on targets where GCC is the principal compiler. In those cases, we get to choose the standard, and we chose the more efficient register return alternative ๐Ÿ‘‘.

Warning: code compiled with -freg-struct-return is not binary compatible with code compiled with -fpcc-struct-return. Only use it to conform to a non-default application binary interface โš ๏ธ.
  • -fshort-enums ๐Ÿ“ โ€” gives an enum type only as many bytes as it needs for its declared range of possible values. Specifically, the enum type ends up equivalent to the smallest integer type that has enough room ๐ŸŒธ.
Warning: the -fshort-enums switch 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 of wchar_t to be short unsigned int instead of the default for the target. This is handy for building programs that run under WINE ๐Ÿท.
Warning: the -fshort-wchar switch 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 option controls where global variables defined without an initializer get placed. These are called tentative definitions in the C standard. They're different from declarations using the extern keyword, which don't allocate any storage ๐Ÿ’œ.

The default is -fno-common, which means the compiler places 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 behaviour is inconsistent with C++, and on many targets it comes with 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. Quiet mode, activated ๐ŸŒ™.
  • -finhibit-size-directive ๐ŸงŠ โ€” doesn't output a .size assembler directive, or anything else that would cause trouble if the function gets split in the middle and the two halves end up placed far apart in memory. This option is used when compiling crtstuff.c, so you shouldn't need it for anything else ๐Ÿ™…โ€โ™€๏ธ.
  • -fverbose-asm ๐Ÿ“ โ€” puts extra commentary into the generated assembly code so it's easier to read. This is honestly only useful for people who actually need to read the generated assembly, maybe while debugging the compiler itself ๐Ÿค“.

-fno-verbose-asm, which is the default, leaves out the extra info and is 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 ๐Ÿ”ฎ.

For example, given this C source file:

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

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

  return total;
}

Compiling it to (x86_64) assembly via -S and emitting the result direct to stdout via -o - looks like this:

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

That gives output similar to this:

        .file   "test.c"
# GNU C11 (GCC) version 7.0.0 20160809 (experimental) (x86_64-pc-linux-gnu)
  [...snip...]
# options passed:
  [...snip...]

        .text
        .globl  test
        .type   test, @function
test:
.LFB0:
        .cfi_startproc
# test.c:4:   int total = 0;
        xorl    %eax, %eax      # <retval>
# test.c:6:   for (i = 0; i < n; i++)
        xorl    %edx, %edx      # i
.L2:
# test.c:6:   for (i = 0; i < n; i++)
        cmpl    %edi, %edx      # n, i
        jge     .L5     #,
# test.c:7:     total += i * i;
        movl    %edx, %ecx      # i, tmp92
        imull   %edx, %ecx      # i, tmp92
# test.c:6:   for (i = 0; i < n; i++)
        incl    %edx    # i
# test.c:7:     total += i * i;
        addl    %ecx, %eax      # tmp92, <retval>
        jmp     .L2     #
.L5:
# test.c:10: }
        ret
        .cfi_endproc
.LFE0:
        .size   test, .-test
        .ident  "GCC: (GNU) 7.0.0 20160809 (experimental)"
        .section        .note.GNU-stack,"",@progbits

The comments are meant for humans rather than machines, so the precise format of them is subject to change ๐Ÿซถโœจ.

  • -frecord-gcc-switches ๐ŸŽ€ โ€” this makes GCC record the command line used to invoke the compiler into the object file being created. It's only implemented on some targets, and the exact format of the recording depends on the target and binary file format. Usually it takes the form of a section containing ASCII text ๐Ÿ“œ. This one is related to -fverbose-asm, but that switch only records info in the assembler output file as comments, so it never reaches the object file ๐Ÿ™…โ€โ™€๏ธ. See also -grecord-gcc-switches for another way of storing compiler options into the object file ๐Ÿ”—.
  • -fpic ๐ŸŒธ โ€” generates position-independent code (PIC) suitable for use in a shared library, if the target machine supports it. This code accesses all constant addresses through a global offset table (GOT). The dynamic loader resolves the GOT entries when the program starts. (The dynamic loader isn't part of GCC; it's part of the operating system ๐Ÿ–ฅ๏ธ.) If the GOT size for the linked executable goes over a machine-specific maximum, you get an error message from the linker saying that -fpic doesn't work. In that case, recompile with -fPIC instead ๐Ÿ”. (These maximums are 8k on the SPARC, 28k on AArch64 and 32k on the m68k and RS/6000. The x86 has no such limit ๐ŸŽ‰.)

Position-independent code 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 it's supported for the target machine, this emits position-independent code suitable for dynamic linking, and it avoids any limit on the size of the global offset table ๐ŸŒˆ. This option makes a difference on AArch64, m68k, PowerPC and SPARC ๐Ÿ’….

Position-independent code needs special support, so it only works on certain machines ๐Ÿ™ˆ.

When this flag is set, the macros __pic__ and __PIC__ are defined to 2 โœจ.

  • -fpie, -fPIE: okay bestie, these two are the cousins of -fpic and -fPIC ๐Ÿฆ‹ The position-independent code they make can only be linked into executables, so no sneaking it into shared libraries. You usually reach for these when you're compiling something that's going to be linked with the -pie GCC option ๐Ÿ’…
    • -fpie and -fPIE both define the macros __pie__ and __PIE__ โœจ
    • The macros are set to 1 for -fpie and 2 for -fPIE.
  • -fno-plt: main character move ๐Ÿ‘‘ Don't use the PLT for external function calls in position-independent code. Instead, load the callee address from the GOT at the call site and branch to it. It's more efficient because it gets rid of PLT stubs and exposes 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 needs the PLT, so with -fno-plt all external symbols get resolved at load time. Be aware of that trade-off ๐Ÿ™ˆ
    • Alternatively, the function attribute noplt can avoid calls through the PLT for specific external functions ๐Ÿงš
    • In position-dependent code, a few targets also convert calls to functions marked to not use the PLT so they use the GOT instead ๐Ÿ’œ
  • -fno-jump-tables: no jump tables for switch statements, even where they'd be more efficient than other strategies ๐Ÿ™… This one is handy alongside -fpic or -fPIC when you're 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 require a GOT, so you won't need this option there ๐Ÿ’…
  • -fno-bit-tests: no bit tests for switch statements, even if they'd be more efficient than other code generation strategies ๐ŸŽ€
  • -ffixed-reg: treat the register named reg as fixed, so the generated code should never touch it (except maybe as a stack pointer, frame pointer, or some other fixed role) ๐Ÿฆ‹
    • reg has to be an actual register name. The accepted names depend on the machine and are defined in the REGISTER_NAMES macro in the machine description macro file ๐ŸŒˆ
    • There's no negative form for this one, since 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 can be used for temporaries or variables that don't live across a call ๐Ÿ’–
    • Functions compiled this way do not save and restore the register reg ๐Ÿ™ˆ
    • It's an error to use this 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 ๐Ÿ˜ญ
    • No negative form, since it's a three-way choice โœจ
  • -fcall-saved-reg: treat the register named reg as an allocable register that's saved by functions. It can even be used for temporaries or variables that live across a call ๐ŸŒธ
    • Functions compiled this way save and restore the register reg if they use it ๐Ÿซถ
    • It's an error to use this 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 ๐Ÿ˜ญ
    • Using it on a register where function values may be returned causes a different kind of disaster ๐Ÿ’€
    • No negative form, since it's a three-way choice โœจ
  • -fpack-struct[=n]: with no value, this packs all structure members together without holes ๐Ÿงฉ If you give it a value, which has to be a small power of two, members get packed according to that value as the maximum alignment. Objects whose default alignment requirements are larger than this get output potentially unaligned at the next fitting location ๐Ÿ“
โš ๏ธ Warning: the -fpack-struct switch makes GCC generate code that is not binary compatible with code generated without that switch. It also makes the code suboptimal, so only use it to conform to a non-default application binary interface ๐Ÿ˜ญ
  • -fleading-underscore: this one and its counterpart, -fno-leading-underscore, forcibly change the way C symbols are represented in the object file ๐Ÿงš One use is to help link with legacy assembly code ๐Ÿ•ฐ๏ธ
โš ๏ธ Warning: the -fleading-underscore switch 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, and know that not all targets fully support it ๐Ÿ’€
  • -ftls-model=model: alter the thread-local storage model. model should be one of global-dynamic, local-dynamic, initial-exec or local-exec ๐Ÿงต
    • The choice is subject to optimization. The compiler might use a more efficient model for symbols that aren't visible outside the translation unit, or if -fpic isn't given on the command line โœจ
    • 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 created at run time on the stack when the address of a nested function is taken. It's used to call the nested function indirectly ๐ŸŒ€
    • Because of that, the stack has to be made executable for the program to work properly ๐Ÿ˜ฌ
    • -fno-trampolines is enabled by default on a language-by-language basis, so the compiler can avoid generating trampolines when it computes that's safe and swap them 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 ๐Ÿ’œ
    • Code compiled with -ftrampolines and code compiled with -fno-trampolines are not binary compatible if nested functions are present. So this option has to be used program-wide and handled with extreme care ๐Ÿšจ
    • For languages other than Ada, -ftrampolines and -fno-trampolines currently have no effect. Trampolines are always generated on platforms that need them for nested functions ๐ŸŒธ
  • -fvisibility=[default|internal|hidden|protected]: set the default ELF image symbol visibility to the option you pick. Every symbol gets marked with this unless the code overrides it ๐ŸŒท Using this can really 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 for any shared objects you distribute ๐Ÿ”ฅ
    • Despite the name, default always means public, which means 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 ๐Ÿ™„
    • If you don't specify -fvisibility, the default is default, which makes every symbol public ๐Ÿ‘€
    • For a good explanation of why correct ELF symbol visibility is worth it, check out "How To Write Shared Libraries" by Ulrich Drepper, which you can find at https://www.akkadia.org/drepper/ ๐Ÿ“š
    • A superior trick this option makes possible, compared to marking things hidden when the default is public, is to make the default hidden and then mark things public. This is the norm with DLLs on Windows. With -fvisibility=hidden and __attribute__ ((visibility("default"))) instead of __declspec(dllexport), you get almost identical semantics with identical syntax. That's a huge win for cross-platform projects ๐ŸŒˆ
    • If you're adding visibility support to existing code, #pragma GCC visibility can help. Wrap the declarations you want to set visibility for with #pragma GCC visibility push(hidden) and #pragma GCC visibility pop ๐Ÿงš
    • Keep in mind that symbol visibility is part of the API interface contract. So all new code should always specify visibility when it isn't the default. Declarations only for use within the local DSO should always be explicitly marked hidden to avoid PLT indirection overheads. Making that clear also helps readability and self-documentation ๐Ÿ’–
    • Because of ISO C++ specification requirements, operator new and operator delete must always have default visibility ๐Ÿ™ƒ
    • Headers from outside your project, especially system headers and headers from any other library you use, may not expect to be compiled with a visibility other than the default. You may need to say #pragma GCC visibility push(default) before including them ๐Ÿซถ
    • extern declarations aren't affected by -fvisibility, so lots of code can be recompiled with -fvisibility=hidden with no modifications ๐ŸŽ€
    • However, that means calls to extern functions with no explicit visibility use the PLT. So it's more effective to use __attribute ((visibility)) and/or #pragma GCC visibility to tell the compiler which extern declarations should be treated as hidden ๐Ÿ’…
    • -fvisibility does affect C++ vague linkage entities. For instance, an exception class that's thrown between DSOs must be explicitly marked with default visibility so the type_info nodes are unified between the DSOs ๐Ÿงพ
    • You can find an overview of these techniques, their benefits, and how to use them at https://gcc.gnu.org/wiki/Visibility โœจ
  • -fstrict-volatile-bitfields โ€” ๐ŸŽ€ Okay bestie, this one is for volatile bit-fields (and other structure fields, though the compiler usually respects those types anyway). Use it when you want each access to be a single access at the width of the field's type, lined up to natural alignment if that's possible. Say your target has memory-mapped peripheral registers that need every access to be 16 bits wide. With this flag you can declare all the peripheral bit-fields as unsigned short (assuming short is 16 bits on those targets) so GCC uses 16-bit accesses instead of, like, a more efficient 32-bit one ๐Ÿ’…

If this option is disabled, the compiler picks the most efficient instruction. In the example above, that might be a 32-bit load, even though it reads bytes with no part of the bit-field in them, or memory-mapped registers unrelated to the one getting updated. ๐Ÿ˜ฌ

In some cases, like when the packed attribute is applied to a structure field, it might not be possible to access the field with one read or write that's correctly aligned for the target machine. When that happens, GCC falls back to generating multiple accesses instead of code that will fault or truncate the result at run time. ๐Ÿ›Ÿ

Note: Due to restrictions of the C/C++11 memory model, write accesses are not allowed to touch non bit-field members. It is 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 one controls whether any out-of-line instance of the __sync family of functions can be used to implement the C++11 __atomic family of functions. It's enabled by default, so the only useful form is -fno-sync-libcalls. It's used in the implementation of the libatomic runtime library. โœจ

โœจ GCC Developer Options โœจ

okay so this section is for the GCC developers ๐Ÿงš It covers command-line options that are mainly for compiler testing, investigating compiler bugs, and looking into compile-time performance problems. That includes options that make debug dumps at various points in compilation, options that print stats 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 compiling and linking, so don't panic if you've never seen them ๐Ÿ’œ

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 left off, GCC builds a default dump file name by sticking together the base dump file name, a pass number, a phase letter, and the pass name. The base dump file name is the name of the output file the compiler made, if you explicitly specified one and it's not an executable. Otherwise it's the source file name. The pass number comes from the order the passes were registered with the compiler's pass manager. That's usually the same as execution order, BUT passes registered by plugins, target-specific passes, or passes that get registered late are numbered higher than the pass named final, even if they actually run earlier. The phase letter is one of i (inter-procedural analysis), l (language-specific), r (RTL), or t (tree). The files get created in the directory of the output file. ๐Ÿ“‚

  • -fcallgraph-info, -fcallgraph-info=MARKERS โ€” ๐Ÿ•ธ๏ธ This makes the compiler output callgraph information for the program, one per object file. 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. If you specify the su marker, the callgraph gets decorated with stack usage information, which is equivalent to -fstack-usage. If you specify the da marker, the callgraph gets decorated with info about dynamically allocated objects. ๐ŸŒˆ
Heads up: When compiling with -flto, no callgraph information is output along with the object file. At LTO link time, -fcallgraph-info may generate multiple callgraph information files next to the intermediate LTO output files. ๐Ÿ‘€
  • -dletters, -fdump-rtl-pass, -fdump-rtl-pass=filename โ€” ๐ŸŒท These say "make debugging dumps during compilation at the times specified by the letters." This is how you debug the RTL-based passes of the compiler. ๐Ÿซถ

Some -dletters switches mean something different when you use -E for preprocessing. ๐Ÿ™ƒ

You can turn on debug dumps with a -fdump-rtl switch or with some -d option letters. Here's what each possible letter/pass name does when you use it:

  • -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 two 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 โ€” โœ–๏ธ Dump after sign/zero extension elimination.
  • -fdump-rtl-seqabstr โ€” ๐Ÿงฌ Dump after common sequence discovery.
  • -fdump-rtl-shorten โ€” ๐Ÿฉณ Dump after shortening branches.
  • -fdump-rtl-sibling โ€” ๐Ÿ‘ฏ Dump after sibling call optimizations.
  • -fdump-rtl-split1, -fdump-rtl-split2, -fdump-rtl-split3, -fdump-rtl-split4, -fdump-rtl-split5 โ€” ๐Ÿช“ These options enable dumping after five rounds of instruction splitting.
  • -fdump-rtl-sms โ€” ๐ŸŒ€ Dump after modulo scheduling. This pass only runs on some architectures.
  • -fdump-rtl-stack โ€” ๐Ÿ“š Dump after the conversion from GCC's "flat register file" registers to the x87's stack-like registers. This pass only runs on x86 variants.
  • -fdump-rtl-subreg1, -fdump-rtl-subreg2 โ€” ๐Ÿงฒ These enable dumping after the two subreg expansion passes.
  • -fdump-rtl-unshare โ€” ๐Ÿ”“ Dump after all RTL has been unshared.
  • -fdump-rtl-vartrack โ€” ๐Ÿ•ต๏ธ Dump after variable tracking.
  • -fdump-rtl-vregs โ€” ๐Ÿชž Dump after converting virtual registers to hard registers.
  • -fdump-rtl-web โ€” ๐Ÿ•ธ๏ธ Dump 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 always produce empty files. Bestie, don't waste your time on them ๐Ÿ’€
  • -da, -fdump-rtl-all โ€” ๐Ÿฐ Produce all the dumps listed above.
  • -dA โ€” ๐Ÿท๏ธ Annotate the assembler output with miscellaneous debugging information.
  • -dD โ€” ๐Ÿ“– Dump all macro definitions, at the end of preprocessing, in addition to the normal output.
  • -dH โ€” ๐Ÿ’ฅ Produce a core dump whenever an error occurs. ๐Ÿ˜ญ
  • -dp โ€” okay bestie, this one sprinkles a little comment into the assembler output telling you which pattern and alternative got used ๐Ÿงš It also prints the length and cost of each instruction ๐Ÿ’…
  • -dP โ€” this dumps the RTL into the assembler output as a comment right before each instruction ๐Ÿ”ฅ It also switches on -dp annotation, so you get both โœจ
  • -dx โ€” no full compile for you! This just generates RTL for a function instead ๐Ÿฆ‹ It's usually paired with -fdump-rtl-expand ๐Ÿ’–

  • -fdump-debug โ€” dumps the debugging info generated during the debug generation phase ๐ŸŒธ
  • -fdump-earlydebug โ€” dumps the debugging info generated during the early debug generation phase ๐Ÿ“
  • -fdump-noaddr โ€” when you're making debugging dumps, this suppresses address output ๐Ÿ™ˆ It makes it way more doable to diff dumps from compiler invocations with different compiler binaries and/or different text / bss / data / heap / stack / dso start locations ๐Ÿ’…
  • -freport-bug โ€” if an internal compiler error (ICE) happens, this collects and dumps debug info into a temporary file for you ๐Ÿ˜ญ
  • -fdump-unnumbered โ€” in debugging dumps, this suppresses instruction numbers and address output ๐Ÿฆ‹ Super helpful for diffing dumps from different options, especially with and without -g ๐Ÿ‘‘
  • -fdump-unnumbered-links โ€” when doing debugging dumps (check the -d option above ๐Ÿ’œ), this suppresses instruction numbers for the links to the previous and next instructions in a sequence ๐Ÿงš

  • -fdump-ipa-switch, -fdump-ipa-switch-options โ€” these control dumping the inter-procedural analysis language tree to a file at various stages ๐ŸŒˆ The file name comes from 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 info about call-graph optimization, unused function removal, and inlining decisions ๐Ÿ’…
    • inline โ€” dumps after function inlining ๐Ÿ”ฅ

On top of that, you can add -optimized, -missed, -note, and -all. They mean the same thing as they do for -fopt-info, and they default to -optimized ๐Ÿ’–

For example, -fdump-ipa-inline-optimized-missed will show you the callsites that got inlined, plus the ones that didn't ๐Ÿ™ˆ

By default, the dump includes messages about successful optimizations (same as -optimized) along with the low-level details of the analysis ๐Ÿซถ

  • -fdump-lang โ€” dumps language-specific info. The file name is the source file name with .lang appended ๐Ÿฆ‹
  • -fdump-lang-all, -fdump-lang-switch, -fdump-lang-switch-options, -fdump-lang-switch-options=filename โ€” these control dumping language-specific info ๐Ÿ’– The options and filename bits work exactly like they do for -fdump-tree ๐Ÿซถ Here are the accepted switch values:
    • all โ€” enables all language-specific dumps ๐ŸŒˆ
    • class โ€” dumps class hierarchy info. Virtual table info gets emitted unless 'slim' is specified. This is C++ only ๐Ÿ‘‘
    • module โ€” dumps module info. The options lineno (locations), graph (reachability), blocks (clusters), uid (serialization), alias (mergeable), asmname (Elrond), eh (mapper) & vops (macros) may add extra info. This is C++ only ๐Ÿงš
    • raw โ€” dumps the raw internal tree data. This is C++ only ๐Ÿ’œ
  • -fdump-passes โ€” prints the list of optimization passes that your current command-line options turn on and off, straight to stderr ๐Ÿ”ฅ
  • -fdump-statistics-option โ€” enables and controls dumping pass statistics into a separate file ๐Ÿ“Š The file name is the source file name with a suffix ending in .statistics appended, and it's created in the same directory as the output file. If you use the -option form, -stats sums the counters over the whole compilation unit, while -details dumps every event as the passes generate it. With no option at all, the counters are summed for each function compiled ๐Ÿ’…

  • -fdump-tree-all, -fdump-tree-switch, -fdump-tree-switch-options, -fdump-tree-switch-options=filename โ€” these control dumping the intermediate language tree at various stages of processing, into a file ๐ŸŒณ If you use the -options form, options is a list of --separated options that control the dump details. Not every option applies to every dump, and the ones that don't make sense get ignored ๐Ÿ™ˆ The available options are:
    • address โ€” prints the address of each node. This usually isn't meaningful because it changes with the environment and source file. Its main job is tying a dump file to a debug environment ๐Ÿงš
    • asmname โ€” if DECL_ASSEMBLER_NAME has been set for a decl, this uses that in the dump instead of DECL_NAME. It's mainly handy for working backward from mangled names in the assembly file ๐Ÿ”ฅ
    • slim โ€” when dumping front-end intermediate representations, this stops members of a scope or function body from being dumped just because the scope was reached. Those only get dumped when some other path directly reaches them. When dumping pretty-printed trees, it skips the bodies of control structures. When dumping RTL, it prints the RTL in slim (condensed) form instead of the default LISP-like representation ๐Ÿ’–
    • raw โ€” prints a raw representation of the tree. By default, trees get pretty-printed into a C-like representation ๐ŸŒธ
    • details โ€” enables more detailed dumps (not every dump option honors it). It also includes info from the optimization passes โœจ
    • stats โ€” enables dumping various statistics about the pass (not every dump option honors it) ๐Ÿ“Š
    • blocks โ€” enables showing basic block boundaries (disabled in raw dumps) ๐Ÿงฑ
    • graph โ€” for each of the other indicated dump files (-fdump-rtl-pass), dumps a control flow graph representation suitable for viewing with GraphViz, written to file.passid.pass.dot. Each function in the file is pretty-printed as a subgraph, so GraphViz can render them all in one plot. This only works for RTL dumps right now, 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 info (only available in certain passes) ๐Ÿ‘‘
    • missed โ€” enables showing missed optimization info (only available in certain passes) ๐Ÿ’€
    • note โ€” enables other detailed optimization info (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 which tree dumps exist, or to find the dump for a pass you care about, follow these steps:

  1. Invoke GCC with -fdump-passes and look in the stderr output for the code matching the pass you want. For example, the codes tree-evrp, tree-vrp1, and tree-vrp2 correspond to the three Value Range Propagation passes. The number at the end tells apart the different invocations of the same pass ๐Ÿงš
  2. To turn on creating the dump file, append the pass code to the -fdump- option prefix and invoke GCC with it. For example, to enable the dump from the Early Value Range Propagation pass, invoke GCC with the -fdump-tree-evrp option. You can optionally name the dump file. If you don't, GCC creates one as described below ๐Ÿ’–
  3. Find the pass dump in a file whose name has three parts separated by periods: the name of the source file GCC was invoked to compile, a numeric suffix for the pass number followed by the letter t for tree passes (or the letter r for RTL passes), and finally the pass code. For example, the Early VRP pass dump might be in a file named myfile.c.038t.evrp in the current working directory. Heads up, though: the numeric codes aren't stable and can change from one version of GCC to another ๐Ÿ˜ญ

  • -fopt-info, -fopt-info-options, -fopt-info-options=filename โ€” these control optimization dumps from the various optimization passes ๐Ÿ’ซ If you use the -options form, options is a list of --separated option keywords that pick the dump details and which optimizations to include.

The options split into three groups:

  1. options describing what kinds of messages should be emitted,
  2. options describing the verbosity of the dump, and
  3. options describing which optimizations should be included.

Options from each group can be mixed freely since they don't overlap. If there's a conflict, the later options on the command line override the earlier ones โœจ

The following options control which kinds of messages get emitted:

  • optimized โ€” prints info when an optimization is successfully applied. It's up to each pass to decide what's relevant. For example, the vectorizer passes print the source location of loops that were successfully vectorized ๐Ÿ‘‘
  • missed โ€” prints info about missed optimizations. Individual passes decide what goes in the output ๐Ÿ’€
  • note โ€” prints verbose info about optimizations, like certain transformations and more detailed messages about decisions ๐Ÿ“
  • all โ€” prints detailed optimization info. This includes optimized, missed, and note ๐Ÿ’…

The following option controls the dump verbosity:

The internals keyword is the deep-dive one ๐Ÿค“ By default, only the "high-level" messages get emitted. This turns on the extra, more detailed messages, which are mostly of interest to GCC developers ๐Ÿ› ๏ธ

One or more of these keywords can be used to describe a group of optimizations ๐ŸŽ€

  • ipa โ€” dumps from all the interprocedural optimizations ๐Ÿฆ‹
  • loop โ€” dumps from all the loop optimizations ๐Ÿ”
  • inline โ€” dumps from all the inlining optimizations ๐ŸŒธ
  • omp โ€” dumps from all OMP (Offloading and Multi Processing) optimizations ๐Ÿงš
  • vec โ€” dumps from all the vectorization optimizations ๐Ÿ’œ
  • optall โ€” dumps from every optimization ๐Ÿ‘‘ It's a superset of the groups above

If you leave the options out, it defaults to optimized-optall โœจ That means you get messages about the successful optimizations from all the passes, minus anything tagged as "internals" ๐Ÿ’€

If you give it a filename, the dumps from all the applicable optimizations get concatenated into that file. Otherwise the dump goes to stderr ๐Ÿ–ฅ๏ธ You can use multiple -fopt-info options, but only one of them can include a filename. If other filenames are provided, then all but the first such option get ignored ๐Ÿ™…โ€โ™€๏ธ

Heads up ๐Ÿšจ the output filename gets overwritten when you have multiple translation units. If you want combined output from several translation units, use stderr instead.

Here's the vibe in action ๐Ÿ“ธ In this example, the optimization info goes to stderr:

gcc -O3 -fopt-info

This example:

gcc -O3 -fopt-info-missed=missed.all

outputs the missed optimization report from all the passes into missed.all. And this one:

gcc -O2 -ftree-vectorize -fopt-info-vec-missed

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 listed after -fopt-info does not matter ๐Ÿซถ

As another example,

gcc -O3 -fopt-info-inline-optimized-missed=inline.txt

outputs info about missed optimizations, plus optimized locations, from all the inlining passes into inline.txt ๐Ÿฆ‹

Finally, consider:

gcc -fopt-info-vec-missed=vec.miss -fopt-info-loop-optimized=loop.opt

Okay this one is a conflict ๐Ÿ˜ค The two output filenames vec.miss and loop.opt clash, since only one output file is allowed. In this case, only the first option takes effect and the subsequent options are ignored. So only vec.miss is produced, and it contains dumps from the vectorizer about missed opportunities ๐Ÿ’…


โœจ -fsave-optimization-record

Writes a SRCFILE.opt-record.json.gz file detailing what optimizations were performed, for those that support -fopt-info ๐Ÿ“

This option is experimental, and the format of the data inside the compressed JSON file is subject to change ๐Ÿ’€

It's roughly a machine-readable version of -fopt-info-all ๐Ÿค– Think of it as a collection of messages with source file, line number, and column number, plus these extra bits for each message:

  • the execution count of the code being optimized, plus metadata about whether it came from actual profile data or was just an estimate, so you can prioritize messages by code hotness ๐Ÿ”ฅ
  • the function name of the code being optimized, where applicable
  • the "inlining chain" for the code being optimized, so when a function is inlined into several different places (which might themselves be inlined), you can tell the copies apart ๐Ÿงฉ
  • objects identifying the parts of the message that refer to expressions, statements, or symbol-table nodes, which of these categories they are, and, when available, their source code location ๐Ÿ“
  • the GCC pass that emitted the message, and
  • the location in GCC's own code from which the message was emitted

Also, some messages are logically nested within other messages, reflecting implementation details of the optimization passes ๐Ÿช†

โœจ -fsched-verbose=n

On targets that use instruction scheduling, this controls how much debugging output the scheduler prints to the dump files ๐Ÿง 

  • For n greater than zero, -fsched-verbose outputs the same information as -fdump-rtl-sched1 and -fdump-rtl-sched2.
  • For n greater than one, it also outputs basic block probabilities, detailed ready list information, and unit/insn info.
  • For n greater than two, it includes RTL at the abort point, control-flow, and regions info.
  • For n over four, -fsched-verbose also includes dependence info.

โœจ -fenable-kind-pass / -fdisable-kind-pass=range-list

This is a set of options for explicitly disabling and enabling optimization passes ๐Ÿ”ง They're meant for debugging GCC ๐Ÿ› Compiler users should use the regular options for enabling and disabling passes instead ๐Ÿ™

  • -fdisable-ipa-pass โ€” Disables the IPA pass pass, where pass is the pass name. If the same pass is statically invoked in the compiler multiple times, append a sequential number starting from 1 to the pass name.
  • -fdisable-rtl-pass, -fdisable-rtl-pass=range-list โ€” Disables the RTL pass pass, where pass is the pass name. If the same pass is statically invoked multiple times, append a sequential number starting from 1 to the pass name. range-list is a comma-separated list of function ranges or assembler names. Each range is a number pair separated by a colon, and it's inclusive at both ends. If the range is trivial, the number pair can be simplified to a single number. If the function's call graph node's uid falls within one of the specified ranges, the pass is disabled for that function ๐Ÿšซ The uid shows up in the function header of a dump file, and you can dump the pass names with the option -fdump-passes.
  • -fdisable-tree-pass, -fdisable-tree-pass=range-list โ€” Disables the tree pass pass. See -fdisable-rtl for the description of option arguments.
  • -fenable-ipa-pass โ€” Enables the IPA pass pass, where pass is the pass name. If the same pass is statically invoked multiple times, append a sequential number starting from 1 to the pass name.
  • -fenable-rtl-pass, -fenable-rtl-pass=range-list โ€” Enables the RTL pass pass. See -fdisable-rtl for option argument description and examples.
  • -fenable-tree-pass, -fenable-tree-pass=range-list โ€” Enables the tree pass pass. See -fdisable-rtl for the description of option arguments.

Here are some examples showing how to use these options ๐ŸŽ€

# disable ccp1 for all functions
   -fdisable-tree-ccp1
# disable complete unroll for function whose cgraph node uid is 1
   -fenable-tree-cunroll=1
# disable gcse2 for functions at the following ranges [1,1],
# [300,400], and [400,1000]
# disable gcse2 for functions foo and foo2
   -fdisable-rtl-gcse2=foo,foo2
# disable early inlining
   -fdisable-tree-einline
# disable ipa inlining
   -fdisable-ipa-inline
# enable tree full unroll
   -fenable-tree-unroll

โœจ -fchecking / -fchecking=n

Enables internal consistency checking ๐Ÿง The default depends on the compiler configuration. -fchecking=2 enables further internal consistency checking that might affect code generation โš ๏ธ

โœจ -frandom-seed=string

This option 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. You can use -frandom-seed to produce reproducibly identical object files ๐Ÿ’–

The string can be a number (decimal, octal, or hex) or an arbitrary string. An arbitrary string gets converted to a number by computing CRC32 ๐Ÿ”ข

The string should be different for every file you compile ๐Ÿซถ

โœจ -save-temps

Stores the usual "temporary" intermediate files permanently ๐Ÿ“ They get named as auxiliary output files, as specified under -dumpbase and -dumpdir.

When used with the -x command-line option, -save-temps is sensible enough to avoid overwriting an input source file that has the same extension as an intermediate file ๐Ÿง  To get the corresponding intermediate file, rename the source file before using -save-temps.

โœจ -save-temps=cwd

Equivalent to -save-temps -dumpdir ./ ๐Ÿ“‚

โœจ -save-temps=obj

Equivalent to -save-temps -dumpdir outdir/, where outdir/ is the directory of the output file specified after the -o option, including any directory separators ๐Ÿ“‚ If the -o option isn't used, -save-temps=obj behaves like -save-temps=cwd.

โœจ -time[=file]

Reports the CPU time taken by each subprocess in the compilation sequence โฑ๏ธ For C source files, that's the compiler proper and the assembler, plus the linker if linking is done.

Without an output file, the output looks like this:

# cc1 0.12 0.01
# as 0.00 0.01

The first number on each line is the "user time", which is the time spent executing the program itself ๐Ÿง‘ The second number is the "system time", which is the time spent in operating system routines on behalf of the program ๐Ÿ–ฅ๏ธ Both numbers are in seconds โณ

With an output file, the output is appended to the named file and looks like this:

0.12 0.01 cc1 <options>
0.00 0.01 as <options>

The "user time" and "system time" get moved before the program name, and the options passed to the program are displayed. That way you can later tell which file was being compiled and with which options ๐Ÿ“‹

  • -fdump-final-insns[=file] โ€” okay so this one dumps the final internal representation (RTL) into file ๐Ÿ’พ. If you leave the optional argument off (or file is "."), the dump file name gets built by tacking .gkd onto the dump base name. See -dumpbase ๐ŸŒธ
  • -fcompare-debug[=opts] โ€” this one is a whole vibe ๐Ÿ”
    • If no error shows up during compilation, the compiler runs a second time, adding opts and -fcompare-debug-second to the arguments for that second run. Both runs dump the final internal representation, and it prints an error if the two dumps don't match ๐Ÿ’…
    • If you leave off the equal sign, the default -gtoggle gets used โœจ
    • The environment variable GCC_COMPARE_DEBUG ๐ŸŒˆ, if it's defined, non-empty and nonzero, implicitly turns on -fcompare-debug. If it's defined to a string that starts with a dash, that string becomes opts. Otherwise you get the default -gtoggle ๐Ÿซถ
    • -fcompare-debug=, with the equal sign but no opts, is the same as -fno-compare-debug. That turns off the dumping and the second compilation, and it stops even GCC_COMPARE_DEBUG from taking effect ๐Ÿ™ˆ
    • Want full coverage during -fcompare-debug testing? Set GCC_COMPARE_DEBUG to -fcompare-debug-not-overridden. GCC rejects that as an invalid option in any real compilation (preprocessing, assembly or linking don't count) ๐Ÿ’€ Just want a warning instead? Setting GCC_COMPARE_DEBUG to -w%n-fcompare-debug not overridden will do the trick ๐Ÿฆ‹
  • -fcompare-debug-second โ€” this one gets passed to the compiler automatically for the second run that -fcompare-debug asks for ๐ŸŽ€. It comes with options that silence warnings, and it drops any other options that would make the compiler write output to files or to standard output as a side effect. Dump files and preserved temporary files get renamed to include the extra .gk extension during that second run, so they don't overwrite the ones from the first run ๐Ÿงš
    • When you pass this option to the compiler driver, the first compilation gets skipped. That makes it pretty much only useful for debugging the compiler itself ๐Ÿค“
  • -gtoggle โ€” flips debug info generation ๐Ÿ”„. If leaving out this option would generate debug info, it turns it off. Otherwise it turns debug info on at level 2 โญ. Its position on the command line doesn't matter. It takes effect after all the other options are processed, and it only does it once, no matter how many times you give it. It's mainly meant to go with -fcompare-debug ๐Ÿ’œ
  • -fvar-tracking-assignments-toggle โ€” toggles -fvar-tracking-assignments the same way -gtoggle toggles -g ๐Ÿฆ‹
  • -Q โ€” makes the compiler print each function name as it gets compiled, and print some statistics about each pass when it's done ๐Ÿ“Š
  • -ftime-report โ€” makes the compiler print some stats about how much time each pass ate when it finishes โฑ๏ธ
  • -ftime-report-details โ€” records the time used by the 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 n is greater than or equal to 10, the dump output goes to stderr in the same format as n minus 10 ๐Ÿ’–
  • -flto-report โ€” prints a report with internal details on how the link-time optimizer works ๐Ÿ”ง. What's in the report changes from version to version. It's meant for GCC developers who are processing object files in LTO mode (via -flto) ๐Ÿง‘โ€๐Ÿ’ป
    • It's disabled by default ๐Ÿ™…โ€โ™€๏ธ
  • -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 stats about permanent memory allocation when it finishes ๐Ÿง 
  • -fmem-report-wpa โ€” makes the compiler print some stats about permanent memory allocation for the WPA phase only ๐Ÿง 
  • -fpre-ipa-mem-report, -fpost-ipa-mem-report โ€” makes the compiler print some stats about permanent memory allocation either before or after interprocedural optimization ๐Ÿ’…
  • -fprofile-report โ€” makes the compiler print some stats about how consistent the (estimated) profile is and what effect each individual pass had ๐Ÿ“ˆ
  • -fstack-usage โ€” this one gives you stack usage info for your program, function by function ๐Ÿฅž. The dump file name is made by appending .su to the auxname. The auxname comes from the output file's name if you explicitly specified one and it isn't 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 handles the stack in a fixed way. A set number of bytes gets allocated for the frame when the function starts and released when it exits, and the function doesn't do any other stack adjustments. The second field is that fixed number of bytes ๐Ÿงฑ

The "dynamic" qualifier means the function also adjusts the stack inside its body on top of that static allocation. For example, it might push and pop arguments around function calls ๐ŸŽข. If "bounded" is also there, the amount of those adjustments has a compile-time bound, and the second field is an upper bound on the total stack the function uses ๐ŸŽฏ. If "bounded" isn't there, the adjustments aren't bounded at compile time, and the second field only covers the bounded part ๐Ÿ™ƒ

  • -fstats โ€” emits stats about front-end processing at the end of compilation ๐Ÿ“. Only the C++ front end supports this, and the info is mostly only useful to the G++ development team ๐Ÿค“
  • -fdbg-cnt-list โ€” prints the name and the counter upper bound for every debug counter ๐Ÿ“‹
  • -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 it's 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. 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 ๐Ÿ—‚๏ธ. 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 picked 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 -, and there are no spaces between multiple switches. This is supposed to make shell processing easier ๐Ÿš
  • -print-multi-os-directory โ€” prints the path to the OS libraries for the selected multilib, relative to some lib subdirectory ๐Ÿ“š
    • If the OS libraries are in the lib subdirectory and no multilibs are used, this is usually just . ๐Ÿ™‚
    • If the OS libraries are in libsuffix sibling directories, it prints something like ../lib64, ../lib or ../lib32 ๐ŸŒ™
    • If the OS libraries are 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 โ€” same vibe as -print-file-name, but it searches for a program like cpp instead ๐Ÿ”Ž
  • -print-libgcc-file-name โ€” same as -print-file-name=libgcc.a ๐ŸŽ
    • This is super useful when you use -nostdlib or -nodefaultlibs but you still want to link with libgcc.a ๐Ÿซถ. You can do:
gcc -nostdlib <files>... `gcc -print-libgcc-file-name`
  • -print-search-dirs โ€” prints the name of the configured installation directory, plus a list of the program and library directories gcc searches. Then it stops, no extra work ๐Ÿ•ต๏ธโ€โ™€๏ธ
    • This one saves you when gcc throws the error installation problem, cannot exec cpp0: No such file or directory. ๐Ÿ˜ญ. To fix it, you either put cpp0 and the other compiler components where gcc expects them, or you 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 used during compilation ๐Ÿ—บ๏ธ. That's the target sysroot set either at configure time or with the --sysroot option, possibly with an extra suffix that depends on compilation options. If no target sysroot is specified, it prints nothing ๐Ÿคทโ€โ™€๏ธ
  • -print-sysroot-headers-suffix โ€” prints the suffix added to the target sysroot when searching for headers. If the compiler isn't configured with a suffix like that, it gives an error instead. Then it stops, no extra work ๐Ÿ“œ
  • -dumpmachine โ€” prints the compiler's target machine, like i686-pc-linux-gnu, and then stops ๐Ÿ–ฅ๏ธ
  • -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 (the major version), two numbers separated by a dot (major and minor), or three numbers separated by dots (major, minor and patchlevel) ๐Ÿงฎ
  • -dumpfullversion โ€” prints the full compiler version, then stops ๐ŸŽ€. The output is always three numbers separated by dots: major, minor and patchlevel ๐Ÿ’ฏ
  • -dumpspecs โ€” prints the compiler's built-in specs, then stops ๐Ÿ›‘. This is what gets used when GCC itself is being built ๐Ÿ› ๏ธ

๐ŸŒˆ Machine-Dependent Options

Each target machine GCC supports can have its own options. For example, they let you compile for a particular processor variant or ABI, or control optimizations specific to that machine ๐Ÿ’–. By convention, machine-specific option names start with -m ๐Ÿ’œ.

โœจ AArch64 Options โœจ

Okay bestie, these options are defined for AArch64 implementations ๐Ÿฆ‹

  • -mabi=name โ€” pick your data model ๐Ÿ’œ The valid picks are ilp32, the SysV-like model where int, long int and pointers are all 32 bits, and lp64, the 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, the LP64 and ILP32 ABIs are not link-compatible ๐Ÿ˜ญ You have to compile your whole program with the same ABI and link it with a compatible set of libraries, or it'll be a mess.
  • -mbig-endian โ€” generate big-endian code ๐ŸŒˆ This is the default when GCC is configured for an aarch64_be-*-* target.
  • -mgeneral-regs-only โ€” only use the general-purpose registers ๐ŸŽ€ This stops the compiler from touching floating-point and Advanced SIMD registers, but it doesn't put any restrictions on the assembler.
  • -mlittle-endian โ€” generate little-endian code ๐ŸŒธ This is the default when GCC is configured for an aarch64-*-* target but not an aarch64_be-*-* one.
  • -mcmodel=tiny โ€” use the tiny code model ๐Ÿงš The program and its statically defined symbols have to be within 1MB of each other. Programs can be statically or dynamically linked.
  • -mcmodel=small โ€” use the small code model ๐Ÿ’– The program and its statically defined symbols have to be within 4GB of each other. Programs can be statically or dynamically linked. This is the default code model, so you're already in it unless you say otherwise โœจ
  • -mcmodel=large โ€” use the large code model ๐Ÿ‘‘ It makes no assumptions about addresses and section sizes, which is very main character energy. Programs can only be statically linked. Also, -mcmodel=large is incompatible with -mabi=ilp32, -fpic and -fPIC, so don't mix them ๐Ÿ’€
  • -mstrict-align, -mno-strict-align โ€” avoid or allow memory accesses that might not be aligned on a natural object boundary, as the architecture spec describes ๐Ÿ”ฅ
  • -momit-leaf-frame-pointer, -mno-omit-leaf-frame-pointer โ€” omit or keep the frame pointer in leaf functions ๐Ÿฆ‹ Omitting it (the -momit-leaf-frame-pointer behaviour) is the default.
  • -mstack-protector-guard=guard, -mstack-protector-guard-reg=reg, -mstack-protector-guard-offset=offset โ€” generate stack protection code that uses 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 also tell GCC which system register to use as the base register for reading the canary, and what offset from that base register to read from. There's no default register or offset for this, because it's entirely meant for use within the Linux kernel ๐Ÿง

  • -mtls-dialect=desc โ€” use TLS descriptors as the thread-local storage mechanism for dynamic accesses of TLS variables. This is the default โœจ
  • -mtls-dialect=traditional โ€” use traditional TLS as the thread-local storage mechanism for dynamic accesses of TLS variables ๐ŸŒ™
  • -mtls-size=size โ€” set the bit size of immediate TLS offsets. The valid values are 12, 24, 32 and 48. Heads up, this one needs binutils 2.26 or newer ๐Ÿงƒ
  • -mfix-cortex-a53-835769, -mno-fix-cortex-a53-835769 โ€” turn the workaround for ARM Cortex-A53 erratum number 835769 on or off ๐Ÿฉน The workaround inserts a NOP instruction between memory instructions and 64-bit integer multiply-accumulate instructions.
  • -mfix-cortex-a53-843419, -mno-fix-cortex-a53-843419 โ€” turn the workaround for ARM Cortex-A53 erratum number 843419 on or off ๐Ÿฉน This workaround happens at link time, so this option only passes the matching flag along to the linker.
  • -mlow-precision-recip-sqrt, -mno-low-precision-recip-sqrt โ€” turn the reciprocal square root approximation on or off ๐Ÿงฎ This option only does anything if -ffast-math or -funsafe-math-optimizations is used too. When it's on, reciprocal square root results drop to about 16 bits of precision for single precision and 32 bits for double precision.
  • -mlow-precision-sqrt, -mno-low-precision-sqrt โ€” turn the square root approximation on or off ๐Ÿงฎ This option only does anything if -ffast-math or -funsafe-math-optimizations is used too. When it's on, square root results drop to about 16 bits of precision for single precision and 32 bits for double precision. If you enable it, it also implies -mlow-precision-recip-sqrt.
  • -mlow-precision-div, -mno-low-precision-div โ€” turn the division approximation on or off โž— This option only does anything if -ffast-math or -funsafe-math-optimizations is used too. When it's on, division results drop to about 16 bits of precision for single precision and 32 bits for double precision.
  • -mtrack-speculation, -mno-track-speculation โ€” turn on or off the extra code that tracks 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 โ€” turn calls to out-of-line helpers for atomic operations on or off ๐Ÿงต At runtime, these helpers figure out whether the LSE instructions from ARMv8.1-A can be used. If they can't, they fall back to the load/store-exclusive instructions that are in the base ARMv8.0 ISA.

This option only applies when you're 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 chosen CPU supports the lse feature. This option is on by default ๐Ÿ’œ

  • -march=name โ€” pick the target architecture and, optionally, one or more feature modifiers ๐Ÿ—๏ธ This option takes the form -march=arch{+[no]feature}*.

Here's the cheat sheet for the permissible arch values and the features each one turns 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.7-a (Armv8.7-A) โ€” includes by default armv8.6-a, +ls64
  • armv8.8-a (Armv8.8-a) โ€” includes by default armv8.7-a, +mops
  • armv9-a (Armv9-A) โ€” includes by default armv8.5-a, +sve, +sve2
  • armv8-r (Armv8-R) โ€” includes by default armv8-r

The value native is available on native AArch64 GNU/Linux and tells the compiler to pick the architecture of the host system. This option has no effect if the compiler can't recognize the host system's architecture,

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 one wins ๐Ÿ‘‰

GCC uses name to decide what kind of instructions it can emit when generating assembly code. If -march is specified without -mtune or -mcpu also being specified, the code gets tuned to perform well across a range of target processors that implement the target architecture ๐ŸŽฏ

  • -mtune=name โ€” pick the target processor that GCC should tune the performance of your 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,
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,
cortex-x2, cortex-a510, cortex-a710, ampere1, native.

The 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 tell GCC to tune for a big.LITTLE system ๐Ÿฃ๐Ÿ˜

The value neoverse-512tvb tells GCC to tune for Neoverse cores that (a) implement SVE and (b) have a total vector bandwidth of 512 bits per cycle. In other words, it's tuning for Neoverse cores that can run 4 128-bit Advanced SIMD arithmetic instructions a cycle, and 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 described below ๐Ÿ’…

On native AArch64 GNU/Linux systems, the value native also tunes performance to the host system. This option has no effect if the compiler can't recognize the processor of the host system ๐Ÿ–ฅ๏ธ

If none of -mtune=, -mcpu= or -march= are specified, the code gets tuned to perform well across a range of target processors ๐ŸŒˆ

This option can't be suffixed with feature modifiers ๐Ÿ™…

  • -mcpu=name โ€” pick the target processor, optionally with one or more feature modifiers tacked on the end ๐Ÿง  This option takes the form -mcpu=cpu{+[no]feature}*, where the permissible values for cpu are the same as the ones for -mtune. The permissible values for feature are documented in the sub-section on aarch64-feature-modifiers,,-march and -mcpu Feature Modifiers. If you specify conflicting feature modifiers, the right-most one is used ๐Ÿ‘‘

okay so -mcpu= is doing double duty bestie ๐Ÿ’… the name you pick decides which instructions GCC is allowed to emit when it writes the assembly (same job as -march) AND which chip it tunes the code to run fast on (same job as -mtune). ๐Ÿ”ฅ If you also pass -march or -mtune, those win and override that part of -mcpu.

-mcpu=neoverse-512tvb is the main character of this whole list ๐Ÿ‘‘ It is NOT one specific core. It's a whole squad of 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 makes code that can run on a Neoverse V1 core, because V1 is the first Neoverse core with those properties ๐Ÿฆ‹ And unless you override it with -mtune, it tunes your code the same way -mtune=neoverse-512tvb would ๐Ÿ’–
  • -moverride=string โ€” this lets you override the tuning decisions the back-end makes when you use -mtune=. The syntax, semantics, and accepted values for string are NOT guaranteed to stay the same across releases ๐Ÿ’€ It's only really meant for people developing GCC itself ๐Ÿงš
  • -mverbose-cost-dump โ€” turns on verbose cost model dumping in the debug dump files ๐ŸŒˆ This one is just for debugging the compiler ๐Ÿ™ˆ
  • -mpc-relative-literal-loads, -mno-pc-relative-literal-loads โ€” enable or disable PC-relative literal loads โœจ With it 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 valid values are none (turns return address signing off), non-leaf (signs pointers for functions that aren't leaf functions), and all (signs pointers for every function). The default is none. Heads up: this option is deprecated in favor of -mbranch-protection ๐Ÿฅ€
  • -mbranch-protection=none|standard|pac-ret[+leaf+b-key]|bti โ€” picks the branch protection features you want ๐Ÿ›ก๏ธ none is the default and turns off every type of branch protection. standard turns on ALL of them, and for any feature with extra tuning options it sets that to its standard level. pac-ret[+leaf] turns on return address signing at its standard level, signing functions that save the return address to memory (non-leaf functions basically always do this) using the a-key. Add the optional leaf argument to extend the signing to leaf functions too. Add the optional b-key argument to sign with the B-key instead of the A-key. 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: retbr and blr. Also, -mharden-sls=all turns on ALL the SLS hardening, and -mharden-sls=none turns off all of it ๐ŸŒธ
  • -msve-vector-bits=bits โ€” sets the number of bits in an SVE vector register ๐Ÿ’œ It only does anything when SVE is enabled, so don't expect magic without it ๐Ÿ™ƒ

GCC does two flavors of SVE codegen, and this is where it gets lowkey technical. "Vector-length agnostic" output works with ANY size of vector register. "Vector-length specific" output lets GCC make assumptions about the vector length when that helps optimization โœจ The valid values for bits are scalable, 128, 256, 512, 1024, and 2048. scalable gives you vector-length agnostic output. Right now, -msve-vector-bits=128 ALSO gives vector-length agnostic output, but only for big-endian targets. Every other value makes vector-length specific code. These values might change in future releases, so the only one you should count on for code that's portable across different hardware SVE vector lengths is scalable ๐Ÿ˜ญ

The default is -msve-vector-bits=scalable, which makes vector-length agnostic code ๐Ÿงš


โœจ -march and -mcpu Feature Modifiers โœจ

okay now the feature modifiers ๐Ÿฆ‹ You can use any of these with -march and -mcpu, and each one also has an inverse you can write as no plus the feature name.

  • crc โ€” enables the CRC extension ๐ŸŒˆ It's on by default for -march=armv8.1-a.
  • crypto โ€” enables the Crypto extension ๐Ÿ” This also turns on Advanced SIMD and floating-point instructions.
  • fp โ€” enables floating-point instructions ๐Ÿ’– It's on by default for every possible value of -march and -mcpu.
  • simd โ€” enables Advanced SIMD instructions ๐Ÿ”ฅ This also turns on floating-point instructions. It's on by default for every possible value of -march and -mcpu too.
  • sve โ€” enables Scalable Vector Extension instructions ๐ŸŒŠ This also turns on Advanced SIMD and floating-point instructions.
  • lse โ€” enables Large System Extension instructions ๐Ÿ’… It's on by default for -march=armv8.1-a.
  • rdma โ€” enables Round Double Multiply Accumulate instructions ๐Ÿ“ It's on by default for -march=armv8.1-a.
  • fp16 โ€” enables the FP16 extension โœจ This also turns on floating-point instructions.
  • fp16fml โ€” enables the FP16 fmla extension ๐ŸŽ€ This also turns on the FP16 extensions and floating-point instructions. It's enabled by default for -march=armv8.4-a. Using this with architectures before Armv8.2-A is NOT supported.
  • rcpc โ€” enables the RcPc extension ๐Ÿซถ This doesn't change the code GCC generates. It just gets passed along to the assembler, so inline asm statements can use RcPc instructions.
  • dotprod โ€” enables the Dot Product extension ๐Ÿ’œ This also turns on Advanced SIMD instructions.
  • aes โ€” enables the Armv8-a aes and pmull crypto extension ๐ŸŒธ This also turns on Advanced SIMD instructions.
  • sha2 โ€” enables the Armv8-a sha2 crypto extension ๐Ÿ“ This also turns on Advanced SIMD instructions.
  • sha3 โ€” enables the sha512 and sha3 crypto extension ๐Ÿ”ฎ This also turns on Advanced SIMD instructions. Using this with architectures before Armv8.2-A is NOT supported.
  • sm4 โ€” enables the sm3 and sm4 crypto extension ๐Ÿฆ‹ This also turns on Advanced SIMD instructions. Using this with architectures before Armv8.2-A is NOT supported.
  • profile โ€” enables the Statistical Profiling extension ๐Ÿ“Š This is only to switch the extension on at the assembler level and doesn't affect code generation.
  • rng โ€” enables the Armv8.5-a Random Number instructions ๐ŸŽฒ Same deal: it's only for the assembler and doesn't affect code generation.
  • memtag โ€” enables the Armv8.5-a Memory Tagging Extensions ๐Ÿท๏ธ Using this with architectures before Armv8.5-A is NOT supported.
  • sb โ€” enables the Armv8-a Speculation Barrier instruction ๐Ÿงฑ This is only for the assembler and doesn't affect code generation. It's enabled by default for -march=armv8.5-a.
  • ssbs โ€” enables the Armv8-a Speculative Store Bypass Safe instruction ๐Ÿ›ก๏ธ This is only for the assembler and doesn't affect code generation. It's enabled by default for -march=armv8.5-a.
  • predres โ€” enables the Armv8-a Execution and Data Prediction Restriction instructions ๐Ÿ™ˆ This is only for the assembler and doesn't affect code generation. It's enabled by default for -march=armv8.5-a.
  • sve2 โ€” enables the Armv8-a Scalable Vector Extension 2 โœจ This also turns on SVE instructions.
  • sve2-bitperm โ€” enables SVE2 bitperm instructions ๐Ÿ’… This also turns on SVE2 instructions.
  • sve2-sm4 โ€” enables SVE2 sm4 instructions ๐ŸŒˆ This also turns on SVE2 instructions.
  • sve2-aes โ€” enables SVE2 aes instructions ๐Ÿ” This also turns on SVE2 instructions.
  • sve2-sha3 โ€” enables SVE2 sha3 instructions ๐Ÿฆ‹ This also turns on SVE2 instructions.
  • tme โ€” enables the Transactional Memory Extension ๐Ÿง 
  • i8mm โ€” enables 8-bit Integer Matrix Multiply instructions ๐Ÿ“ This also turns on Advanced SIMD and floating-point instructions. It's enabled by default for -march=armv8.6-a. Using this with architectures before Armv8.2-A is NOT supported.
  • f32mm โ€” enables 32-bit Floating point Matrix Multiply instructions ๐ŸŒธ This also turns on SVE instructions. Using this with architectures before Armv8.2-A is NOT supported.
  • f64mm โ€” enables 64-bit Floating point Matrix Multiply instructions ๐Ÿ’œ This also turns on SVE instructions. Using this with architectures before Armv8.2-A is NOT supported.
  • bf16 โ€” enables brain half-precision floating-point instructions ๐Ÿง  This also turns on Advanced SIMD and floating-point instructions. It's enabled by default for -march=armv8.6-a. Using this with architectures before Armv8.2-A is NOT supported.
  • ls64 โ€” enables the 64-byte atomic load and store instructions for accelerators ๐Ÿš€ It's enabled by default for -march=armv8.7-a.
  • mops โ€” enables the instructions that speed up memory operations like "memcpy", "memmove", "memset" ๐Ÿงน It's enabled by default for -march=armv8.8-a.
  • flagm โ€” enables the Flag Manipulation instructions Extension ๐Ÿ
  • pauth โ€” enables the Pointer Authentication Extension ๐Ÿ”‘

Feature crypto implies aes, sha2, and simd, which implies fp. Going the other way, nofp implies nosimd, which implies nocrypto, noaes and nosha2 ๐Ÿ’€ Lots of chain reactions here, bestie ๐Ÿซ 


๐ŸŒธ Adapteva Epiphany Options ๐ŸŒธ

these -m options are defined for Adapteva Epiphany ๐Ÿงš

  • -mhalf-reg-file โ€” don't allocate any register in the range "r32"..."r63" ๐Ÿ“ That lets your code run on hardware variants that don't have those registers.
  • -mprefer-short-insn-regs โ€” prefers allocating registers that allow short instruction generation โœจ Heads up: this can increase 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 ๐Ÿ’– This cost is only a heuristic and isn't guaranteed to give consistent results across releases.
  • -mcmove โ€” enables the generation of conditional moves ๐Ÿฆ‹
  • -mnops=num โ€” emits num NOPs before every other generated instruction ๐ŸŒˆ

๐Ÿฆ‹ -mno-soft-cmpsf ๐Ÿฆ‹

  • -mno-soft-cmpsf โ€” ๐Ÿ’… For single-precision floating-point comparisons, this one emits an fsub instruction and tests the flags instead. It's faster than a software comparison โœจ, but it can give you incorrect results with NaNs ๐Ÿ’€, or when two different small numbers get compared and their difference comes out as zero ๐Ÿ™ˆ. The default is -msoft-cmpsf, which is slower but IEEE-compliant ๐Ÿซถ.
  • -mstack-offset=num โ€” ๐Ÿงš Sets the offset between the top of the stack and the stack pointer. 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 one the libraries were built with generally does not work ๐Ÿšจ. It can be useful if you want to check whether a different stack offset gives you better code ๐Ÿ‘€, but to actually build working programs with one, it's recommended to configure the toolchain with the appropriate --with-stack-offset=num option ๐Ÿ’–.
  • -mno-round-nearest โ€” ๐ŸŒธ Makes the scheduler assume the rounding mode has been set to truncating. The default is -mround-nearest.
  • -mlong-calls โ€” ๐Ÿ“ If an attribute doesn't say otherwise, this assumes every call might be beyond the offset range of the b / bl instructions. So it loads the function address into a register before making a (otherwise direct) call. This is the default ๐Ÿ‘‘.
  • -mshort-calls โ€” ๐Ÿฆ‹ If an attribute doesn't say otherwise, this assumes all direct calls are within range of the b / bl instructions, so those instructions get used for direct calls. The default is -mlong-calls.
  • -msmall16 โ€” โœจ Assumes addresses can be loaded as 16-bit unsigned values. This doesn't apply to function addresses where -mlong-calls semantics are in effect.
  • -mfp-mode=mode โ€” ๐ŸŽ€ Sets the prevailing mode of the floating-point unit. This decides which floating-point mode gets provided and expected at function call and return time. Matching it to the mode you predominantly need at function start can make your programs smaller and faster by avoiding unnecessary mode switches ๐Ÿ”ฅ

mode can be set to one of the following values:

  • caller โ€” ๐Ÿง Any mode at function entry is valid, and it gets retained or restored when the function returns and when it calls other functions. This is great for compiling libraries or other compilation units you might want to drop into different programs with different prevailing FPU modes ๐ŸŒˆ. The convenience of a single object file outweighs the extra size and speed overhead of any mode switching that might be needed, compared with a more specific choice of prevailing FPU mode.
  • truncate โ€” ๐Ÿ’ The mode used for floating-point calculations with truncating (round towards zero) rounding. That includes conversion from floating point to integer.
  • round-nearest โ€” ๐Ÿ’œ The mode used for floating-point calculations with round-to-nearest-or-even rounding.
  • int โ€” ๐Ÿงฎ The mode used to perform integer calculations in the FPU, like 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. This is an ABI change, even though many library function interfaces are unaffected if they don't use SIMD vector modes in places that affect the size and/or alignment of the 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 have an impact on 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. At present this option is a placeholder for support that is not yet implemented ๐Ÿšง.

๐ŸŒธ ARC Options ๐ŸŒธ

The following options control the architecture variant that code is being compiled for ๐Ÿงš.

  • -mbarrel-shifter โ€” ๐Ÿ”„ Generates instructions supported by the barrel shifter. This is the default unless -mcpu=ARC601 or -mcpu=ARCEM is in effect.
  • -mjli-always โ€” ๐Ÿ“ž Forces a function to be called using the jli_s instruction. This option is valid only for the ARCv2 architecture.
  • -mcpu=cpu โ€” ๐Ÿง  Sets the architecture type, register usage, and instruction scheduling parameters for cpu. There are also shortcut alias options for backward compatibility and convenience ๐Ÿ’–. Supported values for cpu are:
    • arc600 โ€” ๐ŸŒฑ 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 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. Currently only divaw, adds, subs, and sat16 are supported. Only valid for -mcpu=ARC700 ๐Ÿ’….
  • -mno-mpy โ€” ๐Ÿ™… Does not generate mpy-family instructions for ARC700. This option is deprecated ๐Ÿ’€.
  • -mmul32x16 โ€” โœ–๏ธ Generates 32x16-bit multiply and multiply-accumulate instructions.
  • -mmul64 โ€” โœ–๏ธ Generates mul64 and mulu64 instructions. Only valid for -mcpu=ARC600.
  • -mnorm โ€” ๐Ÿงช Generates norm instructions. This is the default if -mcpu=ARC700 is in effect.
  • -mspfp, -mspfp-compact โ€” ๐ŸŽฏ Generates single-precision FPX instructions, tuned for the compact implementation.
  • -mspfp-fast โ€” โšก Generates single-precision FPX instructions, tuned for the fast implementation.
  • -msimd โ€” ๐ŸŒˆ Enables generation of ARC SIMD instructions via target-specific builtins. Only valid for -mcpu=ARC700.
  • -msoft-float โ€” ๐Ÿซฅ This option is ignored; it's only provided for compatibility purposes. Software floating-point code is emitted by default, and this default can be overridden by FPX options: -mspfp, -mspfp-compact, or -mspfp-fast for single precision, and -mdpfp, -mdpfp-compact, or -mdpfp-fast for double precision ๐Ÿคทโ€โ™€๏ธ.
  • -mswap โ€” ๐Ÿ”€ Generates swap instructions.
  • -matomic โ€” โš›๏ธ Enables use of the locked load/store conditional extension to implement atomic memory built-in functions. Not available for ARC 6xx or ARC EM cores ๐Ÿ™…โ€โ™€๏ธ.
  • -mdiv-rem โ€” โž— Enables div and rem instructions for ARCv2 cores.

Okay so bestie, the ARC options are where things get spicy ๐Ÿ”ฅ. Some of these are on by default for specific chips, some are deprecated and need to be retired gracefully ๐Ÿฅ€, and the multiplier list is basically a menu of hardware vibes ๐Ÿ’…

  • -mcode-density โ€” turns on code density instructions for ARC EM โœจ. It's already on by default for ARC HS ๐Ÿซถ
  • -mll64 โ€” unlocks double load/store operations for ARC HS cores ๐Ÿ’ช
  • -mtp-regno=regno โ€” picks the thread pointer register number ๐Ÿงต
  • -mmpy-option=multo โ€” picks the multiplier design for ARCv2 code ๐ŸŒธ. You can pass multo as a string or a number, and the default is wlh1 ๐Ÿ‘‘. Here's the lineup:
    • 0 or none โ€” no multiplier at all ๐Ÿ’€
    • 1 or w โ€” 16x16 multiplier, fully pipelined ๐Ÿฆ‹. Turns on "mpyw" and "mpyuw".
    • 2 or wlh1 โ€” 32x32 multiplier, fully pipelined with 1 stage ๐Ÿ’– (this is the default โœจ). Also turns on "mpy", "mpyu", "mpym", "mpymu", and "mpy_s".
    • 3 or wlh2 โ€” 32x32 multiplier, fully pipelined with 2 stages ๐ŸŒˆ. Also turns on "mpy", "mpyu", "mpym", "mpymu", and "mpy_s".
    • 4 or wlh3 โ€” two 16x16 multipliers, blocking and sequential ๐Ÿงš. Also turns on "mpy", "mpyu", "mpym", "mpymu", and "mpy_s".
    • 5 or wlh4 โ€” one 16x16 multiplier, blocking and sequential ๐Ÿ“. Also turns on "mpy", "mpyu", "mpym", "mpymu", and "mpy_s".
    • 6 or wlh5 โ€” one 32x4 multiplier, blocking and sequential ๐Ÿซง. Also turns on "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 ๐Ÿ”ฅ

Heads up, this option is only for ARCv2 cores โš ๏ธ

  • -mfpu=fpu โ€” turns on floating-point hardware extensions for ARCv2 cores ๐Ÿฆ‹. These are the valid fpu values:
    • fpus โ€” single-precision floating-point โœจ
    • fpud โ€” double-precision floating-point ๐Ÿ’œ. Single-precision is switched on too. Not available for ARC EM ๐Ÿ™…
    • fpuda โ€” double-precision using the double-precision assist instructions ๐ŸŒธ. Single-precision is also on. ARC EM only.
    • fpuda_div โ€” same double-precision assist vibes as fpuda ๐ŸŒธ, plus the single-precision, square-root, and divide extensions. ARC EM only.
    • fpuda_fma โ€” same double-precision assist vibes as fpuda ๐ŸŒธ, plus single-precision and fused multiply and add. ARC EM only.
    • fpuda_all โ€” same double-precision assist vibes as fpuda ๐ŸŒธ, and all single-precision extensions are on. ARC EM only.
    • fpus_div โ€” single-precision, plus square-root and divide ๐Ÿงฎ
    • fpud_div โ€” double-precision, plus square-root and divide. This one includes fpus_div. Not available for ARC EM ๐Ÿ™…
    • fpus_fma โ€” single-precision, plus fused multiply and add ๐Ÿ“
    • fpud_fma โ€” double-precision, plus fused multiply and add. This one includes fpus_fma. Not available for ARC EM ๐Ÿ™…
    • fpus_all โ€” every single-precision floating-point extension ๐Ÿ‘‘
    • fpud_all โ€” every single- and double-precision floating-point extension. Not available for ARC EM ๐Ÿ™…
  • -mirq-ctrl-saved=register-range, blink, lp_count โ€” picks which general-purpose registers the processor auto saves and restores on interrupt entry and exit ๐Ÿซถ. The register-range is two registers joined by a dash. It always starts at "r0", and the upper limit is the "fp" register. blink and lp_count are optional. This option only works for ARC EM and ARC HS cores ๐Ÿ’…
  • -mrgf-banked-regs=number โ€” sets how many registers get copied into the second register bank when a fast interrupt fires ๐Ÿšจ. Fast interrupts are the ones at the highest priority level, P0. They only save PC and STATUS32 so there are no memory transactions on entry or exit ๐Ÿงš. Use this when you're running fast interrupts on an ARC V2 family processor. Allowed 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 locked at 32 bits ๐Ÿ”’. If the width is less than 32, the compiler won't turn your loops into the zero-delay loop mechanism unless it knows "lp_count" can actually hold the loop counter value ๐Ÿ™ˆ. Depending on the width, the compiler and run-time library might still use the loop mechanism for other stuff. This option also defines the macro "__ARC_LPC_WIDTH__" with the value of width โœจ
  • -mrf16 โ€” tells the compiler to generate code for a 16-entry register file ๐ŸŒท. This also defines the "__ARC_RF16__" preprocessor macro ๐Ÿซง
  • -mbranch-index โ€” lets the compiler use "bi" or "bih" instructions to build jump tables ๐Ÿฆ‹

๐Ÿงš Passed to the assembler too

These options get handed down to the assembler, and they also define preprocessor macro symbols. Double duty, iykyk ๐Ÿ’…

  • -mdsp-packa โ€” passed to the assembler to turn on the DSP Pack A extensions โœจ. Also sets the __Xdsp_packa preprocessor symbol. This option is deprecated ๐Ÿฅ€
  • -mdvbf โ€” passed to the assembler to turn on the dual Viterbi butterfly extension ๐Ÿฆ‹. Also sets the __Xdvbf preprocessor symbol. This option is deprecated ๐Ÿฅ€
  • -mlock โ€” passed to the assembler to turn on the locked load/store conditional extension ๐Ÿ”. Also sets the __Xlock preprocessor symbol
  • -mmac-d16 โ€” passed to the assembler ๐Ÿงต. Also sets the __Xxmac_d16 preprocessor symbol. This option is deprecated ๐Ÿฅ€
  • -mmac-24 โ€” passed to the assembler ๐Ÿงต. Also sets the __Xxmac_24 preprocessor symbol. This option is deprecated ๐Ÿฅ€
  • -mrtsc โ€” passed to the assembler to turn on the 64-bit time-stamp counter extension instruction โฐ. Also sets the __Xrtsc preprocessor symbol. This option is deprecated ๐Ÿฅ€
  • -mswape โ€” passed to the assembler to turn on the swap byte ordering extension instruction ๐Ÿ”„. Also sets the __Xswape preprocessor symbol
  • -mtelephony โ€” passed to the assembler to turn on dual- and single-operand instructions for telephony ๐Ÿ“ž. Also sets the __Xtelephony preprocessor symbol. This option is deprecated ๐Ÿฅ€
  • -mxy โ€” passed to the assembler to turn on the XY memory extension ๐Ÿง . Also sets the __Xxy preprocessor symbol

๐Ÿ“ Assembly annotations

These ones control how your assembly code gets annotated ๐ŸŽ€

  • -misize โ€” annotates assembler instructions with estimated addresses ๐Ÿ“
  • -mannotate-align โ€” explains what alignment considerations led to deciding whether an instruction is short or long ๐Ÿง

๐Ÿ”— Passed to the linker

  • -marclinux โ€” passed to the linker to use the "arclinux" emulation ๐Ÿง. This is on by default in tool chains built for "arc-linux-uclibc" and "arceb-linux-uclibc" targets when profiling isn't requested โœจ
  • -marclinux_prof โ€” passed to the linker to use the "arclinux_prof" emulation ๐Ÿ“Š. This is on by default in tool chains built for "arc-linux-uclibc" and "arceb-linux-uclibc" targets when profiling is requested ๐Ÿ’œ

๐ŸŒˆ Shaping the generated code

  • -mlong-calls โ€” generates calls as register indirect calls, so you get the full 32-bit address range ๐Ÿš€
  • -mmedium-calls โ€” don't use anything less than a 25-bit addressing range for calls ๐Ÿ“. That's the offset an unconditional branch-and-link instruction gets. Conditional execution of function calls is suppressed so the 25-bit range can be used, instead of the 21-bit range you'd get with conditional branch-and-link. This is the default for tool chains built for "arc-linux-uclibc" and "arceb-linux-uclibc" targets ๐Ÿ’–
  • -G num โ€” puts definitions of externally-visible data in a small data section, as long as that data is no bigger than num bytes ๐Ÿงธ. The default num is 4 for any ARC configuration, or 8 when you have double load/store operations ๐ŸŽ€
  • -mno-sdata โ€” no sdata references get generated ๐Ÿ™…. 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 ๐Ÿ’…
  • -mno-volatile-cache โ€” enables cache bypass for volatile references ๐Ÿƒโ€โ™€๏ธ

๐ŸŽ›๏ธ Fine-tuning the codegen

  • -malign-call โ€” does nothing at all ๐Ÿซ . It's only kept around for backward compatibility
  • -mauto-modify-reg โ€” enables pre/post modify with register displacement ๐Ÿฆ‹
  • -mbbit-peephole โ€” enables bbit peephole2 ๐Ÿ”
  • -mno-brcc โ€” disables a target-specific pass in arc_reorg that would generate compare-and-branch ("brcc") instructions ๐Ÿšซ. It doesn't affect those instructions when they're driven by the combiner pass ๐Ÿซถ
  • -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. This option is deprecated ๐Ÿฅ€
  • -mno-cond-exec โ€” disables the ARCompact-specific pass that generates conditional execution instructions ๐Ÿ™…โ€โ™€๏ธ

Okay so the ARC conditional execution thing is a whole mood ๐Ÿ’… Delay slot scheduling, operand numbers, literal sizes, instruction lengths, and conditional execution support all bump into each other, so the target-independent pass that generates conditional execution is often lacking ๐Ÿ˜ญ. That's why the ARC port keeps a special pass that goes hunting for more conditional execution opportunities after register allocation, branch shortening, and delay slot scheduling are done โœจ. It generally, but not always, improves performance and code size, at the cost of extra compilation time, so there's an option to switch it off ๐Ÿ™ˆ. If call instructions are going over their allowable offset range because they got conditionalized, bestie, 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. ngl this one is deprecated ๐Ÿ’€
  • -mindexed-loads โ€” Enables indexed loads. Lowkey problematic, because some optimizers then assume indexed stores exist, and they really don't ๐Ÿ™ƒ
  • -mlra โ€” Enables Local Register Allocation ๐Ÿฆ‹ It's 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 are often shortened by calling a special function in libgcc. That's a millicode call ๐Ÿงš These calls can cause performance issues, and/or linking issues when you link in a nonstandard way, so this option lets you turn millicode call generation on or off ๐Ÿ‘‘
  • -mcode-density-frame โ€” Enables the compiler to emit enter and leave instructions. These are only valid for CPUs with the code-density feature ๐ŸŒˆ
  • -mmixed-code โ€” Does nothing. It's only here for backward compatibility ๐Ÿซ 
  • -mq-class โ€” Deprecated, bestie. Enables q instruction alternatives. This is the default for -Os ๐Ÿ“
  • -mRcq โ€” Enables Rcq constraint handling. Most short code generation depends on this, and it's the default ๐Ÿ’–
  • -mRcw โ€” Enables Rcw constraint handling. Most ccfsm condexec mostly depends on this, and it's the default ๐Ÿ’…
  • -msize-level=level โ€” Fine-tunes size optimization with regards to instruction lengths and alignment. The recognized values for level are:
    • 0 โ€” No size optimization. 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, when this isn't set, the behavior is equivalent to level 1 ๐Ÿซถ

  • -mtune=cpu โ€” Sets instruction scheduling parameters for cpu, overriding anything 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 โ€” Does nothing. Preserved for backward compatibility ๐Ÿ’€

The following options are maintained for backward compatibility, but they're now deprecated and will be removed in a future release. Not the vibe, so don't start new code with them ๐Ÿ™…โ€โ™€๏ธ

  • -margonaut โ€” Obsolete FPX ๐Ÿ’€
  • -mbig-endian, -EB โ€” Compiles code for big-endian targets. Using these 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. Using these 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, so if you're targeting ARM, these are your people ๐Ÿซถ

  • -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 complies with the ARM Procedure Call Standard for all functions, even if that isn't strictly necessary for the code to run correctly ๐Ÿงฑ Specifying -fomit-frame-pointer with this option causes stack frames not to be generated for leaf functions. The default is -mno-apcs-frame. Deprecated ๐Ÿ’€
  • -mapcs โ€” A synonym for -mapcs-frame, and also deprecated ๐Ÿ™ƒ
  • -mthumb-interwork โ€” Generates code that supports calling between the ARM and Thumb instruction sets. Without this option, on pre-v5 architectures, the two instruction sets can't be reliably used inside one program ๐Ÿ˜ฌ The default is -mno-thumb-interwork, since slightly larger code 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 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 that info 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 makes GCC generate output containing library calls for floating-point operations. softfp allows code generation 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.

โš ๏ธ Hard-float and soft-float ABIs are not link-compatible. Compile your whole program with the same ABI, and link with a compatible set of libraries, or it's a total mess ๐Ÿ’€
  • -mgeneral-regs-only โ€” Generates code that uses only the general-purpose registers. This prevents the compiler from using floating-point and Advanced SIMD registers, but it won'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 depends on the selected target architecture. For ARMv6 and later architectures the default is BE8; 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 โœจ

Permissible names are: armv4t, armv5t, armv5te, armv6, armv6j, armv6k, armv6kz, armv6t2, armv6z, armv6zk, armv7, armv7-a, armv7ve, armv8-a, armv8.1-a, armv8.2-a, armv8.3-a, armv8.4-a, armv8.5-a, armv8.6-a, armv9-a, armv7-r, armv8-r, armv6-m, armv6s-m, armv7-m, armv7e-m, armv8-m.base, armv8-m.main, armv8.1-m.main, armv9-a, iwmmxt and iwmmxt2 ๐ŸŒˆ

Additionally, the following architectures, which lack support for the Thumb execution state, are recognized but support is deprecated: armv4 ๐Ÿฅ€

Many of the architectures support extensions. You can add these by appending +extension to the architecture name. Extension options are processed in order and capabilities accumulate. An extension will also enable any necessary base extensions it depends on. For example, the +crypto extension will always enable the +simd extension ๐Ÿงฉ The exception to the additive construction is for extensions prefixed with +no...: these extensions disable the specified option and any other extensions that may depend on the presence of that extension ๐Ÿšซ

For example, -march=armv7-a+simd+nofp+vfpv4 is equivalent to writing -march=armv7-a+vfpv4, since the +simd option is entirely disabled by the +nofp option that follows it ๐Ÿง 

Most extension names are generically named, but their effect depends on the architecture they're applied to. For example, the +simd option can be applied to both armv7-a and armv8-a architectures, but it will enable the original ARMv7-A Advanced SIMD (Neon) extensions for armv7-a and the ARMv8-A variant for armv8-a ๐Ÿ‘‘

The table below lists the supported extensions for each architecture. Architectures not mentioned do not support any extensions ๐Ÿ’œ

okay bestie, the ARM list keeps going and it's giving main character energy ๐Ÿ’– these are the architectures and the extra bits you can bolt on with +. ๐Ÿงš

  • armv5te, armv6, armv6j, armv6k, armv6kz, armv6t2, armv6z, armv6zk ๐ŸŒธ these all share the extras listed below, so you're basically getting the same fit in a bunch of colourways
    • +fp โ€” the VFPv2 floating-point instructions, lowkey iconic. You can also write +vfpv2 and it means the exact same thing ๐ŸŽ€
    • +nofp โ€” switches the floating-point instructions off ๐Ÿ™…โ€โ™€๏ธ
  • armv7 โ€” the common subset shared by ARMv7-A, ARMv7-R and ARMv7-M, so it's the girl-group version of the family ๐Ÿ‘‘
    • +fp โ€” the VFPv3 floating-point instructions, with 16 double-precision registers ๐Ÿ’… +vfpv3-d16 works as an alias here. Heads up though: the base ARMv7-M doesn't support floating-point, but it does vibe with both ARMv7-A and ARMv7-R โœจ
    • +nofp โ€” turns the floating-point instructions off ๐Ÿ™ˆ
  • armv7-a ๐Ÿฆ‹ the full glam version, with a whole buffet of extras
    • +mp โ€” the multiprocessing extension ๐Ÿซถ
    • +sec โ€” the security extension, very protective energy ๐Ÿ”’
    • +fp โ€” the VFPv3 floating-point instructions with 16 double-precision registers. +vfpv3-d16 can be used as an alias ๐Ÿ’–
    • +simd โ€” the Advanced SIMD (Neon) v1 plus the VFPv3 floating-point instructions. +neon and +neon-vfpv3 are both aliases for this one ๐Ÿ”ฅ
    • +vfpv3 โ€” the VFPv3 floating-point instructions, but now with 32 double-precision registers ๐ŸŒˆ
    • +vfpv3-d16-fp16 โ€” VFPv3 floating-point with 16 double-precision registers, plus the half-precision floating-point conversion operations โœจ
    • +vfpv3-fp16 โ€” VFPv3 floating-point with 32 double-precision registers, plus those same half-precision conversion operations ๐Ÿ’œ
    • +vfpv4-d16 โ€” the VFPv4 floating-point instructions with 16 double-precision registers ๐Ÿ“
    • +vfpv4 โ€” the VFPv4 floating-point instructions with 32 double-precision registers ๐Ÿ’…
    • +neon-fp16 โ€” Advanced SIMD (Neon) v1 and VFPv3 floating-point instructions, with the half-precision conversion operations included ๐Ÿงš
    • +neon-vfpv4 โ€” Advanced SIMD (Neon) v2 and VFPv4 floating-point instructions ๐Ÿ‘‘
    • +nosimd โ€” switches off the Advanced SIMD instructions. Floating-point is still on, though, so don't panic ๐Ÿ™…โ€โ™€๏ธ
    • +nofp โ€” switches off the floating-point and Advanced SIMD instructions ๐Ÿ’€
  • armv7ve โ€” the extended ARMv7-A architecture, with support for virtualization. Very put-together ๐ŸŒธ
    • +fp โ€” the VFPv4 floating-point instructions with 16 double-precision registers. +vfpv4-d16 can be used as an alias ๐Ÿ’–
    • +simd โ€” Advanced SIMD (Neon) v2 plus the VFPv4 floating-point instructions. +neon-vfpv4 can be used as an alias for this one ๐Ÿ”ฅ
    • +vfpv3-d16 โ€” the VFPv3 floating-point instructions with 16 double-precision registers ๐Ÿฆ‹
    • +vfpv3 โ€” the VFPv3 floating-point instructions with 32 double-precision registers โœจ
    • +vfpv3-d16-fp16 โ€” VFPv3 with 16 double-precision registers, plus the half-precision conversion operations ๐ŸŽ€
    • +vfpv3-fp16 โ€” VFPv3 with 32 double-precision registers, plus the half-precision conversion operations ๐ŸŒˆ
    • +vfpv4-d16 โ€” the VFPv4 floating-point instructions with 16 double-precision registers ๐Ÿ“
    • +vfpv4 โ€” the VFPv4 floating-point instructions with 32 double-precision registers ๐Ÿ’…
    • +neon โ€” Advanced SIMD (Neon) v1 plus VFPv3 floating-point instructions. +neon-vfpv3 can be used as an alias ๐Ÿงš
    • +neon-fp16 โ€” Advanced SIMD (Neon) v1 and VFPv3 floating-point instructions, with the half-precision conversion operations ๐Ÿ‘‘
    • +nosimd โ€” disables the Advanced SIMD instructions, but floating point stays on ๐Ÿ™ˆ
    • +nofp โ€” disables the floating-point and Advanced SIMD instructions ๐Ÿ’€
  • armv8-a ๐Ÿ’œ the ARMv8 era has entered the chat
    • +crc โ€” the Cyclic Redundancy Check (CRC) instructions ๐Ÿ”ฅ
    • +simd โ€” the ARMv8-A Advanced SIMD and floating-point instructions ๐ŸŒธ
    • +crypto โ€” the cryptographic instructions ๐Ÿ”’
    • +nocrypto โ€” disables the cryptographic instructions ๐Ÿ™…โ€โ™€๏ธ
    • +nofp โ€” disables the floating-point, Advanced SIMD and cryptographic instructions. Full clear-out ๐Ÿ’€
    • +sb โ€” the Speculation Barrier instruction โœจ
    • +predres โ€” the Execution and Data Prediction Restriction instructions ๐Ÿซถ
  • armv8.1-a ๐Ÿฆ‹
    • +simd โ€” the ARMv8.1-A Advanced SIMD and floating-point instructions ๐Ÿ’–
    • +crypto โ€” the cryptographic instructions. This one also turns on the Advanced SIMD and floating-point instructions, so it's a package deal ๐ŸŽ€
    • +nocrypto โ€” disables the cryptographic instructions ๐Ÿ™…โ€โ™€๏ธ
    • +nofp โ€” disables the floating-point, Advanced SIMD and cryptographic instructions ๐Ÿ’€
    • +sb โ€” the Speculation Barrier instruction ๐ŸŒˆ
    • +predres โ€” the Execution and Data Prediction Restriction instructions ๐Ÿงš
  • armv8.2-a, armv8.3-a ๐Ÿ‘‘ these two share the extras below
    • +fp16 โ€” the half-precision floating-point data processing instructions. This also enables the Advanced SIMD and floating-point instructions ๐Ÿ”ฅ
    • +fp16fml โ€” the half-precision floating-point fmla extension. This also enables the half-precision floating-point extension, plus Advanced SIMD and floating-point instructions ๐Ÿ’…
    • +simd โ€” the ARMv8.1-A Advanced SIMD and floating-point instructions ๐ŸŒธ
    • +crypto โ€” the cryptographic instructions. This also enables the Advanced SIMD and floating-point instructions ๐Ÿ”’
    • +dotprod โ€” enables the Dot Product extension. This also turns on Advanced SIMD instructions โœจ
    • +nocrypto โ€” disables the cryptographic extension ๐Ÿ™…โ€โ™€๏ธ
    • +nofp โ€” disables the floating-point, Advanced SIMD and cryptographic instructions ๐Ÿ’€
    • +sb โ€” the Speculation Barrier instruction ๐Ÿซถ
    • +predres โ€” the Execution and Data Prediction Restriction instructions ๐ŸŒˆ
    • +i8mm โ€” the 8-bit Integer Matrix Multiply instructions. This also enables Advanced SIMD and floating-point instructions ๐Ÿ“
    • +bf16 โ€” the Brain half-precision floating-point instructions. This also enables Advanced SIMD and floating-point instructions ๐Ÿ’œ
  • armv8.4-a ๐ŸŒธ the glow-up continues
    • +fp16 โ€” the half-precision floating-point data processing instructions. This also enables the Advanced SIMD and floating-point instructions, plus the Dot Product extension and the half-precision floating-point fmla extension ๐Ÿ”ฅ
    • +simd โ€” the ARMv8.3-A Advanced SIMD and floating-point instructions, plus the Dot Product extension ๐Ÿ’–
    • +crypto โ€” the cryptographic instructions. This also enables the Advanced SIMD and floating-point instructions, plus the Dot Product extension ๐Ÿ”’
    • +nocrypto โ€” disables the cryptographic extension ๐Ÿ™…โ€โ™€๏ธ
    • +nofp โ€” disables the floating-point, Advanced SIMD and cryptographic instructions ๐Ÿ’€
    • +sb โ€” the Speculation Barrier instruction โœจ
    • +predres โ€” the Execution and Data Prediction Restriction instructions ๐Ÿซถ
    • +i8mm โ€” the 8-bit Integer Matrix Multiply instructions. This also enables Advanced SIMD and floating-point instructions ๐Ÿงš
    • +bf16 โ€” the 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, plus the Dot Product extension and the half-precision floating-point fmla extension ๐Ÿ”ฅ
    • +simd โ€” the ARMv8.3-A Advanced SIMD and floating-point instructions, plus the Dot Product extension ๐Ÿ’…
    • +crypto โ€” the cryptographic instructions. This also enables the Advanced SIMD and floating-point instructions, plus the Dot Product extension ๐Ÿ”’
    • +nocrypto โ€” disables the cryptographic extension ๐Ÿ™…โ€โ™€๏ธ
    • +nofp โ€” disables the floating-point, Advanced SIMD and cryptographic instructions ๐Ÿ’€
    • +i8mm โ€” the 8-bit Integer Matrix Multiply instructions. This also enables Advanced SIMD and floating-point instructions ๐Ÿ“
    • +bf16 โ€” the Brain half-precision floating-point instructions. This also enables Advanced SIMD and floating-point instructions ๐Ÿ’œ
  • armv8.6-a ๐Ÿ‘‘ the latest and greatest on this list
    • +fp16 โ€” the half-precision floating-point data processing instructions. This also enables the Advanced SIMD and floating-point instructions, plus the Dot Product extension and the half-precision floating-point fmla extension ๐Ÿ”ฅ
    • +simd โ€” the ARMv8.3-A Advanced SIMD and floating-point instructions, plus the Dot Product extension ๐ŸŒˆ
    • +crypto โ€” the cryptographic instructions. This also enables the Advanced SIMD and floating-point instructions, plus the Dot Product extension ๐Ÿ”’
    • +nocrypto โ€” disables the cryptographic extension ๐Ÿ™…โ€โ™€๏ธ
    • +nofp โ€” disables the floating-point, Advanced SIMD and cryptographic instructions ๐Ÿ’€
  • +i8mm โ€” okay the 8-bit Integer Matrix Multiply instructions ๐Ÿงฎ are so giving. This also enables Advanced SIMD and floating-point instructions too โœจ
  • +bf16 โ€” the Brain half-precision floating-point instructions ๐Ÿง  bestie, this one also turns on Advanced SIMD and floating-point instructions ๐Ÿ’–

๐ŸŽ€ armv7-r

  • +fp.sp โ€” the single-precision VFPv3 floating-point instructions ๐ŸŒธ +vfpv3xd works as an alias for this one, so no stress if you see that name somewhere.
  • +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 โ€” single-precision VFPv3 floating-point instructions with 16 double-precision registers, plus the half-precision floating-point conversion operations ๐Ÿฆ‹
  • +vfpv3-d16-fp16 โ€” VFPv3 floating-point instructions with 16 double-precision registers, plus the half-precision floating-point conversion operations ๐ŸŒˆ
  • +nofp โ€” disables the floating-point extension ๐Ÿšซ
  • +idiv โ€” the ARM-state integer division instructions โž—
  • +noidiv โ€” disables the ARM-state integer division extension ๐Ÿ™ˆ

๐ŸŒธ armv7e-m

  • +fp โ€” the single-precision VFPv4 floating-point instructions โœจ
  • +fpv5 โ€” the single-precision FPv5 floating-point instructions ๐Ÿ’œ
  • +fp.dp โ€” the single- and double-precision FPv5 floating-point instructions ๐Ÿ‘‘
  • +nofp โ€” disables the floating-point extensions ๐Ÿšซ

๐Ÿฆ‹ 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. Main character energy ๐Ÿ”ฅ
  • +fp โ€” the single-precision floating-point instructions โญ
  • +fp.dp โ€” the single- and double-precision floating-point instructions ๐Ÿซถ
  • +nofp โ€” disables the floating-point extension ๐Ÿšซ
  • +cdecp0, +cdecp1, ... , +cdecp7 โ€” enables the Custom Datapath Extension (CDE) on selected coprocessors, according to the numbers you give in the options, in the range 0 to 7 ๐Ÿงš

๐Ÿงš armv8-m.main

  • +dsp โ€” the DSP instructions ๐Ÿ’–
  • +nodsp โ€” disables the DSP extension ๐Ÿ™…
  • +fp โ€” the single-precision floating-point instructions ๐ŸŒˆ
  • +fp.dp โ€” the single- and double-precision floating-point instructions ๐Ÿ’œ
  • +nofp โ€” disables the floating-point extension ๐Ÿšซ
  • +cdecp0, +cdecp1, ... , +cdecp7 โ€” enables the Custom Datapath Extension (CDE) on selected coprocessors, according to the numbers you give 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 โ€” disables the cryptographic instructions ๐Ÿšซ
  • +nofp โ€” disables the floating-point, Advanced SIMD and cryptographic instructions. Big sacrifice, no cap ๐Ÿ’€

-march=native makes the compiler auto-detect the architecture of the build computer ๐Ÿช„. Lowkey it's only supported on GNU/Linux, and not every architecture gets recognized. If the auto-detect doesn't work out, the option just has no effect ๐Ÿฅฒ

๐Ÿ“ -mtune=name

This option tells GCC which target ARM processor to tune the performance of the code for ๐Ÿ’…. For some ARM implementations you can get better performance by using this option โœจ. Permissible names are: arm7tdmi, arm7tdmi-s, arm710t, arm720t, arm740t, strongarm, strongarm110, strongarm1100, strongarm1110, 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, cortex-a710, ares, cortex-r4, cortex-r4f, cortex-r5, cortex-r7, cortex-r8, cortex-r52, cortex-r52plus, 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 ๐Ÿคธ. 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 current most popular processors, balancing the optimizations that help some CPUs in the range while avoiding the performance pitfalls of other CPUs. Just know 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 ๐Ÿ”. Lowkey it's only supported on GNU/Linux, and not every architecture gets recognized. If the auto-detect doesn't work out, 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'd used -march) and the ARM processor type to tune for (as if you'd used -mtune). If you use this option together with -march or -mtune, those options take precedence over the matching part of this option ๐Ÿซถ.

A lot of the supported CPUs have optional architectural extensions ๐Ÿงฉ. When that's the case, the extensions are normally enabled by default. If implementations that lack the extension exist, you can use the extension syntax to disable the extensions that have been left out ๐Ÿ™…. For floating-point and Advanced SIMD (Neon) instructions, you also have to think about the -mfloat-abi and -mfpu options: 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 the extensions +nosimd and +nofp can be used to disable just the SIMD, or both the SIMD and floating-point instructions, respectively ๐Ÿ’–.

Permissible names for this option are the same as the ones for -mtune ๐Ÿ“.

The following extension options are common to the listed CPUs ๐Ÿฆ‹:

  • +nodsp โ€” disables 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. On generic-armv7-a, cortex-a5, cortex-a7, cortex-a8, cortex-a9, cortex-a12, cortex-a15, cortex-a17, cortex-a15.cortex-a7, cortex-a17.cortex-a7, cortex-a32, cortex-a35, cortex-a53 and cortex-a55, it disables the floating-point and SIMD instructions ๐Ÿšซ
  • +nofp.dp โ€” disables the double-precision component of the floating-point instructions on cortex-r5, cortex-r7, cortex-r8, cortex-r52, cortex-r52plus and cortex-m7 ๐Ÿ’œ
  • +nosimd โ€” disables the SIMD (but not floating-point) instructions on generic-armv7-a, cortex-a5, cortex-a7 and cortex-a9 ๐Ÿซ 
  • +crypto โ€” enables the cryptographic instructions on cortex-a32, cortex-a35, cortex-a53, cortex-a55, cortex-a57, cortex-a72, cortex-a73, cortex-a75, exynos-m1, xgene1, cortex-a57.cortex-a53, cortex-a72.cortex-a53, cortex-a73.cortex-a35, cortex-a73.cortex-a53 and cortex-a75.cortex-a55 ๐Ÿ”

Also, the generic-armv7-a pseudo target defaults to VFPv3 with 16 double-precision registers โœจ. It supports these extension options: mp, sec, vfpv3-d16, vfpv3, vfpv3-d16-fp16, vfpv3-fp16, vfpv4-d16, vfpv4, neon, neon-vfpv3, neon-fp16, neon-vfpv4. The meanings are the same as for the extensions to -march=armv7-a ๐ŸŽ€.

-mcpu=generic-arch is also allowed, and it's equivalent to -march=arch -mtune=generic-arch. Check out -mtune for more info ๐Ÿงš.

-mcpu=native makes the compiler auto-detect the CPU of the build computer ๐Ÿ”. Lowkey it's only supported on GNU/Linux, and not every architecture gets recognized. If the auto-detect doesn't work out, the option has no effect ๐Ÿฅฒ.

๐ŸŽ€ -mfpu=name

This specifies what floating-point hardware (or hardware emulation) is available on the target ๐Ÿ”ฅ. Permissible names are: auto, vfpv2, vfpv3, vfpv3-fp16, vfpv3-d16, vfpv3-d16-fp16, vfpv3xd, vfpv3xd-fp16, neon-vfpv3, neon-fp16, vfpv4, vfpv4-d16, fpv4-sp-d16, neon-vfpv4, fpv5-d16, fpv5-sp-d16, fp-armv8, neon-fp-armv8 and crypto-neon-fp-armv8 ๐Ÿ’…. Heads up: neon is an alias for neon-vfpv3, and vfp is an alias for vfpv2 ๐Ÿซถ.

okay so the setting auto is the default and it's lowkey special ๐Ÿ’… It tells the compiler to pick the floating-point and Advanced SIMD instructions based on -mcpu and -march ๐Ÿฆ‹

bestie, if the floating-point hardware you picked includes the NEON extension (e.g. -mfpu=neon), GCC's auto-vectorization pass won't generate floating-point operations unless you also specify -funsafe-math-optimizations ๐Ÿ˜ญ The reason is that NEON hardware doesn't fully implement the IEEE 754 standard for floating-point arithmetic (denormal values get treated as zero), so using NEON instructions may lead to a loss of precision ๐Ÿ’€ Not a vibe.

You can also set the fpu name at function level using the target("fpu=") function attributes or pragmas โœจ


  • -mfp16-format=name โ€” Pick the format for the __fp16 half-precision float type ๐ŸŒธ Your options are none, ieee, and alternative. The default is none, which means __fp16 isn't defined at all ๐Ÿ™ˆ
  • -mstructure-size-boundary=n โ€” This rounds up the size of every structure and union to a multiple of the number of bits you give it ๐Ÿ“ Allowed values are 8, 32 and 64. The default changes depending on your toolchain, and for the COFF targeted toolchain it's 8. A value of 64 only works if the underlying ABI supports it ๐Ÿซถ

A bigger number can give you faster, more efficient code, but it can also make your program bigger ๐Ÿ“ Different values are potentially incompatible, too. Code compiled with one value can't necessarily work with code or libraries compiled with another if they swap info through structures or unions ๐Ÿ˜ญ

This option is deprecated. ๐Ÿ’€
  • -mabort-on-noreturn โ€” Generates a call to the function abort at the end of a noreturn function. It runs if the function tries to return ๐Ÿงš

  • -mlong-calls, -mno-long-calls โ€” Okay, so -mlong-calls makes the compiler do 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 switch on, not every call becomes a long call ๐Ÿ™ƒ The heuristic is that static functions, functions with the short_call attribute, functions inside the scope of a #pragma no_long_calls directive, and functions whose definitions were already compiled within the current compilation unit are not turned into long calls. The exceptions are weak function definitions, functions with the long_call attribute or the section attribute, and functions inside the scope of a #pragma long_calls directive. Those are always turned into long calls ๐Ÿ‘‘

This feature is not enabled by default. -mno-long-calls restores the default behavior, and so does putting the function calls inside a #pragma long_calls_off directive ๐Ÿฆ‹ Also note these switches have zero effect on how calls via function pointers are generated ๐Ÿ’…

  • -msingle-pic-base โ€” Treats the register used for PIC addressing as read-only, instead of loading it in the prologue for each function โœจ The runtime system is responsible for initializing this register with an appropriate value before execution begins ๐Ÿซถ
  • -mpic-register=reg โ€” Picks the register used for PIC addressing ๐ŸŽ€ For the standard PIC base case, the default is any suitable register the compiler determines. For the single PIC base case, the default is R9 if the target is EABI based or stack-checking is enabled, and otherwise it's R10 ๐ŸŒธ
  • -mpic-data-is-text-relative โ€” Assumes the displacement between the text and data segments is fixed at static link time ๐Ÿง  This lets you use PC-relative addressing to access data known to be in the data segment. For non-VxWorks RTP targets it's enabled by default. If you disable it on those targets, it turns on -msingle-pic-base by default instead ๐Ÿ”ฅ
  • -mpoke-function-name โ€” Writes the name of each function into the text section, right before the function prologue ๐Ÿงšโ€โ™€๏ธ The generated code looks 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 do a stack backtrace, code can look at the value of pc stored at fp + 0 ๐Ÿ” If the trace function then looks at location pc - 12 and the top 8 bits are set, we know there's a function name embedded right before that location, and its length is ((pc[-3]) & 0xff000000) ๐Ÿ’–

  • -mthumb, -marm โ€” Pick between generating code that 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 and Thumb mode for each function with the target("thumb") and target("arm") function attributes or pragmas ๐ŸŽ€

  • -mflip-thumb โ€” Switches ARM/Thumb modes on alternating functions ๐Ÿ™ƒ This is only here for regression testing of mixed Thumb/ARM code generation, so it's not meant for ordinary code 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 โ€” Generates a stack frame that follows 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, which switches to Thumb mode before running the rest of the function ๐Ÿ”„ This lets these functions get called from non-interworking code ๐Ÿซถ This option is not valid in AAPCS configurations, because interworking is already enabled by default there โญ
  • -mcaller-super-interworking โ€” Lets calls via function pointers (including virtual functions) run correctly, whether or not the target code was compiled for interworking ๐ŸŒธ There's a small overhead when executing a function pointer if you turn this on ๐Ÿข This option is not valid in AAPCS configurations either, since interworking is enabled 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)
    • auto, which uses the best available method for the selected processor

The default setting is auto โœจ

  • -mtls-dialect=dialect โ€” Picks the dialect for accessing thread local storage ๐Ÿงš Two dialects are supported, 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 gives better performance for shared libraries ๐Ÿš€ The GNU descriptor scheme is compatible with the original scheme, but it does require new assembler, linker and library support ๐Ÿ› ๏ธ Initial and local exec TLS models are unaffected by this option and always use the original scheme ๐Ÿซถ
  • -mword-relocations โ€” Only generates absolute relocations on word-sized values (i.e. R_ARM_ABS32) ๐Ÿงฑ This is enabled by default on targets (uClinux, SymbianOS) where the runtime loader imposes this restriction, and when -fpic or -fPIC is specified. This option conflicts with -mslow-flash-data โš ๏ธ
  • -mfix-cortex-m3-ldrd โ€” Some Cortex-M3 cores can cause data corruption when ldrd instructions with overlapping destination and base registers are used ๐Ÿ˜ฑ This option avoids generating those instructions ๐Ÿ›ก๏ธ It's enabled by default when -mcpu=cortex-m3 is specified ๐Ÿ’–
  • -mfix-cortex-a57-aes-1742098, -mno-fix-cortex-a57-aes-1742098 โ€” Enables (or disables) the mitigation for an erratum on Cortex-A57 that affects the AES cryptographic instructions ๐Ÿ” It's enabled by default when -mcpu=cortex-a57 is specified ๐ŸŒˆ
  • -mfix-cortex-a72-aes-1655431, -mno-fix-cortex-a72-aes-1655431 โ€” Same deal, but for the erratum on Cortex-A72 that affects the AES cryptographic instructions ๐Ÿ” It's enabled by default when -mcpu=cortex-a72 is specified ๐Ÿฆ‹
  • -munaligned-access, -mno-unaligned-access โ€” Enables (or disables) reading and writing of 16- and 32-bit values from addresses that aren't 16- or 32-bit aligned ๐Ÿง By default, unaligned access is disabled for all pre-ARMv6, all ARMv6-M and for ARMv8-M Baseline architectures, and enabled for all other architectures ๐Ÿ™Œ If unaligned access isn't enabled, words in packed data structures get accessed one byte at a time ๐ŸŒ

The ARM attribute Tag_CPU_unaligned_access is set in the generated object file to either true or false, depending on this option ๐Ÿท๏ธ If unaligned access is enabled, the preprocessor symbol __ARM_FEATURE_UNALIGNED is also defined ๐ŸŽ€

  • -mneon-for-64bits โ€” This option is deprecated and has no effect ๐Ÿ’€
  • -mslow-flash-data โ€” Assumes loading data from flash is slower than fetching instructions ๐Ÿข So literal loads get minimized for better performance โšก This option is only supported when compiling for ARMv7 M-profile, and it's off by default ๐Ÿ™…โ€โ™€๏ธ It conflicts with -mword-relocations โš ๏ธ
  • -masm-syntax-unified โ€” Assumes the inline assembler is using unified asm syntax ๐Ÿงฉ The default is currently off, which implies divided syntax ๐Ÿ™ƒ This option has no impact on Thumb2, but that may change in future releases of GCC ๐Ÿ‘€ Divided syntax should be considered deprecated ๐Ÿ˜ญ
  • -mrestrict-it โ€” Restricts generation of IT blocks so they conform to the rules of ARMv8-A ๐Ÿ“ IT blocks can only contain a single 16-bit instruction from a select set of instructions ๐Ÿง  This option is on by default for ARMv8-A Thumb mode ๐Ÿ’…
  • -mprint-tune-info โ€” okay bestie, this one prints the CPU tuning info as a comment inside the assembler file โœจ It's really only for the compiler's own regression testing, so you won't need it for regular code ๐Ÿ™ˆ It's disabled by default.
  • -mverbose-cost-dump โ€” turns on verbose cost model dumping in the debug dump files ๐Ÿ” It's a compiler-debugging tool, so it's very compiler-dev energy ๐Ÿง 
  • -mpure-code โ€” no constant data gets stashed in code sections ๐Ÿšซ And when you're compiling for ELF object format, every text section gets the ELF processor-specific section attribute SHF_ARM_PURECODE ๐Ÿ’œ This one is only available when generating non-pic code for M-profile targets, so it's not for everyone ๐Ÿ’…
  • -mcmse โ€” generates secure code following 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 โ€” mitigates a potential security issue with the "VLLDM" instruction on some M-profile devices when you're using CMSE (CVE-2021-365465) ๐Ÿ›ก๏ธ This one is on 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.
  • -mstack-protector-guard=guard, -mstack-protector-guard-offset=offset โ€” generates stack protection code using a canary at guard ๐Ÿงš The supported locations are global (a global canary) or tls (a canary you can reach through the TLS register). The -mstack-protector-guard-offset= option goes with -fstack-protector-guard=tls, and it's not for user-land code ๐Ÿ’€
  • -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 option 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 should explicitly provide the PIC/PIE-related options as needed.

Note that static linking is not supported, because it would still involve the dynamic linker when the program self-relocates. If that behaviour is acceptable to you, use -static and -Wl,-dynamic-linker options.

The opposite -mno-fdpic option is useful (and required) to build the Linux kernel using the same (arm-*-uclinuxfdpiceabi) toolchain as the one used to build the userland programs ๐Ÿ‘‘

โœจ AVR Options โœจ

These options are defined for AVR implementations, so they're strictly for AVR chips ๐Ÿ

  • -mmcu=mcu โ€” picks the Atmel AVR instruction set architecture (ISA) or MCU type ๐Ÿ’– The default for this option is avr2.

GCC supports the following AVR devices and ISAs:

  • avr2 โ€” "Classic" devices with up to 8 KiB of program memory.
    • mcu = 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. This is a big one, bestie ๐ŸŒธ
    • 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, atmega324pb, 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 a 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, plus 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 that all data in static storage can be accessed by LDS / STS instructions โœจ This option 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/releases the needed stack space for them once, in the function prologue/epilogue ๐ŸŽ€ Without this option, outgoing arguments are pushed before calling a function and popped afterwards.

Popping the arguments after the function call can be expensive on AVR, so accumulating the stack space might lead to smaller executables, because arguments don't need to be removed from the stack after each such function call ๐Ÿซถ

This option can lead to reduced code size for functions that make several calls to functions that get their arguments on the stack, like calls to printf-like functions ๐ŸŒˆ

  • -mbranch-cost=cost โ€” sets the branch costs for conditional branch instructions to cost ๐Ÿ’œ Reasonable values for cost are small, non-negative integers. The default branch cost is 0.
  • -mcall-prologues โ€” functions prologues/epilogues are expanded as calls to appropriate subroutines, so your code size gets smaller ๐Ÿงš
  • -mdouble=bits โ€” โœจ bestie, this one sets the size (in bits) of the "double" type ๐Ÿ’–. The only 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 ๐Ÿงš (see https://gcc.gnu.org/install/configure.html#avr), and the same goes for the default values of those options ๐ŸŽ€.
  • -mlong-double=bits โ€” same energy, but for the "long double" type ๐Ÿ’œ. The possible values are 32 and 64 again, and it's the same deal with the configure options and their defaults ๐Ÿ’….
  • -mgas-isr-prologues โ€” ๐Ÿฆ‹ ISRs (interrupt service routines) are allowed to use the __gcc_isr pseudo instruction, which GNU Binutils supports. If this option is on, you can still turn the feature off for individual ISRs with the "no_gccisr" function attribute from AVR Function Attributes ๐Ÿ™ˆ. It's switched on by default when optimization is on (but not with -Og, see @pxref{Optimize Options}), and only if GNU Binutils supports PR21683 (https://sourceware.org/PR21683) ๐Ÿ”ฅ.
  • -mint8 โ€” ๐Ÿ“ this one tells the compiler to assume int is an 8-bit integer. That changes the sizes 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. Smaller code size, yay! ๐Ÿง
โš ๏ธ Heads up, bestie: -mint8 does not conform to the C standards. It shrinks the code, but the types won't behave like the standard says they should ๐Ÿ’€.
  • -mmain-is-OS_task โ€” ๐Ÿ‘‘ don't save registers in main. It does the same thing as slapping the AVR Function Attributes "OS_task" attribute onto main ๐Ÿ’…. It's switched on by default when optimization is on โœจ.
  • -mn-flash=num โ€” ๐ŸŒˆ tells the compiler to assume the flash memory is num times 64 KiB big ๐Ÿงš.
  • -mno-interrupts โ€” ๐Ÿ™…โ€โ™€๏ธ the generated code is not compatible with hardware interrupts. The upside is that the code size gets smaller ๐ŸŒธ.
  • -mrelax โ€” ๐Ÿฆ‹ okay so this tries to swap CALL or JMP instructions for the shorter RCALL or RJMP instructions, 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 is located ๐Ÿง . So the assembler code the compiler generates is the same, but the instructions in the executable may end up different from the ones in the assembler code ๐Ÿคฏ.

Relaxing must be turned on if linker stubs are needed. Check out the section on "EIND" and linker stubs below ๐Ÿ‘€.

  • -mrmw โ€” ๐Ÿ’œ assume the device supports the Read-Modify-Write instructions XCH, LAC, LAS and LAT โœจ.
  • -mshort-calls โ€” ๐ŸŒธ assume that 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 โ€” ๐ŸŽ€ treat the stack pointer register as an 8-bit register, i.e. assume the high byte of the stack pointer is zero. Generally, 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 architectures avr2 and avr25. These architectures mix devices with and without SPH ๐Ÿงฉ. For any setting other than -mmcu=avr2 or -mmcu=avr25, the compiler driver adds or removes this option from the compiler proper's command line, because the compiler then knows whether the device or architecture has an 8-bit stack pointer (and therefore no SPH register) or not ๐Ÿ”ฅ.

  • -mstrict-X โ€” ๐Ÿ‘‘ use the address register X the way the hardware intends ๐Ÿ’–. That means X is only used in indirect, post-increment or pre-decrement addressing ๐ŸŒˆ.

Without this option, the X register can be used the same way as Y or Z, which then gets emulated with extra instructions ๐Ÿ™ˆ. For example, loading a value with X+const addressing, where const is small and non-negative (const < 64), into a register Rn looks like this:

adiw r26, const   ; X += const
ld   <Rn>, X        ; <Rn> = *X
sbiw r26, const   ; X -= const
  • -mtiny-stack โ€” ๐Ÿฆ‹ only change the lower 8 bits of the stack pointer โœจ.
  • -mfract-convert-truncate โ€” ๐Ÿ“ allow 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 ๐Ÿซถ. This means you take responsibility for giving the subprocesses (compiler proper, assembler and linker) the right command line options ๐Ÿ’€. You have to supply your own device specs file with -specs=path-to-specs-file, and there's no more need for -mmcu=mcu ๐ŸŽ€.

This option can also replace the older way of doing custom device-specs files. That one needed -B some-path to point at 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 โ€” โš ๏ธ warn about conversions between address spaces when the resulting address space isn't contained in the incoming address space ๐Ÿ‘€.
  • -Wmisspelled-isr โ€” ๐Ÿ”ฅ warn if the ISR is misspelled, i.e. written without the __vector prefix. This one is enabled by default โœจ.

โœจ "EIND" and Devices with More Than 128 Ki Bytes of Flash โœจ

Pointers in the implementation are 16 bits wide ๐Ÿง . The address of a function or label is represented as a word address, so indirect jumps and calls can target any code address in the range of 64 Ki words ๐Ÿฆ‹.

To make indirect jumps work on devices with more than 128 Ki bytes of program memory, 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 using a RET instruction ๐Ÿงš.
  • The compiler assumes 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 jumps to such a stub, and 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 where EIND points to ๐Ÿ”ฅ.
  • The startup code from libgcc never sets EIND. Heads up 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 at 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 in the 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 this is not supported ๐Ÿ™…โ€โ™€๏ธ:
int main (void)
{
    /* Call function at word address 0x2 */
    return ((int(*)(void)) 0x2)();
}

Instead, a stub has to be set up, i.e. the function has to be called through a symbol (func_4 in the example) ๐Ÿงš:

int main (void)
{
    extern int func_4 (void);

    /* Call function at byte address 0x4 */
    return func_4();
}

and the application has 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 โœจ

Some AVR devices support memories larger than the 64 KiB range that can be accessed with 16-bit pointers ๐ŸŒ. To access memory locations outside this 64 KiB range, the content of a RAMP register is used as the high part of the address ๐Ÿง . The X, Y and Z address registers are concatenated with the RAMPX, RAMPY and RAMPZ special function registers, respectively, to get a wide address ๐Ÿฆ‹. Similarly, RAMPD is used together with direct addressing ๐Ÿ’–.

  • The startup code initializes the RAMP special function registers with zero ๐Ÿซถ.
  • If a named address space (see AVR Named Address Spaces) other than generic or __flash is used, then RAMPZ is set as needed before the operation ๐Ÿ”ฅ.
  • If the device supports RAM bigger than 64 KiB and the compiler has to change RAMPZ to pull off an operation, RAMPZ gets reset to zero afterward. ๐Ÿงน
  • If the device has a specific RAMP register, the ISR prologue/epilogue saves and restores that SFR and sets it to zero, just in case the ISR code might (implicitly) use it. ๐Ÿ›ก๏ธ
  • > โš ๏ธ RAM larger than 64 KiB is not supported by GCC for AVR targets. If you use inline assembler to read from locations outside the 16-bit address range and change one of the RAMP registers, you must reset it to zero after the access. Do not skip this, bestie. ๐Ÿ’€

โœจ AVR Built-in Macros โœจ

GCC defines a bunch of built-in macros so your code can check whether certain features are there or not. Almost any of the following built-in macros are deduced from device capabilities, so 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__

This built-in macro resolves to a decimal number that identifies the architecture, and it depends on the -mmcu=mcu option. ๐Ÿฆ‹ The possible values are:

  • mcu="avr2" โ†’ 2
  • mcu="avr25" โ†’ 25
  • mcu="avr3" โ†’ 3
  • mcu="avr31" โ†’ 31
  • mcu="avr35" โ†’ 35
  • mcu="avr4" โ†’ 4
  • mcu="avr5" โ†’ 5
  • mcu="avr51" โ†’ 51
  • mcu="avr6" โ†’ 6
  • mcu="avrtiny" โ†’ 100
  • mcu="avrxmega2" โ†’ 102
  • mcu="avrxmega3" โ†’ 103
  • mcu="avrxmega4" โ†’ 104
  • mcu="avrxmega5" โ†’ 105
  • mcu="avrxmega6" โ†’ 106
  • mcu="avrxmega7" โ†’ 107

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 __AVR_ATmega8__, and -mmcu=attiny261a defines __AVR_ATtiny261A__, etc. ๐Ÿงš

The built-in macro names follow the scheme __AVR_Device__, where Device is the device name as it appears in the AVR user manual. The difference between Device in the built-in macro and device in -mmcu=device is that the latter is always lowercase. ๐Ÿ”ค

If device is not a device but only a core architecture like avr51, this macro is not defined. ๐Ÿ™ˆ

__AVR_DEVICE_NAME__

Setting -mmcu=device defines this built-in macro to the device's name. For example, with -mmcu=atmega8 the macro is defined to "atmega8". โœจ

If device is not a device but only a core architecture like avr51, this macro is not defined. ๐Ÿ’…

__AVR_XMEGA__

The device or architecture belongs to the XMEGA family of devices. ๐Ÿ‘‘

__AVR_HAVE_ELPM__

The device has the ELPM instruction. ๐Ÿ”ฅ

__AVR_HAVE_ELPMX__

The device has the ELPM Rn,Z and ELPM Rn,Z+ instructions. ๐ŸŒˆ

__AVR_HAVE_MOVW__

The device has the MOVW instruction, which performs 16-bit register-to-register moves. ๐Ÿฆ‹

__AVR_HAVE_LPMX__

The device has the LPM Rn,Z and LPM Rn,Z+ instructions. ๐Ÿ’œ

__AVR_HAVE_MUL__

The device has a hardware multiplier. โญ

__AVR_HAVE_JMP_CALL__

The device has the JMP and CALL instructions. This is the case for devices with more than 8 KiB of program memory. ๐Ÿ“

__AVR_HAVE_EIJMP_EICALL__ and __AVR_3_BYTE_PC__

The device has the EIJMP and EICALL instructions. This is the case for devices with more than 128 KiB of program memory. It 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__ and __AVR_HAVE_16BIT_SP__

The compiler treats the stack pointer (SP) register as an 8-bit or 16-bit register, respectively. The definition of these macros is affected by -mtiny-stack. ๐Ÿ“š

__AVR_HAVE_SPH__ and __AVR_SP8__

The device has the SPH (high part of stack pointer) special function register, or has an 8-bit stack pointer, respectively. The definition of these macros is affected by -mmcu=, and in the cases of -mmcu=avr2 and -mmcu=avr25, also by -msp8. ๐Ÿ˜ญ

__AVR_HAVE_RAMPD__, __AVR_HAVE_RAMPX__, __AVR_HAVE_RAMPY__, and __AVR_HAVE_RAMPZ__

The device has the RAMPD, RAMPX, RAMPY, or RAMPZ special function register, respectively. ๐ŸŽ€

__NO_INTERRUPTS__

This macro reflects the -mno-interrupts command-line option. ๐Ÿ›‘

__AVR_ERRATA_SKIP__ and __AVR_ERRATA_SKIP_JMP_CALL__

Some AVR devices (AT90S8515, ATmega103) must not skip 32-bit instructions because of a hardware erratum. The skip instructions are SBRS, SBRC, SBIS, SBIC, and CPSE. The second macro is only defined if __AVR_HAVE_JMP_CALL__ is also set. ๐Ÿ™…โ€โ™€๏ธ

__AVR_ISA_RMW__

The device has Read-Modify-Write instructions (XCH, LAC, LAS, and LAT). ๐Ÿ”

__AVR_SFR_OFFSET__=offset

Instructions that can address I/O special function registers directly, like IN, OUT, SBI, etc., may use a different address than an instruction that accesses RAM, like LD or STS. This offset depends on the device architecture, and it 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 by means of 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 is no need to put .rodata into RAM. This is handled by the default linker description file, and it is currently available for avrtiny and avrxmega3. Even more convenient, there is no need to use address spaces like __flash or features like the progmem attribute 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__ and __HAVE_DOUBLE64__

Defined if the compiler supports 32-bit double or 64-bit double, respectively. The actual layout is specified by the -mdouble= option. ๐Ÿ“

__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__, and __DEFAULT_LONG_DOUBLE__

Same as above, but for long double instead of double. ๐Ÿ’ซ

__WITH_DOUBLE_COMPARISON__

This reflects the --with-double-comparison={tristate|bool|libf7} configure option (https://gcc.gnu.org/install/configure.html#avr), and it is defined to 2 or 3. ๐ŸŒท

__WITH_LIBF7_LIBGCC__, __WITH_LIBF7_MATH__, and __WITH_LIBF7_MATH_SYMBOLS__

These reflect the --with-libf7={libgcc|math|math-symbols} configure option (https://gcc.gnu.org/install/configure.html#avr). ๐ŸŽถ


๐Ÿฆ‹ Blackfin Options ๐Ÿฆ‹

  • -mcpu=cpu[-sirevision] โ€” This picks the target Blackfin processor. Right now, cpu can be one of bf512, bf514, bf516, bf518, bf522, bf523, bf524, bf525, bf526, bf527, bf531, bf532, bf533, bf534, bf536, bf537, bf538, bf539, bf542, bf544, bf547, bf548, bf549, bf542m, bf544m, bf547m, bf548m, bf549m, bf561, or bf592. ๐Ÿ”ฅ

The optional sirevision picks the silicon revision of the target Blackfin processor, and any workarounds for that revision get enabled. If sirevision is none, no workarounds are enabled. If it 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 of 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 only has an effect 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 skips the instructions that save, set up, and restore frame pointers, and it frees up an extra register in leaf functions. ๐Ÿƒ
  • -mspecld-anomaly โ€” When enabled, the compiler makes sure 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 happening. ๐Ÿ™…โ€โ™€๏ธ
  • -mcsync-anomaly โ€” When enabled, the compiler makes sure 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 happening 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. ๐Ÿ“ฆ
  • -mstack-check-l1 โ€” Does stack checking using information placed into L1 scratchpad memory by the uClinux kernel. ๐Ÿ”
  • -mid-shared-library โ€” Generates code that supports shared libraries via the library ID method. This allows for execute-in-place and shared libraries in an environment without virtual memory management. This option implies -fPIC. With a bfin-elf target, this option implies -msim. ๐ŸŒˆ
  • -mno-id-shared-library โ€” Generates code that doesn't assume ID-based shared libraries are being used. This is the default. ๐Ÿ’œ
  • -mleaf-id-shared-library โ€” okay so this one has GCC generate code that works with ID-based shared libraries (the library ID method), but it assumes your library or executable won't link against any other ID shared libraries. The payoff is that the compiler can use faster code for jumps and calls. ๐ŸŽ๏ธโœจ
  • -mno-leaf-id-shared-library โ€” the opposite energy ๐Ÿ™ˆ 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 you're compiling. 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 allows execute in place in an environment without virtual memory management, by getting rid of relocations against the text section. ๐Ÿงš
  • -mno-sep-data โ€” assumes the data segment follows the text segment. This is the default, so you're already set ๐Ÿ’…
  • -mlong-calls, -mno-long-calls โ€” this tells the compiler to do 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 is outside the 24-bit addressing range of the offset-based version of the subroutine call instruction. It's not on by default, and -mno-long-calls puts you back to default. Also, these switches have no effect on how function calls through function pointers get generated, so don't expect them to do anything there ๐Ÿซ 
  • -mfast-fp โ€” links with the fast floating-point library. It relaxes some of the IEEE floating-point standard's rules for checking inputs against Not-a-Number (NAN), all for the sake of performance. โšก
  • -minline-plt โ€” enables inlining of PLT entries in function calls to functions that aren't known to bind locally. It has no effect without -mfdpic. ๐ŸŒธ
  • -mmulticore โ€” builds a standalone application for multicore Blackfin processors. It uses proper start files and link scripts that support multicore, and it defines the macro "__BFIN_MULTICORE". This one can only be used with -mcpu=bf561[-sirevision]. It can pair with -mcorea or -mcoreb for the one-application-per-core programming model. Without either of those, you get the single-application/dual-core model, where the main function of Core B should be named "coreb_main". If you skip this option entirely, the single-core application programming model is used. ๐Ÿ‘‘
  • -mcorea โ€” builds a standalone application for Core A of BF561 in the one-application-per-core model. Proper start files and link scripts support Core A, and the macro "__BFIN_COREA" gets defined. This only works together with -mmulticore. ๐Ÿฆ‹
  • -mcoreb โ€” builds a standalone application for Core B of BF561 in the one-application-per-core model. Proper start files and link scripts support Core B, and the macro "__BFIN_COREB" gets defined. When you use this, "coreb_main" replaces "main". This only works together with -mmulticore. ๐ŸŒˆ
  • -msdram โ€” builds a standalone application for SDRAM. Proper start files and link scripts put the app into SDRAM, and the macro "__BFIN_SDRAM" gets defined. Heads up: the loader should initialize SDRAM before loading the application ๐Ÿง 
  • -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 โ€” specifies the name of the target architecture. GCC uses this name to figure out what kinds of instructions it's allowed to emit when generating assembly code. Permissible names are c62x, c64x, c64x+, c67x, c67x+, 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 suit 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 the .bss section, which sits right next to .neardata. Small read-only data goes in the .rodata section. For big chunks of data, the matching sections are .fardata, .far and .const. ๐Ÿ“ฆ
  • -msdata=all โ€” puts all data, not just the small stuff, into the sections reserved for small data, and uses addressing relative to the B14 register to get at it. ๐ŸŒŸ
  • -msdata=none โ€” makes no use of the sections reserved for small data, and uses absolute addresses to access all data. All initialized global and static data goes in the .fardata section, and all uninitialized data goes in the .far section. All constant data goes in the .const section. ๐Ÿฐ

โœจ CRIS Options โœจ

These options are defined specifically for the CRIS ports ๐Ÿ’–

  • -march=architecture-type, -mcpu=architecture-type โ€” generates code for the architecture you pick. The choices are v3, v8 and v10, which are for ETRAX 4, ETRAX 100, and ETRAX 100 LX respectively. The default is v0, except for cris-axis-linux-gnu, where the default is v10. ๐Ÿงฉ
  • -mtune=architecture-type โ€” tunes everything that applies to the generated code for the architecture you pick, except the ABI and 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, for CPU models where it applies. This one's disabled by default. ๐Ÿ›
  • -mpdebug โ€” turns on CRIS-specific verbose debug-related info in the assembly code. It also turns off the #NO_APP formatted-code indicator that gets sent to the assembler at the start of the assembly file. ๐Ÿ”
  • -mcc-init โ€” doesn't use condition-code results from previous instructions. It always emits compare and test instructions before condition codes get used. ๐Ÿงผ
  • -mno-side-effects โ€” doesn't emit instructions with side effects in addressing modes other than post-increment. ๐Ÿง˜
  • -mstack-align, -mno-stack-align, -mdata-align, -mno-data-align, -mconst-align, -mno-const-align โ€” these (the no- ones) arrange, or un-arrange, for the stack frame, individual data and constants to be aligned for the maximum single data access size of the chosen CPU model. The default is 32-bit alignment. ABI details like structure layout are not affected by these options. ๐Ÿ“
  • -m32-bit, -m16-bit, -m8-bit โ€” similar to the stack, data and const align options above, these arrange for the stack frame, writable data and constants to all be 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 get generated.
Use -mno-prologue-epilogue only together with visual inspection of the compiled code, bestie ๐Ÿ˜ญ No warnings or errors get generated when call-saved registers need to be saved, or when storage for local variables needs to be allocated.
  • -mno-gotplt, -mgotplt โ€” with -fpic and -fPIC, -mno-gotplt means don't generate instruction sequences that load addresses for functions from the PLT part of the GOT, and -mgotplt means do generate them. Other architectures normally just call the PLT, so this is a CRIS thing. The default is -mgotplt. ๐ŸŒท
  • -melf โ€” a legacy no-op option, only recognized with the cris-axis-elf and cris-axis-linux-gnu targets. ๐Ÿฆ•
  • -mlinux โ€” a legacy no-op option, only recognized with the cris-axis-linux-gnu target. ๐Ÿฆ–
  • -sim โ€” recognized for cris-axis-elf. It links with input-output functions from a simulator library. Code, initialized data and zero-initialized data get allocated consecutively. ๐Ÿ–ฅ๏ธ
  • -sim2 โ€” like -sim, but it 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 the use of 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. This only applies to the ELF compiler. ๐Ÿงช
  • -mint32 โ€” chooses 32-bit wide integer type. ๐Ÿ”ข
  • -mbit-ops โ€” generates "sbit"/"cbit" instructions for bit manipulations. ๐ŸŽฏ
  • -mdata-model=model โ€” chooses a data model. The choices are near, far or medium. medium is the default. Heads up though, 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 โ€” specifies the C-SKY target processor. Valid values for cpu are ck801, ck801t, ck802, ck802t, ck802j, ck803, ck803h, ck803t, ck803ht, ck803f, ck803fh, ck803e, ck803eh, ck803et, ck803eht, ck803ef, ck803efh, ck803ft, ck803eft, ck803efht, ck803r1, ck803hr1, ck803tr1, ck803htr1, ck803fr1, ck803fhr1, ck803er1, ck803ehr1, ck803etr1, ck803ehtr1, ck803efr1, ck803efhr1, ck803ftr1, ck803eftr1, ck803efhtr1, ck803s, ck803st, ck803se, ck803sf, ck803sef, ck803seft, ck807e, ck807ef, ck807, ck807f, ck810e, ck810et, ck810ef, ck810eft, ck810, ck810v, ck810f, ck810t, ck810fv, ck810tv, ck810ft, and ck810ftv. That is a lot of chips, the way they're all lined up ๐Ÿ˜ญ๐Ÿ”ฅ
  • -mbig-endian, -EB, -mlittle-endian, -EL โ€” okay bestie, these pick your byte order ๐Ÿงš -mbig-endian (or -EB) gives you big-endian code, and -mlittle-endian (or -EL) gives you little-endian. Little-endian is the default, so you're already slaying if you don't touch these โœจ
  • -mfloat-abi=name โ€” this one lets you pick your floating-point ABI ๐Ÿฆ‹ The valid vibes are soft, softfp, and hard.
    • soft makes GCC generate output full of library calls for floating-point operations.
    • softfp lets the code use hardware floating-point instructions, but it still sticks with the soft-float calling conventions.
    • hard lets the code use floating-point instructions and the FPU-specific calling conventions.

The default depends on your specific target configuration. Also, 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, or it's a whole mess.

  • -mhard-float, -msoft-float โ€” pick hardware or software floating-point implementations ๐ŸŒธ The default is soft float.
  • -mdouble-float, -mno-double-float โ€” when -mhard-float is in effect, these turn on (or off) generation of double-precision float instructions ๐Ÿ’œ This is the default except when compiling for CK803.
  • -mfdivdu, -mno-fdivdu โ€” when -mhard-float is in effect, these enable the "frecipd", "fsqrtd", and "fdivd" instructions ๐Ÿ”ฅ This is the default except when compiling for CK803.
  • -mfpu=fpu โ€” choose your floating-point processor ๐Ÿ‘‘ This one can only be used with -mhard-float. The values for fpu are:
    • fpv2_sf, which is the same as -mno-double-float -mno-fdivdu
    • fpv2, which is the same as -mdouble-float -mno-divdu
    • fpv2_divd, which is the same as -mdouble-float -mdivdu
  • -melrw, -mno-elrw โ€” enable (or disable) the extended "lrw" instruction โœจ This defaults to on for CK801 and off for everything else.
  • -mistack, -mno-istack โ€” enable interrupt stack instructions. The default is off ๐Ÿ™ˆ
The -mistack option is required if you want to handle the "interrupt" and "isr" function attributes. No -mistack, no handling, bestie.
  • -mmp โ€” enable multiprocessor instructions ๐Ÿงš The default is off.
  • -mcp โ€” enable coprocessor instructions ๐ŸŒˆ The default is off.
  • -mcache โ€” enable coprocessor instructions ๐Ÿ“ The default is off.
  • -msecurity โ€” enable C-SKY security instructions ๐Ÿ”’ The default is off.
  • -mtrust โ€” enable C-SKY trust instructions ๐Ÿซถ The default is off.
  • -mdsp, -medsp, -mvdsp โ€” enable C-SKY DSP, Enhanced DSP, or Vector DSP instructions, respectively ๐ŸŽ€ All of these default to off.
  • -mdiv, -mno-div โ€” generate divide instructions ๐Ÿ’… The default is off.
  • -msmart, -mno-smart โ€” generate code for Smart Mode, which only uses registers numbered 0-7 so you can use 16-bit instructions ๐Ÿฆ‹ This one is ignored for CK801, where this is already the required behavior, and it defaults to on for CK802. For other targets the default is off.
  • -mhigh-registers, -mno-high-registers โ€” generate code using the high registers numbered 16-31 ๐Ÿ‘‘ This option 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 one 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 it's 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, this can give you code that isn't compliant with the C-SKY V2 ABI prologue requirements, and that code can't be debugged or backtraced ๐Ÿ’€ It's disabled by default.
  • -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 ๐ŸŒˆ

FSF GCC on Darwin doesn't make "fat" object files. Instead, it makes an object file for the single architecture that GCC was built to target. Apple's GCC on Darwin does make "fat" files when 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 (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 can do it ๐Ÿ”ฅ

The Darwin tools act differently when they run into an ISA mismatch ๐Ÿ‘€ The assembler, as, only lets you use instructions that are valid for the subtype of the file it's generating. So you literally cannot 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 โ€” add the framework directory dir to the head of the list of directories searched for header files ๐Ÿ“‚ These directories get interleaved with the ones from -I options, and they're scanned in a left-to-right order.

A framework directory is a directory with frameworks in it. A framework is a directory that ends in .framework and has a Headers and/or PrivateHeaders directory sitting directly inside it. The name of a framework is the name of that directory excluding the .framework part. Headers for the framework are found in one of those two directories, and Headers gets 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 should not have the same name as a framework, and a warning gets issued if you break that rule โš ๏ธ Right now a subframework can't have subframeworks of its own, but the mechanism might be extended to support that in the future.

The standard frameworks live in /System/Library/Frameworks and /Library/Frameworks. An example include looks like #include <Framework/header.h>, where Framework is the name of the framework and header.h is found in the PrivateHeaders or Headers directory ๐Ÿ’–

  • -iframeworkdir โ€” this is like -F, except the directory gets treated as a system directory ๐ŸŒธ The main difference is that with -iframework, the compiler doesn't warn about constructs inside header files found via 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. This is ON by default.
  • -gfull โ€” emit debugging information for all symbols and types ๐Ÿง 
  • -mmacosx-version-min=version โ€” sets the earliest version of MacOS X that this executable will run on, which is version ๐Ÿ Typical values of version include 10.1, 10.2, and 10.3.9.

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 is to make choices that are compatible with as many systems and code bases as possible โœจ

  • -mkernel โ€” enable 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: the -mone-byte-bool switch causes GCC to 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 the system libraries. Only use this switch to conform to a non-default data model.
  • -mfix-and-continue, -ffix-and-continue, -findirect-data โ€” generate code that's good for fast turnaround development ๐Ÿ”ฅ This lets things like GDB dynamically load .o files into programs that are already running ๐Ÿฆ‹ -findirect-data and -ffix-and-continue are only provided for backwards compatibility.
  • -all_load โ€” loads all members of static archive libraries ๐Ÿ“ฆ See man ld(1) for more information.
  • -arch_errors_fatal โ€” makes errors about files with the wrong architecture fatal ๐Ÿ’€
  • -bind_at_load โ€” marks the output file so the dynamic linker binds all undefined references when the file is loaded or launched ๐Ÿงš
  • -bundle โ€” produces a Mach-o bundle format file ๐ŸŽ See man ld(1) for more information.
  • -bundle_loader executable โ€” specifies the executable that will load the build output file being linked ๐Ÿซถ See man ld(1) for more information.
  • -dynamiclib โ€” when you pass this, GCC produces a dynamic library instead of an executable when linking, using the Darwin libtool command ๐ŸŒˆ
  • -force_cpusubtype_ALL โ€” gives GCC's output file the ALL subtype, instead of the one controlled by -mcpu or -march โญ
  • -allowable_client client_name โ€” Darwin linker flag that takes a client_name ๐Ÿ’…
  • -client_name โ€” Darwin linker flag ๐Ÿฆ‹
  • -compatibility_version โ€” Darwin linker flag ๐ŸŒธ
  • -current_version โ€” Darwin linker flag โœจ
  • -dead_strip โ€” Darwin linker flag ๐Ÿ’€
  • -dependency-file โ€” Darwin linker flag ๐Ÿงš
  • -dylib_file โ€” Darwin linker flag ๐Ÿ“
  • -dylinker_install_name โ€” Darwin linker flag ๐ŸŽ€
  • -dynamic โ€” Darwin linker flag ๐Ÿ”ฅ
  • -exported_symbols_list โ€” Darwin linker flag ๐ŸŒˆ
  • -filelist โ€” Darwin linker flag ๐Ÿ“‚
  • -flat_namespace โ€” Darwin linker flag ๐Ÿซถ
  • -force_flat_namespace โ€” Darwin linker flag ๐Ÿ‘‘
  • -headerpad_max_install_names โ€” Darwin linker flag ๐Ÿฆ„
  • -image_base โ€” Darwin linker flag ๐Ÿ–ผ๏ธ
  • -init โ€” Darwin linker flag ๐ŸŒฑ
  • -install_name โ€” Darwin linker flag ๐Ÿชช
  • -keep_private_externs โ€” Darwin linker flag ๐Ÿ”’
  • -multi_module โ€” Darwin linker flag ๐Ÿงฉ
  • -multiply_defined โ€” Darwin linker flag ๐Ÿ‘ฏ
  • -multiply_defined_unused โ€” Darwin linker flag ๐Ÿ‘€
  • -noall_load โ€” Darwin linker flag ๐Ÿ™…
  • -no_dead_strip_inits_and_terms โ€” Darwin linker flag ๐Ÿ’–
  • -nofixprebinding โ€” Darwin linker flag ๐Ÿ› ๏ธ
  • -nomultidefs โ€” Darwin linker flag ๐Ÿญ
  • -noprebind โ€” Darwin linker flag ๐Ÿšซ
  • -noseglinkedit โ€” Darwin linker flag ๐Ÿชก
  • -pagezero_size โ€” Darwin linker flag ๐Ÿ“
  • -prebind โ€” Darwin linker flag ๐Ÿง
  • -prebind_all_twolevel_modules โ€” Darwin linker flag ๐ŸŒท
  • -private_bundle โ€” Darwin linker flag ๐Ÿซง
  • -read_only_relocs โ€” Darwin linker flag ๐Ÿ“–
  • -sectalign โ€” Darwin linker flag ๐Ÿ“
  • -sectobjectsymbols โ€” Darwin linker flag ๐Ÿงพ
  • -whyload โ€” Darwin linker flag ๐Ÿค”
  • -seg1addr โ€” Darwin linker flag ๐Ÿ 
  • -sectcreate โ€” Darwin linker flag ๐Ÿ›–
  • -sectobjectsymbols โ€” Darwin linker flag, yes it's listed twice in the original ๐Ÿ™ˆ
  • -sectorder โ€” Darwin linker flag ๐Ÿ—‚๏ธ
  • -segaddr โ€” Darwin linker flag ๐Ÿ“
  • -segs_read_only_addr โ€” Darwin linker flag ๐Ÿ”
  • -segs_read_write_addr โ€” Darwin linker flag โœ๏ธ
  • -seg_addr_table โ€” Darwin linker flag ๐Ÿ“š
  • -seg_addr_table_filename โ€” Darwin linker flag ๐Ÿ—ƒ๏ธ
  • -seglinkedit โ€” Darwin linker flag ๐Ÿช„
  • -segprot โ€” Darwin linker flag ๐Ÿ›ก๏ธ
  • -segs_read_only_addr โ€” Darwin linker flag, listed again here too ๐Ÿ™ƒ
  • -segs_read_write_addr โ€” Darwin linker flag, listed again here too ๐Ÿ™ƒ
  • -single_module โ€” Darwin linker flag โ˜๏ธ
  • -static โ€” Darwin linker flag ๐Ÿ—ฟ
  • -sub_library โ€” Darwin linker flag ๐Ÿช…
  • -sub_umbrella โ€” Darwin linker flag โ˜‚๏ธ
  • -twolevel_namespace โ€” Darwin linker flag 2๏ธโƒฃ
  • -umbrella โ€” Darwin linker flag โ˜‚๏ธ
  • -undefined โ€” Darwin linker flag โ“
  • -unexported_symbols_list โ€” Darwin linker flag ๐Ÿ™Š
  • -weak_reference_mismatches โ€” Darwin linker flag ๐Ÿ•ธ๏ธ
  • -whatsloaded โ€” Darwin linker flag ๐Ÿ”

Okay so all of these get passed straight through to the Darwin linker ๐Ÿฆ‹, and the Darwin linker man page is where you'll find the full deets ๐Ÿ’–.

โœจ DEC Alpha Options ๐Ÿ’Ž

These -m options are defined for the DEC Alpha implementations, so if you're on Alpha, these are your girls ๐Ÿ’œ

  • -mno-soft-float, -msoft-float โ€” Okay so -mno-soft-float uses the hardware floating-point instructions, and -msoft-float says don't use them ๐Ÿ™…. With -msoft-float, functions in libgcc.a handle the floating-point operations instead. Unless they get swapped out for routines that emulate floating-point operations, or get compiled to call such emulation routines, these routines issue floating-point operations themselves ๐Ÿ™ˆ. If you're compiling for an Alpha without floating-point operations, you must make sure the library is built so it doesn't call them. Also, Alpha implementations without floating-point operations are still required to have floating-point registers ๐Ÿงš.
  • -mfp-reg, -mno-fp-regs โ€” -mfp-reg makes the code use the floating-point register set, and -mno-fp-regs makes it skip that set ๐ŸŒธ. -mno-fp-regs implies -msoft-float. When the floating-point register set isn't used, floating-point operands are passed in integer registers as if they were integers, and floating-point results are 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 gets called by code compiled with -mno-fp-regs must also be compiled with that option ๐Ÿ“ž. A typical use is building a kernel that doesn't use, and hence doesn't need to save and restore, any floating-point registers ๐Ÿ”ฅ.
  • -mieee โ€” The Alpha architecture has floating-point hardware built for maximum performance, and it's mostly IEEE compliant, but full compliance needs a little 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 resulting code is less efficient, but it can correctly support denormalized numbers and exceptional IEEE values like not-a-number and plus/minus infinity โœจ. Other Alpha compilers call this option -ieee_with_no_inexact.
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, because the software functions in the GNU libc math libraries generate denormalized numbers, NaNs, and infs (all of which will cause a program to SIGFPE when it attempts to use the results without -mieee) ๐Ÿ’€.
  • -mieee-with-inexact โ€” This is like -mieee, except the generated code also maintains the IEEE inexact-flag ๐Ÿง . Turning it on makes the generated code fully-compliant IEEE math. In addition to "_IEEE_FP", "_IEEE_FP_EXACT" is defined as a preprocessor macro. On some Alpha implementations the resulting code may run significantly slower than the default, and since there's very little code that 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 โ€” This controls which floating-point-related traps are enabled ๐Ÿชค. Other Alpha compilers call this option -fptm trap-mode. The trap mode can be set to one of four values:
    • n โ€” This is the default (normal) setting. The only traps enabled are the ones that can't be disabled in software (for example, the division by zero trap).
    • u โ€” In addition to the traps enabled by n, underflow traps are enabled too.
    • su โ€” Like u, but the instructions are marked as safe for software completion (see the Alpha architecture manual for details).
    • sui โ€” Like su, but inexact traps are enabled too.
  • -mfp-rounding-mode=rounding-mode โ€” This selects the IEEE rounding mode ๐ŸŽ€. Other Alpha compilers call this option -fprm rounding-mode. The rounding-mode can be one of:
    • n โ€” Normal IEEE rounding mode. Floating-point numbers are rounded towards the nearest machine number, or towards the even machine number in case of a tie.
    • m โ€” Round towards minus infinity.
    • c โ€” Chopped rounding mode. Floating-point numbers are rounded towards zero.
    • d โ€” Dynamic rounding mode. A field in the floating-point control register (fpcr, see the Alpha architecture reference manual) controls the rounding mode in effect. The C library initializes this register for rounding towards plus infinity, so unless your program modifies the fpcr, d corresponds to round towards plus infinity ๐ŸŒˆ.
  • -mtrap-precision=trap-precision โ€” In the Alpha architecture, floating-point traps are imprecise ๐Ÿ˜ต. That means without software assistance it's impossible to recover from a floating trap, and program execution normally needs 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 a level 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 โ€” This option marks the generated code as IEEE conformant ๐Ÿ“œ. You must not use it 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 construct it from smaller constants in two or three instructions. If it cannot, 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 construct 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. Being a shared library itself, it must 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 โ€” These indicate whether GCC should generate code to use the optional BWX, CIX, FIX and MAX instruction sets ๐ŸŽ›๏ธ. The default is to use the instruction sets supported by the CPU type specified via the -mcpu= option, or that of the CPU on which GCC was built if none is specified.
  • -mfloat-vax, -mfloat-ieee โ€” -mfloat-vax makes the code use VAX F and G floating-point arithmetic instead of IEEE single and double precision, and -mfloat-ieee makes it not do that ๐Ÿฆ–.
  • -mexplicit-relocs, -mno-explicit-relocs โ€” Older Alpha assemblers provided no way to generate symbol relocations except via 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 should apply to which instructions. This option is mostly useful for debugging, since GCC detects the capabilities of the assembler when it is built and sets the default accordingly.
  • -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 are 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 via a single instruction โšก. The default is -mlarge-data. With this option the data area is limited to just below 2GB. Programs that require 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.
  • -msmall-text, -mlarge-text โ€” When -msmall-text is used, the compiler assumes the code of the entire program (or shared library) fits in 4MB, and is thus reachable with a branch instruction ๐Ÿฆ‹. When -msmall-data is used, the compiler can assume that all local symbols share the same $gp value, and thus reduce the number of instructions required for a function call from 4 to 1 โœจ. The default is -mlarge-text.
  • -mcpu=cpu_type โ€” okay so this one sets the instruction set and the instruction scheduling parameters for machine type cpu_type ๐Ÿ’… You can pass either the EV style name or the matching chip number. GCC has scheduling parameters for the EV4, EV5 and EV6 family, and it picks the default instruction set from whichever processor you name. If you don't name a processor type, GCC defaults to the processor the compiler was built on ๐Ÿงš

Supported values for cpu_type are:

  • ev4, ev45, 21064 โ€” schedules as an EV4 and has no instruction set extensions ๐ŸŒธ
  • ev5, 21164 โ€” schedules as an EV5 and has no instruction set extensions ๐ŸŒธ
  • ev56, 21164a โ€” schedules as an EV5 and supports the BWX extension ๐Ÿ’–
  • pca56, 21164pc, 21164PC โ€” schedules as an EV5 and supports the BWX and MAX extensions ๐Ÿ’–
  • ev6, 21264 โ€” schedules as an EV6 and supports the BWX, FIX, and MAX extensions โœจ
  • ev67, 21264a โ€” schedules as an EV6 and supports the BWX, CIX, FIX, and MAX extensions ๐Ÿ‘‘

Native toolchains also 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 โ€” this one only touches the instruction scheduling parameters for cpu_type. The instruction set stays exactly the same โœจ

Native toolchains also support the value native, 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 โ€” this sets the latency the scheduler should assume for typical memory references as seen by the application. Honestly this number is highly dependent on the memory access patterns the application uses and the size of the external cache on the machine ๐Ÿง 

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 for the Level 1, 2 & 3 caches (also called Dcache, Scache, and Bcache), as well as for main memory. Note that L3 is only valid for EV5 ๐Ÿฅบ

โœจ eBPF Options โœจ

  • -mframe-limit=bytes โ€” this 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 is imposed by the version of the Linux kernel being targeted ๐Ÿง
  • -mkernel=version โ€” this is the minimum kernel version that will run your compiled program. GCC uses it to decide which instructions to use, which kernel helpers to allow, etc. ๐Ÿงš Currently, 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 and native
  • -mbig-endian โ€” generate code for a big-endian target ๐ŸŒˆ
  • -mlittle-endian โ€” generate code for a little-endian target. This is the default ๐Ÿ’œ
  • -mjmpext โ€” enables generation of extra conditional-branch instructions. It's enabled for CPU v2 and above ๐Ÿฆ‹
  • -mjmp32 โ€” enables 32-bit jump instructions. It's enabled for CPU v3 and above ๐ŸŒธ
  • -malu32 โ€” enables 32-bit ALU instructions. It's enabled for CPU v3 and above ๐Ÿ’…
  • -mcpu=version โ€” this picks which version of the eBPF ISA to target. Newer versions may not be supported by all kernels, so be careful ๐Ÿ™ˆ The default is v3.

Supported values for version are:

  • v1 โ€” the first stable eBPF ISA, with no special features or extensions ๐Ÿ“
  • v2 โ€” supports the jump extensions, as in -mjmpext โœจ
  • v3 โ€” all features of v2, plus:
    • -<32-bit jump operations, as in -mjmp32>
    • -<32-bit ALU operations, as in -malu32>
  • -mco-re โ€” enables BPF Compile Once - Run Everywhere (CO-RE) support. It requires and is implied by -gbtf ๐ŸŽ€
  • -mno-co-re โ€” disables BPF Compile Once - Run Everywhere (CO-RE) support. BPF CO-RE support is enabled by default when generating BTF debug information for the BPF target ๐Ÿ™…โ€โ™€๏ธ
  • -mxbpf โ€” generates code for an expanded version of BPF, which relaxes some of the restrictions imposed by the BPF architecture ๐Ÿ”ฅ
    • -<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. This can produce smaller code, but it does assume that all symbolic values and addresses fit into a 20-bit range ๐Ÿฃ
  • -mno-lsim โ€” assumes runtime support has already been provided, so there's no need to include the simulator library (libsim.a) on the linker command line ๐Ÿซง

๐Ÿฆ‹ FT32 Options ๐Ÿฆ‹

These options are defined specifically for the FT32 port ๐Ÿ’–

  • -msim โ€” specifies that the program will run on the simulator. This causes an alternate runtime startup and library to be linked ๐ŸŽฎ
๐Ÿ’€ 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 are needed.
  • -mlra โ€” enables Local Register Allocation. This is still experimental for FT32, so by default the compiler uses standard reload ๐Ÿงช
  • -mnodiv โ€” don'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 โ€” don't generate code that reads program memory ๐Ÿ”’

๐ŸŒˆ FRV Options ๐ŸŒˆ

  • -mgpr-32 โ€” only use the first 32 general-purpose registers ๐Ÿ”ข
  • -mgpr-64 โ€” use all 64 general-purpose registers ๐Ÿ’ช
  • -mfpr-32 โ€” use only the first 32 floating-point registers ๐Ÿƒ
  • -mfpr-64 โ€” use all 64 floating-point registers ๐ŸŒŸ
  • -mhard-float โ€” use hardware instructions for floating-point operations โšก
  • -msoft-float โ€” use library routines for floating-point operations ๐Ÿ“š
  • -malloc-cc โ€” dynamically allocate condition code registers ๐ŸŽˆ
  • -mfixed-cc โ€” don't try to dynamically allocate condition code registers. Only use "icc0" and "fcc0" ๐Ÿ“Œ
  • -mdword โ€” changes the ABI to use double word insns ๐Ÿ‘‘
  • -mno-dword โ€” don't use double word instructions ๐Ÿ™ƒ
  • -mdouble โ€” use floating-point double instructions ๐Ÿ’œ
  • -mno-double โ€” don't use floating-point double instructions ๐Ÿ’…
  • -mmedia โ€” use media instructions ๐ŸŽฌ
  • -mno-media โ€” don't use media instructions ๐Ÿ™ˆ
  • -mmuladd โ€” use multiply and add/subtract instructions โž•
  • -mno-muladd โ€” don't use multiply and add/subtract instructions โž–
  • -mfdpic โ€” selects the FDPIC ABI, which uses function descriptors to represent pointers to functions. Without any PIC/PIE-related options, it implies -fPIE. With -fpic or -fpie, it assumes GOT entries and small data are within a 12-bit range from the GOT base address; with -fPIC or -fPIE, GOT offsets are computed with 32 bits. With a bfin-elf target, this option implies -msim ๐Ÿงฉ
  • -minline-plt โ€” enables inlining of PLT entries in function calls to functions that aren't known to bind locally. It has no effect without -mfdpic. It's enabled by default if you're optimizing for speed and compiling for shared libraries (i.e., -fPIC or -fpic), or when an optimization option such as -O3 or above is on the command line ๐Ÿš€
  • -mTLS โ€” assumes a large TLS segment when generating thread-local code ๐Ÿงต
  • -mtls โ€” doesn't assume a large TLS segment when generating thread-local code ๐Ÿชก
  • -mgprel-ro โ€” enables the use of "GPREL" relocations in the FDPIC ABI for data known to be in read-only sections. It's enabled by default, except for -fpic or -fpie. Even though it may help make the global offset table smaller, it trades 1 instruction for 4. With -fPIC or -fPIE, it trades 3 instructions for 4, one of which may be shared by multiple symbols, and it 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. This option is enabled by default and can be disabled 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 option only has an effect 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 โ€” use only the first four media accumulator registers 4๏ธโƒฃ
  • -macc-8 โ€” use all eight media accumulator registers 8๏ธโƒฃ
  • -mpack โ€” packs VLIW instructions ๐Ÿ“ฆ
  • -mno-pack โ€” don't pack VLIW instructions ๐Ÿšซ
  • -mno-eflags โ€” don't mark ABI switches in e_flags ๐Ÿณ๏ธ
  • -mcond-move โ€” enables the use of conditional-move instructions (default) ๐ŸŒธ
๐Ÿ™ˆ This switch is mainly for debugging the compiler and will 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 will likely be removed in a future version.
  • -mscc โ€” enables the use of conditional set instructions (default) โœจ
๐Ÿ™ˆ This switch is mainly for debugging the compiler and will 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 will likely be removed in a future version.
  • -mcond-exec โ€” enables the use of conditional execution (default) ๐Ÿฆ„
๐Ÿ™ˆ This switch is mainly for debugging the compiler and will 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 will likely be removed in a future version.
  • -mvliw-branch โ€” okay so this one runs a pass that packs branches into VLIW instructions ๐Ÿซถ It's on by default. This switch is mainly for debugging the compiler and will probably get removed in a future version ๐Ÿ’€
  • -mno-vliw-branch โ€” the opposite! Skips the pass that packs branches into VLIW instructions. Also mostly a debugging switch that will likely be removed in a future version ๐Ÿ™ˆ
  • -mmulti-cond-exec โ€” turns on optimization of "&&" and "||" in conditional execution โœจ It's the default. Also debugging-only and likely to be removed someday ๐Ÿฅ€
  • -mno-multi-cond-exec โ€” turns that optimization off for "&&" and "||" in conditional execution. Debugging-only, likely removed later ๐Ÿงš
  • -mnested-cond-exec โ€” enables nested conditional execution optimizations. Default, obviously ๐Ÿ‘‘ Debugging-only, will probably be removed later too
  • -mno-nested-cond-exec โ€” disables nested conditional execution optimizations. Debugging-only, likely removed in a future version ๐Ÿ’…
  • -moptimize-membar โ€” removes redundant "membar" instructions from the compiler-generated code. It's on by default, so you get the glow-up automatically ๐Ÿ’–
  • -mno-optimize-membar โ€” disables that automatic removal of redundant "membar" instructions from the generated code. Your membars stay put ๐ŸŒธ
  • -mtomcat-stats โ€” makes gas print out tomcat statistics ๐Ÿ“Š
  • -mcpu=cpu โ€” picks the processor type you want code generated for. The possible values are frv, fr550, tomcat, fr500, fr450, fr405, fr400, fr300 and simple ๐Ÿฆ‹

๐ŸŽ€ GNU/Linux Options ๐ŸŽ€

These -m options are defined for GNU/Linux targets, bestie ๐Ÿง

  • -mglibc โ€” uses the GNU C library. This is the default except on *-*-linux-*uclibc*, *-*-linux-*musl* and *-*-linux-*android* targets ๐ŸŒˆ
  • -muclibc โ€” uses the uClibc C library. This is the default on *-*-linux-*uclibc* targets ๐Ÿ“
  • -mmusl โ€” uses the musl C library. This is the default on *-*-linux-*musl* targets ๐Ÿ’œ
  • -mbionic โ€” uses the Bionic C library. This is the default on *-*-linux-*android* targets ๐Ÿค–
  • -mandroid โ€” compiles code that's compatible with the Android platform. It's the default on *-*-linux-*android* targets, so it's giving main character energy ๐Ÿ“ฑ
    • 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 ๐Ÿ”—
    • 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 linker just gets standard Linux linking options ๐Ÿฃ

๐Ÿฆ‹ H8/300 Options ๐Ÿฆ‹

These -m options are defined for the H8/300 implementations, so if you're doing that, here's the tea โ˜•

  • -mrelax โ€” shortens some address references at link time, when it's possible. It uses the linker option -relax to do it ๐Ÿช„
  • -mh โ€” generates code for the H8/300H ๐Ÿ’ซ
  • -ms โ€” generates code for the H8S ๐ŸŒŸ
  • -mn โ€” generates code for the H8S and H8/300H in the normal mode. You have to use this with either -mh or -ms, no skipping ๐Ÿซถ
  • -ms2600 โ€” generates code for the H8S/2600. This one must be used together with -ms ๐ŸŽ€
  • -mexr โ€” the extended registers get stored on the stack before a function with the monitor attribute runs. This is the default option โœจ It's only valid for H8S targets, so keep that in mind ๐Ÿ’…
  • -mno-exr โ€” the extended registers do not get stored on the stack before a function with the monitor attribute runs. The default option here is -mno-exr, and it's again 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 H8/300H and H8S normally align longs and floats on 4-byte boundaries, but -malign-300 pushes them to 2-byte boundaries instead. It has no effect on the H8/300 ๐ŸŒธ

๐ŸŒท HPPA Options ๐ŸŒท

These -m options are defined for the HPPA family of computers. Let's get into it ๐Ÿงš

  • -march=architecture-type โ€” generates code for the architecture you pick. 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. If you're unsure which one is yours, check out /usr/lib/sched.models on an HP-UX system ๐Ÿ” Code compiled for lower-numbered architectures runs on higher-numbered ones, but not the other way around ๐Ÿšซ
  • -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. Use this one with care, because it isn't compatible with the default 32-bit runtime ๐Ÿ˜ฌ That said, only aggregates larger than eight bytes get passed by hidden reference, and this option gives you better compatibility with OpenMP ๐Ÿซถ
  • -mjump-in-delay โ€” this is ignored. It's only here for compatibility purposes ๐Ÿ™ƒ
  • -mdisable-fpregs โ€” stops floating-point registers from being used in any manner. This is necessary for compiling kernels that do lazy context switching of floating-point registers ๐Ÿ”ง If you use this option and then try to do floating-point operations, the compiler aborts ๐Ÿ’€
  • -mdisable-indexing โ€” stops the compiler from using indexing address modes. This dodges 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 make faster indirect calls and use unscaled index address modes โšก
    • Code like this is suitable for level 0 PA systems and kernels ๐Ÿ–ฅ๏ธ
  • -mfast-indirect-calls โ€” generates code that assumes calls never cross space boundaries, so GCC can emit code that does faster indirect calls ๐Ÿƒโ€โ™€๏ธ
    • This option does not work in the presence of shared libraries or nested functions โŒ
  • -mfixed-range=register-range โ€” generates code that treats the given register range as fixed registers. A fixed register is one the register allocator can't use. This is super useful when compiling kernel code ๐Ÿ‘‘ A register range is written as two registers separated by a dash, and you can separate multiple ranges with a comma ๐ŸŽ€
  • -mlong-load-store โ€” generates 3-instruction load and store sequences, which the HP-UX 10 linker sometimes needs. This is equivalent to the +k option on 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 are 700 7100, 7100LC, 7200, 7300 and 8000. Check /usr/lib/sched.models on an HP-UX system to find the right scheduling option for your machine ๐Ÿ“… The default scheduling is 8000 โœจ
  • -mlinker-opt โ€” enables the optimization pass in the HP-UX linker. Heads up though, this makes symbolic debugging impossible ๐Ÿ˜ญ It also triggers a bug in the HP-UX 8 and HP-UX 9 linkers, where they give bogus error messages when linking some programs ๐Ÿ™ˆ
  • -msoft-float โ€” generates output that contains library calls for floating point ๐Ÿงฎ
โš ๏ธ Warning, bestie: the requisite libraries are not available for all HPPA targets. Normally the facilities of the machine's usual C compiler are used, but that can't be done directly in cross-compilation. You'll have to make your own arrangements to provide suitable library functions for cross-compilation ๐Ÿซ 
  • -msoft-float changes the calling convention in the output file, so it's only useful if you compile all of a program with this option ๐Ÿงต
  • You also 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 doesn't change which ld gets called. It only changes what parameters get passed to that ld. The ld that's called is decided by the --with-ld configure option, GCC's program search path, and finally 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 ๐Ÿ’… Just like -mgnu-ld, this doesn't affect which ld is called, only the parameters. That's decided by the --with-ld configure option, GCC's program search path, and finally the user's PATH ๐Ÿงญ Print the linker 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` ๐ŸŒธ
  • -mlong-calls โ€” generates code that uses long call sequences. This makes sure a call can always reach linker-generated stubs ๐Ÿงฉ By default, long calls are only generated when the distance from the call site to the beginning of the function or translation unit (depending on the case) goes over a predefined limit set by the branch type being used. The limits for normal calls are 7,600,000 and 240,000 bytes, for PA 2.0 and PA 1.X architectures respectively. Sibcalls are always limited at 240,000 bytes ๐Ÿ“
    • Distances are measured from the beginning of functions when using -ffunction-sections, or when using -mgas and -mno-portable-runtime together under HP-UX with the SOM linker ๐Ÿ”
    • Honestly, it's usually not desirable to use this option because it degrades performance ๐Ÿ˜ฉ But it may be useful in large applications, especially when partial linking is used to build the application ๐Ÿซถ

The types of long calls used depend on what the assembler and linker can do, plus the kind of code being generated. Systems that support long absolute calls, and long pic symbol-difference or pc-relative calls, should barely notice the impact ๐Ÿงš. But on 32-bit ELF systems in pic code, an indirect call gets used instead, and it's quite long ๐Ÿ˜ญ

  • -munix=unix-std โ€” Sets up the compiler predefines and picks a startfile for the UNIX standard you choose ๐Ÿ’…. The options are 93, 95 and 98. 93 works on every HP-UX version. 95 needs HP-UX 10.10 or later, and 98 needs HP-UX 11.11 or later. By default you get 93 on HP-UX 10.00, 95 on HP-UX 10.10 through 11.00, and 98 on HP-UX 11.11 and up.

-munix=93 gives you the same predefines as GCC 3.3 and 3.4. -munix=95 adds predefines for "XOPEN_UNIX" and "_XOPEN_SOURCE_EXTENDED", plus the startfile unix95.o. -munix=98 adds predefines for "_XOPEN_UNIX", "_XOPEN_SOURCE_EXTENDED", "_INCLUDE__STDC_A1_SOURCE" and "_INCLUDE_XOPEN_SOURCE_500", plus the startfile unix98.o.

Heads up, bestie: this option changes the interfaces of various library routines, and it also affects how the C library behaves ๐Ÿ˜ฌ So you need to be extra careful with it.

Library code that's meant to work with more than one UNIX standard has to test, set and restore the variable "__xpg4_extended_mask" as needed. Most GNU software doesn't do this, so don't expect it ๐Ÿ™ˆ

  • -nolibdld โ€” Stops the driver from adding the link options that search libdld.sl when you use -static on HP-UX 10 and later ๐Ÿ”—
  • -static โ€” Here's the tea โ˜• The HP-UX version of setlocale in libc depends on libdld.sl, and there's no archive version of libdld.sl. So when you pass -static, you need special link options to sort this out.

On HP-UX 10 and later, the GCC driver adds the link options it needs to link with libdld.sl whenever you use -static. 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 driver adding these link options, use -nolibdld ๐Ÿ’œ

  • -threads โ€” Adds multithreading support using the dce thread library under HP-UX ๐Ÿงต This option sets flags for both the preprocessor and the linker.

โœจ IA-64 Options โœจ

These are the -m options for the Intel IA-64 architecture ๐Ÿ’–

  • -mbig-endian โ€” Generates code for a big-endian target. This is the default on HP-UX.
  • -mlittle-endian โ€” Generates code for a little-endian target. This is the default on AIX5 and GNU/Linux.
  • -mgnu-as, -mno-gnu-as โ€” Generates code for the GNU assembler, or doesn't. Generating it is the default.
  • -mgnu-ld, -mno-gnu-ld โ€” Generates code for the GNU linker, or doesn't. Generating it is the default.
  • -mno-pic โ€” Generates code that doesn't use a global pointer register. The result is not position independent code, and it breaks the IA-64 ABI ๐Ÿ’€
  • -mvolatile-asm-stop, -mno-volatile-asm-stop โ€” Generates (or doesn't) a stop bit right before and after volatile asm statements ๐Ÿ›‘
  • -mregister-names, -mno-register-names โ€” Generates (or doesn't) the in, loc, and out register names for the stacked registers. This might make the assembler output easier to read ๐Ÿ‘€
  • -mno-sdata, -msdata โ€” Disables (or enables) optimizations that use the small data section. This can be handy for working around optimizer bugs ๐Ÿ›
  • -mconstant-gp โ€” Generates code that uses one single constant global pointer value. This is useful when compiling kernel code ๐Ÿง 
  • -mauto-pic โ€” Generates code that is self-relocatable. This implies -mconstant-gp. It's useful when compiling firmware code ๐Ÿ”ง
  • -minline-float-divide-min-latency โ€” Generates inline divides of floating-point values using the minimum latency algorithm.
  • -minline-float-divide-max-throughput โ€” Generates inline divides of floating-point values using the maximum throughput algorithm.
  • -mno-inline-float-divide โ€” Doesn't generate inline code for divides of floating-point values.
  • -minline-int-divide-min-latency โ€” Generates inline divides of integer values using the minimum latency algorithm.
  • -minline-int-divide-max-throughput โ€” Generates inline divides of integer values using the maximum throughput algorithm.
  • -mno-inline-int-divide โ€” Doesn't generate inline code for divides of integer values.
  • -minline-sqrt-min-latency โ€” Generates inline square roots using the minimum latency algorithm.
  • -minline-sqrt-max-throughput โ€” Generates inline square roots using the maximum throughput algorithm.
  • -mno-inline-sqrt โ€” Doesn't generate inline code for sqrt.
  • -mfused-madd, -mno-fused-madd โ€” Does (or doesn't) generate code using 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 might be useful when you're not using the GNU assembler.
  • -mearly-stop-bits, -mno-early-stop-bits โ€” Lets stop bits go earlier than right before the instruction that triggered them. This can improve instruction scheduling, but it doesn't always ๐Ÿคทโ€โ™€๏ธ
  • -mfixed-range=register-range โ€” Generates code that treats the given register range as fixed registers. A fixed register is one the register allocator can't use. This is useful when compiling kernel code ๐Ÿงฉ You give a register range as two registers separated by a dash, and you can list several ranges separated by commas.
  • -mtls-size=tls-size โ€” Sets the bit size of immediate TLS offsets. The valid values are 14, 22, and 64.
  • -mtune=cpu-type โ€” Tunes instruction scheduling for a particular CPU. The 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 โ€” Disables (or enables) data speculative scheduling before reload. This produces ld.a instructions and the matching check instructions (ld.c / chk.a). The default is disabled.
  • -msched-ar-data-spec, -mno-sched-ar-data-spec โ€” Enables (or disables) data speculative scheduling after reload. This produces ld.a instructions and the matching check instructions (ld.c / chk.a). The default is enabled.
  • -mno-sched-control-spec, -msched-control-spec โ€” Disables (or enables) control speculative scheduling. This only works during region scheduling, which means before reload. It produces the ld.s instructions and the matching check instructions chk.s. The default is disabled.
  • -msched-br-in-data-spec, -mno-sched-br-in-data-spec โ€” Enables (or disables) speculative scheduling of instructions that depend on the data speculative loads before reload. This only does anything with -msched-br-data-spec enabled. The default is enabled.
  • -msched-ar-in-data-spec, -mno-sched-ar-in-data-spec โ€” Enables (or disables) speculative scheduling of instructions that depend on the data speculative loads after reload. This only does anything with -msched-ar-data-spec enabled. The default is enabled.
  • -msched-in-control-spec, -mno-sched-in-control-spec โ€” Enables (or disables) speculative scheduling of instructions that depend on the control speculative loads. This only does anything with -msched-control-spec enabled. The default is enabled.
  • -mno-sched-prefer-non-data-spec-insns, -msched-prefer-non-data-spec-insns โ€” When enabled, data-speculative instructions only get scheduled if there are no other choices at the moment. This makes data speculation much more conservative. The default is disabled.
  • -mno-sched-prefer-non-control-spec-insns, -msched-prefer-non-control-spec-insns โ€” When enabled, control-speculative instructions only get scheduled if there are no other choices at the moment. This makes control speculation much more conservative. The default is disabled.
  • -mno-sched-count-spec-in-critical-path, -msched-count-spec-in-critical-path โ€” When enabled, speculative dependencies are considered when computing instruction priorities. This makes speculation a bit more conservative. The default 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 aren't likely to 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 โ€” Limits the number of memory insns per instruction group, giving lower priority to later memory insns that try to schedule in the same group. This is often handy for avoiding cache bank conflicts ๐ŸงŠ The default value is 1.
  • -msched-max-memory-insns-hard-limit โ€” Turns the limit set by msched-max-memory-insns into a hard limit, so no more than that number of memory insns can go in one instruction group. Otherwise the limit is "soft": non-memory operations are preferred once the limit is reached, but memory operations can still get scheduled ๐Ÿ’…

๐Ÿ’œ LM32 Options ๐Ÿ’œ

These -m options are defined for the LatticeMico32 architecture ๐ŸŒˆ

  • -mbarrel-shift-enabled โ€” Enables barrel-shift instructions.

-mdivide-enabled okay bestie ๐Ÿ’– turns on the divide and modulus instructions ๐Ÿงฎโœจ no cap they're a whole vibe.

  • -mmultiply-enabled โ€” enables the multiply instructions ๐Ÿฆ‹
  • -msign-extend-enabled โ€” enables the sign extend instructions ๐ŸŒธ
  • -muser-enabled โ€” enables user-defined instructions ๐Ÿงš

โœจ M32C Options โœจ

  • -mcpu=name โ€” pick the CPU you're generating code for ๐Ÿ‘‘ the name can be r8c for the R8C/Tiny series, m16c for the M16C (up to /60) series, m32cm for the M16C/80 series, or m32c for the M32C/80 series ๐Ÿ’…
  • -msim โ€” tells GCC the program will run on the simulator ๐Ÿ”ฎ this links in an alternate runtime library that supports stuff like file I/O ๐Ÿ“ > โš ๏ธ bestie, DO NOT use this for programs running on real hardware!! ๐Ÿ˜ญ you need to bring your own runtime library for whatever I/O functions you need ๐Ÿซถ
  • -memregs=number โ€” sets how many memory-based pseudo-registers GCC uses during code generation ๐Ÿง  they act like real registers, so it's a tradeoff between fitting code into registers and the performance hit of using memory instead ๐Ÿ’€ every module in your program has to be compiled with the same value ๐Ÿ™ˆ and since of that, you must not use this option with GCC's default runtime libraries ๐Ÿ˜ญ

โœจ M32R/D Options โœจ

These -m options are defined for Renesas M32R/D architectures ๐ŸŒˆ

  • -m32r2 โ€” generates code for the M32R/2 ๐Ÿฆ‹
  • -m32rx โ€” generates code for the M32R/X ๐Ÿฆ‹
  • -m32r โ€” generates code for the M32R ๐Ÿฆ‹ this one's the default ๐Ÿ’–
  • -mmodel=small โ€” assumes all objects live in the lower 16MB of memory ๐ŸŒธ so their addresses can be loaded with the "ld24" instruction, and all subroutines are reachable with the "bl" instruction ๐Ÿงš this is the default โœจ

The addressability of a particular object can be set with the "model" attribute ๐ŸŽ€

  • -mmodel=medium โ€” assumes objects may be anywhere in the 32-bit address space ๐ŸŒ GCC generates "seth/add3" instructions to load their addresses, and all subroutines are still reachable with the "bl" instruction ๐Ÿซถ
  • -mmodel=large โ€” assumes objects may be anywhere in the 32-bit address space AND subroutines may not be reachable with "bl" ๐Ÿ˜ฑ GCC generates "seth/add3" to load addresses and the much slower "seth/add3/jl" sequence for calls ๐Ÿข
  • -msdata=none โ€” disables the small data area ๐Ÿ‘ variables go into ".data", ".bss", or ".rodata" (unless the "section" attribute is specified) ๐Ÿ’… this is the default ๐Ÿ’–

The small data area is made of the ".sdata" and ".sbss" sections ๐Ÿง you can explicitly put objects there 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 any 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 num is 8 ๐Ÿ’… the -msdata option has to be set to sdata or use for this to do anything ๐Ÿซ 

All modules should be compiled with the same -G num value ๐Ÿซถ using different values might or might 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 your programs ๐Ÿ”
  • -malign-loops โ€” aligns all loops to a 32-byte boundary ๐Ÿ“
  • -mno-align-loops โ€” does not enforce 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 โ€” sets the branch cost ๐Ÿ’ธ 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 used to flush the cache ๐Ÿงน the default is 12 ๐Ÿ’… valid numbers are between 0 and 15 inclusive ๐Ÿ”ข
  • -mno-flush-trap โ€” says 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 isn't available ๐Ÿซค
  • -mno-flush-func โ€” says there is no OS function for flushing the cache ๐Ÿ™…โ€โ™€๏ธ

โœจ M680x0 Options โœจ

These are the -m options defined for M680x0 and ColdFire processors ๐Ÿ–ฅ๏ธ the defaults depend on which architecture was selected when the compiler was configured ๐Ÿ› ๏ธ the defaults for the most common choices are listed below ๐Ÿ“‹

  • -march=arch โ€” generates code for a specific M680x0 or ColdFire instruction set architecture ๐ŸŽฏ for M680x0, arch can be 68000, 68010, 68020, 68030, 68040, 68060 or cpu32 ๐Ÿ’… ColdFire architectures are picked by Freescale's ISA classification, and the options are isaa, isaaplus, isab and isac ๐ŸŒˆ

GCC defines a macro "__mcfarch__" whenever it's generating code for a ColdFire target ๐Ÿงš the arch in that macro is one of the -march arguments above โœจ

When you use -march and -mtune together, you get code that runs on a family of similar processors but is optimized for one 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 them 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 ๐Ÿค any other combos 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 comes from the table above ๐Ÿ“‹

  • -mtune=tune โ€” tunes the code for a particular microarchitecture within the limits 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 pretty well on 68020, 68030 and 68040 targets ๐Ÿงก -mtune=68020-60 is similar but also includes 68060 targets ๐Ÿ’œ these two 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 -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 stops the use of 68881/68882 instructions that would have to be emulated in software on the 68040 ๐Ÿ™…โ€โ™€๏ธ use it if your 68040 doesn't have code to emulate those instructions ๐Ÿซ 

  • -m68060 โ€” generates output for a 68060 ๐ŸŒธ this is the default when the compiler is configured for 68060-based systems ๐Ÿ’– it's equivalent to -march=68060 โœจ

This option stops the use of 68020 and 68881/68882 instructions that have to be emulated in software on the 68060 ๐Ÿ™…โ€โ™€๏ธ use it 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, but it's deprecated in favour 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 ๐Ÿ–ฅ๏ธ this option is deprecated now, so use the equivalent -mcpu=5206e instead ๐Ÿ’…
  • -m528x โ€” Okay bestie, this one generates code for the ColdFire 528X family ๐Ÿฆ‹. It's deprecated now, so use -mcpu=528x instead ๐Ÿ’….
  • -m5307 โ€” Generates output for a ColdFire 5307 CPU ๐ŸŒธ. Also deprecated, so -mcpu=5307 is the move โœจ.
  • -m5407 โ€” Generates output for a ColdFire 5407 CPU ๐Ÿ’–. Deprecated too, so go with -mcpu=5407 ๐Ÿซถ.
  • -mcfv4e โ€” Generates output for a ColdFire V4e family CPU, like the 547x/548x chips ๐Ÿ”ฅ. This includes hardware floating-point instructions. It's the same as -mcpu=547x, and it's deprecated in favor of that one ๐Ÿ’….
  • -m68020-40 โ€” Generates output for a 68040 but skips all the new instructions ๐ŸŒˆ. The result runs pretty efficiently on a 68020/68881, a 68030, or a 68040. The code does use the 68881 instructions, which get emulated on the 68040 ๐Ÿงš. This is equivalent to -march=68020 -mtune=68020-40.
  • -m68020-60 โ€” Generates output for a 68060 and also skips the new instructions ๐Ÿ“. Same deal: it runs pretty efficiently on a 68020/68881, a 68030, or a 68040. The code uses the 68881 instructions, which 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 with an FPU. It defines the macro __HAVE_68881__ on M680x0 targets and __mcffpu__ on ColdFire targets ๐ŸŽ€.
  • -msoft-float โ€” Skips floating-point instructions and uses library calls instead ๐Ÿ™ˆ. This is the default for 68000, 68010, and 68832 targets. It's also the default for ColdFire devices that don't have an FPU ๐Ÿ’€.
  • -mdiv, -mno-div โ€” Lets you choose whether to generate ColdFire hardware divide and remainder instructions ๐Ÿ”ฅ. If you use -march 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 whatever you set with -mcpu. For example, the default is "off" for -mcpu=5206 and "on" for -mcpu=5206e โœจ.

When this option is enabled, GCC defines the macro __mcfhwdiv__ ๐Ÿฆ‹.

  • -mshort โ€” Treats type "int" as 16 bits wide, just like "short int" ๐ŸŒธ. Parameters passed on the stack also get aligned to a 16-bit boundary, even on targets that normally promote to 32-bit ๐Ÿซถ.
  • -mno-short โ€” Does not treat type "int" as 16 bits wide. This is the default ๐Ÿ’….
  • -mnobitfield, -mno-bitfield โ€” Skips the bit-field instructions ๐Ÿ™…โ€โ™€๏ธ. The -m68000, -mcpu32, and -m5200 options all imply -mnobitfield ๐Ÿ’œ.
  • -mbitfield โ€” Uses the bit-field instructions ๐Ÿงš. The -m68020 option implies -mbitfield, and this is the default if you're using a configuration designed for a 68020 โœจ.
  • -mrtd โ€” Switches to a different function-calling convention ๐ŸŒˆ. Functions that take a fixed number of arguments return with the "rtd" instruction, which pops their arguments as it returns. This saves one instruction in the caller, since the caller doesn't need to pop the arguments ๐Ÿ“.

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". If you skip them, GCC generates 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 with this option they aren't ๐Ÿ˜ญ.

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 -malign-int, GCC aligns structures containing those types differently than most published application binary interface specifications for the m68k. Lowkey a big deal, so watch out ๐Ÿ˜ญ.
  • -mpcrel โ€” Uses the pc-relative addressing mode of the 68000 directly, instead of a global offset table ๐Ÿงš. Right now this option implies -fpic, which allows at most a 16-bit offset for pc-relative addressing ๐ŸŒธ. -fPIC isn't currently 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 the system handles unaligned memory references, 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 lets you do 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 โ€” Sets the identification number of the ID-based shared library being compiled ๐ŸŒธ. Using 0 gives you more compact code. Other values force that number onto 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 even if the GOT has more than 8192 entries ๐Ÿ”ฅ. This code is larger and slower than code generated without the 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 you see that, recompile your code with -mxgot. It should then 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 fewer ๐Ÿ’–.
  • -mdiv, -mno-div โ€” 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 โ€” 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 it leaves the simulator library (libsim.a) off the linker command line ๐Ÿ‘‘.
  • -mstack-increment=size โ€” Sets the maximum amount for a single stack increment operation ๐ŸŽ€. Large values can speed up programs with functions that need a lot of stack space, but they can also trigger 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: average, multiply, divide, bit operations, leading zero, absolute difference, min/max, clip, and saturation ๐Ÿ”ฅ.
  • -maverage โ€” Enables the "ave" instruction, which computes the average of two registers ๐Ÿซถ.
  • -mbased=n โ€” Puts variables of size n bytes or smaller 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 ๐Ÿ’…. 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 โ€” Selects one of the built-in core configurations ๐Ÿ‘‘. Each MeP chip has one or more modules, and each module has a core CPU plus a variety 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 corresponding 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.

Okay bestie, so -mivc2 turns on IVC2 scheduling ๐Ÿฆ‹ and IVC2 is a 64-bit VLIW coprocessor (a whole coprocessor, not just a vibe) โœจ

-mdc Causes constant variables to be placed in the ".near" section.

-mdc puts constant variables into the ".near" section ๐ŸŒธ

-mdiv Enables the "div" and "divu" instructions.

-mdiv unlocks the "div" and "divu" instructions ๐Ÿ’…

-meb Generate big-endian code.

-meb means big-endian code, no cap ๐Ÿซถ

-mel Generate little-endian code.

-mel gives you little-endian code ๐Ÿ’œ

-mio-volatile Tells the compiler that any variable marked with the "io" attribute is to be considered volatile.

-mio-volatile tells the compiler that anything with the "io" attribute is treated as volatile ๐Ÿ”ฅ iykyk

-ml Causes variables to be assigned to the ".far" section by default.

-ml sends variables to the ".far" section by default ๐ŸŒˆ

-mleadz Enables the "leadz" (leading zero) instruction.

-mleadz enables the "leadz" (leading zero) instruction ๐Ÿงš

-mm Causes variables to be assigned to the ".near" section by default.

-mm makes variables default to the ".near" section ๐Ÿ“

-mminmax Enables the "min" and "max" instructions.

-mminmax enables the "min" and "max" instructions โญ

-mmult Enables the multiplication and multiply-accumulate instructions.

-mmult turns on the multiplication and multiply-accumulate instructions ๐Ÿ‘‘

-mno-opts Disables all the optional instructions enabled by -mall-opts.

-mno-opts disables all the optional instructions that -mall-opts turned on ๐Ÿ™ˆ

-mrepeat Enables the "repeat" and "erepeat" instructions, used for low- overhead looping.

-mrepeat enables the "repeat" and "erepeat" instructions, which are 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.

-ms makes all variables default to the ".tiny" section ๐Ÿ’– Heads up, bestie: this section has a 65536-byte limit โš ๏ธ and 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".

-msatur enables the saturation instructions โœจ Note that the compiler doesn't currently generate these itself, but the option is included for compatibility with other tools, like "as" ๐Ÿซถ

-msdram Link the SDRAM-based runtime instead of the default ROM-based runtime.

-msdram links the SDRAM-based runtime instead of the default ROM-based runtime ๐ŸŒธ

-msim Link the simulator run-time libraries.

-msim links the simulator run-time libraries ๐Ÿงš

-msimnovec Link the simulator runtime libraries, excluding built-in support for reset and exception vectors and tables.

-msimnovec links the simulator runtime libraries but leaves out the 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.

-mtf makes all functions default to the ".far" section ๐Ÿ‘‘ Without it, 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.

-mtiny=n sends variables that are n bytes or smaller to the ".tiny" section, and they use the $gp base register ๐ŸŽ€ The default is 4, but remember the 65536-byte limit on the ".tiny" section ๐Ÿ’€


โœจ MicroBlaze Options โœจ

-msoft-float Use software emulation for floating point (default).

-msoft-float uses software emulation for floating point (this is the default) ๐ŸŒˆ

-mhard-float Use hardware floating-point instructions.

-mhard-float uses hardware floating-point instructions ๐Ÿ”ฅ

-mmemcpy Do not optimize block moves, use "memcpy".

-mmemcpy skips optimizing block moves and uses "memcpy" instead ๐Ÿฆ‹

-mno-clearbss This option is deprecated. Use -fno-zero-initialized-in-bss instead.

-mno-clearbss is deprecated, so bestie, use -fno-zero-initialized-in-bss instead ๐Ÿ˜ญ

-mcpu=cpu-type Use features of, and schedule 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.

-mcpu=cpu-type uses the features of the given CPU and schedules code for it ๐Ÿ’– Supported values look like vX.YY.Z, where X is the major version, YY is the minor version, and Z is compatibility code. Example values: v3.00.a, v4.00.b, v5.00.a, v5.00.b, v6.00.a ๐Ÿงš

-mxl-soft-mul Use software multiply emulation (default).

-mxl-soft-mul uses software multiply emulation (default) ๐Ÿ“

-mxl-soft-div Use software emulation for divides (default).

-mxl-soft-div uses software emulation for divides (default) ๐ŸŒธ

-mxl-barrel-shift Use the hardware barrel shifter.

-mxl-barrel-shift uses the hardware barrel shifter โญ

-mxl-pattern-compare Use pattern compare instructions.

-mxl-pattern-compare uses pattern compare instructions ๐Ÿ’…

-msmall-divides Use table lookup optimization for small signed integer divisions.

-msmall-divides uses table lookup optimization for small signed integer divisions ๐Ÿ‘‘

-mxl-stack-check This option is deprecated. Use -fstack-check instead.

-mxl-stack-check is deprecated, so use -fstack-check instead ๐Ÿ™ˆ

-mxl-gp-opt Use GP-relative ".sdata"/".sbss" sections.

-mxl-gp-opt uses GP-relative ".sdata"/".sbss" sections ๐Ÿฆ‹

-mxl-multiply-high Use multiply high instructions for high part of 32x32 multiply.

-mxl-multiply-high uses multiply high instructions for the high part of a 32x32 multiply ๐Ÿ’–

-mxl-float-convert Use hardware floating-point conversion instructions.

-mxl-float-convert uses hardware floating-point conversion instructions ๐Ÿงš

-mxl-float-sqrt Use hardware floating-point square root instruction.

-mxl-float-sqrt uses the hardware floating-point square root instruction ๐ŸŽ€

-mbig-endian Generate code for a big-endian target.

-mbig-endian generates code for a big-endian target ๐Ÿซถ

-mlittle-endian Generate code for a little-endian target.

-mlittle-endian generates code for a little-endian target ๐Ÿ’œ

-mxl-reorder Use reorder instructions (swap and byte reversed load/store).

-mxl-reorder uses reorder instructions (swap and byte reversed load/store) ๐ŸŒˆ

-mxl-mode-app-model Select application model app-model. Valid models are

executable normal executable (default), uses startup code crt0.o.

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.

-mxl-mode-app-model selects the application model app-model. Valid models are:

  • executable โ€” normal executable (default), uses startup code crt0.o ๐ŸŒธ
  • xmdstub โ€” for use with the Xilinx Microprocessor Debugger (XMD) based software intrusive debug agent called xmdstub ๐Ÿงš This uses startup file crt1.o and sets the 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. It's suitable for transferring control on a processor reset to the bootloader rather than the application.
  • novectors โ€” for applications that don't need 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 โš ๏ธ

-mpic-data-is-text-relative Assume 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.

-mpic-data-is-text-relative assumes the displacement between the text and data segments is fixed at static link time ๐Ÿ’… This lets data be referenced by offset from the start of the text address instead of the GOT, since PC-relative addressing isn't supported.


โœจ MIPS Options โœจ

-EB Generate big-endian code.

-EB generates big-endian code ๐ŸŽ€

-EL Generate little-endian code. This is the default for mips*el-- configurations.

-EL generates little-endian code ๐Ÿ’– This is the default for mips*el-*-* configurations.

-march=arch Generate 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 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.

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

ISA names: mips1, mips2, mips3, mips4, mips32, mips32r2, mips32r3, mips32r5, mips32r6, mips64, mips64r2, mips64r3, mips64r5 and mips64r6.

Processor names: 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 picks 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 picks the best architecture option for the host processor. -march=native has no effect if GCC doesn't recognize the processor ๐ŸŒˆ

In processor names, a final 000 can be abbreviated as k (for example, -march=r2k). Prefixes are optional, and vr may be written r โœจ

Names of the form nf2_1 refer to processors with FPUs clocked at half the rate of the core, names of the form nf1_1 refer to processors with FPUs clocked at the same rate as the core, and names of the form nf3_2 refer to processors with FPUs clocked at a 3:2 ratio with respect to the core. For compatibility reasons, nf is accepted as a synonym for nf2_1, while nx and bfx are accepted as synonyms for nf1_1 ๐Ÿงš

GCC defines two macros based on the value of this option. The first is "_MIPS_ARCH", which gives the name of the target architecture as a string. The second has the form "_MIPS_ARCH_foo", where foo is the capitalized value of "_MIPS_ARCH". For example, -march=r2000 sets "_MIPS_ARCH" to "r2000" and defines the macro "_MIPS_ARCH_R2000" ๐ŸŽ€

Note that the "_MIPS_ARCH" macro uses the processor names given above. In other words, it has the full prefix and 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 Optimize 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.

-mtune=arch optimizes for arch ๐ŸŒธ Among other things, it controls the way instructions are scheduled and the perceived cost of arithmetic operations. The list of arch values is the same as for -march.

When this option isn't used, GCC optimizes for the processor specified by -march. Using -march and -mtune together lets you generate code that runs on a family of processors, but optimize it for one particular member of that family ๐Ÿ’–

-mtune defines the macros "_MIPS_TUNE" and "_MIPS_TUNE_foo", which work the same way as the -march ones described above ๐Ÿงš

-mips1 Equivalent to -march=mips1.

-mips1 is the same as -march=mips1 ๐Ÿ“

-mips2 Equivalent to -march=mips2.

-mips2 is the same as -march=mips2 ๐Ÿ“

-mips3 Equivalent to -march=mips3.

-mips3 is the same as -march=mips3 ๐Ÿ“

-mips4 Equivalent to -march=mips4.

-mips4 is the same as -march=mips4 ๐Ÿ“

-mips32 Equivalent to -march=mips32.

-mips32 is the same as -march=mips32 ๐Ÿ“

-mips32r3 Equivalent to -march=mips32r3.

-mips32r3 is the same as -march=mips32r3 ๐Ÿ“

-mips32r5 Equivalent to -march=mips32r5.

-mips32r5 is the same as -march=mips32r5 ๐Ÿ“

-mips32r6 Equivalent to -march=mips32r6.

-mips32r6 is the same as -march=mips32r6 ๐Ÿ“

-mips64 Equivalent to -march=mips64.

-mips64 is the same as -march=mips64 ๐Ÿ“

-mips64r2 Equivalent to -march=mips64r2.

-mips64r2 is the same as -march=mips64r2 ๐Ÿ“

-mips64r3 Equivalent to -march=mips64r3.

-mips64r3 is the same as -march=mips64r3 ๐Ÿ“

-mips64r5 Equivalent to -march=mips64r5.

-mips64r5 is the same as -march=mips64r5 ๐Ÿ“

-mips64r6 Equivalent to -march=mips64r6.

-mips64r6 is the same as -march=mips64r6 ๐Ÿ“

-mips16 -mno-mips16 Generate (do 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.

-mips16 / -mno-mips16 generates (or doesn't 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 using the "mips16" and "nomips16" attributes ๐Ÿ’œ

-mflip-mips16 Generate 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.

-mflip-mips16 generates MIPS16 code on alternating functions ๐Ÿ™ˆ It's there 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 Require (do 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-compressed / -mno-interlink-compressed require (or don't 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 can't jump directly to MIPS16 or microMIPS code; it has to use a call or an indirect jump. -minterlink-compressed therefore disables direct jumps unless GCC knows that the target of the jump isn't 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.

-minterlink-mips16 / -mno-interlink-mips16 are aliases of -minterlink-compressed and -mno-interlink-compressed ๐ŸŒˆ These options predate the microMIPS ASE and are kept for backwards compatibility.

-mabi=32 -mabi=o64 -mabi=n32 -mabi=64 -mabi=eabi Generate 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 <https://gcc.gnu.org/projects/mipso64-abi.html>.

-mabi=32, -mabi=o64, -mabi=n32, -mabi=64 and -mabi=eabi generate 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 https://gcc.gnu.org/projects/mipso64-abi.html ๐Ÿฆ‹

okay so GCC has this spicy variant of the o32 ABI where the floating-point registers are 64 bits wide instead of 32 ๐Ÿฆ‹ You pick it with -mabi=32 -mfp64, and honestly it's giving upgrade. BUT it leans on the mthc1 and mfhc1 instructions, so it's only a thing on MIPS32R2, MIPS32R3 and MIPS32R5 processors. ๐Ÿ’…

The register assignments for arguments and return values stay exactly the same โœจ The only glow-up is that each scalar value gets squished into one 64-bit register instead of a pair of 32-bit ones. Like, scalar floating-point values come back in $f0 only, not a $f0/$f1 pair. The call-saved set is also unchanged, so the even-numbered double-precision registers still get saved. ๐Ÿซถ

There are two more o32 variants for the transition era from 32-bit to 64-bit registers ๐ŸŒˆ They're FPXX (-mfpxx) and FP64A (-mfp64 -mno-odd-spreg). FPXX is mandatory vibes: all code has to run correctly with 32-bit or 64-bit registers. It can be interlinked with FP32 or FP64, but not both, so no mixing, periodt. FP64A is similar to FP64 but it forbids odd-numbered single-precision registers. It can be used with the "FRE" mode of FPUs in MIPS32R5 processors, and that lets FP32 and FP64A code interlink and run in the same process without changing FPU modes. Iconic ๐Ÿ‘‘


  • -mabicalls, -mno-abicalls โ€” generate (or don't generate) code that's suitable for SVR4-style dynamic objects. -mabicalls is the default on SVR4-based systems. ๐ŸŒธ
  • -mshared, -mno-shared โ€” generate (or don't generate) 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, regardless of options like -fPIC and -fpic. However, 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. This mode is selected by -mno-shared.

-mno-shared depends on binutils 2.16 or higher, and it generates objects that can only be linked by the GNU linker. However, it doesn't affect the ABI of the final executable; 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 โ€” assume (or don't assume) that the static and dynamic linkers support PLTs and copy relocations. This option only affects -mno-shared -mabicalls. For the n64 ABI, this option has no effect without -msym32. ๐Ÿงš

You can make -mplt the default by configuring GCC with --with-mips-plt. Otherwise the default is -mno-plt.

  • -mxgot, -mno-xgot โ€” lift (or don't lift) the usual restrictions on the size of the global offset table. ๐Ÿ“

GCC normally uses a single instruction to load values from the GOT. It's relatively efficient, but it only works if the GOT is smaller than about 64k. Anything larger makes the linker report an error like this:

relocation truncated to fit: R_MIPS_GOT16 foobar

If that happens, recompile your code with -mxgot. It works with very large GOTs, although the code is less efficient, since it takes three instructions to fetch the value of a global symbol. ๐Ÿ™ˆ

Note that some linkers can create multiple GOTs. If you have one of those, you should only need -mxgot when a single object file accesses more than 64k's worth of GOT entries. Very few do.

These options have no effect unless GCC is generating position independent code.

  • -mgp32 โ€” assume general-purpose registers are 32 bits wide.
  • -mgp64 โ€” assume general-purpose registers are 64 bits wide.
  • -mfp32 โ€” assume floating-point registers are 32 bits wide.
  • -mfp64 โ€” assume floating-point registers are 64 bits wide.
  • -mfpxx โ€” don't assume a width for floating-point registers at all. ๐ŸŒˆ
  • -mhard-float โ€” use floating-point coprocessor instructions. ๐Ÿ”ฅ
  • -msoft-float โ€” don't use floating-point coprocessor instructions. Do floating-point math with library calls instead.
  • -mno-float โ€” same as -msoft-float, but it also asserts that the program being compiled doesn't do any floating-point operations at all. Right now this is only supported by some bare-metal MIPS configurations, where it may pick a special set of libraries that lack all floating-point support (including, for example, the floating-point "printf" formats). โš ๏ธ Watch out: if code compiled with -mno-float accidentally contains floating-point operations, it's likely to hit a link-time or run-time failure. ๐Ÿ’€
  • -msingle-float โ€” assume the floating-point coprocessor only supports single-precision operations.
  • -mdouble-float โ€” assume the floating-point coprocessor supports double-precision operations. This is the default. ๐Ÿ‘‘
  • -modd-spreg, -mno-odd-spreg โ€” enable (or don't enable) the use of odd-numbered single-precision floating-point registers for the o32 ABI. This is the default for processors that are known to support these registers. When using the o32 FPXX ABI, -mno-odd-spreg is set by default.
  • -mabs=2008, -mabs=legacy โ€” control how the special not-a-number (NaN) IEEE 754 floating-point data gets treated by the "abs.fmt" and "neg.fmt" machine instructions. ๐Ÿซง

By default, or when -mabs=legacy is used, the legacy treatment is selected. In this case these instructions count as arithmetic, so they're avoided wherever correct operation is required and the input operand might be a NaN. A longer sequence of instructions that manipulates the sign bit of the floating-point datum manually is used instead, unless the -ffinite-math-only option has also been specified.

The -mabs=2008 option selects the IEEE 754-2008 treatment. In this case these instructions count as non-arithmetic, so they operate correctly in all cases, including where the input operand is a NaN. These instructions are therefore always used for the respective operations.

  • -mnan=2008, -mnan=legacy โ€” control the encoding of the special not-a-number (NaN) IEEE 754 floating-point data. ๐Ÿฆ‹

-mnan=legacy selects the legacy encoding. Here, quiet NaNs (qNaNs) are denoted by the first bit of their trailing significand field being 0, whereas signaling NaNs (sNaNs) are denoted by the first bit of their trailing significand field being 1.

-mnan=2008 selects the IEEE 754-2008 encoding. In this case qNaNs are denoted by the first bit of their trailing significand field being 1, whereas sNaNs are denoted by the first bit of their trailing significand field being 0.

The default is -mnan=legacy unless GCC has been configured with --with-nan=2008.

  • -mllsc, -mno-llsc โ€” use (or don't use) ll, sc, and sync instructions to implement atomic memory built-in functions. When neither option is specified, GCC uses the instructions if the target architecture supports them. ๐Ÿ’–

-mllsc is useful if the runtime environment can emulate the instructions, and -mno-llsc can be useful when compiling for nonstandard ISAs. You can make either option the default by configuring GCC with --with-llsc and --without-llsc respectively. --with-llsc is the default for some configurations, so check the installation documentation for details.

  • -mdsp, -mno-dsp โ€” use (or don't use) revision 1 of the MIPS DSP ASE. This option defines the preprocessor macro __mips_dsp, and it also defines __mips_dsp_rev to 1. โœจ
  • -mdspr2, -mno-dspr2 โ€” use (or don't use) revision 2 of the MIPS DSP ASE. This option defines the preprocessor macros __mips_dsp and __mips_dspr2, and it also defines __mips_dsp_rev to 2. โœจ
  • -msmartmips, -mno-smartmips โ€” use (or don't use) the MIPS SmartMIPS ASE. ๐ŸŽ€
  • -mpaired-single, -mno-paired-single โ€” use (or don't use) paired-single floating-point instructions. This option requires hardware floating-point support to be enabled. ๐Ÿ”ฅ
  • -mdmx, -mno-mdmx โ€” use (or don't use) MIPS Digital Media Extension instructions. This option can only be used when generating 64-bit code, and it requires hardware floating-point support to be enabled. ๐Ÿ’œ
  • -mips3d, -mno-mips3d โ€” use (or don't use) the MIPS-3D ASE. The option -mips3d implies -mpaired-single. ๐ŸŒธ
  • -mmicromips, -mno-micromips โ€” generate (or don't generate) microMIPS code.

microMIPS code generation can also be controlled on a per-function basis by means of "micromips" and "nomicromips" attributes. ๐Ÿงš

  • -mmt, -mno-mt โ€” use (or don't use) MT Multithreading instructions. ๐Ÿงต
  • -mmcu, -mno-mcu โ€” use (or don't use) the MIPS MCU ASE instructions. ๐Ÿฆ‹
  • -meva, -mno-eva โ€” use (or don't use) the MIPS Enhanced Virtual Addressing instructions. ๐ŸŒˆ
  • -mvirt, -mno-virt โ€” use (or don't use) the MIPS Virtualization (VZ) instructions. ๐Ÿซถ
  • -mxpa, -mno-xpa โ€” use (or don't use) the MIPS eXtended Physical Address (XPA) instructions. ๐Ÿ“
  • -mcrc, -mno-crc โ€” use (or don't use) the MIPS Cyclic Redundancy Check (CRC) instructions. โœจ
  • -mginv, -mno-ginv โ€” use (or don't use) the MIPS Global INValidate (GINV) instructions. ๐Ÿ’…
  • -mloongson-mmi, -mno-loongson-mmi โ€” use (or don't use) the MIPS Loongson MultiMedia extensions Instructions (MMI). ๐ŸŒŸ
  • -mloongson-ext, -mno-loongson-ext โ€” use (or don't use) the MIPS Loongson EXTensions (EXT) instructions. ๐ŸŒŸ
  • -mloongson-ext2, -mno-loongson-ext2 โ€” use (or don't use) the MIPS Loongson EXTensions r2 (EXT2) instructions. ๐ŸŒŸ
  • -mlong64 โ€” force "long" types to be 64 bits wide. See -mlong32 for an explanation of the default and the way the pointer size is determined. ๐Ÿ’–
  • -mlong32 โ€” force "long", "int", and pointer types to be 32 bits wide. ๐Ÿ’–

The default size of "int"s, "long"s and pointers depends on the ABI. All the supported ABIs use 32-bit "int"s. The n64 ABI uses 64-bit "long"s, as does the 64-bit EABI, and 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. main character energy, honestly ๐Ÿ‘‘

  • -msym32, -mno-sym32 โ€” okay so this one decides whether GCC just assumes every symbol has a 32-bit value, no matter which ABI you picked ๐Ÿ’… -msym32 makes that assumption and -mno-sym32 doesn't. It's giving main character energy with -mabi=64 and -mno-abicalls because GCC can then make shorter, faster references to symbolic addresses โœจ
  • -G num โ€” put externally-visible data in a small data section ๐ŸŽ€ as long as that data is no bigger than num bytes. GCC can then access the data more efficiently, and -mgpopt has all the juicy details ๐Ÿงš

The default -G value depends on your configuration, so check what your setup is using ๐ŸŒธ

  • -mlocal-sdata, -mno-local-sdata โ€” extend (or don't extend) the -G behaviour to local data too, like static variables in C ๐Ÿฆ‹ -mlocal-sdata is the default for all configurations.

If the linker is yelling that an application is using too much small data, try rebuilding the less performance-critical parts with -mno-local-sdata ๐Ÿ˜ญ You might also want to build large libraries with -mno-local-sdata so they leave more room for the main program ๐Ÿซถ

  • -mextern-sdata, -mno-extern-sdata โ€” assume (or don'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.

Bestie, listen up ๐Ÿ™ˆ If you compile a module Mod with -mextern-sdata -G num -mgpopt, and Mod references a variable Var that is no bigger than num bytes, you must make sure Var is placed in a small data section. If Var is defined by another module, you either need to compile that module with a high-enough -G setting or attach a "section" attribute to Var's definition. If Var is common, you have to link the application with a high-enough -G setting โš ๏ธ

The easiest way to keep the vibes consistent is to compile and link every module with the same -G option ๐Ÿ’– But if you want a library that supports several different small data limits, compile it with the highest supported -G setting and also use -mno-extern-sdata 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 when the $gp register might not hold the value of "_gp" ๐Ÿฅบ For example, if your code is part of a library that might get 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 โ€” allocate variables to the read-only data section first if possible, then the small data section if possible, and otherwise to data ๐Ÿฆ‹ It gives slightly slower code than the default, but uses less RAM while executing, so it might be the move for some embedded systems โœจ
  • -muninit-const-in-rodata, -mno-uninit-const-in-rodata โ€” put uninitialized const variables in the read-only data section ๐ŸŒธ This option is only meaningful alongside -membedded-data.
  • -mcode-readable=setting โ€” specify whether GCC is allowed to generate code that reads from executable sections ๐Ÿงš There are three possible settings, and they're all very different:
    • -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 option is useful on 4KSc and 4KSd processors when the code TLBs have the Read Inhibit bit set. It's also useful on processors that can be configured to have a dual instruction/data SRAM interface and that, like the M4K, automatically redirect PC-relative loads to the instruction RAM.
    • -mcode-readable=no โ€” instructions must not access executable sections ๐Ÿ’€ This can be useful on targets configured with a dual instruction/data SRAM interface that (unlike the M4K) do not automatically redirect PC-relative loads to the instruction RAM.
  • -msplit-addresses, -mno-split-addresses โ€” enable (or disable) use of the %hi() and %lo() assembler relocation operators ๐Ÿ•ฐ๏ธ This option has been superseded by -mexplicit-relocs but is kept around for backwards compatibility.
  • -mexplicit-relocs, -mno-explicit-relocs โ€” use (or don't use) assembler relocation operators when dealing with symbolic addresses ๐Ÿ’œ The alternative, selected by -mno-explicit-relocs, is to use assembler macros instead.

-mexplicit-relocs is the default if GCC was configured to use an assembler that supports relocation operators โœจ

  • -mcheck-zero-division, -mno-check-zero-division โ€” trap (or don't trap) on integer division by zero ๐Ÿ”ฅ The default is -mcheck-zero-division.
  • -mdivide-traps, -mdivide-breaks โ€” MIPS systems check for division by zero by generating either a conditional trap or a break instruction ๐ŸŒˆ Traps give you smaller code, but they're only supported on MIPS II and later. Also, some versions of the Linux kernel have a bug that stops trap from generating the proper signal ("SIGFPE") ๐Ÿ˜ญ Use -mdivide-traps to allow conditional traps on architectures that support them, and -mdivide-breaks to force the use of breaks.

The default is usually -mdivide-traps, but you can override that at configure time with --with-divide=breaks ๐ŸŽ€ Divide-by-zero checks can be completely disabled using -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 ๐Ÿซถ This option is enabled by default, but it only takes effect when the selected architecture is known to support bonding.
  • -munaligned-access, -mno-unaligned-access โ€” enable (or disable) direct unaligned access for MIPS Release 6 ๐Ÿฆ‹ MIPSr6 requires load/store unaligned-access support, either by hardware or by trap&emulate. So -mno-unaligned-access may be needed by the kernel ๐Ÿ‘‘
  • -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 ๐Ÿ’€ That might 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 โ€” tell the MIPS assembler to not run its preprocessor over user assembler files (with a .s suffix) when assembling them ๐ŸŽ€
  • -mfix-24k, -mno-fix-24k โ€” work around the 24K E48 (lost data on stores during refill) errata ๐Ÿ› ๏ธ The workarounds are implemented by the assembler rather than by GCC, so don't blame GCC for it ๐Ÿ˜ญ
  • -mfix-r4000, -mno-fix-r4000 โ€” work 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 โ€” work 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 โ€” work 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, and -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. Instead, always schedule a nop instruction there ๐Ÿงš The short loop bug can, under certain conditions, make loops execute only once or twice, thanks to a hardware bug in the R5900 chip ๐Ÿ˜ญ The workaround is implemented by the assembler rather than by GCC.
  • -mfix-rm7000, -mno-fix-rm7000 โ€” work around the RM7000 dmult/dmultu errata ๐ŸŒธ The workarounds are implemented by the assembler rather than by GCC.
  • -mfix-vr4120, -mno-fix-vr4120 โ€” work 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 โ€” okay so this one is a VR4130 errata fix ๐Ÿ”ง It works around the mflo/mfhi bug, but the actual workarounds are done by the assembler, not GCC ๐Ÿ’… GCC is lowkey smart though, and it avoids mflo and mfhi altogether when the VR4130 macc, macchi, dmacc and dmacchi instructions are available instead โœจ
  • -mfix-sb1, -mno-fix-sb1 โ€” bestie, this one works around certain SB-1 CPU core errata ๐ŸŒธ Right now it only handles the SB-1 revision 2 F1 and F2 floating-point errata.
  • -mr10k-cache-barrier=setting โ€” this one is giving very deep processor drama ๐Ÿฆ‹ It decides whether GCC should insert cache barriers to avoid the side effects of speculation on R10K processors.

The R10K is like many other processors. It tries to guess how a conditional branch will go and starts running instructions from the "taken" branch ahead of time. If the guess was wrong, it throws those instructions away. The problem is that on the R10K, even the thrown-away instructions can leave side effects behind ๐Ÿ˜ญ

This only really affects kernel stores and, depending on the system, kernel loads. For example, a store that gets speculated might pull the target memory into cache and mark that cache line as dirty, even if the store is later aborted. If a DMA operation writes to that same memory before the dirty line gets flushed, the cached data overwrites the DMA-ed data. The R10K processor manual has the full scoop, including other potential problems ๐Ÿ“–

One workaround is to insert cache barrier instructions before every memory access that might get speculatively executed and that might have side effects even if it's aborted. -mr10k-cache-barrier=setting controls how GCC does this. It assumes that aborted accesses to any byte in the following regions have no side effects:

  1. the memory occupied by the current function's stack frame;
  2. the memory occupied by an incoming stack argument;
  3. the memory occupied by an object with a link-time-constant address.

Making sure speculative accesses to these regions are actually safe is the kernel's job, not GCC's ๐Ÿซถ

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, and it expects non-GCC functions (like hand-written assembly) to do the same ๐Ÿ’œ

The option comes in three forms:

  • -mr10k-cache-barrier=load-store โ€” inserts a cache barrier before a load or store that might be speculatively executed and that might have side effects even if aborted.
  • -mr10k-cache-barrier=store โ€” inserts a cache barrier before a store that might be speculatively executed and that might have side effects even if aborted.
  • -mr10k-cache-barrier=none โ€” disables the insertion of cache barriers. This is the default setting ๐Ÿ“
  • -mflush-func=func, -mno-flush-func โ€” picks the function GCC calls to flush the I and D caches, or tells it 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 what target GCC was configured for, but it's commonly either _flush_func or __cpu_flush.
  • mbranch-cost=num โ€” sets the cost of branches to roughly num "simple" instructions ๐Ÿงš This cost is only a heuristic, so don't count on it giving the same results across releases. A zero cost just selects the default, which is based on the -mtune setting.
  • -mbranch-likely, -mno-branch-likely โ€” enables or disables Branch Likely instructions, no matter what the default is for the selected architecture ๐Ÿ’… By default, they may be generated if the selected architecture supports them. The one exception is the MIPS32 and MIPS64 architectures, plus processors that implement them. For those, Branch Likely instructions are not generated by default, because those architectures specifically deprecate their use ๐Ÿ™ˆ
  • -mcompact-branches=never, -mcompact-branches=optimal, -mcompact-branches=always โ€” these options control which form of branches gets generated. The default is -mcompact-branches=optimal.
    • -mcompact-branches=never โ€” makes sure compact branch instructions are never generated.
    • -mcompact-branches=always โ€” makes sure a compact branch instruction is generated if one is available. If it isn't, a delay slot form of the branch gets used instead.

This option is supported from MIPS Release 6 onwards.

  • -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 chosen instead, as long as one is available ๐Ÿ‘‘
  • -mfp-exceptions, -mno-fp-exceptions โ€” specifies whether FP exceptions are enabled. This affects how FP instructions get scheduled on some processors. The default is that FP exceptions are enabled ๐Ÿ”ฅ

For example, 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 is enabled, GCC aligns pairs of instructions that it thinks should execute in parallel ๐Ÿฆ‹

This only does anything when you're optimizing for the VR4130. It usually makes code faster, but the trade-off is that the code gets bigger. It's enabled by default at optimization level -O3.

  • -msynci, -mno-synci โ€” enables (or disables) generation of synci instructions on architectures that support them. If enabled, the synci instructions 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 for single processor systems, it's generally safe to use synci.

Heads up, bestie ๐Ÿšจ On many multi-core (SMP) systems, synci doesn't invalidate the instruction caches on all cores, and it may lead to undefined behavior. ๐Ÿ’€
  • -mrelax-pic-calls, -mno-relax-pic-calls โ€” tries to turn PIC calls that normally go through 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 any 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 gets 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 ๐Ÿง  With the o32 ABI, calling functions allocate 16 bytes on the stack for the called function to write out register arguments. When this is enabled, the optimization skips allocating the frame header if it can be determined that it's unused.

This optimization is off by default at all optimization levels.

  • -mlxc1-sxc1, -mno-lxc1-sxc1 โ€” when applicable, enables (or disables) generation of the lwxc1, swxc1, ldxc1 and sdxc1 instructions. Enabled by default ๐Ÿ’–
  • -mmadd4, -mno-madd4 โ€” when applicable, enables (or disables) generation of 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, with all values passed 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, this uses (or doesn't use) zero-extending load instructions by default, instead of sign-extending ones ๐Ÿ’…
  • -mknuthdiv, -mno-knuthdiv โ€” makes the result of a division that yields 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 โ€” okay so these two decide whether the compiler generates code that uses base addresses ๐Ÿ’–. Using one auto-generates a request (the assembler and linker handle it) to set up a constant in a global register โœจ. That register then serves one or more base address requests within the range 0 to 255 from the value it holds ๐Ÿฆ‹. This usually gives you short and fast code, but ngl there's a catch: the number of different data items you can address is limited ๐Ÿ˜ญ. So if your program has tons of static data, you may need -mno-base-addresses ๐Ÿซถ.
  • -msingle-exit, -mno-single-exit โ€” force (or don't force) the generated code to have one single exit point in each function ๐ŸŽ€.

๐ŸŽ€ MN10300 Options ๐ŸŽ€

These -m options are defined for Matsushita MN10300 architectures ๐ŸŒธ.

  • -mmult-bug โ€” generate code that dodges bugs in the multiply instructions for MN10300 processors. This is the default ๐Ÿ’….
  • -mno-mult-bug โ€” don't generate that bug-dodging code for the MN10300 multiply instructions.
  • -mam33 โ€” generate code using features specific to the AM33 processor ๐Ÿ”ฅ.
  • -mno-am33 โ€” don't generate code using AM33-specific features. This is the default.
  • -mam33-2 โ€” generate code using features specific to the AM33/2.0 processor โœจ.
  • -mam34 โ€” generate code using features specific to the AM34 processor ๐Ÿฆ‹.
  • -mtune=cpu-type โ€” schedule instructions using the timing characteristics of the CPU type you pick ๐Ÿงš. This does not change the targeted processor type, so it's just timing vibes. The CPU type must be one of mn10300, am33, am33-2 or am34 ๐Ÿ’œ.
  • -mreturn-pointer-on-d0 โ€” when generating a function that returns a pointer, return it in both "a0" and "d0" ๐Ÿ‘‘. Otherwise the pointer only comes back in "a0", and trying to call those functions without a prototype throws errors ๐Ÿ’€. This option is on by default, but you can turn 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 ๐Ÿ˜ญ. Proceed with caution, bestie.
  • -mliw โ€” allow the compiler to generate Long Instruction Word instructions if the target is AM33 or later ๐Ÿ“. This is the default, and it defines the preprocessor macro "__LIW__" ๐Ÿซถ.
  • -mno-liw โ€” don't let the compiler generate Long Instruction Word instructions. This defines the preprocessor macro "__NO_LIW__" ๐Ÿ™ˆ.
  • -msetlb โ€” allow the compiler to generate the SETLB and Lcc instructions if the target is AM33 or later ๐Ÿ’–. This is the default, and it defines the preprocessor macro "__SETLB__" โœจ.
  • -mno-setlb โ€” no SETLB or Lcc instructions for you ๐Ÿšซ. This defines the preprocessor macro "__NO_SETLB__" ๐ŸŒธ.

๐Ÿฆ‹ Moxie Options ๐Ÿฆ‹

  • -meb โ€” generate big-endian code. This is the default for moxie-*-* configurations ๐Ÿ’….
  • -mel โ€” generate 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 ๐Ÿ‘‘.

  • -masm-hex โ€” force assembly output to always use hex constants ๐ŸŽ€. Normally they're signed decimals, but this one is there for testsuite and/or aesthetic purposes ๐Ÿ’….
  • -mmcu= โ€” pick the MCU you're targeting ๐ŸŽฏ. GCC uses the MCU name, uppercased and wrapped in __ on both sides, to create a C preprocessor symbol. The msp430.h header then uses that symbol to choose an MCU-specific supplementary header file ๐Ÿซถ.

This option also picks the ISA. If the MCU only supports the 430 ISA, that's what gets selected. Otherwise you get the 430X ISA โœจ. The generic MCU name msp430 selects the 430 ISA, and the generic msp430x selects the 430X ISA ๐Ÿฆ‹.

An MCU-specific linker script also gets added to the linker command line. Its name is the MCU name with .ld tacked on, so -mmcu=xxx defines the C preprocessor symbol "__XXX__" and makes the linker look for a script called xxx.ld ๐ŸŒธ.

The ISA and hardware multiply support for each MCU are hard-coded into GCC ๐Ÿง . But if you want more device support, you can extend it with an external devices.csv file ๐Ÿ’–.

GCC looks for devices.csv using the methods below, in this order of precedence. The first method beats the second, and the second beats the third ๐Ÿ‘‘.

  1. Include path specified with -I and -L โ€” devices.csv gets searched for in each directory listed as an include path or a linker library search path ๐Ÿ”.
  2. Path specified by the environment variable MSP430_GCC_INCLUDE_DIR โ€” set this global environment variable to the full path of the directory that contains devices.csv, and GCC will search there ๐ŸŒˆ. If it finds the file, that directory also gets registered as an include path and a linker library path. That means header files and linker scripts in there work without manually specifying -I and -L on the command line โœจ.
  3. The msp430-elf{,bare}/include/devices directory โ€” finally, GCC checks msp430-elf{,bare}/include/devices under the toolchain root directory ๐Ÿงš. This one doesn't exist in a default installation. But if you've made it yourself and copied devices.csv in there, the MCU data gets read โญ. Like before, 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 ๐Ÿ’….

  • -mwarn-mcu, -mno-warn-mcu โ€” 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 ๐Ÿšจ. It also toggles warnings about unrecognized MCU names. This option is on by default ๐ŸŒธ.
  • -mcpu= โ€” specifies the ISA to use. The accepted values are msp430, msp430x and msp430xv2 ๐Ÿ“.
This option is deprecated ๐Ÿ’€. Use -mmcu= to select the ISA instead, bestie.
  • -msim โ€” links to the simulator runtime libraries and linker script ๐ŸŽฎ. It overrides any scripts that -mmcu= would have selected ๐Ÿ‘‘.
  • -mlarge โ€” use large-model addressing, with 20-bit pointers and a 20-bit "size_t" ๐ŸŒ.
  • -msmall โ€” use small-model addressing, with 16-bit pointers and a 16-bit "size_t" ๐Ÿฆ‹.
  • -mrelax โ€” this gets passed to the assembler and linker, letting the linker do certain optimizations that can't happen until the final link โญ.
  • mhwmult= โ€” describes the type of hardware multiply the target supports ๐Ÿ”ฅ. The accepted values are:
    • none for no hardware multiply at all.
    • 16bit for the original 16-bit-only multiply that early MCUs had.
    • 32bit for the 16/32-bit multiply that later MCUs have.
    • f5series for the 16/32-bit multiply on F5-series MCUs.
    • auto tells GCC to figure out the hardware multiply support from the MCU name you gave to -mmcu. If there's no -mmcu, or the MCU name isn't recognized, no hardware multiply support is assumed ๐Ÿง .

auto is the default setting ๐Ÿ’–.

Hardware multiplies usually happen by calling a library routine, which saves space in your code ๐Ÿซถ. But when you compile at -O3 or higher, the hardware multiplier gets invoked inline ๐Ÿš€. That makes the code bigger, but faster ๐Ÿ’….

The hardware multiply routines turn off interrupts while they run and restore the previous interrupt state when they finish ๐Ÿ›ก๏ธ. 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 ๐Ÿงธ. This one is 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 aren't reentrant, so be careful using them in multi-threaded applications ๐Ÿ˜ฌ.

Stream support has been removed. The string to print always goes to stdout through the "write" syscall, and it 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 should be emitted to shift by a constant amount ๐Ÿ”ข. Once that limit would be exceeded, an mspabi helper function gets used instead. The default value is 4 ๐Ÿ’….

This only matters when a shift by multiple positions can't be done with one instruction, like all shifts over 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 that result is used instead ๐Ÿงฎ.

  • -mcode-region=, -mdata-region= โ€” these tell the compiler where to place functions and data that don't have a "lower", "upper", "either" or "section" attribute ๐Ÿ“. The possible values are "lower", "upper", "either" or "any". The first three behave like the matching attribute. The fourth one, "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 the fixes for the named silicon errata ๐Ÿ›โœจ.
  • -msilicon-errata-warn= โ€” okay so this one tells the assembler to start raising its hand ๐Ÿ™‹ with warnings whenever a silicon errata might need to be applied. Main character assembler behavior ๐Ÿ’…
  • -mwarn-devices-csv, -mno-warn-devices-csv โ€” this pair controls whether you get a heads-up if devices.csv is missing or if there's trouble parsing it. It's on by default ๐Ÿซถ

โœจ NDS32 Options โœจ

okay bestie, these are defined for NDS32 implementations ๐Ÿฆ‹

  • -mbig-endian โ€” generate code in big-endian mode ๐ŸŒธ
  • -mlittle-endian โ€” generate code in little-endian mode ๐ŸŒˆ
  • -mreduced-regs โ€” use the reduced-set registers when doing register allocation ๐Ÿงš
  • -mfull-regs โ€” use the full-set registers for register allocation instead ๐Ÿ’œ
  • -mcmov โ€” generate conditional move instructions โœจ
  • -mno-cmov โ€” nope, 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 โ€” do not generate performance extension 2 instructions ๐Ÿ™ˆ
  • -mext-string โ€” generate string extension instructions ๐ŸŽ€
  • -mno-ext-string โ€” do not generate string extension instructions ๐Ÿ“
  • -mv3push โ€” generate v3 push25/pop25 instructions ๐Ÿฆ‹
  • -mno-v3push โ€” do not generate v3 push25/pop25 instructions ๐Ÿ’…
  • -m16-bit โ€” generate 16-bit instructions ๐Ÿ‘‘
  • -mno-16-bit โ€” do not generate 16-bit instructions ๐Ÿ˜ญ
  • -misr-vector-size=num โ€” set the size of each interrupt vector. It has to be 4 or 16, no other vibes allowed ๐ŸŒธ
  • -mcache-block-size=num โ€” set the size of each cache block. It must be a power of 2 between 4 and 512 ๐Ÿงš
  • -march=arch โ€” specify the name of the target architecture ๐ŸŒˆ
  • -mcmodel=code-model โ€” sets the code model to one of the following ๐Ÿ’–
    • small โ€” all the data and read-only data segments must be within 512KB of addressing space. The text segment must be within 16MB of addressing space ๐Ÿ“
    • medium โ€” the data segment must be within 512KB, while the read-only data segment can be within 4GB of addressing space. The text segment should still be within 16MB of addressing space ๐Ÿฆ‹
    • large โ€” all the text and data segments can be within 4GB of addressing space ๐Ÿ‘‘
  • -mctor-dtor โ€” enable the constructor/destructor feature โœจ
  • -mrelax โ€” guides the linker to relax instructions ๐Ÿซถ

๐ŸŒธ Nios II Options ๐ŸŒธ

these are the options defined for the Altera Nios II processor ๐Ÿ’œ

  • -G num โ€” put global and static objects that are less than or equal to num bytes into the small data or BSS sections, instead of the normal data or BSS sections. The default value of num is 8 ๐ŸŽ€
  • -mgpopt=option, -mgpopt, -mno-gpopt โ€” this controls whether GP-relative accesses get generated (or not). These option names are recognized ๐Ÿงš
    • none โ€” do not generate GP-relative accesses ๐Ÿ™…โ€โ™€๏ธ
    • local โ€” generate GP-relative accesses for small data objects that are not external, weak, or uninitialized common symbols. GP-relative addressing is also used for objects that have been explicitly placed in a small data section via a "section" attribute ๐ŸŒˆ
    • global โ€” same as local, but it also generates GP-relative accesses for small data objects that are external, weak, or common. If you use this option, you must make sure that all parts of your program (including libraries) are compiled with the same -G setting ๐Ÿ”ฅ
    • data โ€” generate GP-relative accesses for all data objects in the program. If you use this option, the entire data and BSS segments of your program must fit in 64K of memory, and you must use an appropriate linker script to allocate them within the addressable range of the global pointer ๐Ÿ’€
    • all โ€” generate GP-relative addresses for function pointers as well as data pointers. If you use this option, the entire text, data, and BSS segments of your program must fit in 64K of memory, and you must use an appropriate linker script to allocate them within the addressable range of the global pointer ๐Ÿ˜ญ

-mgpopt is equivalent to -mgpopt=local, and -mno-gpopt is equivalent to -mgpopt=none ๐Ÿ’…

The default is -mgpopt except when -fpic or -fPIC is specified to generate position-independent code. Note that the Nios II ABI does not permit GP-relative accesses from shared libraries ๐Ÿซถ

โš ๏ธ bestie, you may need to specify -mno-gpopt explicitly when building programs that include large amounts 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 โ€” this option specifies additional 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 does not affect how -G behaves. The specified sections are in addition to the standard .sdata and .sbss small-data sections that are recognized by -mgpopt โœจ

  • -mr0rel-sec=regexp โ€” this option names sections that can be accessed via a 16-bit offset from r0, meaning in 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. There are also no conventional section names used in standard linker scripts for sections in the low or high areas of memory ๐Ÿงš

  • -mel, -meb โ€” generate little-endian (the default) or big-endian (experimental) code, respectively ๐ŸŒˆ
  • -march=arch โ€” this specifies the name of the target Nios II architecture. GCC uses this name to figure out what kinds of instructions it can emit when generating assembly code. Permissible names are: r1, r2 ๐Ÿ’–

The preprocessor macro "__nios2_arch__" is available to programs, with value 1 or 2, indicating the targeted ISA level ๐Ÿค“

  • -mbypass-cache, -mno-bypass-cache โ€” forces all load and store instructions to always bypass the cache by using the I/O variants of the instructions. The default is not to bypass the cache ๐Ÿ“
  • -mno-cache-volatile, -mcache-volatile โ€” volatile memory accesses bypass the cache 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 โ€” do not 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 โ€” enable or disable the compiler emitting the mul, mulx, and div families of instructions. The default is to emit mul and not emit div or mulx ๐Ÿ’…
  • -mbmx, -mno-bmx, -mcdx, -mno-cdx โ€” enable or disable generation of Nios II R2 BMX (bit manipulation) and CDX (code density) instructions. Enabling these instructions also requires -march=r2. Since they're optional extensions to the R2 architecture, the default is not to emit them ๐Ÿฆ‹
  • -mcustom-insn=N, -mno-custom-insn โ€” each -mcustom-insn=N option enables use of a custom instruction with encoding N when generating code that uses insn. For example, -mcustom-fadds=253 generates custom instruction 253 for single-precision floating-point add operations, instead of the default behavior of using a library call ๐Ÿงš

The following values of insn are supported. Except as otherwise noted, floating-point operations are expected to be implemented with normal IEEE 754 semantics and to correspond directly to the C operators or the equivalent GCC built-in functions ๐Ÿค“

Single-precision floating point:

  • fadds, fsubs, fdivs, fmuls โ€” binary arithmetic operations ๐Ÿ”ฅ
  • fnegs โ€” unary negation ๐Ÿ’€
  • fabss โ€” unary absolute value ๐ŸŒˆ
  • fcmpeqs, fcmpges, fcmpgts, fcmples, fcmplts, fcmpnes โ€” comparison operations ๐Ÿ’–
  • fmins, fmaxs โ€” floating-point minimum and maximum. These 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 ๐Ÿ’–

In addition, all of these transfer instructions for internal registers X and Y have to be set up before you can use any of the double-precision floating-point instructions ๐Ÿ’–. Custom instructions that take two double-precision source operands expect the first operand in the 64-bit register X ๐Ÿฆ‹. The other operand (or the only operand, if it's a unary operation) goes to the custom arithmetic instruction with its least significant half in source register src1 and its most significant half in src2 โœจ. When a custom instruction returns a double-precision result, you get the most significant 32 bits in the destination register, and the other half comes back in the 32-bit register Y ๐Ÿ”ฅ. The best part is that GCC automatically generates the code sequences needed to write register X and/or read register Y whenever you use double-precision floating-point instructions. It's literally doing the work for you, periodt ๐Ÿ’….

Here are the transfer instructions you've got to know about:

  • fwrx โ€” writes src1 into the least significant half of X and src2 into the most significant half of X ๐ŸŒธ.
  • fwry โ€” writes src1 into Y ๐Ÿงš.
  • frdxhi, frdxlo โ€” read the most or least (respectively) significant half of X and store it in dest ๐Ÿ’œ.
  • frdy โ€” reads the value of Y and stores it into dest ๐Ÿ“.

Heads up, bestie: you can get more local control over how Nios II custom instructions are generated by using the target("custom-insn=N") and target("no-custom-insn") function attributes or pragmas ๐Ÿ™ˆ.

-mcustom-fpu-cfg=name

This option turns on a predefined, named set of custom instruction encodings (see -mcustom-insn above) โœจ. These are the sets defined right now:

-mcustom-fpu-cfg=60-1 is equivalent to:

-mcustom-fmuls=252 -mcustom-fadds=253 -mcustom-fsubs=254 -fsingle-precision-constant

-mcustom-fpu-cfg=60-2 is equivalent to:

-mcustom-fmuls=252 -mcustom-fadds=253 -mcustom-fsubs=254 -mcustom-fdivs=255 -fsingle-precision-constant

-mcustom-fpu-cfg=72-3 is equivalent to:

-mcustom-floatus=243 -mcustom-fixsi=244 -mcustom-floatis=245 -mcustom-fcmpgts=246 -mcustom-fcmples=249 -mcustom-fcmpeqs=250 -mcustom-fcmpnes=251 -mcustom-fmuls=252 -mcustom-fadds=253 -mcustom-fsubs=254 -mcustom-fdivs=255 -fsingle-precision-constant

-mcustom-fpu-cfg=fph2 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

Custom instruction assignments given by individual -mcustom-insn= options override the ones from -mcustom-fpu-cfg=, no matter what order they show up in on the command line ๐ŸŽ€.

Want more local control over which FPU configuration applies? Use the target("custom-fpu-cfg=name") function attribute or pragma ๐Ÿ’ซ.

The name fph2 is short for Nios II Floating Point Hardware 2 Component ๐ŸŒˆ. Please note that the custom instructions enabled by -mcustom-fmins=233 and -mcustom-fmaxs=234 are only generated if -ffinite-math-only is specified ๐Ÿ™ˆ. The custom instruction enabled by -mcustom-round=248 is only generated if -fno-math-errno is specified. Unlike the other configurations, -fsingle-precision-constant is not set ๐Ÿ˜ญ.

These additional -m options are available for the Altera Nios II ELF (bare-metal) target:

  • -mhal โ€” links with the HAL BSP. This suppresses linking with the GCC-provided C runtime startup and termination code, and it's typically used with -msys-crt0= to point at the alternate startup code the HAL BSP provides ๐Ÿงš.
  • -msmallc โ€” links with a limited version of the C library, -lsmallc, instead of Newlib ๐Ÿ“.
  • -msys-crt0=startfile โ€” startfile is the file name of the startfile (crt0) to use when linking. This is only useful together with -mhal ๐ŸŒธ.
  • -msys-lib=systemlib โ€” systemlib is the library name of the library that provides low-level system calls the C library needs, like "read" and "write". Typically used to link with a library provided by 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 โ€” generates 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 โœจ.
  • -mptx=version-string โ€” generates code for the specified PTX version (e.g. 6.3). Valid version strings include 3.1 and 6.3. The default PTX version is 3.1 ๐Ÿ”ฅ.
  • -mmainkernel โ€” links in code for a __main kernel. This is for stand-alone execution instead of offloading execution ๐Ÿ‘‘.
  • -moptimize โ€” applies partitioned execution optimizations. This is the default whenever any level of optimization is selected ๐ŸŒˆ.
  • -msoft-stack โ€” generates 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 as the underlying storage, it 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 so you can test the compiler. To generate code suitable for linking into programs that use OpenMP offloading, use -mgomp instead ๐Ÿงš.
  • -muniform-simt โ€” switches to a code generation variant that lets every thread in each warp execute, while keeping memory state and side effects as if only one thread in each warp was active outside OpenMP SIMD regions. All atomic operations and calls to the 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 SIMD regions, lane 0 is the master; inside, each thread sees itself as the master. The shared memory array int __nvptx_uni[] stores all-zeros or all-ones bitmasks for each warp, indicating the current mode (0 outside SIMD regions). Each thread can bitwise-and the bitmask at position tid.y with the current lane index to compute the master lane index ๐Ÿคฏ.
  • -mgomp โ€” generates code for OpenMP offloading. This enables -msoft-stack and -muniform-simt, and selects the corresponding multilib variant ๐Ÿ’–.

๐ŸŒˆ OpenRISC Options ๐ŸŒˆ

These options are defined for OpenRISC:

  • -mboard=name โ€” configures a board-specific runtime. This gets passed to the linker for newlib board library linking. The default is "or1ksim" ๐Ÿ“.
  • -mnewlib โ€” ignored, it's only here for compatibility. It used to select linker and preprocessor options for use with newlib ๐Ÿ™ˆ.
  • -msoft-div, -mhard-div โ€” select software or hardware divide (l.div, l.divu) instructions. The default is hardware divide โœจ.
  • -msoft-mul, -mhard-mul โ€” select software or hardware multiply (l.mul, l.muli) instructions. The default is hardware multiply ๐Ÿ”ฅ.
  • -msoft-float, -mhard-float โ€” select 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 โ€” enables generation of conditional move (l.cmov) instructions. By default, the equivalent is generated using set and branch ๐Ÿงš.
  • -mror โ€” enables generation of rotate right (l.ror) instructions. By default, functions from libgcc are used for rotate right operations ๐ŸŽ€.
  • -mrori โ€” enables generation of rotate right with immediate (l.rori) instructions. By default, functions from libgcc are used for rotate right with immediate operations ๐Ÿ’ซ.
  • -msext โ€” enables generation of sign extension (l.ext*) instructions. By default, memory loads are used to perform sign extension ๐Ÿ“.
  • -msfimm โ€” enables generation of compare and set flag with immediate (l.sf*i) instructions. By default, extra instructions get generated to store the immediate in a register first ๐Ÿ˜ญ.
  • -mshftimm โ€” enables generation of shift with immediate (l.srai, l.srli, l.slli) instructions. By default, extra instructions get generated to store the immediate in a register first ๐Ÿ’….
  • -mcmodel=small โ€” generates OpenRISC code for the small model: the GOT is limited to 64k. This is the default model ๐ŸŒธ.
  • -mcmodel=large โ€” generates OpenRISC code for the large model: the GOT may grow up to 4G in size ๐Ÿ‘‘.

๐Ÿงธ PDP-11 Options ๐Ÿงธ

These options are defined for the PDP-11:

  • -mfpu โ€” uses hardware FPP floating point. This is the default. (FIS floating point on the PDP-11/40 is not supported.) Implies -m45 ๐Ÿ”ฅ.
  • -msoft-float โ€” doesn't use hardware floating point ๐ŸŒธ.
  • -mac0 โ€” returns floating-point results in ac0 (fr0 in Unix assembler syntax) ๐Ÿ’œ.
  • -mno-ac0 โ€” returns floating-point results in memory. This is the default ๐Ÿฆ‹.
  • -m40 โ€” generates code for a PDP-11/40. Implies -msoft-float -mno-split ๐Ÿงš.
  • -m45 โ€” generates code for a PDP-11/45. This is the default ๐ŸŽ€.
  • -m10 โ€” generates code for a PDP-11/10. Implies -msoft-float -mno-split ๐Ÿ’ซ.
  • -mint16, -mno-int32 โ€” uses 16-bit "int". This is the default ๐Ÿ“.
  • -mint32, -mno-int16 โ€” uses 32-bit "int" ๐Ÿ™ˆ.
  • -msplit โ€” the target has split instruction and data space. Implies -m45 โœจ.
  • -munix-asm โ€” uses Unix assembler syntax ๐ŸŒˆ.
  • -mdec-asm โ€” uses DEC assembler syntax ๐Ÿ’….
  • -mgnu-asm โ€” uses GNU assembler syntax. This is the default ๐Ÿซถ.
  • -mlra โ€” uses the new LRA register allocator. By default, the old "reload" allocator is used ๐Ÿ˜ญ.

๐Ÿงš picoChip Options ๐Ÿงš

These -m options are defined for picoChip implementations:

-mae=ae_type

Okay so -mae=ae_type is the big one ๐Ÿ’… It sets the instruction set, register set, and instruction scheduling parameters for the array element type ae_type, and the supported values are ANY, MUL, and MAC ๐ŸŽ€

  • -mae=ANY โ€” this is the totally generic AE type ๐ŸŒˆ Code built with it runs on any of the other AE types, but it isn't as efficient as a build targeting one specific AE type, and some operations (e.g., multiplication) don't work properly on every AE type ๐Ÿ˜ญ
  • -mae=MUL โ€” the most useful AE type for compiled code โœจ It's also the default, so you get it if you don't pick anything ๐Ÿ’–
  • -mae=MAC โ€” a DSP-style MAC AE ๐Ÿฆ‹ Heads up bestie: code built with this one can perform poorly when doing byte (char) manipulation, because the DSP AE has no hardware support for byte load/stores ๐Ÿ’€
  • -msymbol-as-address โ€” lets the compiler use a symbol name directly as an address in a load/store instruction, skipping the step of loading it into a register first ๐Ÿงš Usually this makes bigger programs that run faster, but the results vary from program to program, so it's a user option instead of being permanently on ๐ŸŒธ
  • -mno-inefficient-warnings โ€” turns off the warnings about inefficient code ๐Ÿ™ˆ Those can pop up when you do byte-level memory operations on the MAC AE type. MAC has no hardware support for byte-level memory operations, so every byte load/store has to be synthesized from word load/stores, which is inefficient. The warning is basically telling you to rewrite the code to avoid byte operations, or to target an AE type with the right hardware support. This option silences all of that ๐Ÿซถ

โœจ PowerPC Options โœจ

These are listed under


๐ŸŒธ PRU Options ๐ŸŒธ

These command-line options are defined for the PRU target ๐Ÿงš

  • -minrt โ€” links with a minimum runtime environment that has no support for static initializers and constructors ๐Ÿ’… Using it can seriously shrink the final ELF binary. Beware though, the compiler could still generate code with static initializers and constructors, so it's up to you to make sure your source program won't use those features ๐Ÿ˜ญ
  • -mmcu=mcu โ€” picks the PRU MCU variant to use ๐ŸŽ€ Check Newlib for the exact list of supported MCUs ๐Ÿ’–
  • -mno-relax โ€” tells GCC to pass the --no-relax option to the linker instead of --relax โœจ
  • -mloop โ€” allows (or doesn't allow) GCC to use the LOOP instruction ๐ŸŒˆ
  • -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 differ:
    • Function Pointer Size โ€” the TI ABI says function (code) pointers are 16-bit, whereas GNU only supports 32-bit data and code pointers ๐Ÿฆ‹
    • Optional Return Value Pointer โ€” return values larger than 64 bits get passed through a hidden pointer as the first argument of the function ๐Ÿ“ The TI ABI says that pointer can be NULL if the caller isn't using the returned value. GNU always passes and expects a valid return value pointer ๐Ÿ™ˆ
The current -mabi=ti implementation just raises a compile error whenever any of the above code constructs shows up ๐Ÿ˜ญ So the standard C library can't be built, and it gets left out when linking with -mabi=ti.

Relaxation is a GNU feature, and for safety reasons it's disabled when you use -mabi=ti ๐Ÿ”’ The TI toolchain doesn't emit relocations for QBBx instructions, so the GNU linker can't adjust them when shortening adjacent LDI32 pseudo instructions ๐Ÿ’€


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

These command-line options are defined for RISC-V targets ๐ŸŒธ

  • -mbranch-cost=n โ€” sets the cost of branches to roughly n instructions ๐Ÿ’–
  • -mplt, -mno-plt โ€” when generating PIC code, this decides whether PLTs are allowed or not ๐ŸŽ€ It's ignored for non-PIC code, and the default is -mplt โœจ
  • -mabi=ABI-string โ€” picks the integer and floating-point calling convention ๐Ÿ‘‘ The ABI string has two parts: the size of integer types, and which registers get used for floating-point types. For example, -march=rv64ifd -mabi=lp64d means long and pointers are 64-bit (which implicitly makes int 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 using 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 one is system dependent, so if you want a specific calling convention, pick it yourself ๐Ÿ’… The valid calling conventions are ilp32, ilp32f, ilp32d, lp64, lp64f, and lp64d โœจ Some combos just can't work on certain ISAs. For example, -march=rv32if -mabi=ilp32d is invalid, because that 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 be careful ๐Ÿ™ˆ

  • -mfdiv, -mno-fdiv โ€” uses (or doesn't use) hardware floating-point divide and square root instructions ๐Ÿ”ฅ This needs the F or D extensions for floating-point registers. The default is to use them if the architecture you specified has them ๐Ÿ’–
  • -mdiv, -mno-div โ€” uses (or doesn't use) hardware instructions for integer division ๐ŸŒˆ This needs the M extension. The default is to use them if the architecture has them ๐ŸŽ€
  • -misa-spec=ISA-spec-string โ€” picks the version of the RISC-V Unprivileged (formerly User-Level) ISA specification your code should conform to ๐Ÿ“œ The options are:
    • 2.2 โ€” produces code conforming to version 2.2 โœจ
    • 20190608 โ€” produces code conforming to version 20190608 ๐Ÿฆ‹
    • 20191213 โ€” produces code conforming to version 20191213 ๐ŸŒธ

The default is -misa-spec=20191213, unless GCC was configured with --with-isa-spec= set to a different default version ๐Ÿ’…

  • -march=ISA-string โ€” generates code for the given RISC-V ISA (e.g. 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 missing, the default is system dependent, so if you want specific architecture extensions, spell them out yourself ๐Ÿ‘‘
  • -mcpu=processor-string โ€” uses the architecture of, and optimizes the output for, the given processor by its particular CPU name ๐Ÿ”ฅ The permitted 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, named by microarchitecture or particular CPU name ๐ŸŽ€ The permitted values are rocket, sifive-3-series, sifive-5-series, sifive-7-series, size, and all valid options for -mcpu= ๐ŸŒˆ

If -mtune= isn't specified, it uses the setting from -mcpu, and if neither is given, the default is rocket ๐Ÿ’… The size choice isn't meant for end-users. It's used when -Os is specified, and it overrides the instruction cost info from -mtune=, but not the pipeline info. The result is smaller code that still performs well ๐Ÿซถ

  • -mpreferred-stack-boundary=num โ€” tries to keep the stack boundary aligned to a 2 raised to num byte boundary ๐Ÿ“š If -mpreferred-stack-boundary isn't specified, the default is 4 (16 bytes, or 128 bits) ๐Ÿฆ‹
Warning: if you use this switch, you have to build all modules with the same value, including any libraries. That includes the system libraries and startup modules ๐Ÿ˜ญ
  • -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 โ€” uses (or doesn't use) smaller but slower prologue and epilogue code that calls library functions ๐Ÿงš The default is fast inline prologues and epilogues โœจ
  • -mshorten-memrefs, -mno-shorten-memrefs โ€” does (or doesn't) try to make more use of compressed load/store instructions 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 do not generate unaligned memory accesses, and -mno-strict-align means do 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 must lie within 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 must be within any single 2 GiB address range ๐Ÿ’– Programs can be statically or dynamically linked ๐ŸŽ€
  • -mexplicit-relocs, -mno-exlicit-relocs โ€” uses (or doesn't 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 โ€” okay so this one controls how GCC lines up variables and constants of array, structure, or union types ๐Ÿ“โœจ Your choices 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 โ€” bestie, this is the stack protection squad ๐Ÿ›ก๏ธ It 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 ๐Ÿงต

If you go with tls, then -mstack-protector-guard-reg=reg and -mstack-protector-guard-offset=offset decide which register is the base register for reading the canary, and what offset gets applied from that base register. There's no default register or offset here, because this is entirely for use within the Linux kernel ๐Ÿง๐Ÿ’€

๐ŸŒธ RL78 Options โœจ

  • -msim โ€” links in extra target libraries so your code can run inside a simulator ๐ŸŽฎ
  • -mmul=none, -mmul=g10, -mmul=g13, -mmul=g14, -mmul=rl78 โ€” this picks which kind of hardware multiplication and division support you get ๐Ÿงฎ The simplest one is "none", which uses software for both multiplication and division, and it'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 "rl78" value is an alias for "g14", and the "mg10" value is an alias for "none" ๐Ÿซ 

Also, a C preprocessor macro gets defined based on this setting. The possible values are "__RL78_MUL_NONE__", "__RL78_MUL_G13__", or "__RL78_MUL_G14__" ๐ŸŒท

  • -mcpu=g10, -mcpu=g13, -mcpu=g14, -mcpu=rl78 โ€” this specifies which RL78 core you're targeting ๐ŸŽฏ The default is the G14 core, which is also known as an S3 core or just RL78 ๐Ÿ‘‘ The G13 (S2) core doesn't have multiply or divide instructions. Instead it uses a hardware peripheral for those operations ๐Ÿง  The G10 (S1) core doesn't have register banks, so it uses a different calling convention ๐Ÿ™ƒ

If you set this option, it also picks the type of hardware multiply support to use, unless you override it with an explicit -mmul=none on the command line. So -mcpu=g13 turns on the G13 hardware multiply peripheral, and -mcpu=g10 turns off hardware multiplications altogether ๐Ÿšซ

Heads up, babe: even though the RL78/G14 core is the default target, specifying -mcpu=g14 or -mcpu=rl78 on the command line does change how the toolchain behaves, because it also turns on G14 hardware multiply support. If you don't specify these on the command line, software multiplication routines get used even though the code targets the RL78 core. This is for backwards compatibility with older toolchains that didn't have hardware multiply and divide support ๐Ÿ•ฐ๏ธ

There's also a C preprocessor macro defined based on this setting. The possible values are "__RL78_G10__", "__RL78_G13__", or "__RL78_G14__" ๐Ÿฆ‹

  • -mg10, -mg13, -mg14, -mrl78 โ€” these are aliases for the matching -mcpu= option ๐Ÿซถ They're only here for backwards compatibility, so you don't have to change your old builds ๐Ÿ“
  • -mallregs โ€” lets the compiler use all of the available registers ๐ŸŒˆ By default, registers "r24..r31" are reserved for interrupt handlers. With this option on, those registers can also be used in ordinary functions ๐Ÿ’œ
  • -m64bit-doubles, -m32bit-doubles โ€” makes the "double" data type 64 bits (-m64bit-doubles) or 32 bits (-m32bit-doubles) in size โœจ The default is -m32bit-doubles ๐Ÿงš
  • -msave-mduc-in-interrupts, -mno-save-mduc-in-interrupts โ€” this tells interrupt handler functions to preserve the MDUC registers ๐Ÿ›Ÿ You only really need it if normal code might touch the MDUC registers, like if it does multiplication and division ๐Ÿงฎ The default is to ignore the MDUC registers, because that makes the interrupt handlers faster โšก You need to pass the target option -mg13 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 if it calls another function ๐ŸŒธ

๐Ÿฆ‹ IBM RS/6000 and PowerPC Options ๐Ÿ’…

These -m options are defined for the IBM RS/6000 and PowerPC ๐ŸŒŸ

  • -mpowerpc-gpopt, -mno-powerpc-gpopt โ€” lets GCC use the optional PowerPC architecture instructions in the General Purpose group, including floating-point square root ๐Ÿงฎ
  • -mpowerpc-gfxopt, -mno-powerpc-gfxopt โ€” lets GCC use the optional PowerPC architecture instructions in the Graphics group, including floating-point select ๐ŸŽจ
  • -mmfcrf, -mno-mfcrf โ€” lets GCC generate the move from condition register field instruction, which is implemented on the POWER4 and other processors that support the PowerPC V2.01 architecture ๐Ÿ”
  • -mpopcntb, -mno-popcntb โ€” lets GCC generate the popcount and double-precision FP reciprocal estimate instruction, which is implemented on the POWER5 and other processors that support the PowerPC V2.02 architecture ๐Ÿ”ข
  • -mpopcntd, -mno-popcntd โ€” lets GCC generate the popcount instruction implemented on the POWER7 and other processors that support the PowerPC V2.06 architecture ๐Ÿ’œ
  • -mfprnd, -mno-fprnd โ€” lets GCC generate the FP round to integer instructions implemented on the POWER5+ and other processors that support the PowerPC V2.03 architecture ๐Ÿ”„
  • -mcmpb, -mno-cmpb โ€” lets GCC generate the compare bytes instruction implemented on the POWER6 and other processors that support the PowerPC V2.05 architecture ๐Ÿงฉ
  • -mhard-dfp, -mno-hard-dfp โ€” lets GCC generate the decimal floating-point instructions implemented on some POWER processors ๐Ÿช™
  • -mpowerpc64, -mno-powerpc64 โ€” lets GCC generate the additional 64-bit instructions found in the full PowerPC64 architecture, and treats GPRs as 64-bit doubleword quantities ๐Ÿš€ GCC defaults to -mno-powerpc64 ๐Ÿ™ˆ

The default value of all of these is determined when GCC is configured. Specifying -mcpu=cpu_type overrides these options, so we recommend you use -mcpu=cpu_type instead of the options listed above ๐Ÿซถ

  • -mcpu=cpu_type โ€” sets the architecture type, register usage, and instruction scheduling parameters for the machine type cpu_type ๐Ÿ–ฅ๏ธ 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 give you pure 32-bit PowerPC (either endian), 64-bit big endian PowerPC, and 64-bit little endian PowerPC machine types ๐Ÿงš They come with a generic processor model for scheduling purposes ๐Ÿ“…

Specifying native detects the host processor of the system doing the compilation and picks the matching architecture option ๐Ÿ•ต๏ธ -mcpu=native has no effect if GCC doesn't recognize the processor ๐Ÿคทโ€โ™€๏ธ

The other options each specify a specific processor. Code generated under those options runs best on that processor, and it 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 ๐Ÿช„

Which options get set for a particular CPU changes between compiler versions, depending on what seems to produce the best code for that CPU ๐Ÿ”„ It doesn't necessarily match the actual hardware's capabilities, so don't assume it does ๐Ÿซ  If you want to set one individual option to a particular value, you can put it after the -mcpu option, like -mcpu=970 -mno-altivec ๐Ÿ’…

On AIX, the -maltivec and -mpowerpc64 options are not enabled or disabled by -mcpu at the moment, 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 โ€” sets the instruction scheduling parameters for the machine type cpu_type, but doesn't 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 โ€” ๐ŸŽ€ okay so -maltivec makes GCC generate code that uses AltiVec instructions, and it also unlocks built-in functions for more direct access to the AltiVec instruction set. -mno-altivec turns that off. You might also need -mabi=altivec to adjust the current ABI with the AltiVec ABI enhancements โœจ

When -maltivec is on, the element order for AltiVec intrinsics like vec_splat, vec_extract, and vec_insert matches the array element order for your target's endianness ๐Ÿซถ Element zero is the leftmost element in a vector register on a big-endian target, and the rightmost one on a little-endian target. Bestie, this one is lowkey the most important bit ๐Ÿ™ˆ

  • -mvrsave, -mno-vrsave โ€” ๐ŸŒธ generates VRSAVE instructions when GCC is making AltiVec code (or doesn't, with the -mno- version).
  • -msecure-plt โ€” ๐Ÿ” makes code so that ld and ld.so can build executables and shared libraries with non-executable .plt and .got sections. This is a PowerPC 32-bit SYSV ABI option, so it's only for that combo ๐Ÿ’…
  • -mbss-plt โ€” ๐Ÿฆ‹ makes code that uses a BSS .plt section that ld.so fills in. The catch is it needs .plt and .got sections that are both writable and executable. Also a PowerPC 32-bit SYSV ABI option.
  • -misel, -mno-isel โ€” โญ switches ISEL instruction generation on or off. That's the whole tea โ˜•
  • -mvsx, -mno-vsx โ€” ๐Ÿ‘‘ generates code that uses (or avoids) vector/scalar (VSX) instructions, and also enables built-in functions that give more direct access to the VSX instruction set.
  • -mcrypto, -mno-crypto โ€” ๐Ÿ”ฅ enables (or disables) the built-in functions for direct access to the cryptographic instructions added in version 2.07 of the PowerPC ISA.
  • -mhtm, -mno-htm โ€” ๐Ÿงš enables (or disables) the built-in functions for direct access to the Hardware Transactional Memory (HTM) instructions, which were also added in version 2.07 of the PowerPC ISA.
  • -mpower8-fusion, -mno-power8-fusion โ€” ๐Ÿ’œ generates code that keeps some integer operations next to each other, so the instructions can get fused together on POWER8 and later processors. The -mno- version does not keep them adjacent, so no fusing ๐Ÿ™ˆ
  • -mpower8-vector, -mno-power8-vector โ€” ๐Ÿ’– generates code that uses (or skips) the vector and scalar instructions added in version 2.07 of the PowerPC ISA. It also enables built-in functions for more direct access to the vector instructions, obsessed โœจ
  • -mquad-memory, -mno-quad-memory โ€” ๐Ÿ“ generates code that uses (or skips) the non-atomic quad word memory instructions. Heads up: -mquad-memory requires 64-bit mode ๐Ÿ™…โ€โ™€๏ธ
  • -mquad-memory-atomic, -mno-quad-memory-atomic โ€” ๐ŸŒˆ same deal, but for the atomic quad word memory instructions. -mquad-memory-atomic also requires 64-bit mode.
  • -mfloat128, -mno-float128 โ€” ๐Ÿ’… enables or disables the __float128 keyword for IEEE 128-bit floating point, and picks between software emulation or hardware instructions for it.

Okay, the IEEE 128-bit floating point support needs the VSX instruction set (-mvsx) to be enabled first. It's also only supported on Linux, so no cap, that's a hard limit ๐Ÿง

The default for -mfloat128 is enabled on PowerPC Linux systems using the VSX instruction set, and disabled on other systems โœจ

If you use the ISA 3.0 instruction set (-mpower9-vector or -mcpu=power9) on a 64-bit system, IEEE 128-bit floating point support will also turn on the generation of ISA 3.0 IEEE 128-bit floating point instructions ๐Ÿš€ Otherwise, if you don't ask for ISA 3.0 instructions, or you're targeting a 32-bit big endian system, IEEE 128-bit floating point gets done with software emulation ๐Ÿซ 

  • -mfloat128-hardware, -mno-float128-hardware โ€” ๐Ÿ”ฅ enables or disables using ISA 3.0 hardware instructions to support the __float128 data type.

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 โ€” ๐Ÿ‘‘ generates code for the 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 makes code that runs on any PowerPC variant. The 64-bit environment sets int to 32 bits, long and pointer to 64 bits, and generates code for PowerPC64, same as -mpowerpc64 ๐Ÿงš
  • -mfull-toc, -mno-fp-in-toc, -mno-sum-in-toc, -mminimal-toc โ€” ๐Ÿ“š these change how the TOC (Table Of Contents) gets generated, and every executable file gets one. -mfull-toc is the default, and in that mode GCC gives at least one TOC entry for each unique non-automatic variable reference in your program. It also puts floating-point constants in the TOC. The catch? Only 16,384 entries fit in the TOC ๐Ÿ˜ญ

If a linker error tells you that you've overflowed the available TOC space, you can shrink the TOC usage with -mno-fp-in-toc and -mno-sum-in-toc. -mno-fp-in-toc stops GCC from putting floating-point constants in the TOC, and -mno-sum-in-toc makes GCC generate code that calculates the sum of an address and a constant at run time, instead of stuffing that sum into the TOC. You can use one or both, and each one makes the code very slightly slower and larger in exchange for saving TOC space ๐ŸŒธ

Still out of room even with both? Try -mminimal-toc. It makes GCC create only one TOC entry for every file. The code is slower and larger, but it uses extremely little TOC space. Maybe only use it on files with less frequently-executed code ๐Ÿฅบ

  • -maix64, -maix32 โ€” ๐ŸŒˆ enables the 64-bit AIX ABI and calling convention, which means 64-bit pointers, a 64-bit long type, and the infrastructure needed to support them. -maix64 implies -mpowerpc64, while -maix32 disables the 64-bit ABI and implies -mno-powerpc64. GCC defaults to -maix32 โœจ
  • -mxl-compat, -mno-xl-compat โ€” ๐ŸŽ€ produces code that conforms more closely to IBM XL compiler semantics when you're using the AIX-compatible ABI. Here's the tea: it passes floating-point arguments to prototyped functions beyond the register save area (RSA) on the stack, in addition to the argument FPRs. It also doesn't assume the most significant double in a 128-bit long double value is properly rounded when comparing values and converting to double. And it uses XL symbol names for long double support routines.

The AIX calling convention got extended, but that wasn't documented at first, to handle an obscure K&R C case: calling a function that takes the address of its arguments with fewer arguments than declared. IBM XL compilers read floating-point arguments that don't fit in the RSA from the stack when a subroutine is compiled without optimization. Storing floating-point arguments on the stack all the time is inefficient and rarely needed, so this option isn't on by default. You only really need it when calling subroutines compiled by IBM XL compilers without optimization ๐Ÿ™ƒ

  • -mpe โ€” ๐Ÿงœโ€โ™€๏ธ supports the IBM RS/6000 SP Parallel Environment (PE). It links an application written to use message passing with special startup code so the application can actually run. The system needs PE installed in the standard location (/usr/lpp/ppe.poe/), or you have to override the specs file with -specs= to point at the right directory.
โš ๏ธ The Parallel Environment doesn't support threads, so -mpe and -pthread are incompatible. Don't mix them, bestie ๐Ÿ’€
  • -malign-natural, -malign-power โ€” ๐Ÿ“ on AIX, 32-bit Darwin, and 64-bit PowerPC GNU/Linux, -malign-natural overrides the ABI-defined alignment of larger types, like floating-point doubles, and puts them on their natural size-based boundary. -malign-power tells GCC to follow the ABI-specified alignment rules instead. GCC defaults to the standard alignment defined in the ABI.

On 64-bit Darwin, natural alignment is the default, and -malign-power isn't supported there ๐Ÿ™…โ€โ™€๏ธ

  • -msoft-float, -mhard-float โ€” ๐ŸŒŠ generates code that does not use (or does use) the floating-point register set. If you use -msoft-float, software floating-point emulation is provided, but you have to pass the option to GCC when linking too.
  • -mmultiple, -mno-multiple โ€” ๐Ÿงฉ generates code that uses (or doesn't use) the load multiple word and store multiple word instructions. These get generated by default on POWER systems, but not on PowerPC systems.
โš ๏ธ Do not use -mmultiple on little-endian PowerPC systems, since those instructions don't work when the processor is in little-endian mode. The exceptions are PPC740 and PPC750, which do permit these instructions in little-endian mode.
  • -mupdate, -mno-update โ€” ๐Ÿ”„ generates code that uses (or doesn't use) the load or store instructions that update the base register to the address of the calculated memory location. These are generated by default.
๐Ÿ˜ฑ If you use -mno-update, there's a small window between the time the stack pointer gets updated and the time the address of the previous frame gets stored. That means code that walks the stack frame across interrupts or signals might end up with corrupted data.
  • -mavoid-indexed-addresses, -mno-avoid-indexed-addresses โ€” ๐Ÿฆ‹ generates code that tries to avoid (or doesn't avoid) indexed load or store instructions. Those can cause 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 โ€” ๐Ÿ’ซ generates code that uses (or doesn't use) the floating-point multiply and accumulate instructions. These are generated by default if hardware floating point is used. The machine-dependent -mfused-madd is now mapped to the machine-independent -ffp-contract=fast, and -mno-fused-madd is mapped to -ffp-contract=off ๐ŸŒˆ
  • -mmulhw, -mno-mulhw โ€” okay bestie, these two decide whether your code uses the half-word multiply and multiply-accumulate instructions on the IBM 405, 440, 464 and 476 processors. -mmulhw makes the code use them, and -mno-mulhw makes it skip them. They're on by default when you're targeting those chips, so you're already winning ๐Ÿ’…
  • -mdlmzb, -mno-dlmzb โ€” ๐Ÿ” this one controls the string-search dlmzb instruction on the IBM 405, 440, 464 and 476 processors. -mdlmzb generates code that uses it and -mno-dlmzb generates code that doesn't. Same energy as before: it's on by default for those targets ๐Ÿซถ
  • -mno-bit-align, -mbit-align โ€” on System V.4 and embedded PowerPC systems, -mno-bit-align means structs and unions with bit-fields are not forced to line up with the bit-field's base type, and -mbit-align means they are forced to. The vibe check here is memory layout ๐ŸŽ€

By default, a struct with nothing but 8 unsigned bit-fields of length 1 gets aligned to a 4-byte boundary and ends up 4 bytes big. With -mno-bit-align, that same struct is aligned to a 1-byte boundary and is just 1 byte in size. Iconic glow-up ๐Ÿฆ‹

  • -mno-strict-align, -mstrict-align โ€” on System V.4 and embedded PowerPC systems, -mno-strict-align means the compiler does not assume the system handles unaligned memory references, while -mstrict-align means it does assume that ๐Ÿงš
  • -mrelocatable, -mno-relocatable โ€” โœจ these generate code that either allows or doesn't allow a static executable to be relocated to a different address at run time. A simple embedded PowerPC system loader is expected to relocate the whole of .got2, plus the 4-byte locations listed in the .fixup section (a table of 32-bit addresses generated by this option). For this to work, every object linked together has to be compiled with -mrelocatable or -mrelocatable-lib. Also, -mrelocatable code aligns the stack to an 8-byte boundary, so keep that in mind bestie ๐ŸŒธ
  • -mrelocatable-lib, -mno-relocatable-lib โ€” this is basically -mrelocatable with a glow-up. It still generates a .fixup section so static executables can be relocated at run time, but it does not use the smaller stack alignment that -mrelocatable does. Objects built with -mrelocatable-lib can be linked with objects built with any combination of the -mrelocatable options, which is so convenient ๐Ÿ’œ
  • -mno-toc, -mtoc โ€” on System V.4 and embedded PowerPC systems, -mno-toc means the compiler does not assume register 2 holds a pointer to a global area with the addresses the program uses. -mtoc is the one that does assume it ๐Ÿ“
  • -mlittle, -mlittle-endian โ€” ๐ŸŒˆ on System V.4 and embedded PowerPC systems, this compiles your code for the processor in little-endian mode. -mlittle-endian is exactly the same as -mlittle, so pick whichever you vibe with.
  • -mbig, -mbig-endian โ€” ๐ŸŒŠ on System V.4 and embedded PowerPC systems, this compiles your code for the processor in big-endian mode. -mbig-endian is the same as -mbig, no drama.
  • -mdynamic-no-pic โ€” ๐ŸŽ on Darwin and Mac OS X systems, this compiles code so it's not relocatable, but its external references are relocatable. The result is suitable for applications, but not for shared libraries, so don't try to ship it as a .dylib ๐Ÿ™ˆ
  • -msingle-pic-base โ€” this treats the register used for PIC addressing as read-only, instead of loading it in the prologue for every function. Your runtime system has to set that register to the right value before execution starts, because nobody else is going to do it for you ๐Ÿ‘‘
  • -mprioritize-restricted-insns=priority โ€” this controls the priority given to dispatch-slot restricted instructions during the second scheduling pass. The priority argument takes 0, 1, or 2, which give no priority, the highest priority, or the second-highest priority to those instructions (in that order) ๐Ÿ“Š
  • -msched-costly-dep=dependence_type โ€” this decides which dependences the target counts as costly during instruction scheduling. The dependence_type argument takes one of these values:
    • no โ€” no dependence is costly. Chill vibes only ๐Ÿ˜Œ
    • all โ€” every dependence is costly. Intense ๐Ÿ’€
    • 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 which NOP insertion scheme gets used during the second scheduling pass. The scheme argument takes one of these values:
    • no โ€” don't insert NOPs at all.
    • pad โ€” pad any dispatch group that has vacant issue slots with NOPs, according to the scheduler's grouping. ๐Ÿงธ
    • regroup_exact โ€” insert NOPs to force costly dependent insns into separate groups. It inserts exactly as many NOPs as needed to push an insn into a new group, according to the estimated processor grouping. Precise, bestie โœจ
    • number โ€” insert NOPs to force costly dependent insns into separate groups, with number NOPs used to force an insn into a new group.
  • -mcall-sysv โ€” on System V.4 and embedded PowerPC systems, this compiles code using calling conventions that follow the March 1995 draft of the System V Application Binary Interface, PowerPC processor supplement. This is the default unless you configured GCC using powerpc-*-eabiaix, so it's basically the classic move ๐Ÿ‘‘
  • -mcall-sysv-eabi, -mcall-eabi โ€” this one is a two-for-one: it's the same as specifying both -mcall-sysv and -meabi ๐Ÿ’–
  • -mcall-sysv-noeabi โ€” another combo deal ๐ŸŽ€ this is the 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 โ€” this selects the type of traceback table. The valid values for traceback_type are full, part, and no. Pick your fighter ๐Ÿ”ฅ
  • -maix-struct-return โ€” this returns all structures in memory, which is what the AIX ABI specifies ๐Ÿงฑ
  • -msvr4-struct-return โ€” this returns structures smaller than 8 bytes in registers, as specified by the SVR4 ABI. Smaller structs, faster vibes โœจ
  • -mabi=abi-type โ€” this extends the current ABI with a particular extension, or removes that extension. The valid values are altivec, no-altivec, ibmlongdouble, ieeelongdouble, elfv1, elfv2, and, for AIX, vec-extabi and vec-default. That's a lot of options, so take a breath ๐Ÿซ 
  • -mabi=ibmlongdouble โ€” this changes the current ABI to use IBM extended-precision long double. โš ๏ธ This is not likely to work if your system defaults to IEEE extended-precision long double. If you switch the long double type away from IEEE extended-precision, the compiler will issue a warning unless you use -Wno-psabi. It also requires -mlong-double-128 to be enabled.
  • -mabi=ieeelongdouble โ€” this changes the current ABI to use IEEE extended-precision long double. โš ๏ธ This is not likely to work if your system defaults to IBM extended-precision long double. If you switch away from IBM extended-precision, the compiler will issue a warning unless you use -Wno-psabi. It also requires -mlong-double-128 to be enabled.
  • -mabi=elfv1 โ€” this changes the current ABI to the ELFv1 ABI. It's the default ABI for big-endian PowerPC 64-bit Linux. Overriding the default ABI needs special system support, and it's likely to fail in spectacular ways ๐Ÿ’€
  • -mabi=elfv2 โ€” this changes the current ABI to the ELFv2 ABI. It's the default ABI for little-endian PowerPC 64-bit Linux. Overriding the default ABI needs special system support, and it's likely to fail in spectacular ways too, so please don't ๐Ÿ™ˆ
  • -mgnu-attribute, -mno-gnu-attribute โ€” these control whether the compiler emits .gnu_attribute assembly directives. Those directives set tag/value pairs in a .gnu.attributes section, which specify ABI variations in function parameters or return values ๐Ÿ“œ
  • -mprototype, -mno-prototype โ€” on System V.4 and embedded PowerPC systems, -mprototype assumes that all calls to variable argument functions are properly prototyped. Without it, the compiler has to insert an instruction before every non-prototyped call to set or clear bit 6 of the condition code register (CR), which 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 that 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 tells the compiler you're building for a VxWorks system ๐Ÿš€
  • -memb โ€” on embedded PowerPC systems, this sets the PPC_EMB bit in the ELF flags header to indicate that eabi extended relocations are used ๐Ÿงฉ

  • -meabi, -mno-eabi โ€” on System V.4 and embedded PowerPC systems, these decide whether you adhere to the Embedded Applications Binary Interface (EABI), which is a set of modifications to the System V.4 specifications. โœจ Here's the tea:
    • -meabi aligns the stack to an 8-byte boundary, calls a function __eabi from main to set up the EABI environment, and lets the -msdata option use both r2 and r13 to point to two separate small data areas.
    • -mno-eabi aligns the stack to a 16-byte boundary, doesn't call any EABI initialization function from main, and lets the -msdata option use only r13 to point to a single small data area.

-meabi is on by default if you configured GCC using one of the powerpc*-*-eabi* options, so that's the default main character energy ๐Ÿ‘‘

  • -msdata=eabi: okay bestie, on System V.4 and embedded PowerPC systems, small initialized const global and static data goes into the .sdata2 section, which is pointed to by register r2 ๐Ÿ’–. Small initialized non-const global and static data goes into .sdata instead, pointed to by register r13 โœจ. Small uninitialized global and static data gets tucked into .sbss, which sits right next to .sdata ๐Ÿฆ‹. Heads up: -msdata=eabi is incompatible with -mrelocatable ๐Ÿšซ, and it also turns on -memb ๐Ÿซถ.
  • -msdata=sysv: same vibe on System V.4 and embedded PowerPC systems, but way simpler ๐Ÿ’…. Small global and static data goes into .sdata, pointed to by register r13. Small uninitialized global and static data goes into .sbss, which is adjacent to .sdata. Just know that -msdata=sysv is incompatible with -mrelocatable ๐Ÿšซ.
  • -msdata=default, -msdata: this one is giving "it depends" ๐Ÿ™ˆ. On System V.4 and embedded PowerPC systems, if -meabi is used, the code gets compiled the same as -msdata=eabi. Otherwise, it gets compiled the same as -msdata=sysv ๐ŸŒธ.
  • -msdata=data: on System V.4 and embedded PowerPC systems, small global data goes into .sdata, and small uninitialized global data goes into .sbss ๐Ÿงš. The catch is that register r13 does not get used to address small data here. This is the default unless other -msdata options are used.
  • -msdata=none, -mno-sdata: on embedded PowerPC systems, all initialized global and static data goes into .data, and all uninitialized data goes into .bss ๐Ÿ“.
  • -mreadonly-in-sdata: read-only objects get put into .sdata as well โœจ. This is the default, so you're already getting it ๐Ÿ‘‘.
  • -mblock-move-inline-limit=num: inline every block move (think calls to memcpy or structure copies) that's 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 is target-specific.
  • -mblock-compare-inline-limit=num: generate 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, then all inline expansion, both non-loop and loop, of block compare is disabled ๐Ÿšซ. The default is target-specific.
  • -mblock-compare-inline-loop-limit=num: this one makes an inline expansion using loop code for all block compares that are less than or equal to num bytes, but bigger than the limit for the non-loop inline block compare ๐ŸŒˆ. If the block length isn't constant, at most num bytes get compared before memcmp is called to handle the rest of the block. The default is target-specific.
  • -mstring-compare-inline-limit=num: compare at most num string bytes with inline code ๐ŸŽ€. If the difference or the end of the string isn't found by the end of the inline compare, a call to strcmp or strncmp takes care of the rest. The default is 64 bytes.
  • -G num: on embedded PowerPC systems, global and static items that are less than or equal to num bytes get put into the small data or BSS sections, instead of the normal data or BSS section ๐Ÿง. By default, num is 8. The -G num switch also gets passed to the linker ๐Ÿ”—. All modules should be compiled with the same -G num value, bestie, or things get messy ๐Ÿ™ƒ.
  • -mregnames, -mno-regnames: on System V.4 and embedded PowerPC systems, this does (or does not) emit register names in the assembly language output using symbolic forms ๐Ÿฆ‹.
  • -mlongcall, -mno-longcall: by default, the compiler assumes all calls are far away ๐ŸŒ, so it uses a longer and more expensive calling sequence. This is required 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 detect out-of-range calls and generate glue code on the fly ๐Ÿช„. On those systems, long calls are unnecessary and generate slower code ๐Ÿ˜ญ. As of this writing, the AIX linker can do this, and so can the GNU linker for PowerPC/64. It's planned to add this feature to the GNU linker for 32-bit PowerPC systems too.

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 it generates bl callee if the PPC bl instruction can reach the callee directly. Otherwise, the linker generates bl L42 to call the branch island. The branch island gets appended to the body of the calling function, and it computes the full 32-bit address of the callee and jumps to it ๐Ÿฆ˜.

On Mach-O (Darwin) systems, this option tells the compiler to emit the glue for every direct call, and then the Darwin linker decides whether to use it or toss it ๐Ÿ—‘๏ธ.

In the future, GCC may ignore all longcall specifications when the linker is known to generate glue ๐Ÿ‘‘.

  • -mpltseq, -mno-pltseq: this implements (or does not implement) -fno-plt and long calls using an inline PLT call sequence ๐Ÿ€. That sequence supports lazy linking and long calls to functions in dlopen'd shared libraries. Inline PLT calls are only supported on PowerPC64 ELFv2 and 32-bit PowerPC systems with newer GNU linkers. They're enabled by default if support is detected when configuring GCC, and, for 32-bit PowerPC, if GCC is configured with --enable-secureplt โš™๏ธ. Heads up: -mpltseq code and -mbss-plt 32-bit PowerPC relocatable objects may not be linked together ๐Ÿšซ.
  • -mtls-markers, -mno-tls-markers: this marks (or does not mark) calls to __tls_get_addr with a relocation that specifies the function argument ๐Ÿท๏ธ. The relocation lets the linker reliably connect the function call with the argument setup instructions for TLS optimization. That in turn lets GCC better schedule the sequence ๐ŸŽฏ.
  • -mrecip, -mno-recip: this enables the use of the reciprocal estimate and reciprocal square root estimate instructions, with extra Newton-Raphson steps to boost precision ๐Ÿงฎ. It's used instead of doing a divide, or a square root and then 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 ๐Ÿซถ. The throughput of the sequence is generally higher than the throughput of the non-reciprocal instruction โšก. But the precision can drop by up to 2 ulp (i.e. the inverse of 1.0 equals 0.99999994) for reciprocal square roots ๐Ÿ˜ฌ.
  • -mrecip=opt: this controls which reciprocal estimate instructions may be used ๐ŸŽ›๏ธ. opt is a comma-separated list of options, and any of them can be preceded by a ! to invert it. Here's the menu:
    • 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 FRSQRTE, XSRSQRTEDP, and XVRSQRTEDP, which handle the double-precision reciprocal square root calculations ๐Ÿ’€.

  • -mrecip-precision, -mno-recip-precision: this assumes (or does not 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 converge 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 with external libraries. When generating code for power7, 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 ๐ŸŒˆ. Both -ftree-vectorize and -funsafe-math-optimizations must also be enabled ๐Ÿซถ. And the MASS libraries must be specified at link time ๐Ÿ”—.
  • -mfriz, -mno-friz: this generates (or does not generate) the friz instruction when -funsafe-math-optimizations is used to optimize rounding of floating-point values to 64-bit integers and back to floating point ๐Ÿซง. Watch out, though: the friz instruction doesn't 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

Okay so bestie, these two are a matched pair ๐Ÿ’… Generate (or don't generate) code that loads up the static chain register ("r11") when you call through a pointer on AIX and 64-bit Linux systems, where a function pointer points to a 3-word descriptor holding the function address, the TOC value to load into register "r2", and the static chain value to load into register "r11". ๐ŸŽ€ The -mpointers-to-nested-functions one is on by default. โœจ But 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. ๐Ÿ’€ That's a whole vibe check, so be careful with it ๐Ÿ˜ญ

-msave-toc-indirect -mno-save-toc-indirect

Generate (or don't generate) code that saves the TOC value in the reserved stack location in the function prologue, if the function calls through a pointer on AIX and 64-bit Linux systems. ๐Ÿฆ‹ If the TOC value isn't saved in the prologue, it gets saved just before the call through the pointer. ๐ŸŒธ The -mno-save-toc-indirect option is the default, so that's your baseline ๐Ÿซถ

-mcompat-align-parm -mno-compat-align-parm

Generate (or don't generate) code that passes structure parameters with a maximum alignment of 64 bits, for compatibility with older versions of GCC. ๐Ÿงš

Okay so the older versions of GCC (prior to 4.9.0) incorrectly did not align a structure parameter on a 128-bit boundary when that structure had a member that needed 128-bit alignment. ๐Ÿ˜ญ This got fixed in more recent versions of GCC. ๐Ÿ‘‘ You can use this option if you need code that plays nicely with functions compiled by those older versions ๐Ÿ“

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

Generate stack protection code that uses a canary at guard. ๐Ÿ”ฅ The supported locations are global for a global canary, or tls for a per-thread canary in the TLS block. ๐ŸŒˆ The tls one is the default with GNU libc version 2.4 or later. โญ

With the tls choice, the options -mstack-protector-guard-reg=reg and -mstack-protector-guard-offset=offset also decide which register 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 says. ๐Ÿ’…

-mstack-protector-guard-symbol=symbol overrides the offset with a symbol reference to a canary in the TLS block. โœจ

-mpcrel -mno-pcrel

Generate (or don't generate) pc-relative addressing. ๐Ÿฆ‹ The -mpcrel option needs the medium code model (-mcmodel=medium) and prefixed addressing (-mprefixed) to both be enabled. ๐ŸŽ€

-mprefixed -mno-prefixed

Generate (or don't generate) addressing modes that use prefixed load and store instructions. ๐ŸŒธ The -mprefixed option needs -mcpu=power10 (or later) to be enabled. ๐Ÿ‘‘

-mmma -mno-mma

Generate (or don't generate) the MMA instructions. ๐Ÿ’– The -mma option needs -mcpu=power10 (or later) to be enabled ๐Ÿงš

-mrop-protect -mno-rop-protect

Generate (or don't generate) ROP protection instructions when the target processor supports them. ๐Ÿ›ก๏ธ Heads up, right now this option disables the shrink-wrap optimization (-fshrink-wrap). ๐Ÿ’€

-mprivileged -mno-privileged

Generate (or don't generate) code that runs in privileged state. ๐Ÿ‘‘

-mblock-ops-unaligned-vsx -mno-block-ops-unaligned-vsx

Generate (or don'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 ๐Ÿฆ‹

-m64bit-doubles -m32bit-doubles

Makes the "double" data type 64 bits (-m64bit-doubles) or 32 bits (-m32bit-doubles) in size. ๐Ÿ’– The default is -m32bit-doubles. ngl the reason is that RX floating-point hardware only works on 32-bit values ๐Ÿ™ˆ

-fpu -nofpu

Enables (-fpu) or disables (-nofpu) the use of RX floating-point hardware. ๐Ÿ”ฅ It's on by default for the RX600 series and off for the RX200 series. ๐ŸŒธ

Floating-point instructions are only generated for 32-bit floating-point values, though. ๐Ÿ˜ญ So the FPU hardware isn't used for doubles if the -m64bit-doubles option is used. ๐Ÿ’…

Note: if -fpu is enabled, then -funsafe-math-optimizations also gets enabled automatically. ๐Ÿ’€ This is because the RX FPU instructions are themselves unsafe. ๐Ÿ™ˆ

-mcpu=name

Picks the type of RX CPU to target. ๐ŸŽ€ Right now there are three supported types: the generic RX600 and RX200 series hardware, and the specific RX610 CPU. โœจ The default is RX600. ๐Ÿ’œ

The only difference between RX600 and RX610 is that the RX610 doesn't support the "MVTIPL" instruction. ๐Ÿงš

The RX200 series doesn't have a hardware floating-point unit, so -nofpu gets enabled by default when this type is selected. ๐Ÿซถ

-mbig-endian-data -mlittle-endian-data

Stores data (but not code) in big-endian format. ๐ŸŒˆ The default is -mlittle-endian-data, so data gets stored in little-endian format by default. ๐Ÿ“

-msmall-data-limit=N

Specifies the maximum size in bytes of global and static variables that can be placed into the small data area. ๐ŸŒธ Using the small data area can lead to smaller and faster code, but the area is limited, so it's up to the programmer 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 to this area, so the compiler can't use it anymore. ๐Ÿ’€ That could make the code slower and/or larger if variables get pushed onto the stack instead of being held in this register. ๐Ÿ™ˆ

Note, common variables (variables that haven't been initialized) and constants aren't 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 with higher optimization levels (-O2 etc), because reserving a register can have potentially detrimental effects. ๐Ÿ‘‘ It's up to the programmer to experiment and figure out whether it helps their program. ๐Ÿซถ See the description of the -mpid option for how the actual register to hold the small data area pointer is chosen. โœจ

-msim -mno-sim

Uses the simulator runtime. ๐Ÿงš The default is to use the libgloss board-specific runtime. ๐Ÿ’œ

-mas100-syntax -mno-as100-syntax

When generating assembler output, uses a syntax that's compatible with Renesas's AS100 assembler. ๐ŸŒธ This syntax can also be handled by the GAS assembler, but it has some restrictions, so it isn't generated by default. ๐Ÿ™ˆ

-mmax-constant-size=N

Specifies the maximum size, in bytes, of a constant that can be used as an operand in an RX instruction. ๐Ÿ”ฅ The RX instruction set does allow constants up to 4 bytes long in instructions, but a longer value means a longer instruction. ๐Ÿ˜ญ So in some situations it can be beneficial to restrict the size of constants used in instructions. ๐ŸŒˆ Constants that are too big get placed into a constant pool and referenced via register indirection instead. ๐Ÿซถ

The value N can be between 0 and 4. ๐Ÿ’… A value of 0 (the default) or 4 means constants of any size are allowed. โœจ

-mrelax

Enables linker relaxation. ๐Ÿฆ‹ This is a process where the linker tries to shrink a program by finding shorter versions of various instructions. ๐ŸŽ€ It's disabled by default. ๐Ÿ’œ

-mint-register=N

Specifies the number of registers to reserve for fast interrupt handler functions. ๐Ÿ‘‘ The value N can be between 0 and 4. ๐ŸŒˆ A value of 1 means register "r13" is reserved for the exclusive use of fast interrupt handlers. ๐Ÿงš A value of 2 reserves "r13" and "r12". ๐Ÿ“ A value of 3 reserves "r13", "r12" and "r11", and a value of 4 reserves "r13" through "r10". ๐Ÿ’– A value of 0, the default, doesn't reserve any registers. ๐ŸŒธ

-msave-acc-in-interrupts

Specifies that interrupt handler functions should preserve the accumulator register. ๐Ÿ’… This is only necessary if normal code might use the accumulator register, for example because it does 64-bit multiplications. ๐Ÿ™ˆ The default is to ignore the accumulator, because that makes the interrupt handlers faster. โญ

-mpid -mno-pid

Enables the generation of position independent data. ๐Ÿฆ‹ When enabled, any access to constant data is done via an offset from a base address held in a register. ๐Ÿซถ This lets the location of constant data be 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. ๐Ÿ’œ

Note, using this feature reserves a register, usually "r13", for the constant data base address. ๐Ÿ˜ญ This can make the code slower and/or larger, especially in complicated functions. ๐Ÿ’€

The actual register chosen to hold the constant data base address depends on whether -msmall-data-limit and/or -mint-register are enabled. ๐ŸŒˆ Starting with register "r13" and going downwards, registers get allocated first to satisfy -mint-register, then -mpid, and finally -msmall-data-limit. ๐Ÿงš So it's possible for the small data area register to be "r8" if both -mint-register=4 and -mpid are specified on the command line. ๐Ÿ“

By default this feature isn't enabled. ๐ŸŒธ You can restore the default with the -mno-pid command-line option. ๐Ÿ’–

-mno-warn-multiple-fast-interrupts -mwarn-multiple-fast-interrupts

Stops GCC from issuing a warning if it finds more than one fast interrupt handler while compiling a file. ๐Ÿ™ˆ The default is to issue a warning for each extra fast interrupt handler found, since the RX only supports one such interrupt. ๐Ÿ”ฅ

-mallow-string-insns -mno-allow-string-insns

Enables or disables the use of the string manipulation instructions "SMOVF", "SCMPU", "SMOVB", "SMOVU", "SUNTIL" "SWHILE" and also the "RMPA" instruction. ๐Ÿ’… These instructions may prefetch data, which isn't safe to do when accessing an I/O register. ๐Ÿ˜ญ (See section 12.2.7 of the RX62N Group User's Manual for more information.) ๐Ÿซถ

Okay so the default is to allow these instructions ๐Ÿ’…, but GCC can't reliably spot every situation where a string instruction might touch an I/O register, so it can't turn them off automatically ๐Ÿ™ˆ. That part's on you, bestie. If your program pokes at I/O space, you need to pass -mno-allow-string-insns yourself โœจ.

When the instructions are on, GCC defines the C preprocessor symbol __RX_ALLOW_STRING_INSNS__. When they're off, it defines __RX_DISALLOW_STRING_INSNS__ instead ๐Ÿฆ‹.

  • -mjsr, -mno-jsr โ€” Use only (or not only) JSR instructions to call functions ๐Ÿ“ž. This comes in handy when your code is bigger than what BSR instructions can reach ๐Ÿ“. Heads up, -mno-jsr doesn't mean "never use JSR" ๐Ÿ™ƒ. It just means any kind of branch is fair game ๐ŸŒˆ.

Note: the generic GCC command-line option -ffixed-reg has a special vibe on the RX port when you pair it with the interrupt function attribute ๐Ÿ‘‘. That attribute marks a function meant to handle fast interrupts โšก. GCC makes sure it only touches r10, r11, r12 and/or r13, and only when the normal use of those registers has been restricted through the -ffixed-reg or -mint-register command-line options ๐Ÿซถ.


๐ŸŒธ S/390 and zSeries Options ๐ŸŒธ

These are the -m options for the S/390 and zSeries architecture ๐Ÿ’œ.

  • -mhard-float, -msoft-float โ€” Use (or skip) the hardware floating-point instructions and registers for floating-point math ๐Ÿ”ฅ. With -msoft-float, the functions in libgcc.a do the floating-point work instead ๐Ÿงš. With -mhard-float, the compiler generates IEEE floating-point instructions ๐Ÿ’–. Hard float is the default โœจ.
  • -mhard-dfp, -mno-hard-dfp โ€” Use (or skip) the hardware decimal-floating-point instructions for decimal-floating-point operations ๐ŸŽ€. With -mno-hard-dfp, the functions in libgcc.a handle decimal floating point ๐Ÿ™ˆ. With -mhard-dfp, the compiler generates the 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 the same as double ๐Ÿฆ‹. This is the default ๐Ÿ’….
  • -mbackchain, -mno-backchain โ€” Store (or don't store) the address of the caller's frame as a backchain pointer in the callee's stack frame ๐Ÿ”—. A backchain can be needed to debug with tools that don't understand DWARF call frame information ๐Ÿ”. When -mno-packed-stack is in effect, the backchain pointer lives at the bottom of the stack frame ๐Ÿชจ. When -mpacked-stack is in effect, the backchain goes into the topmost word of the 96/160 byte register save area ๐Ÿซง.

Okay, so, code built with -mbackchain is call-compatible with code built with -mno-backchain ๐Ÿ’–. Using the backchain for debugging usually means the whole binary has to be built with -mbackchain ๐Ÿง.

โš ๏ธ The combination of -mbackchain, -mpacked-stack and -mhard-float is not supported ๐Ÿ’€. If you want to build a Linux kernel, use -msoft-float ๐Ÿง.

The default is to not maintain the backchain ๐ŸŒ™.

  • -mpacked-stack, -mno-packed-stack โ€” Use (or skip) 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 purpose ๐Ÿงธ. Unused fields still eat stack space ๐Ÿ˜ญ. With -mpacked-stack, register save slots get densely packed at the top of the register save area ๐Ÿฑ. Unused space gets reused for other things, which is way more efficient with the stack space ๐Ÿง . 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 ๐Ÿซถ. Heads up though, some non-FSF releases of GCC 2.95 for S/390 or zSeries generated code that uses the stack frame backchain at run time, not just for debugging ๐Ÿ˜ฌ. That code isn't call-compatible with code compiled with -mpacked-stack ๐Ÿ™…โ€โ™€๏ธ. Also, the combination of -mbackchain, -mpacked-stack and -mhard-float is not supported ๐Ÿšซ. For a Linux kernel, use -msoft-float ๐Ÿง.

The default is to not use the packed stack layout ๐ŸŒ™.

  • -msmall-exec, -mno-small-exec โ€” Generate (or don't generate) code that uses the bras instruction for subroutine calls ๐Ÿ“ž. This only works reliably if the total executable size doesn't go over 64k ๐Ÿ“. The default is to use the basr instruction instead, which doesn't have that limit ๐Ÿ’….
  • -m64, -m31 โ€” With -m31, the compiler generates code compliant with the GNU/Linux for S/390 ABI ๐Ÿงฉ. With -m64, it generates code compliant with the GNU/Linux for zSeries ABI ๐ŸŒˆ. This lets GCC generate 64-bit instructions ๐Ÿ’œ. For the s390 targets, the default is -m31, while the s390x targets default to -m64 โœจ.
  • -mzarch, -mesa โ€” With -mzarch, the compiler generates code using the instructions available on z/Architecture ๐Ÿฆ‹. With -mesa, it uses the instructions available on ESA/390 ๐Ÿ›๏ธ. Heads up, -mesa isn't possible with -m64 ๐Ÿ™…โ€โ™€๏ธ. When generating GNU/Linux for S/390 ABI code, the default is -mesa. When generating GNU/Linux for zSeries ABI code, the default is -mzarch ๐Ÿ’–.
  • -mhtm, -mno-htm โ€” The -mhtm option turns on a set of builtins that use instructions from the transactional execution facility, introduced with the IBM zEnterprise EC12 machine generation ๐Ÿง . These are the S/390 System z Built-in Functions ๐Ÿ”ฅ. -mhtm is on by default when you use -march=zEC12 ๐ŸŽ€.
  • -mvx, -mno-vx โ€” With -mvx, the compiler 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 it used ๐Ÿท๏ธ. -mvx is on by default when you use -march=z13 ๐Ÿ‘‘.
  • -mzvector, -mno-zvector โ€” The -mzvector option enables vector language extensions and builtins using instructions from the vector extension facility, introduced with the IBM z13 machine generation ๐Ÿ’ซ. It adds support for vector as a keyword to define vector type variables and arguments ๐Ÿง. Okay, the vector keyword is only available when GNU extensions are enabled ๐Ÿ™ˆ. It won't get expanded if you ask for strict standard compliance, like with -std=c99 ๐Ÿšซ. On top of the GCC low-level builtins, -mzvector turns on 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, it uses an mvc loop instead ๐Ÿ”. This is the default unless you're optimizing for size ๐Ÿ“.
  • -mdebug, -mno-debug โ€” Print (or don't print) extra 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 ๐Ÿ’ป. The 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, and native ๐Ÿ“œ. The default is -march=z900 ๐ŸŒธ. Specifying 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 ๐Ÿคทโ€โ™€๏ธ.
  • -mtune=cpu-type โ€” Tune everything applicable in the generated code to cpu-type, except for the ABI and the set of available instructions ๐ŸŽถ. The list of cpu-type values is the same as for -march ๐Ÿ“‹. The default is the value used for -march ๐Ÿ’œ.
  • -mtpf-trace, -mno-tpf-trace โ€” Generate code that adds (or doesn't add) TPF OS specific branches to trace routines in the operating system ๐Ÿ›ค๏ธ. This option is off by default, even when compiling for the TPF OS ๐Ÿ™ƒ.
  • -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 ๐ŸŽฏ. Those routines 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 specifying -mtpf-trace ๐ŸŒ™.
  • -mfused-madd, -mno-fused-madd โ€” Generate code that uses (or doesn't use) the floating-point multiply and accumulate instructions โœ–๏ธโž•. These instructions are generated by default if hardware floating point is used ๐Ÿ’….
  • -mwarn-framesize=framesize โ€” Emit a warning if the current function exceeds the given frame size ๐Ÿšจ. Because this is a compile-time check, it doesn't have to be a real problem when the program runs ๐Ÿง˜โ€โ™€๏ธ. It's meant to catch functions that most likely cause a stack overflow ๐Ÿ˜ฑ. 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 when the stack size is limited ๐Ÿ’€.
  • -mstack-guard=stack-guard, -mstack-size=stack-size โ€” okay so these two are a debugging duo ๐Ÿ•ต๏ธโ€โ™€๏ธ๐Ÿ’– On S/390, passing them makes the back end sneak extra instructions into the function prologue that trigger a trap if the stack size gets stack-guard bytes above stack-size (remember, the S/390 stack grows downward, so keep that in mind ๐Ÿงš). If you skip stack-guard, GCC picks the smallest power of 2 that's larger than the frame size of the compiled function. These are meant for chasing stack overflow problems, but the extra code adds only little overhead, so it can even run on production-like systems without greater performance degradation โœจ Just know the values have to be exact powers of 2, stack-size has to be greater than stack-guard without going over 64k, and the extra code assumes the stack starts at an address aligned to the value of stack-size. Also, stack-guard can only be used together with stack-size ๐ŸŽ€
  • -mhotpatch=pre-halfwords,post-halfwords โ€” this one is giving "hot-patching" vibes ๐Ÿ”ฅ When it's enabled, every function in the compilation unit gets a hot-patching prologue. The function label gets prepended with pre-halfwords two-byte NOP instructions (max 1000000), and after the label, 2 * post-halfwords bytes get tacked on using the largest NOP-like instructions the architecture allows (max 1000000). If both arguments are zero, hotpatching is disabled ๐Ÿ™ˆ And you can override it for individual functions with the hotpatch attribute ๐Ÿ’…

โœจ Score Options โœจ

These options are defined for Score implementations, bestie ๐ŸŒธ

  • -meb โ€” compile for big-endian mode. This is the default ๐Ÿ’œ
  • -mel โ€” compile for little-endian mode ๐Ÿงš
  • -mnhwloop โ€” disable generation of bcnz instructions ๐Ÿ’€
  • -muls โ€” enable generation of unaligned load and store instructions ๐Ÿฆ‹
  • -mmac โ€” enable multiply-accumulate instructions. Disabled by default, so you have to ask for it ๐Ÿ’…
  • -mscore5 โ€” target the SCORE5 architecture ๐ŸŒˆ
  • -mscore5u โ€” target the SCORE5U architecture ๐ŸŒˆ
  • -mscore7 โ€” target the SCORE7 architecture. This is the default ๐Ÿ‘‘
  • -mscore7d โ€” target the SCORE7D architecture ๐Ÿ“

๐Ÿฆ‹ SH Options ๐Ÿฆ‹

These -m options are defined for the SH implementations, and they are a whole vibe ๐Ÿ˜ญ

  • -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 an SH2a-FPU in a way that the floating-point unit is not used ๐Ÿซถ
  • -m2a-single-only โ€” generate code for the SH2a-FPU so 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 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 so that no double-precision floating-point operations are used ๐Ÿ’–
  • -m4-200 โ€” generate code for SH4-200 ๐ŸŒˆ
  • -m4-200-nofpu โ€” generate code for SH4-200 in a way that the floating-point unit is not used ๐Ÿซถ
  • -m4-200-single โ€” generate code for SH4-200, assuming the floating-point unit is in single-precision mode by default ๐Ÿ’–
  • -m4-200-single-only โ€” generate code for SH4-200 so that no double-precision floating-point operations are used ๐Ÿ’–
  • -m4-300 โ€” generate code for SH4-300 ๐ŸŒˆ
  • -m4-300-nofpu โ€” generate code for SH4-300 in a way that the floating-point unit is not used ๐Ÿซถ
  • -m4-300-single โ€” generate code for SH4-300 so that no double-precision floating-point operations are used ๐Ÿ’–
  • -m4-300-single-only โ€” generate code for SH4-300 so that no double-precision floating-point operations are used ๐Ÿ’–
  • -m4-340 โ€” generate code for SH4-340 (no MMU, no FPU) ๐Ÿงš
  • -m4-500 โ€” generate code for SH4-500 (no FPU). It passes -isa=sh4-nofpu to the assembler ๐Ÿ“
  • -m4a-nofpu โ€” generate code for the SH4al-dsp, or for an SH4a in a way that the floating-point unit is not used ๐Ÿซถ
  • -m4a-single-only โ€” generate code for the SH4a so that no double-precision floating-point operations are used ๐Ÿ’–
  • -m4a-single โ€” generate code for the SH4a, assuming the floating-point unit is in single-precision mode by default ๐Ÿ’–
  • -m4a โ€” generate code for the SH4a โœจ
  • -m4al โ€” same as -m4a-nofpu, except it implicitly passes -dsp to the assembler. GCC doesn't generate any DSP instructions at the moment, so it's just vibes for now ๐Ÿ™ˆ
  • -mb โ€” compile for the processor in big-endian mode ๐Ÿ’œ
  • -ml โ€” compile for the processor in little-endian mode ๐Ÿ’œ
  • -mdalign โ€” align doubles at 64-bit boundaries ๐Ÿ“
Heads up, bestie: -mdalign changes the calling conventions, so some functions from the standard C library won't work unless you recompile them first with -mdalign ๐Ÿ˜ญ
  • -mrelax โ€” shorten some address references at link time, when possible. It uses the linker option -relax ๐Ÿฆ‹
  • -mbigtable โ€” use 32-bit offsets in switch tables. The default is 16-bit offsets ๐ŸŒธ
  • -mbitops โ€” enable bit manipulation instructions on SH2A ๐Ÿ’…
  • -mfmovd โ€” enable the fmovd instruction. Check -mdalign for alignment constraints ๐ŸŽ€
  • -mrenesas โ€” comply with the calling conventions defined by Renesas ๐Ÿ‘‘
  • -mno-renesas โ€” comply with the calling conventions GCC used before the Renesas conventions were available. This is the default for all targets of the SH toolchain ๐Ÿ‘‘
  • -mnomacsave โ€” mark the MAC register as call-clobbered, even if -mrenesas is given ๐ŸŒˆ
  • -mieee, -mno-ieee โ€” control the IEEE compliance of floating-point comparisons, which affects how unordered comparison results get handled ๐Ÿง  By default, -mieee is implicitly enabled. If -ffinite-math-only is enabled, -mno-ieee is implicitly set, which makes floating-point greater-equal and less-equal comparisons faster โšก You can override either implicit setting by specifying -mieee or -mno-ieee yourself ๐Ÿ’…
  • -minline-ic_invalidate โ€” inline code that invalidates instruction cache entries after setting up nested function trampolines ๐Ÿงš This has no effect if -musermode is in effect and your selected code generation option (like -m4) doesn't allow the icbi instruction. If the selected option doesn't allow icbi and -musermode isn't in effect, the inlined code pokes the instruction cache address array directly with an associative write. That means it needs privileged mode at run time, and it fails if the cache line was mapped via the TLB and has become unmapped ๐Ÿ˜ญ
This one is a little spicy: it needs privileged mode at run time, and it fails if the cache line was mapped via the TLB and has since become unmapped ๐Ÿ’€
  • -misize โ€” dump instruction size and location in the assembly code ๐Ÿ”
  • -mpadstruct โ€” this option is deprecated ๐Ÿ’€ It pads structures to a multiple of 4 bytes, which is incompatible with the SH ABI
Deprecated alert: -mpadstruct is on its way out, and it's incompatible with the SH ABI, so maybe leave it alone ๐Ÿ™ˆ
  • -matomic-model=model โ€” sets the model of atomic operations, plus any additional parameters, as a comma-separated list. For details on the atomic built-in functions, see __atomic Builtins ๐Ÿซถ These are the models and parameters that are supported:
    • none โ€” disable compiler-generated atomic sequences and emit library calls for atomic operations instead. This is the default if the target is not sh*-*-linux* ๐Ÿ’œ
    • soft-gusa โ€” generate GNU/Linux compatible gUSA software atomic sequences for the atomic built-in functions. These sequences need extra support from the system's interrupt/exception handling code and are only suitable for single-core SH3* and SH4* systems. This 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 the code more efficient, unless strict is specified โœจ
    • soft-tcb โ€” generate software atomic sequences that use a variable in the thread control block. This is a variation of the gUSA sequences that can also be used on SH1* and SH2* targets. It needs extra support from the interrupt/exception handling code and is only suitable for single-core systems. When using this model, the gbr-offset= parameter has to be specified as well ๐Ÿงš
    • soft-imask โ€” generate software atomic sequences that temporarily disable interrupts by setting SR.IMASK = 1111. This model only works when the program runs in privileged mode and is only suitable for single-core systems. It doesn't require extra 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 โ€” generate hardware atomic sequences using only the movli.l and movco.l instructions. This is only available on SH4A and is suitable for multi-core systems. Since the hardware instructions only support 32-bit atomic variable access, 8-bit and 16-bit variables are 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 require extra support from the interrupt/exception handling code ๐ŸŒˆ
  • gbr-offset= โ€” okay so this one sets the byte offset of the variable inside the thread control block structure that the generated atomic sequences should use, but only when the soft-tcb model is selected ๐Ÿงš For any other model it gets ignored, so no stress ๐Ÿ’… The value has to be an integer multiple of 4 and fall in the range 0-1020 ๐ŸŽ€
  • strict โ€” this one is lowkey strict in the best way ๐Ÿซถ It stops you from mixing multiple atomic models, even when they're compatible, and makes the compiler generate atomic sequences of the specified model only ๐Ÿ”ฅ
  • -mtas โ€” this makes the compiler generate the tas.b opcode for __atomic_test_and_set ๐Ÿ’œ ngl it can drag your overall performance because of the operand cache line flushes that tas.b implies, depending on your hardware and software setup ๐Ÿ˜ญ On multi-core SH4A processors, tas.b needs to be handled with caution, since it can cause data corruption with certain cache configurations ๐Ÿ’€
Bestie, tas.b on multi-core SH4A can corrupt your data for certain cache configs. Be careful ๐Ÿ™ˆ
  • -mprefergot โ€” when you're generating position-independent code, this emits function calls through the Global Offset Table instead of the Procedure Linkage Table ๐Ÿฆ‹
  • -musermode, -mno-usermode โ€” this one is about whether the compiler is allowed to generate privileged mode code ๐Ÿ‘‘ -musermode says don't allow it, and -mno-usermode says go ahead and allow it โœจ Using -musermode also implies -mno-inline-ic_invalidate if the inlined code wouldn't work in user mode ๐ŸŒธ -musermode is the default when the target is sh*-*-linux* ๐ŸŒˆ If the target is SH1* or SH2*, -musermode has no effect, since there's no user mode there ๐Ÿ™ˆ
  • -multcost=number โ€” sets the cost the compiler assumes for a multiply insn ๐Ÿ”ฅ
  • -mdiv=strategy โ€” picks the division strategy 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 do the operation ๐Ÿงš Dividing by zero gives an unspecified result and doesn't trap ๐Ÿ™ˆ This is the default except for SH4, SH2A, and SHcompact ๐Ÿ’–
    • call-fp โ€” calls a library function that does the operation in double precision floating point ๐Ÿฆ‹ Dividing by zero causes a floating-point exception ๐Ÿ’€ This is the default for SHcompact with FPU ๐Ÿ‘‘ If you specify this for targets without a double precision FPU, it 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 ๐ŸŒธ Dividing by zero gives an unspecified result and doesn't trap ๐Ÿ’œ This is the default for SH4 โœจ If you specify this for targets without dynamic shift instructions, it defaults to call-div1 ๐ŸŽ€

Oh, and if you don't specify a division strategy, the compiler picks the default based on the current target ๐Ÿ“ For SH2A, the default is to use the divs and divu instructions instead of library function calls ๐Ÿ”ฅ

  • -maccumulate-outgoing-args โ€” reserves space once for outgoing arguments in the function prologue, instead of around each call ๐Ÿงš This is generally beneficial for performance and size ๐Ÿ“ˆ It's also needed for unwinding, so the stack frame doesn't get changed around conditional code ๐Ÿซถ
  • -mdivsi3_libfunc=name โ€” sets the name of the library function used for 32-bit signed division to name ๐ŸŒˆ It only affects the name used in the call division strategies, and the compiler still expects the same sets of input, output, and clobbered registers as if this option weren't there ๐Ÿ’…
  • -mfixed-range=register-range โ€” makes the compiler treat the given register range as fixed registers ๐Ÿ”’ A fixed register is one the register allocator can't use, which is super useful when you're compiling kernel code ๐Ÿ‘‘ A register range is written as two registers separated by a dash, and you can specify multiple ranges separated by a comma ๐ŸŽ€
  • -mbranch-cost=num โ€” assumes num is the cost for a branch instruction ๐Ÿฆ‹ Higher numbers make the compiler try to generate more branch-free code when it can ๐Ÿ’– If you don't specify it, the value is picked based on the processor type you're compiling for โœจ
  • -mzdcbranch, -mno-zdcbranch โ€” this is about whether zero displacement conditional branch instructions bt and bf are fast ๐Ÿš€ With -mzdcbranch, the compiler prefers zero displacement branch code sequences ๐Ÿ’œ It's enabled by default when generating code for SH4 and SH4A, and you can explicitly turn it off with -mno-zdcbranch ๐Ÿ™ˆ
  • -mcbranch-force-delay-slot โ€” forces the use of delay slots for conditional branches, which fills the delay slot with a nop if a suitable instruction can't be found ๐Ÿซ  This is disabled by default ๐ŸŒธ You can enable it to work around hardware bugs found in the original SH7055 ๐Ÿ› ๏ธ
  • -mfused-madd, -mno-fused-madd โ€” generate code that does (or doesn't) use the floating-point multiply and accumulate instructions ๐Ÿ“ 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 ๐Ÿงš
  • -mfsca, -mno-fsca โ€” lets you allow or disallow the compiler from emitting the fsca instruction for sine and cosine approximations ๐ŸŒˆ The option -mfsca must be used in combination with -funsafe-math-optimizations ๐Ÿซถ It's enabled by default when generating code for SH4A ๐Ÿ’– Using -mno-fsca disables sine and cosine approximations even if -funsafe-math-optimizations is in effect ๐Ÿ™…โ€โ™€๏ธ
  • -mfsrra, -mno-fsrra โ€” lets you allow or disallow the compiler from emitting the fsrra instruction for reciprocal square root approximations โœจ The option -mfsrra must be used in combination with -funsafe-math-optimizations and -ffinite-math-only ๐Ÿ’… It's enabled by default when generating code for SH4A ๐Ÿฆ‹ Using -mno-fsrra disables reciprocal square root approximations even if -funsafe-math-optimizations and -ffinite-math-only are in effect ๐Ÿ™ˆ
  • -mpretend-cmove โ€” prefers zero-displacement conditional branches for conditional move instruction patterns ๐Ÿš€ This can result in faster code on the SH4 processor ๐Ÿ’œ
  • -mfdpic โ€” generates code using the FDPIC ABI ๐Ÿ‘‘

๐ŸŒธ Solaris 2 Options ๐ŸŒธ

These -m options are supported on Solaris 2 ๐Ÿฆ‹

  • -mclear-hwcap โ€” tells the compiler to remove the hardware capabilities generated by the Solaris assembler ๐Ÿงš This is only necessary when object files use ISA extensions the current machine doesn't support, but check at runtime whether or not to use them ๐Ÿซถ
  • -mimpure-text โ€” used in addition to -shared, this tells the compiler to not pass -z text to the linker when linking a shared object ๐Ÿ’– With this option, you can link position-dependent code into a shared object โœจ

-mimpure-text suppresses the "relocations remain against allocatable but non-writable sections" linker error message ๐Ÿ™ˆ However, the necessary relocations trigger copy-on-write, and the shared object is not actually shared across processes ๐Ÿ’€ Instead of using -mimpure-text, you should compile all source code with -fpic or -fPIC ๐Ÿ”ฅ

These switches are supported in addition to the above on Solaris 2 ๐ŸŒˆ

  • -pthreads โ€” this is a synonym for -pthread ๐Ÿ’…

๐ŸŒˆ SPARC Options ๐ŸŒˆ

These -m options are supported on the SPARC ๐Ÿ“

  • -mno-app-regs, -mapp-regs โ€” specify -mapp-regs to generate output using the global registers 2 through 4, which the SPARC SVR4 ABI reserves for applications ๐Ÿ’œ Like global register 1, each of global registers 2 through 4 is then treated as an allocable register that gets clobbered by function calls ๐Ÿงš This is the default ๐ŸŒธ

To be fully SVR4 ABI-compliant (with some performance loss), specify -mno-app-regs ๐Ÿซถ You should compile libraries and system software with this option ๐Ÿ”ฅ

  • -mflat, -mno-flat โ€” with -mflat, the compiler doesn't generate save/restore instructions and uses a "flat" or single register window model ๐Ÿฆ‹ This model is compatible with the regular register window model ๐Ÿ’– The local registers and the input registers (0--5) are still treated as "call-saved" registers and get saved on the stack as needed โœจ

With -mno-flat (the default), the compiler generates save/restore instructions, except for leaf functions ๐Ÿ’… This is the normal operating mode ๐Ÿ‘‘

  • -mfpu, -mhard-float โ€” generates output containing floating-point instructions ๐Ÿš€ This is the default ๐Ÿ’œ
  • -mno-fpu, -msoft-float โ€” generates output containing library calls for floating point ๐Ÿ™ˆ
Warning: the requisite libraries aren't available for all SPARC targets ๐Ÿ˜ญ Normally the facilities of the machine's usual C compiler are used, but this can't be done directly in cross-compilation ๐Ÿ’€ You 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 all of a program with this option ๐Ÿซถ In particular, you need to compile libgcc.a, the library that comes with GCC, with -msoft-float for this to work ๐Ÿ”ฅ

  • -mhard-quad-float โ€” generates output containing quad-word (long double) floating-point instructions ๐Ÿฆ‹
  • -msoft-quad-float โ€” generates output containing library calls for quad-word (long double) floating-point instructions ๐Ÿงš The functions called are the ones specified in the SPARC ABI ๐Ÿ’– This is the default โœจ

As of this writing, there are no SPARC implementations with hardware support for the quad-word floating-point instructions ๐Ÿ˜ญ They all invoke a trap handler for one of these instructions, and then the trap handler emulates the effect of the instruction ๐Ÿ’€ Because of that trap handler overhead, this is much slower than calling the ABI library routines ๐Ÿ™ˆ Thus, the -msoft-quad-float option is the default ๐Ÿ‘‘

  • -mno-unaligned-doubles, -munaligned-doubles โ€” assumes that doubles have 8-byte alignment ๐ŸŒธ This is the default ๐Ÿ’…

-munaligned-doubles keeps doubles at 8-byte alignment only when they're tucked inside another type or have an absolute address. Otherwise, GCC gives them 4-byte alignment ๐ŸŒธ This dodges some rare compatibility drama with code from other compilers, but it's not the default because it costs performance, especially in floating-point code ๐Ÿ˜ญ

  • -muser-mode, -mno-user-mode โ€” Okay so -muser-mode means no code that can only run in supervisor mode gets generated ๐Ÿ™ˆ This only matters for the casa instruction emitted for the LEON3 processor. This is the default ๐Ÿ’–
  • -mfaster-structs, -mno-faster-structs โ€” With -mfaster-structs, GCC assumes structures should have 8-byte alignment โœจ That lets structure assignment copies use pairs of ldd and std instructions instead of twice as many ld and st pairs ๐Ÿ”ฅ
โš ๏ธ Big warning, bestie: this changed alignment directly violates the SPARC ABI ๐Ÿ’€ So it's only for targets where the developer knows and accepts that the code isn't fully in line with the ABI rules.
  • -mstd-struct-return, -mno-std-struct-return โ€” With -mstd-struct-return, GCC adds checking code to functions that return structures or unions ๐Ÿ‘‘ It catches size mismatches between the two sides of a function call, as per the 32-bit ABI.

The default is -mno-std-struct-return. This option has no effect in 64-bit mode ๐Ÿ™ƒ

  • -mlra, -mno-lra โ€” Turns on Local Register Allocation ๐Ÿงš This has been the default for SPARC since GCC 7, so if you want the old Reload, you gotta pass -mno-lra ๐Ÿซถ
  • -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 picks the best architecture option for the host processor โœจ -mcpu=native has no effect if GCC doesn't recognize the processor ๐Ÿคท

Default instruction scheduling parameters are used for values that pick an architecture instead of a specific implementation. Those are v7, v8, sparclite, sparclet and v9 ๐ŸŽ€

Here's the lowdown on each architecture and the chips it covers ๐Ÿ”

  • 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 also optimizes for the Cypress CY7C602 chip, as used in the SPARCStation/SPARCServer 3xx series. It's also a good fit for the older SPARCStation 1, 2, IPX etc. ๐Ÿ“

With -mcpu=v8, GCC generates code for the V8 variant of the SPARC architecture ๐Ÿ’œ The only difference from V7 code is that the compiler emits the integer multiply and integer divide instructions that exist in SPARC-V8 but not in SPARC-V7. With -mcpu=supersparc, the compiler also optimizes for the SuperSPARC chip, as used in the SPARCStation 10, 1000 and 2000 series ๐Ÿ‘‘

With -mcpu=sparclite, GCC generates code for the SPARClite variant of the SPARC architecture ๐Ÿ”ฅ This adds the integer multiply, integer divide step and scan (ffs) instructions that exist in SPARClite but not in SPARC-V7. With -mcpu=f930, the compiler also optimizes for the Fujitsu MB86930 chip, which is the original SPARClite with no FPU. With -mcpu=f934, it optimizes for the Fujitsu MB86934 chip, the more recent SPARClite with an FPU ๐Ÿ’–

With -mcpu=sparclet, GCC generates code for the SPARClet variant of the SPARC architecture ๐ŸŒธ This adds the integer multiply, multiply/accumulate, integer divide step and scan (ffs) instructions that exist in SPARClet but not in SPARC-V7. With -mcpu=tsc701, the compiler also optimizes for the TEMIC SPARClet chip ๐Ÿงš

With -mcpu=v9, GCC generates code for the V9 variant of the SPARC architecture ๐ŸŒˆ This adds 64-bit integer and floating-point move instructions, 3 additional floating-point condition code registers and conditional move instructions. With -mcpu=ultrasparc, the compiler also optimizes for the Sun UltraSPARC I/II/IIi chips. With -mcpu=ultrasparc3, it optimizes for the Sun UltraSPARC III/III+/IIIi/IIIi+/IV/IV+ chips ๐Ÿ’… With -mcpu=niagara, it optimizes for Sun UltraSPARC T1 chips. With -mcpu=niagara2, it optimizes for Sun UltraSPARC T2 chips. With -mcpu=niagara3, it optimizes for Sun UltraSPARC T3 chips. With -mcpu=niagara4, it optimizes for Sun UltraSPARC T4 chips ๐ŸŽ€ With -mcpu=niagara7, it optimizes for Oracle SPARC M7 chips. With -mcpu=m8, it optimizes for Oracle M8 chips โญ

  • -mtune=cpu_type โ€” Sets the instruction scheduling parameters for machine type cpu_type, but unlike -mcpu=cpu_type, it does not touch the instruction set or register set ๐Ÿซถ

The same values for -mcpu=cpu_type work for -mtune=cpu_type, but the only useful ones are those that pick a particular CPU implementation. Those are 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, native can also be used โœจ

  • -mv8plus, -mno-v8plus โ€” With -mv8plus, GCC generates code for the SPARC-V8+ ABI ๐Ÿฆ‹ The difference from the V8 ABI is that the global and out registers are considered 64 bits wide. This is enabled by default on Solaris in 32-bit mode for all SPARC-V9 processors ๐Ÿ’œ
  • -mvis, -mno-vis โ€” With -mvis, GCC generates code that takes advantage of the UltraSPARC Visual Instruction Set extensions ๐ŸŒธ The default is -mno-vis ๐Ÿ™ˆ
  • -mvis2, -mno-vis2 โ€” With -mvis2, GCC generates code that takes advantage of version 2.0 of the UltraSPARC Visual Instruction Set extensions ๐Ÿ”ฅ The default is -mvis2 when targeting a CPU that supports such instructions, like UltraSPARC-III and later. Setting -mvis2 also sets -mvis โœจ
  • -mvis3, -mno-vis3 โ€” With -mvis3, GCC generates code that takes advantage of version 3.0 of the UltraSPARC Visual Instruction Set extensions ๐Ÿงš The default is -mvis3 when targeting a CPU that supports such instructions, like niagara-3 and later. Setting -mvis3 also sets -mvis2 and -mvis ๐Ÿ‘‘
  • -mvis4, -mno-vis4 โ€” With -mvis4, GCC generates code that takes advantage of version 4.0 of the UltraSPARC Visual Instruction Set extensions ๐Ÿ’– The default is -mvis4 when targeting a CPU that supports such instructions, like niagara-7 and later. Setting -mvis4 also sets -mvis3, -mvis2 and -mvis ๐ŸŒˆ
  • -mvis4b, -mno-vis4b โ€” With -mvis4b, GCC generates code that takes advantage of version 4.0 of the UltraSPARC Visual Instruction Set extensions, plus the extra VIS instructions introduced in the Oracle SPARC Architecture 2017 ๐ŸŽ€ The default is -mvis4b when targeting a CPU that supports such instructions, like m8 and later. Setting -mvis4b also sets -mvis4, -mvis3, -mvis2 and -mvis ๐Ÿซถ
  • -mcbcond, -mno-cbcond โ€” With -mcbcond, GCC generates code that takes advantage of the UltraSPARC Compare-and-Branch-on-Condition instructions ๐Ÿ“ The default is -mcbcond when targeting a CPU that supports such instructions, like Niagara-4 and later โœจ
  • -mfmaf, -mno-fmaf โ€” With -mfmaf, GCC generates code that takes advantage of the UltraSPARC Fused Multiply-Add Floating-point instructions ๐Ÿ”ฅ The default is -mfmaf when targeting a CPU that supports such instructions, like Niagara-3 and later ๐Ÿ’…
  • -mfsmuld, -mno-fsmuld โ€” With -mfsmuld, GCC generates code that takes advantage of the Floating-point Multiply Single to Double (FsMULd) instruction ๐Ÿฆ‹ The default is -mfsmuld when targeting a CPU that supports the architecture versions V8 or V9 with an FPU, except -mcpu=leon ๐Ÿ™ƒ
  • -mpopc, -mno-popc โ€” With -mpopc, GCC generates code that takes advantage of the UltraSPARC Population Count instruction ๐ŸŒธ The default is -mpopc when targeting a CPU that supports such an instruction, like Niagara-2 and later ๐Ÿ’œ
  • -msubxc, -mno-subxc โ€” With -msubxc, GCC generates code that takes advantage of the UltraSPARC Subtract-Extended-with-Carry instruction ๐Ÿงš The default is -msubxc when targeting a CPU that supports such an instruction, like Niagara-7 and later ๐Ÿ‘‘
  • -mfix-at697f โ€” Enables the documented workaround for the single erratum of the Atmel AT697F processor (which is erratum #13 of the AT697E processor) ๐Ÿ”ง
  • -mfix-ut699 โ€” Enables the documented workarounds for the floating-point errata and the data cache nullify errata of the UT699 processor ๐Ÿ› ๏ธ
  • -mfix-ut700 โ€” Enables the documented workaround for the back-to-back store errata of the UT699E/UT700 processor ๐Ÿฉน
  • -mfix-gr712rc โ€” Enables the documented workaround for the back-to-back store errata of the GR712RC processor ๐ŸŒท

On SPARC-V9 processors in 64-bit environments, you also get these -m options ๐ŸŒˆโœจ

  • -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 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! You get 64-bit addresses, and programs can be linked literally anywhere in memory. The catch: the text and data segments must each be under 2GB, and the data segment has to sit within 2GB of the text segment. ๐Ÿซถ
  • embmedany โ€” โœจ The embedded version of Medium/Anywhere, for embedded systems. You still get 64-bit addresses and text and data segments under 2GB each, but both can start anywhere in memory, and that gets sorted out 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 โ€” ๐Ÿง  Pick the memory model for the processor from one of these:
    • default โ€” the default memory model for the processor and operating system, no drama.
    • 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're set in the processor's PSTATE.MM field. Very academic, very iconic. ๐Ÿ“š

  • -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. You have to add that back whenever you make stack frame references. This is the default in 64-bit mode. Otherwise, GCC assumes there's no offset at all.

๐ŸŽ€ Options for System V ๐ŸŽ€

These additional options are available on System V Release 4 so they play nice with other compilers on those systems: ๐Ÿฆ‹

  • -G โ€” Creates a shared object. It's recommended to use -symbolic or -shared instead, bestie.
  • -Qy โ€” Identifies the version of each tool the compiler used, and drops them into a .ident assembler directive in the output. ๐Ÿ”
  • -Qn โ€” Refrains from adding .ident directives to the output file. This is the default, so you're already good. ๐Ÿ’…
  • -YP,dirs โ€” Searches the directories dirs, and no others, for libraries specified with -l. Strict guest list energy. ๐Ÿšช
  • -Ym,dir โ€” Looks in the directory dir to find the M4 preprocessor. The assembler uses this one. ๐Ÿงฉ

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

These -m options are supported on the TILE-Gx: ๐Ÿ’œ

  • -mcmodel=small โ€” Generates code for the small model. Direct calls can only reach 500M in either direction. PC-relative addresses are 32 bits, but absolute addresses support the full address range. โœจ
  • -mcmodel=large โ€” Generates code for the large model. No limits on call distance, PC-relative addresses, or absolute addresses. Main character energy. ๐Ÿ‘‘
  • -mcpu=name โ€” Selects the CPU type to target. Right now the only supported type is tilegx. ๐ŸŽฏ
  • -m32, -m64 โ€” Generates code for a 32-bit or 64-bit environment. The 32-bit environment sets int, long, and pointer to 32 bits. The 64-bit environment sets int to 32 bits, and long and pointer to 64 bits. ๐Ÿ“
  • -mbig-endian, -mlittle-endian โ€” Generates code in big or little endian mode, respectively. ๐ŸŒธ

๐Ÿฆ‹ TILEPro Options ๐Ÿฆ‹

These -m options are supported on the TILEPro: ๐ŸŽ€

  • -mcpu=name โ€” Selects the CPU type 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 behaviour, so the flag is basically ignored. Lowkey a little extra, but it's fine. ๐Ÿ™ˆ

๐Ÿ”ฅ V850 Options ๐Ÿ”ฅ

These -m options are defined for V850 implementations: ๐Ÿ’…

  • -mlong-calls, -mno-long-calls โ€” Treats all calls as being far away (or near, for the -mno- version). If calls are assumed to be far away, the compiler always loads the function's address into a register and calls indirectly through that pointer. ๐Ÿ“ž
  • -mno-ep, -mep โ€” Doesn't optimize (or does optimize) basic blocks that use the same index pointer 4 or more times to copy the pointer into the ep register, and then uses the shorter sld and sst instructions. The -mep option is on by default if you optimize. โšก
  • -mno-prolog-function, -mprolog-function โ€” Doesn't use (or does use) external functions to save and restore registers in the prologue and epilogue of a function. Those external functions are slower, but they take up less code space if more than one function saves the same number of registers. The -mprolog-function option is on by default if you optimize. ๐Ÿง 
  • -mspace โ€” Tries to make the code as small as possible. Right now, this just turns on -mep and -mprolog-function. ๐Ÿค
  • -mtda=n โ€” Puts static or global variables whose size is n bytes or less into the tiny data area that the ep register points to. The tiny data area can hold up to 256 bytes in total, with 128 bytes for byte references. ๐Ÿฃ
  • -msda=n โ€” Puts static or global variables whose size is n bytes or less into the small data area that the gp register points to. The small data area can hold up to 64 kilobytes. ๐ŸŒท
  • -mzda=n โ€” Puts static or global variables whose size is n bytes or less into the first 32 kilobytes of memory. ๐Ÿงธ
  • -mv850 โ€” Says the target processor is the V850. ๐ŸŽฏ
  • -mv850e3v5 โ€” Says the target processor is the V850E3V5. The preprocessor constant __v850e3v5__ is defined if you use this option. ๐Ÿ’œ
  • -mv850e2v4 โ€” Says the target processor is the V850E3V5. This is an alias for -mv850e3v5, so it's the exact same vibe. ๐Ÿ”
  • -mv850e2v3 โ€” Says the target processor is the V850E2V3. The preprocessor constant __v850e2v3__ is defined if you use this option. ๐Ÿฆ„
  • -mv850e2 โ€” Says the target processor is the V850E2. The preprocessor constant __v850e2__ is defined if you use this option. ๐ŸŒŸ
  • -mv850e1 โ€” Says the target processor is the V850E1. The preprocessor constants __v850e1__ and __v850e__ are defined if you use this option. โœจ
  • -mv850es โ€” Says the target processor is the V850ES. This is an alias for -mv850e1. ๐Ÿ”
  • -mv850e โ€” Says the target processor is the V850E. The preprocessor constant __v850e__ is defined if you use this option. ๐Ÿ’–

If none of -mv850, -mv850e, -mv850e1, -mv850e2, -mv850e2v3, or -mv850e3v5 are defined, then a default target processor gets chosen, and the matching __v850*__ preprocessor constant is defined. ๐Ÿคทโ€โ™€๏ธ

The preprocessor constants __v850 and __v851__ are always defined, no matter which processor variant you're targeting. ๐Ÿซถ

  • -mdisable-callt, -mno-disable-callt โ€” Suppresses generation of the CALLT instruction for the v850e, v850e1, v850e2, v850e2v3, and v850e3v5 flavours of the v850 architecture. This option is 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, then the C preprocessor symbol __V850_CALLT__ is 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 option only matters when the target architecture is V850E2V3 or higher. If hardware floating point instructions are being generated, then the C preprocessor symbol __FPU_OK__ is defined. Otherwise, the symbol __NO_FPU__ is defined. ๐Ÿ”ข
  • -mloop โ€” Enables the use of the e3v5 LOOP instruction. This instruction isn't 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, these 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__ is defined. ๐ŸŒˆ

  • -mgcc-abi โ€” Enables support for the old GCC version of the V850 ABI. With this version, these rules apply:
    • Integer sized structures and unions are returned in register r10.
    • Large structures and unions (more than 8 bytes in size) are passed by reference.
    • Functions are aligned to 32-bit boundaries, unless you're optimizing for size.
    • The -m8byte-align command-line option is not supported.
    • The -mdisable-callt command-line option is supported, but it's not enabled by default.

When this version of the ABI is enabled, the C preprocessor symbol __V850_GCC_ABI__ is defined. ๐Ÿ•ฐ๏ธ

  • -m8byte-align, -mno-8byte-align โ€” Enables 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__ is defined. ๐Ÿ“
  • -mbig-switch โ€” Generates code suitable for big switch tables. Only use this option if the assembler or linker complains about out of range branches within a switch table. ๐Ÿšจ
  • -mapp-regs โ€” Causes r2 and r5 to be used in the code the compiler generates. This setting is the default. ๐ŸŽจ
  • -mno-app-regs โ€” Causes r2 and r5 to be treated as fixed registers. ๐Ÿงฑ

๐ŸŒธ VAX Options ๐ŸŒธ

These -m options are defined for the VAX: ๐Ÿผ

  • -munix โ€” Doesn't output certain jump instructions (like aobleq and so on) that the Unix assembler for the VAX can't handle across long ranges. ๐Ÿšซ
  • -mgnu โ€” Does output those jump instructions, on the assumption that the GNU assembler is being used. ๐Ÿƒ
  • -mg โ€” Outputs code for G-format floating-point numbers instead of D-format. ๐Ÿ”ข
  • -mlra, -mno-lra โ€” Enables Local Register Allocation. This is still experimental for the VAX, so by default the compiler uses standard reload. ๐Ÿงช

๐Ÿฆ„ 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. Run the program on the target under the control of the GDB remote debugging stub. ๐Ÿ›๐Ÿ’–

-msim ๐Ÿ’… A program that does file I/O and is meant to run on the simulator should be linked with option. ๐Ÿ™ˆ The page never names the option here, so just know it's the one that pulls in libc.a and libsim.a. โœจ

  • -mfpu, -mhard-float โ€” ๐Ÿ’– Generates code with floating-point instructions. This is the default. ๐ŸŒธ
  • -mno-fpu, -msoft-float โ€” ๐ŸŽ€ Generates code that uses library calls for floating-point instead.
โš ๏ธ -msoft-float changes the calling convention in the output file, so it's only useful if you compile your whole program with it. ๐Ÿ˜ญ You also need to build libgcc.a (the library that ships with GCC) with -msoft-float for this to work.
  • -mcpu=cpu_type โ€” ๐Ÿฆ‹ Sets the instruction set, register set, and instruction scheduling parameters for the machine type cpu_type. The supported values are mcm, gr5, and gr6.

mcm is just a synonym for gr5, kept around for backward compatibility. ๐Ÿซถ

By default (unless it's configured otherwise), GCC generates code for the GR5 variant of the Visium architecture. โœจ

With -mcpu=gr6, GCC generates code for the GR6 variant. The only difference from GR5 code is that the compiler will generate block move instructions. ๐Ÿ”ฅ

  • -mtune=cpu_type โ€” ๐Ÿงš Sets the instruction scheduling parameters for the machine type cpu_type, but doesn't touch the instruction set or register set the way -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". By default it returns POSIX-style condition (e.g. error) codes instead. ๐ŸŒˆ
  • -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. The valid values 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. ๐Ÿ™ƒ That last 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 instead of 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 it's 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 you picked. ๐Ÿ˜ญ Specifying -march=cpu-type implies -mtune=cpu-type, except where noted otherwise. ๐ŸŒˆ

The choices for cpu-type are:

  • native โ€” โœจ Selects the CPU to generate code for at compile time by figuring out the processor type of the machine doing the compiling. Using -march=native enables all instruction subsets supported by the local machine, so the result might not run on different machines. ๐Ÿ™ˆ Using -mtune=native produces code optimized for the local machine under the constraints of the selected instruction set. ๐Ÿ’–
  • x86-64 โ€” ๐ŸŽ€ A generic CPU with 64-bit extensions. ๐ŸŒธ
  • x86-64-v2, x86-64-v3, x86-64-v4 โ€” ๐Ÿงš These choices select the matching micro-architecture level from the x86-64 psABI. 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 cpu-type values don't have a corresponding -mtune setting, using -march with them enables 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. ๐Ÿ“
  • i486 โ€” ๐ŸŒท The Intel i486 CPU. (No scheduling is implemented for this chip. ๐Ÿ™ˆ)
  • i586, pentium โ€” ๐Ÿ’œ The Intel Pentium CPU with no MMX support. ๐Ÿ’…
  • lakemont โ€” ๐Ÿ”ฌ The Intel Lakemont MCU, based on the Intel Pentium CPU. โœจ
  • pentium-mmx โ€” ๐ŸŽน The Intel Pentium MMX CPU, based on the Pentium core with MMX instruction set support. ๐ŸŒˆ
  • pentiumpro โ€” ๐Ÿš€ The Intel Pentium Pro CPU. ๐Ÿ‘‘
  • i686 โ€” ๐Ÿ’– When used with -march, the Pentium Pro instruction set is used, so the code runs on all i686 family chips. When used with -mtune, it has the same meaning as generic. ๐Ÿซถ
  • pentium2 โ€” ๐ŸŒธ The Intel Pentium II CPU, based on the Pentium Pro core with MMX instruction set support. ๐ŸŽ€
  • pentium3, pentium3m โ€” ๐Ÿ”ฅ The Intel Pentium III CPU, based on the Pentium Pro core with MMX and SSE instruction set support. โญ
  • pentium-m โ€” ๐Ÿ’ป The Intel Pentium M, a low-power version of the Intel Pentium III CPU with MMX, SSE and SSE2 instruction set support. It's used by Centrino notebooks. ๐Ÿฆ‹
  • pentium4, pentium4m โ€” ๐ŸŒŸ The 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 โ€” โ˜• The Intel Core 2 CPU with 64-bit extensions, MMX, SSE, SSE2, SSE3 and SSSE3 instruction set support. ๐Ÿซถ
  • nehalem โ€” ๐ŸŒˆ The Intel Nehalem CPU with 64-bit extensions, MMX, SSE, SSE2, SSE3, SSSE3, SSE4.1, SSE4.2 and POPCNT instruction set support. ๐Ÿ‘‘
  • westmere โ€” ๐ŸŽ€ The Intel Westmere CPU with 64-bit extensions, MMX, SSE, SSE2, SSE3, SSSE3, SSE4.1, SSE4.2, POPCNT, AES and PCLMUL instruction set support. ๐Ÿ”ฅ
  • sandybridge โ€” ๐ŸŒ… The 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 โ€” ๐ŸŒฟ The 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 โ€” ๐ŸŒธ The 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 โ€” ๐ŸŒท The 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 โ€” ๐ŸŒŠ The 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 โ€” ๐Ÿญ The Intel Bonnell CPU with 64-bit extensions, MOVBE, MMX, SSE, SSE2, SSE3 and SSSE3 instruction set support. ๐Ÿซง
  • silvermont โ€” โ„๏ธ The 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 โ€” ๐Ÿฅ‡ The 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 โ€” ๐Ÿฅˆ The 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 โ€” ๐ŸŒฒ The 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 โ€” ๐Ÿ‰ The 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 โ€” ๐ŸŒ™ The 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 โ€” ๐Ÿ”๏ธ The 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 โ€” okay bestie, this one is an 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 โ€” the Intel Icelake Client CPU is giving 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 โ€” the server version of Icelake, the Intel Icelake Server CPU, comes 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 โ€” an 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 โ€” this Intel cooperlake CPU is literally built 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 โ€” the Intel Tigerlake CPU is a whole vibe 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 โ€” an Intel sapphirerapids 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, AVX512BF16, MOVDIRI, MOVDIR64B, AVX512VP2INTERSECT, ENQCMD, CLDEMOTE, PTWRITE, WAITPKG, SERIALIZE, TSXLDTRK, UINTR, AMX-BF16, AMX-TILE, AMX-INT8 and AVX-VNNI instruction set support ๐ŸŒˆ
  • alderlake โ€” the Intel Alderlake CPU has 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 CPU energy 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 ๐Ÿ’œ
  • k6 โ€” the AMD K6 CPU, with MMX instruction set support. Vintage, but iconic ๐Ÿ“
  • k6-2, k6-3 โ€” improved versions of the AMD K6 CPU, with MMX and 3DNow! instruction set support. Glow-up era โœจ
  • athlon, athlon-tbird โ€” the AMD Athlon CPU with MMX, 3dNOW!, enhanced 3DNow! and SSE prefetch instructions support ๐ŸŒธ
  • athlon-4, athlon-xp, athlon-mp โ€” an improved AMD Athlon CPU with MMX, 3DNow!, enhanced 3DNow! and full SSE instruction set support. Main character upgrade ๐Ÿ‘‘
  • k8, opteron, athlon64, athlon-fx โ€” processors based on the AMD K8 core with x86-64 instruction set support, including the AMD Opteron, Athlon 64, and Athlon 64 FX processors. (This supersets MMX, SSE, SSE2, 3DNow!, enhanced 3DNow! and 64-bit instruction set extensions.) Iykyk ๐Ÿฆ‹
  • k8-sse3, opteron-sse3, athlon64-sse3 โ€” improved versions of AMD K8 cores with SSE3 instruction set support. Lowkey the sequel we needed ๐Ÿ’–
  • amdfam10, barcelona โ€” CPUs based on AMD Family 10h cores with x86-64 instruction set support. (This supersets MMX, SSE, SSE2, SSE3, SSE4A, 3DNow!, enhanced 3DNow!, ABM and 64-bit instruction set extensions.) ๐Ÿซถ
  • bdver1 โ€” CPUs based on AMD Family 15h cores with x86-64 instruction set support. (This supersets FMA4, AVX, XOP, LWP, AES, 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. (This 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.) Upgrade energy ๐Ÿ’…
  • bdver3 โ€” AMD Family 15h core based CPUs with x86-64 instruction set support. (This supersets BMI, TBM, F16C, FMA, FMA4, FSGSBASE, AVX, XOP, LWP, AES, 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. (This 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.) Still slaying ๐Ÿ’€
  • znver1 โ€” AMD Family 17h core based CPUs with x86-64 instruction set support. (This supersets BMI, BMI2, F16C, FMA, FSGSBASE, AVX, AVX2, ADCX, RDSEED, MWAITX, SHA, CLZERO, AES, 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. (This 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. (This 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.) Newest in the group chat ๐ŸŽ€
  • btver1 โ€” CPUs based on AMD Family 14h cores with x86-64 instruction set support. (This supersets MMX, SSE, SSE2, SSE3, SSSE3, SSE4A, CX16, ABM and 64-bit instruction set extensions.) ๐ŸŒธ
  • btver2 โ€” CPUs based on AMD Family 16h cores with x86-64 instruction set support. This includes MOVBE, F16C, BMI, AVX, PCLMUL, AES, SSE4.2, SSE4.1, CX16, ABM, SSE4A, SSSE3, SSE3, SSE2, SSE, MMX and 64-bit instruction set extensions. Ngl, very well-rounded ๐Ÿซถ
  • winchip-c6 โ€” IDT WinChip C6 CPU, dealt with the same way as i486, with additional MMX instruction set support. Retro bestie ๐Ÿงธ
  • winchip2 โ€” IDT WinChip 2 CPU, dealt with the same way as i486, with additional MMX and 3DNow! instruction set support. Vintage but still vibing ๐Ÿ“
  • 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.) Glow-up unlocked โœจ
  • 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.) Peak VIA era ๐Ÿ‘‘
  • 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 โœจ

okay so -mtune is about tuning everything in the generated code except the ABI and the set of available instructions ๐Ÿ’… Picking a specific cpu-type schedules things nicely for that exact chip, but the compiler still won't spit out code that can't run on the default machine type, unless you also use a -march=cpu-type option ๐Ÿซถ For example, if GCC is configured for i686-pc-linux-gnu, then -mtune=pentium4 makes code tuned for Pentium 4 that still runs on i686 machines. iconic, honestly ๐Ÿ”ฅ

The choices for cpu-type are the same as for -march. On top of that, -mtune gets 2 extra choices ๐Ÿ‘‘

  • generic โ€” ๐ŸŒˆ Produces code optimized for the most common IA32/AMD64/EM64T processors. If you already know which CPU your code will run on, use the matching -mtune or -march option instead of -mtune=generic. But if you have no idea what CPU your users will have, this is the one to pick ๐Ÿงš

As new processors hit the market, the behavior of this option changes. So if you upgrade to a newer GCC, the code generated by this option shifts to match whatever processors are most common when that GCC version gets released ๐Ÿฆ‹

There is no -march=generic option, because -march is about the instruction set the compiler is allowed to use, and there's no generic instruction set that works for every processor. -mtune, on the other hand, is about the processor (or, in this case, the whole collection of processors) the code is optimized for โœจ

  • intel โ€” ๐Ÿ’– Produces code optimized for the most current Intel processors, which for this version of GCC are Haswell and Silvermont. If you know the CPU your code will run on, use the matching -mtune or -march option instead of -mtune=intel. But if you want your app to perform well on both Haswell and Silvermont, this is your option ๐ŸŽ€

As new Intel processors get deployed, this option's behavior will change. So if you upgrade to a newer GCC, the generated code will reflect the most current Intel processors at the time that version 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 for all processors. -mtune is about the processor (or, here, the collection of processors) the code is optimized for ๐Ÿ’œ

โœจ -mcpu=cpu-type โœจ

ngl this one is just a deprecated synonym for -mtune. Don't start new code with it ๐Ÿ™ˆ

โœจ -mfpmath=unit โœจ

This one decides what unit does your floating-point math ๐Ÿงฎ The choices for unit are:

  • 387 โ€” ๐ŸŒˆ Uses the standard 387 floating-point coprocessor that's on the majority of chips, and emulates it otherwise. Code compiled this way runs almost everywhere ๐Ÿ’… The temporary results get computed in 80-bit precision instead of the precision the type asks for, so you can get slightly different results compared to most other chips. See -ffloat-store for a more detailed description. This is the default choice for non-Darwin x86-32 targets.
  • sse โ€” โญ Uses scalar floating-point instructions from the SSE instruction set. It's supported by Pentium III and newer chips, and on the AMD side by Athlon-4, Athlon XP and Athlon MP chips. The earlier version of SSE only does single-precision arithmetic, so double and extended-precision math still goes through 387. A later version, only on Pentium 4 and AMD x86-64 chips, handles double-precision arithmetic too ๐Ÿฆ‹

For the x86-32 compiler, you have to use -march=cpu-type, -msse or -msse2 to enable the SSE extensions and make this option work. For the x86-64 compiler, those extensions are on by default ๐Ÿซถ

The resulting code should be way faster in most cases and avoids the numerical instability problems of 387 code. Heads up though: it may 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 once. This effectively doubles the number of available registers, and on chips with separate execution units for 387 and SSE, it doubles the execution resources too. Use this one with care, because it's still experimental: the GCC register allocator doesn't model separate functional units well, which leads to unstable performance ๐Ÿ’€

โœจ -masm=dialect โœจ

This makes the compiler output assembly instructions in the dialect you pick โœ๏ธ It also decides 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, sorry bestie ๐Ÿฅบ

โœจ -mieee-fp / -mno-ieee-fp โœจ

These control whether or not the compiler uses IEEE floating-point comparisons. The IEEE ones correctly handle the case where the result of a comparison is unordered, which is lowkey important ๐Ÿ”

โœจ -m80387 / -mhard-float โœจ

Generates output containing 80387 instructions for floating point ๐ŸŒธ

โœจ -mno-80387 / -msoft-float โœจ

Generates output containing library calls for floating point instead ๐Ÿ“š

Warning: the libraries you need are not part of GCC ๐Ÿšจ Normally the facilities of the machine's usual C compiler get used, but that can't be done directly during cross-compilation. You have to set up your own suitable library functions for cross-compilation yourself. Be prepared!

On machines where a function returns floating-point results in the 80387 register stack, some floating-point opcodes might still get emitted even when -msoft-float is used ๐Ÿ‘€

โœจ -mno-fp-ret-in-387 โœจ

Do not use the FPU registers for function return values ๐Ÿ™…โ€โ™€๏ธ

The usual calling convention has functions return float and double values in an FPU register, even when there's no FPU at all. The idea is that the operating system should emulate the FPU ๐Ÿงš The option -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, so this option tells the compiler to avoid generating those instructions ๐ŸŒˆ This option gets overridden when -march says the target CPU always has an FPU, since then the instruction doesn't need emulating. Also, these instructions aren't generated unless you also use the -funsafe-math-optimizations switch ๐Ÿฆ‹

โœจ -malign-double / -mno-align-double โœจ

These control whether GCC aligns double, long double, and long long variables on a two-word boundary or a one-word boundary ๐Ÿ“ Aligning double variables on a two-word boundary makes code run a bit faster on a Pentium, at the cost of more memory ๐Ÿง 

On x86-64, -malign-double is enabled by default.

Warning: if you use the -malign-double switch, structures containing those types are aligned differently than the published application binary interface specifications for x86-32. They won't be binary compatible with structures in code compiled without that switch ๐Ÿ˜ญ

โœจ -m96bit-long-double / -m128bit-long-double โœจ

These switches control the size of the long double type ๐Ÿ“ The x86-32 application binary interface says the size should be 96 bits, so -m96bit-long-double is the default in 32-bit mode.

Modern architectures (Pentium and newer) prefer long double to be aligned to an 8- or 16-byte boundary. In arrays or structures that follow the ABI, that's not 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, because its ABI says long double is aligned on a 16-byte boundary ๐Ÿ‘‘

Notice that neither of these options gives you 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. It also modifies the function calling convention for functions taking long double. So they won't be binary-compatible with code compiled without that switch ๐Ÿšจ

โœจ -mlong-double-64 / -mlong-double-80 / -mlong-double-128 โœจ

Same deal here: these switches control the size of the long double type ๐ŸŽ€ A size of 64 bits makes long double equivalent to double. 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. It also modifies the function calling convention for functions taking long double. So they aren't binary-compatible with code compiled without that switch ๐Ÿ’€

โœจ -malign-data=type โœจ

This controls how GCC aligns variables ๐Ÿ“ฆ The supported values for type are:

  • compat โ€” uses an increased alignment value, and it's compatible with what GCC 4.8 and earlier used. 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 โ€” ๐Ÿ“ฆ okay so when you pick -mcmodel=medium, any data object bigger than threshold gets tucked into the large data section. Every object linked into the binary has to agree on this number, and it defaults to 65535 โœจ.
  • -mrtd โ€” ๐Ÿ’… this one's a whole different function-calling convention. Functions with a fixed number of arguments return with the ret num instruction, which pops their arguments on the way out, so the caller saves one instruction ๐Ÿซถ. You can give a single function the stdcall function attribute to call it this way, or use the cdecl attribute to override -mrtd for that function ๐ŸŽ€.
โš ๏ธ Warning, bestie ๐Ÿ˜ญ: this calling convention is incompatible with the one normally used on Unix, so you cannot use it if you need to call libraries compiled with the Unix compiler.

Also, you must provide function prototypes for all functions that take variable numbers of arguments (including printf), or incorrect code gets generated for calls to those functions ๐Ÿ™ˆ.

In addition, seriously incorrect code results if you call a function with too many arguments. (Normally, extra arguments are harmlessly ignored ๐Ÿงš.)

  • -mregparm=num โ€” ๐Ÿ”ฅ controls how many registers get used to pass integer arguments. By default, no registers are used for arguments, and at most 3 registers can be used. You can tweak this for one specific function with the regparm function attribute ๐Ÿ’œ.
โš ๏ธ 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 sseregparm function attribute ๐Ÿฆ‹.
โš ๏ธ 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, to match the ABI of the Sun Studio compilers until version 12. Only use this if you need to stay compatible with existing code made by those older compiler versions or older versions of GCC ๐Ÿ™ˆ.
  • -mpc32 โ€” ๐ŸŒธ sets 80387 floating-point precision to 32 bits. The significands of floating-point results get rounded to 24 bits (single precision).
  • -mpc64 โ€” ๐ŸŒธ sets 80387 floating-point precision to 64 bits. The significands of floating-point results get rounded to 53 bits (double precision).
  • -mpc80 โ€” ๐Ÿ‘‘ sets 80387 floating-point precision to 80 bits. The significands of floating-point results get rounded to 64 bits (extended double precision). This is the default โœจ.

When you use one of these, floating-point operations in higher precisions aren't available to the programmer unless you set the FPU control word explicitly ๐Ÿง .

Setting the rounding to less than the default 80 bits can speed some programs up by 2% or more ๐ŸŽ๏ธ. But ngl, some mathematical libraries assume extended-precision (80-bit) floating-point operations are enabled by default. Routines in those libraries could suffer significant loss of accuracy, typically through so-called "catastrophic cancellation", when this option sets the precision below extended precision ๐Ÿ˜ญ.

  • -mstackrealign โ€” ๐Ÿงš realigns the stack at entry. On x86, this option generates an alternate prologue and epilogue that realigns the run-time stack if necessary. It's how legacy code that keeps 4-byte stack alignment can mix with modern code that keeps 16-byte stack alignment for SSE compatibility ๐Ÿซถ. See also the attribute force_align_arg_pointer, which applies to individual functions.
  • -mpreferred-stack-boundary=num โ€” ๐Ÿงฑ attempts to keep the stack boundary aligned to a 2 raised to num byte boundary. If you don't specify -mpreferred-stack-boundary, the default is 4 (16 bytes or 128 bits).
โš ๏ธ Warning: when generating code for the x86-64 architecture with SSE extensions disabled, -mpreferred-stack-boundary=3 can be used to keep the stack boundary aligned to an 8 byte boundary. The x86-64 ABI requires 16 byte stack alignment, so this is ABI incompatible and only meant for a controlled environment where stack space is a seriously important limitation ๐Ÿ˜ฌ. This option leads to wrong code when functions compiled with 16 byte stack alignment (such as functions from a standard library) are called with a misaligned stack. In that case, SSE instructions may lead to misaligned memory access traps. Variable arguments are also handled incorrectly for 16 byte aligned objects (including x87 long double and __int128), which leads to wrong results. You must build all modules with -mpreferred-stack-boundary=3, including any libraries. That includes the system libraries and startup modules.
  • -mincoming-stack-boundary=num โ€” ๐ŸŽ€ assumes the incoming stack is aligned to a 2 raised to num byte boundary. If you don't specify -mincoming-stack-boundary, the one specified by -mpreferred-stack-boundary is used.

On Pentium and Pentium Pro, double and long double values should be aligned to an 8-byte boundary (see -malign-double) or you'll take significant run time performance penalties ๐Ÿข. On Pentium III, the Streaming SIMD Extension (SSE) data type __m128 may not work properly if it isn't 16-byte aligned.

To make sure these values get proper alignment on the stack, the stack boundary has to be at least as aligned as whatever any value stored on the stack requires. Every function also has to be generated so it keeps the stack aligned. So calling a function compiled with a higher preferred stack boundary from a function compiled with a lower one most likely misaligns the stack ๐Ÿ’€. It's recommended that libraries that use callbacks always use the default setting ๐Ÿซถ.

This extra alignment does eat up extra stack space and generally increases code size. Code that's sensitive to stack space usage, like embedded systems and operating system kernels, may want to reduce the preferred alignment to -mpreferred-stack-boundary=2 ๐Ÿงš.


Now for the big ol' squad of instruction set switches. Each one of these turns on its own extension, and every single one has a matching -mno- buddy to turn it off ๐Ÿ’œ:

  • -mmmx โ€” ๐Ÿ”“ unlocks this instruction set.
  • -msse โ€” ๐Ÿ”“ unlocks this instruction set.
  • -msse2 โ€” ๐Ÿ”“ unlocks this instruction set.
  • -msse3 โ€” ๐Ÿ”“ unlocks this instruction set.
  • -mssse3 โ€” ๐Ÿ”“ unlocks this instruction set.
  • -msse4 โ€” ๐Ÿ”“ unlocks this instruction set.
  • -msse4a โ€” ๐Ÿ”“ unlocks this instruction set.
  • -msse4.1 โ€” ๐Ÿ”“ unlocks this instruction set.
  • -msse4.2 โ€” ๐Ÿ”“ unlocks this instruction set.
  • -mavx โ€” ๐Ÿ”“ unlocks this instruction set.
  • -mavx2 โ€” ๐Ÿ”“ unlocks this instruction set.
  • -mavx512f โ€” ๐Ÿ”“ unlocks this instruction set.
  • -mavx512pf โ€” ๐Ÿ”“ unlocks this instruction set.
  • -mavx512er โ€” ๐Ÿ”“ unlocks this instruction set.
  • -mavx512cd โ€” ๐Ÿ”“ unlocks this instruction set.
  • -mavx512vl โ€” ๐Ÿ”“ unlocks this instruction set.
  • -mavx512bw โ€” ๐Ÿ”“ unlocks this instruction set.
  • -mavx512dq โ€” ๐Ÿ”“ unlocks this instruction set.
  • -mavx512ifma โ€” ๐Ÿ”“ unlocks this instruction set.
  • -mavx512vbmi โ€” ๐Ÿ”“ unlocks this instruction set.
  • -msha โ€” ๐Ÿ”“ unlocks this instruction set.
  • -maes โ€” ๐Ÿ”“ unlocks this instruction set.
  • -mpclmul โ€” ๐Ÿ”“ unlocks this instruction set.
  • -mclflushopt โ€” ๐Ÿ”“ unlocks this instruction set.
  • -mclwb โ€” ๐Ÿ”“ unlocks this instruction set.
  • -mfsgsbase โ€” ๐Ÿ”“ unlocks this instruction set.
  • -mptwrite โ€” ๐Ÿ”“ unlocks this instruction set.
  • -mrdrnd โ€” ๐Ÿ”“ unlocks this instruction set.
  • -mf16c โ€” ๐Ÿ”“ unlocks this instruction set.
  • -mfma โ€” ๐Ÿ”“ unlocks this instruction set.
  • -mpconfig โ€” ๐Ÿ”“ unlocks this instruction set.
  • -mwbnoinvd โ€” ๐Ÿ”“ unlocks this instruction set.
  • -mfma4 โ€” ๐Ÿ”“ unlocks this instruction set.
  • -mprfchw โ€” ๐Ÿ”“ unlocks this instruction set.
  • -mrdpid โ€” ๐Ÿ”“ unlocks this instruction set.
  • -mprefetchwt1 โ€” ๐Ÿ”“ unlocks this instruction set.
  • -mrdseed โ€” ๐Ÿ”“ unlocks this instruction set.
  • -msgx โ€” ๐Ÿ”“ unlocks this instruction set.
  • -mxop โ€” ๐Ÿ”“ unlocks this instruction set.
  • -mlwp โ€” ๐Ÿ”“ unlocks this instruction set.
  • -m3dnow โ€” ๐Ÿ”“ unlocks this instruction set.
  • -m3dnowa โ€” ๐Ÿ”“ unlocks this instruction set.
  • -mpopcnt โ€” ๐Ÿ”“ unlocks this instruction set.
  • -mabm โ€” ๐Ÿ”“ unlocks this instruction set.
  • -madx โ€” ๐Ÿ”“ unlocks this instruction set.
  • -mbmi โ€” ๐Ÿ”“ unlocks this instruction set.
  • -mbmi2 โ€” ๐Ÿ”“ unlocks this instruction set.
  • -mlzcnt โ€” ๐Ÿ”“ unlocks this instruction set.
  • -mfxsr โ€” ๐Ÿ”“ unlocks this instruction set.
  • -mxsave โ€” ๐Ÿ”“ unlocks this instruction set.
  • -mxsaveopt โ€” ๐Ÿ”“ unlocks this instruction set.
  • -mxsavec โ€” ๐Ÿ”“ unlocks this instruction set.
  • -mxsaves โ€” ๐Ÿ”“ unlocks this instruction set.
  • -mrtm โ€” ๐Ÿ”“ unlocks this instruction set.
  • -mhle โ€” ๐Ÿ”“ unlocks this instruction set.
  • -mtbm โ€” ๐Ÿ”“ unlocks this instruction set.
  • -mmwaitx โ€” ๐Ÿ”“ unlocks this instruction set.
  • -mclzero โ€” ๐Ÿ”“ unlocks this instruction set.
  • -mpku โ€” ๐Ÿ”“ unlocks this instruction set.
  • -mavx512vbmi2 โ€” ๐Ÿ”“ unlocks this instruction set.
  • -mavx512bf16 โ€” ๐Ÿ”“ unlocks this instruction set.
  • -mavx512fp16 โ€” ๐Ÿ”“ unlocks this instruction set.
  • -mgfni โ€” ๐Ÿ”“ unlocks this instruction set.
  • -mvaes โ€” ๐Ÿ”“ unlocks this instruction set.
  • -mwaitpkg โ€” ๐Ÿ”“ unlocks this instruction set.
  • -mvpclmulqdq โ€” ๐Ÿ”“ unlocks this instruction set.
  • -mavx512bitalg โ€” ๐Ÿ”“ unlocks this instruction set.
  • -mmovdiri โ€” ๐Ÿ”“ unlocks this instruction set.
  • -mmovdir64b โ€” ๐Ÿ”“ unlocks this instruction set.
  • -menqcmd โ€” ๐Ÿ”“ unlocks this instruction set.
  • -muintr โ€” ๐Ÿ”“ unlocks this instruction set.
  • -mtsxldtrk โ€” ๐Ÿ”“ unlocks this instruction set.
  • -mavx512vpopcntdq โ€” ๐Ÿ”“ unlocks this instruction set.
  • -mavx512vp2intersect โ€” ๐Ÿ”“ unlocks this instruction set.
  • -mavx5124fmaps โ€” ๐Ÿ”“ unlocks this instruction set.
  • -mavx512vnni โ€” ๐Ÿ”“ unlocks this instruction set.
  • -mavxvnni โ€” ๐Ÿ”“ unlocks this instruction set.
  • -mavx5124vnniw โ€” ๐Ÿ”“ unlocks this instruction set.
  • -mcldemote โ€” ๐Ÿ”“ unlocks this instruction set.
  • -mserialize โ€” ๐Ÿ”“ unlocks this instruction set.
  • -mamx-tile โ€” ๐Ÿ”“ unlocks this instruction set.
  • -mamx-int8 โ€” ๐Ÿ”“ unlocks this instruction set.
  • -mamx-bf16 โ€” ๐Ÿ”“ unlocks this instruction set.
  • -mhreset โ€” ๐Ÿ”“ unlocks this instruction set.
  • -mkl โ€” ๐Ÿ”“ unlocks this instruction set.
  • -mwidekl โ€” ๐Ÿ”“ unlocks this instruction set.

These switches enable the use of instructions in 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, AVX512FP16 or CLDEMOTE extended instruction sets. Each has a corresponding -mno- option to disable use of these instructions ๐ŸŒˆ.

These extensions are also available as built-in functions: see x86 Built-in Functions, for details of the functions enabled and disabled by these switches ๐Ÿงš.

To generate SSE/SSE2 instructions automatically from floating-point code (as opposed to 387 instructions), see -mfpmath=sse โœจ.

GCC depresses SSEx instructions when -mavx is used. Instead, it generates new AVX instructions or AVX equivalence for all SSEx instructions when needed ๐Ÿ’….

These options enable GCC to use these extended instructions in generated code, even without -mfpmath=sse. Applications that perform run-time CPU detection must compile separate files for each supported architecture, using the appropriate flags. In particular, the file containing the CPU detection code should be compiled without these options ๐Ÿซถ.

  • -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 โ€” ๐ŸŽ›๏ธ lets you do fine-grained control of x86 code generation features. feature-list is a comma separated list of feature names. See also -mdump-tune-features. When specified, a feature gets turned on if it isn't preceded with ^, and turned off if it is ๐Ÿ‘‘.
โš ๏ธ Warning: -mtune-ctrl=feature-list is intended to be used by GCC developers. Using it may lead to code paths not covered by testing, and can potentially result in compiler ICEs or runtime errors ๐Ÿ’€.
  • -mno-default โ€” ๐Ÿงน tells GCC to turn off all tunable features. See also -mtune-ctrl=feature-list and -mdump-tune-features ๐ŸŒธ.
  • -mcld โ€” ๐Ÿ’… okay so this one tells GCC to slip a cld instruction into the prologue of any function that uses string instructions ๐ŸŽ€. String instructions check the DF flag to decide whether they go forward (autoincrement) or backward (autodecrement) ๐Ÿฆ‹. The ABI says DF should be cleared on function entry, but some operating systems forget to clear it in their exception dispatchers ๐Ÿ’€. So the exception handler can get called with DF set, and then string instructions go the wrong direction ๐Ÿ˜ญ. This can be turned on by default on 32-bit x86 targets if you configure GCC with the --enable-cld configure option. In that case you can still turn off cld generation with the -mno-cld compiler option ๐Ÿ™….
  • -mvzeroupper โ€” โœจ GCC drops a vzeroupper instruction right before control flow leaves the function โœจ. This keeps the AVX to SSE transition penalty low ๐Ÿ“‰, and it also removes unnecessary zeroupper intrinsics ๐Ÿงน.
  • -mprefer-avx128 โ€” ๐ŸŒธ tells the auto-vectorizer to use 128-bit AVX instructions instead of 256-bit AVX instructions ๐ŸŒธ.
  • -mprefer-vector-width=opt โ€” ๐Ÿงš tells GCC to use an opt-bit vector width in instructions instead of the default for the platform you picked ๐Ÿงš.
  • -mmove-max=bits โ€” ๐Ÿฆ‹ sets the max number of bits that can be moved from memory to memory efficiently to bits. The valid values are 128, 256 and 512.
  • -mstore-max=bits โ€” ๐Ÿ“ sets the max number of bits that can be stored to memory efficiently to bits. The valid values are 128, 256 and 512.

Here's the little value menu that sits right after that one ๐Ÿ‘‡

  • none โ€” no extra limits on GCC beyond whatever the selected platform already sets ๐Ÿ™Œ.
  • 128 โ€” prefer 128-bit vector width for instructions ๐Ÿ’œ.
  • 256 โ€” prefer 256-bit vector width for instructions ๐Ÿ’™.
  • 512 โ€” prefer 512-bit vector width for instructions ๐ŸŒˆ.
  • -mcx16 โ€” ๐Ÿ’– lets GCC generate CMPXCHG16B instructions in 64-bit code, so it can do compare-and-exchange on 16-byte aligned 128-bit objects ๐Ÿ’–. This is super useful for atomic updates on data structures bigger than one machine word ๐Ÿ”ฅ. The compiler uses this instruction to implement __sync Builtins. For __atomic Builtins on 128-bit integers, though, it always uses a library call ๐Ÿ“š.
  • -msahf โ€” ๐Ÿง  enables generation of SAHF instructions in 64-bit code. Early Intel Pentium 4 CPUs with Intel 64 support, which came out 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, SAHF 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 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 so they generate the crc32 machine instruction.
  • -mmwait โ€” โณ enables the built-in functions __builtin_ia32_monitor and __builtin_ia32_mwait so they generate the monitor and mwait machine instructions.
  • -mrecip โ€” ๐Ÿ”ฎ enables RCPSS and RSQRTSS (plus their vectorized friends RCPPS and RSQRTPS) with an extra Newton-Raphson step for precision. They're used 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: the throughput of the sequence is higher than the non-reciprocal instruction's, but precision can drop by up to 2 ulp (like, the inverse of 1.0 comes out as 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 note that GCC already emits the above sequence with the extra Newton-Raphson step for vectorized single-float division and vectorized sqrtf(x) with -ffast-math (or the option combination above), so you don't need -mrecip for those either ๐Ÿ™Œ.

  • -mrecip=opt โ€” ๐ŸŽ› controls which reciprocal estimate instructions may be used. opt is a comma-separated list of options, and any of them can be preceded by a ! to invert it:
    • all โ€” enable all estimate instructions.
    • default โ€” enable the default instructions, equivalent to -mrecip.
    • none โ€” disable all estimate instructions, equivalent to -mno-recip.
    • div โ€” enable the approximation for scalar division.
    • vec-div โ€” enable the approximation for vectorized division.
    • sqrt โ€” enable the approximation for scalar square root.
    • vec-sqrt โ€” enable the approximation for vectorized square root.

So, for example, -mrecip=all,!sqrt enables all of the reciprocal approximations except for square root โœ‚๏ธ.

  • -mveclibabi=type โ€” ๐Ÿ“š specifies the ABI type to use when vectorizing intrinsics with an external library. Supported values for type are svml for the Intel short vector math library and acml for the AMD math core library. To use this option, both -ftree-vectorize and -funsafe-math-optimizations have to be enabled, and an SVML or ACML ABI-compatible library has to be specified at link time ๐Ÿ”—.

When -mveclibabi=svml is used, 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=acml is used, GCC currently emits calls to __vrd2_sin, __vrd2_cos, __vrd2_exp, __vrd2_log, __vrd2_log2, __vrd2_log10, __vrs4_sinf, __vrs4_cosf, __vrs4_expf, __vrs4_logf, __vrs4_log2f, __vrs4_log10f and __vrs4_powf for the corresponding function type ๐Ÿงฎ.

  • -mabi=name โ€” ๐ŸŒ generates code for the specified calling convention. Permissible values are sysv for the ABI used on GNU/Linux and other systems, and ms for the Microsoft ABI. The default is the Microsoft ABI when targeting Microsoft Windows and the SysV ABI on all other systems. You can control this for specific functions with the function attributes ms_abi and sysv_abi ๐ŸŽฏ.
  • -mforce-indirect-call โ€” ๐Ÿงญ forces all calls to functions to be indirect. This is handy when using Intel Processor Trace, since it gives more precise timing info for function calls โฑ.
  • -mmanual-endbr โ€” ๐ŸŽฏ inserts the ENDBR instruction at function entry only through the cf_check function attribute. This is useful when used with -fcf-protection=branch to control ENDBR insertion at function entry.
  • -mcall-ms2sysv-xlogues โ€” ๐Ÿงต because of differences between the 64-bit ABIs, any Microsoft ABI function that calls a System V ABI function has to treat RSI, RDI and XMM6-15 as clobbered. By default, the code that saves and restores 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. That shrinks function size at the cost of a few extra instructions ๐Ÿค.
  • -mtls-dialect=type โ€” ๐Ÿงถ generates code to access thread-local storage using the gnu or gnu2 conventions. gnu is the conservative default. gnu2 is more efficient, but it may add compile- and run-time requirements that 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 thanks to better scheduling and reduced dependencies ๐Ÿ“ˆ.
  • -maccumulate-outgoing-args โ€” ๐Ÿงบ if enabled, the maximum amount of space needed for outgoing arguments is computed in the function prologue. This is faster on most modern CPUs because of reduced dependencies, improved scheduling, and reduced stack usage when the preferred stack boundary isn't equal to 2. The drawback is a notable increase in code size ๐Ÿ˜ฌ. This switch implies -mno-push-args.
  • -mthreads โ€” ๐Ÿงต supports thread-safe exception handling on MinGW. Programs that rely on thread-safe exception handling must compile and link all code with the -mthreads option. When compiling, -mthreads defines -D_MT. When linking, it links in the special thread helper library -lmingwthrd, which cleans up per-thread exception-handling data ๐Ÿงน.
  • -mms-bitfields, -mno-ms-bitfields โ€” ๐ŸŽ€ enables or disables bit-field layout that's compatible with the native Microsoft Windows compiler.

If packed is used on a structure, or if bit-fields are used, the Microsoft ABI may lay out the structure differently than GCC normally does. Especially when moving packed data between functions compiled with GCC and the native Microsoft compiler (either via function call or as data in a file), you may need to access either format ๐Ÿง.

This option is enabled by default for Microsoft Windows targets. You can also control it locally with variable or type attributes. For more information, see x86 Variable Attributes and x86 Type Attributes ๐Ÿ“.

The Microsoft structure layout algorithm is fairly simple, except for bit-field packing. The padding and alignment of structure members, and whether a bit-field can straddle a storage-unit boundary, are determined by these rules:

  1. Members line up in order ๐Ÿงš Structure members are stored sequentially in the order they're declared. The first member gets the lowest memory address and the last one gets the highest.
  2. Everything has an alignment requirement ๐Ÿ“ Every data object has one. For everything except structures, unions, and arrays, it's either the size of the object or the current packing size (set with the "aligned" attribute or the "pack" pragma), whichever is less. For structures, unions, and arrays, it's the biggest alignment requirement among their members. Every object gets an offset so that:
offset % alignment_requirement == 0
  1. Bit-fields get cozy ๐Ÿงธ Adjacent bit-fields get packed into the same 1-, 2-, or 4-byte allocation unit if their integral types are the same size, and if the next bit-field fits into the current allocation unit without crossing the boundary set by the common alignment requirements of the bit-fields.

Now, MSVC has its own zero-length bit-field drama ๐Ÿ™ƒ Here's how it handles them:

  1. If a zero-length bit-field gets inserted between two bit-fields that would normally be coalesced, those 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 gets aligned as the type of the zero-length bit-field. ๐Ÿ’…

For example:

struct
 {
   char foo : 4;
   short : 0;
   char bar;
 } t2;

struct
 {
   char foo : 4;
   short : 0;
   double bar;
 } t3;

For t2, bar 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 following non-bit-field members are ignored ๐Ÿซ 
struct
 {
   char foo;
   long : 0;
   char bar;
 } t5;

Here, t5 takes up 2 bytes. ๐ŸŒธ


  • -mno-align-stringops โ€” Don't align the destination of inlined string operations ๐Ÿ™…โ€โ™€๏ธ This makes the code smaller and can speed things up when the destination is already aligned, but GCC doesn't know that's the case.
  • -minline-all-stringops โ€” By default, GCC only inlines string operations when the destination is known to be aligned to at least a 4-byte boundary. This turns on way more inlining, which bumps up the code size but may improve performance for code that depends on fast memcpy and memset for short lengths. It also enables inline expansion of strlen for all pointer alignments. ๐Ÿ”ฅ
  • -minline-stringops-dynamically โ€” For string operations of unknown size, use run-time checks with inline code for small blocks and a library call for large blocks. ๐Ÿงš
  • -mstringop-strategy=alg โ€” Overrides the internal decision heuristic for which algorithm gets used when inlining string operations. The allowed values for alg are:
    • rep_byte, rep_4byte, rep_8byte โ€” Expand using i386 rep prefix of the specified size.
    • byte_loop, loop, unrolled_loop โ€” Expand into an inline loop.
    • libcall โ€” Always use a library call.
  • -mmemcpy-strategy=strategy โ€” Overrides the internal heuristic that decides if __builtin_memcpy should be inlined, and which inline algorithm to use when the expected size of the copy operation is known. strategy is a comma-separated list of alg:max_size:dest_align triplets. alg is specified in -mstringop-strategy, and max_size sets the max byte size that the inline algorithm alg is allowed to handle. For the last triplet, the max_size must be -1. The max_size values in the list must go in increasing order. The minimal byte size for alg is 0 for the first triplet, and max_size + 1 of the preceding range for the rest. ๐Ÿ“
  • -mmemset-strategy=strategy โ€” Basically the same vibe as -mmemcpy-strategy=, except this one controls __builtin_memset expansion. ๐Ÿ’œ
  • -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 removes the frame pointer for leaf functions, which might make debugging harder. ๐Ÿ›
  • -mtls-direct-seg-refs, -mno-tls-direct-seg-refs โ€” Controls whether TLS variables can be accessed with offsets from the TLS segment register (%gs for 32-bit, %fs for 64-bit), or whether the thread base pointer has to be added. Whether or not this is valid depends on the operating system, and on whether it maps the segment to cover the entire TLS area. For systems that use the GNU C Library, the default is on. ๐Ÿฆ‹
  • -msse2avx, -mno-sse2avx โ€” Tells the assembler to encode SSE instructions with the VEX prefix. The option -mavx turns this on by default. โœจ
  • -mfentry, -mno-fentry โ€” If profiling is active (-pg), put the profiling counter call before the prologue.
Note: On x86 architectures, the attribute ms_hook_prologue isn't possible at the moment for -mfentry and -pg. ๐Ÿ™ƒ
  • -mrecord-mcount, -mno-record-mcount โ€” If profiling is active (-pg), generate a __mcount_loc section that contains pointers to each profiling call. This is useful for automatically patching out calls. ๐ŸŽ€
  • -mnop-mcount, -mno-nop-mcount โ€” If profiling is active (-pg), generate the calls to the profiling functions as NOPs. This is useful when they should be patched in later, dynamically. This is likely only useful together with -mrecord-mcount. ๐ŸŒˆ
  • -minstrument-return=type โ€” Instruments function exit in -pg -mfentry instrumented functions with a call to the specified function. This only instruments true returns ending with ret, not sibling calls ending with jump. Valid types are:
    • none โ€” to not instrument
    • call โ€” to generate a call to __return__
    • nop5 โ€” to generate a 5 byte nop
  • -mrecord-return, -mno-record-return โ€” Generates a __return_loc section pointing to all return instrumentation code. ๐Ÿ“
  • -mfentry-name=name โ€” Sets the name of the __fentry__ symbol that gets called at function entry for -pg -mfentry functions. ๐Ÿท๏ธ
  • -mfentry-section=name โ€” Sets the name of the section where -mrecord-mcount calls get recorded (default __mcount_loc). ๐Ÿ—‚๏ธ
  • -mskip-rax-setup, -mno-skip-rax-setup โ€” When generating code for the x86-64 architecture with SSE extensions disabled, -mskip-rax-setup can be used to skip setting up the RAX register when there are no variable arguments passed in vector registers.
Warning: The RAX register is used to avoid unnecessarily saving vector registers on the stack when passing variable arguments, so the impacts of this option are that callees may waste some stack space, misbehave, or jump to a random location. GCC 4.4 or newer don't have those issues, regardless of the RAX register value. ๐Ÿ˜ฑ
  • -m8bit-idiv, -mno-8bit-idiv โ€” On some processors, like Intel Atom, 8-bit unsigned integer divide is much faster than 32-bit/64-bit integer divide. This option generates a run-time check. If both the dividend and divisor are within the range of 0 to 255, 8-bit unsigned integer divide is used instead of 32-bit/64-bit integer divide. ๐ŸŽ๏ธ
  • -mavx256-split-unaligned-load, -mavx256-split-unaligned-store โ€” Splits 32-byte AVX unaligned loads and stores. ๐Ÿช„
  • -mstack-protector-guard=guard, -mstack-protector-guard-reg=reg, -mstack-protector-guard-offset=offset โ€” Generates stack protection code using a canary at guard. The supported locations are global for a global canary, or tls for a per-thread canary in the TLS block (the default). This 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 further specify which segment register (%fs or %gs) to use as the base register for reading the canary, and from what offset from that base register. The defaults for those are as specified in the relevant ABI. ๐Ÿงฉ

  • -mgeneral-regs-only โ€” Generates code that uses only the general-purpose registers. This stops the compiler from using floating-point, vector, mask, and bound registers. ๐Ÿซถ
  • -mrelax-cmpxchg-loop โ€” Relaxes the cmpxchg loop by emitting an early load and compare before cmpxchg, and executing pause if the loaded value isn't the one expected. This reduces excessive cache line bouncing, and it works for all atomic logic fetch builtins that generate a compare-and-swap loop. ๐Ÿ’–

-mindirect-branch=choice

Okay so this one is about how indirect calls and jumps get handled ๐Ÿ’…

  • -mindirect-branch=choice: Converts indirect calls and jumps using choice. The default is keep, which leaves them totally unmodified ๐Ÿฆ‹ thunk turns them into call and return thunks. thunk-inline turns them into inlined call and return thunks. thunk-extern turns them into external call and return thunks that live in a separate object file โœจ You can control this for one specific function with the function attribute "indirect_branch" ๐Ÿซถ

Note that -mcmodel=large is incompatible with -mindirect-branch=thunk and -mindirect-branch=thunk-extern ๐Ÿ’€ The thunk function may not be reachable in the large code model, so it's a no-go.

Note that -mindirect-branch=thunk-extern is compatible with -fcf-protection=branch, since the external thunk can be made to enable control-flow check ๐ŸŒˆ

  • -mfunction-return=choice: Converts function returns using choice. The default is keep, which keeps returns unmodified ๐ŸŒธ thunk turns function returns into call and return thunks. thunk-inline turns them into inlined call and return thunks. thunk-extern turns them into external call and return thunks provided in a separate object file. You can control this for one specific function with the function attribute "function_return" ๐Ÿ’œ

Note that -mindirect-return=thunk-extern is compatible with -fcf-protection=branch, since the external thunk can be made to enable control-flow check โœจ

Note that -mcmodel=large is incompatible with -mfunction-return=thunk and -mfunction-return=thunk-extern ๐Ÿ™ˆ Same deal as before: 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) using choice ๐Ÿ›ก๏ธ The default is none, which disables all SLS hardening. return turns on SLS hardening for function returns. indirect-jmp turns it on for indirect jumps. all turns on every single bit of SLS hardening ๐Ÿ‘‘
  • -mindirect-branch-cs-prefix: Adds a CS prefix to call and jmp to an indirect thunk when the branch target is in the r8-r15 registers ๐Ÿ“ That makes the call and jmp instruction length 6 bytes, so they can be swapped at run-time for lfence; call *%r8-r15 or lfence; jmp *%r8-r15 ๐Ÿ”ฅ

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 on any i386 system ๐ŸŒธ
    • -m64 sets int to 32 bits and long and pointer types to 64 bits, and generates code for the x86-64 architecture ๐Ÿฆ‹ For Darwin only, -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: Don'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 touch, so it can be used for temporary data without adjusting the stack pointer โœจ This flag disables that red zone.
  • -mcmodel=small: Generates code for the small code model ๐Ÿฃ The program and its symbols must be linked in the lower 2 GB of the address space. Pointers are 64 bits. Programs can be statically or dynamically linked. This is the default code model ๐Ÿ’–
  • -mcmodel=kernel: Generates code for the kernel code model ๐ŸงŠ The kernel runs in the negative 2 GB of the address space. This model has to be used for Linux kernel code ๐Ÿง
  • -mcmodel=medium: Generates code for the medium model ๐ŸŒท The program is linked in the lower 2 GB of the address space, and small symbols are placed there too. Symbols with sizes larger than -mlarge-data-threshold are put into large data or BSS sections and can be located above 2GB. Programs can be statically or dynamically linked.
  • -mcmodel=large: Generates code for the large model ๐ŸŒŒ This model makes no assumptions about addresses and sizes of sections.
  • -maddress-mode=long: Generates code for long address mode ๐Ÿ“ This is only supported for 64-bit and x32 environments. It's the default address mode for 64-bit environments.
  • -maddress-mode=short: Generates code for short address mode ๐Ÿชถ This is only supported for 32-bit and x32 environments. It's the default address mode for 32-bit and x32 environments.
  • -mneeded, -mno-needed: Emits the GNU_PROPERTY_X86_ISA_1_NEEDED GNU property for Linux targets ๐Ÿท๏ธ It tells you the micro-architecture ISA level required to execute the binary.
  • -mno-direct-extern-access: Without -fpic or -fPIC, always use the GOT pointer to access external symbols ๐Ÿ—๏ธ With -fpic or -fPIC, treat access to protected symbols as local symbols. The default is -mdirect-extern-access.
Warning: shared libraries compiled with -mno-direct-extern-access and executables compiled with -mdirect-extern-access may not be binary compatible if protected symbols are used in shared libraries and executables ๐Ÿšจ Be careful, bestie!

โœจ x86 Windows Options โœจ

These additional options are available for Microsoft Windows targets ๐ŸชŸ

  • -mconsole: Specifies that a console application is to be generated ๐Ÿ–ฅ๏ธ This is done by instructing the linker to set the PE header subsystem type required for console applications. This option is available for Cygwin and MinGW targets and is enabled by default on those targets ๐Ÿ’œ
  • -mdll: Available for Cygwin and MinGW targets ๐Ÿงฉ It specifies that a DLL---a dynamic link library---is to be generated, which enables the selection of the required runtime startup object and entry point.
  • -mnop-fun-dllimport: Available for Cygwin and MinGW targets ๐Ÿ™… It specifies that the "dllimport" attribute should be ignored.
  • -mthreads: Available for MinGW targets ๐Ÿงต It specifies that MinGW-specific thread support is to be used.
  • -municode: Available for MinGW-w64 targets ๐ŸŒ It causes the "UNICODE" preprocessor macro to be predefined, and chooses Unicode-capable runtime startup code.
  • -mwin32: Available for Cygwin and MinGW targets ๐ŸชŸ It specifies that the typical Microsoft Windows predefined macros are set in the preprocessor, but it doesn't influence the choice of runtime library or startup code.
  • -mwindows: Available for Cygwin and MinGW targets ๐ŸŽจ It specifies that a GUI application is to be generated, by instructing the linker to set the PE header subsystem type appropriately.
  • -fno-set-stack-executable: Available for MinGW targets ๐Ÿ”’ It specifies that the executable flag for the stack used by nested functions isn't set. This is necessary for binaries running in kernel mode of Microsoft Windows, since the User32 API (which is used to set executable privileges) isn't available there.
  • -fwritable-relocated-rdata: Available for MinGW and Cygwin targets โœ๏ธ It specifies that relocated data in a read-only section is put into the ".data" section. This is necessary for older runtimes that don't support modification of ".rdata" sections for pseudo-relocation.
  • -mpe-aligned-commons: Available for Cygwin and MinGW targets ๐Ÿ“ It specifies that the GNU extension to the PE file format, which permits the correct alignment of COMMON variables, should be used when generating code. It's enabled by default if GCC detects that the target assembler found during configuration supports the feature.

See also under x86 Options for standard options ๐Ÿ“–


โœจ Xstormy16 Options โœจ

These options are defined for Xstormy16 โšก

  • -msim: Chooses startup files and a linker script suitable for the simulator ๐ŸŽฎ

โœจ Xtensa Options โœจ

These options are supported for Xtensa targets ๐ŸŒŸ

  • -mconst16, -mno-const16: Enables or disables use of CONST16 instructions for loading constant values ๐Ÿ”ข The CONST16 instruction is currently not a standard option from Tensilica. When enabled, CONST16 instructions are always used in place of the standard L32R instructions. The use of CONST16 is enabled by default only if the L32R instruction is not available.
  • -mfused-madd, -mno-fused-madd: Enables or disables use of fused multiply/add and multiply/subtract instructions in the floating-point option ๐Ÿงฎ This has no effect if the floating-point option isn't also enabled. Disabling them forces the compiler to use separate instructions for the multiply and add/subtract operations. This can be desirable when strict IEEE 754-compliant results are required ๐ŸŽฏ The fused multiply add/subtract instructions don't round the intermediate result, so they produce results with more bits of precision than the IEEE standard specifies. Disabling them also ensures the program output isn't sensitive to the compiler's ability to combine multiply and add/subtract operations โœจ
  • -mserialize-volatile, -mno-serialize-volatile: When enabled, GCC inserts MEMW instructions before volatile memory references to guarantee sequential consistency ๐Ÿ” The default is -mserialize-volatile. Use -mno-serialize-volatile to omit the MEMW instructions.
  • -mforce-no-pic: For targets like GNU/Linux, where all user-mode Xtensa code must be position-independent code (PIC), this option disables PIC for compiling kernel code ๐Ÿš
  • -mtext-section-literals, -mno-text-section-literals โ€” okay so these two control where literal pools end up ๐Ÿงš The default is -mno-text-section-literals, which tucks literals into their own separate section in the output file ๐Ÿ“ฆ That lets the literal pool sit in a data RAM/ROM, and it also lets the linker merge literal pools from separate object files to kill redundant literals and shrink code size ๐Ÿ’… With -mtext-section-literals, the literals get interspersed right in the text section so they stay as close as possible to their references ๐Ÿฆ‹ This may be necessary for large assembly files ๐Ÿ˜ญ Literals for each function are placed right before that function โœจ
  • -mauto-litpools, -mno-auto-litpools โ€” these are the literal pool vibes again, but make it assembler-driven ๐ŸŒˆ The default is -mno-auto-litpools, which puts literals in a separate section in the output file unless -mtext-section-literals is used ๐ŸŽ€ With -mauto-litpools, the assembler interleaves the literals into the text section itself ๐Ÿงš 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 wherever they're needed ๐Ÿ’œ This lets the assembler create several literal pools per function and assemble very big functions, which may not be possible with -mtext-section-literals ๐Ÿ”ฅ
  • -mtarget-align, -mno-target-align โ€” when this is enabled, GCC tells the assembler to auto-align instructions so branch penalties go down ๐Ÿฆ‹ The tradeoff is a little less code density, but it's giving performance โœจ The assembler tries to widen density instructions so branch targets and the instructions right after call instructions get aligned ๐ŸŒธ If there aren't enough safe density instructions before a target to line it up, no widening happens ๐Ÿ™ˆ The default is -mtarget-align ๐Ÿ’– These options don't touch auto-aligned instructions like LOOP, which the assembler always aligns either by widening density instructions or by inserting NOP instructions ๐Ÿซถ
  • -mlongcalls, -mno-longcalls โ€” when enabled, GCC tells the assembler to turn direct calls into indirect calls, unless it can prove the target is within the range the call instruction allows ๐ŸŒˆ This usually happens for calls to functions in other source files ๐Ÿงš Specifically, the assembler swaps a direct CALL for an L32R followed by a CALLX instruction ๐Ÿ’… The default is -mno-longcalls ๐ŸŽ€ Use this option in programs where the call target might be out of range ๐Ÿ˜ญ Fun twist: this is handled in the assembler, not the compiler, so the assembly GCC generates still shows direct call instructions. Look at the disassembled object code to see what's actually running ๐Ÿ‘€ Also note that the assembler uses an indirect call for every cross-file call, not just the ones that really are out of range ๐Ÿ’€
  • -mabi=name โ€” generate code for the specified ABI ๐Ÿ‘‘ The permissible values are call0 and windowed โœจ If you don't pick one, the default ABI is chosen by the Xtensa core configuration ๐Ÿซถ
  • -mabi=call0 โ€” the main character ABI ๐Ÿ’œ 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__ is defined ๐ŸŒธ
  • -mabi=windowed โ€” the other main character ABI ๐Ÿฆ‹ 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 show up 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__ is defined โœจ

๐Ÿ’œ zSeries Options ๐Ÿ’œ

These are listed under

โœจ ENVIRONMENT โœจ

okay bestie, this is where GCC tells you which environment variables it's gonna listen to ๐Ÿ‘‘. some of them point it at directories or prefixes to hunt for files, and others tweak the whole compilation vibe ๐Ÿ’…

ngl you can also tell GCC where to search with options like -B, -I and -L. those take precedence over environment variables ๐Ÿซถ, and environment variables take precedence over whatever the GCC configuration says ๐Ÿ’–. main character energy for the flags, honestly.


LANG, LC_CTYPE, LC_MESSAGES, LC_ALL ๐ŸŒˆ

these are the localization ones ๐ŸŒ. they let GCC work with different national conventions. GCC looks at the locale categories LC_CTYPE and LC_MESSAGES if it's been configured to do that, and they can be set to any value your installation supports ๐Ÿงš. a typical value is en_GB.UTF-8 for English in the United Kingdom encoded in UTF-8.

  • LC_CTYPE โ€” character classification ๐Ÿ”ค. GCC uses it to figure out the character boundaries in a string. this matters for some multibyte encodings that have quote and escape characters that would otherwise get read as a string end or an escape ๐Ÿ˜ญ.
  • LC_MESSAGES โ€” picks the language for diagnostic messages ๐Ÿ’ฌ.
  • LC_ALL โ€” if it's set, it overrides LC_CTYPE and LC_MESSAGES ๐Ÿ‘‘. otherwise those two default to the value of LANG. if none of these are set, GCC defaults to traditional C English behavior ๐Ÿ™ˆ.

LANG (yes, again) ๐ŸŽ€

this one passes locale info to the compiler ๐Ÿ’…. one thing it's used for is deciding which character set to use when character literals, string literals and comments get parsed 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 ๐Ÿฆ‹.


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's gonna be the input for the next stage. for example, the output of the preprocessor is the input to the compiler proper.


GCC_COMPARE_DEBUG ๐Ÿ”

setting GCC_COMPARE_DEBUG is nearly the same as passing -fcompare-debug to the compiler driver โœจ. check out the docs for that option for the full tea.


GCC_EXEC_PREFIX ๐Ÿงš

if GCC_EXEC_PREFIX is set, it specifies a prefix to use in the names of the subprograms the compiler runs ๐Ÿš€. no slash gets added when the prefix is combined with a subprogram name, but you can totally end your prefix with a slash if you want one.

if GCC_EXEC_PREFIX isn't set, GCC tries to figure out an appropriate prefix based on the pathname it was invoked with ๐Ÿ”Ž. and if it can't find the subprogram using the prefix you gave it, it tries the usual places instead ๐Ÿ™.

the default value is prefix/lib/gcc/, where prefix is the prefix of the installed compiler. in lots of cases that prefix is whatever "prefix" was when you ran the configure script ๐Ÿ› ๏ธ.

prefixes given with -B take precedence over this one ๐Ÿ‘‘. this prefix is also used to find files like crt0.o that get used for linking ๐Ÿ”—.

here's the unusual bit ๐Ÿ˜ตโ€๐Ÿ’ซ: the prefix also gets used to find the directories to search for header files. for each standard directory whose name normally begins with /usr/local/lib/gcc (more precisely, with the value of GCC_INCLUDE_DIR), GCC tries swapping that beginning out for the specified prefix to make an alternate directory name. so with -Bfoo/, GCC searches foo/bar just before it searches the standard directory /usr/local/lib/bar. and if a standard directory begins with the configured prefix, the value of prefix gets replaced by GCC_EXEC_PREFIX when GCC looks for header files ๐Ÿคฏ.


COMPILER_PATH ๐Ÿ—บ๏ธ

the value is a colon-separated list of directories, kinda like PATH ๐Ÿ’–. GCC tries these directories when it's searching for subprograms, but only if it can't find them using GCC_EXEC_PREFIX.


LIBRARY_PATH ๐Ÿ“š

also a colon-separated list of directories, much like PATH ๐ŸŒˆ. when GCC is configured as a native compiler, it tries these directories when searching for special linker files, but only if it can't find them using GCC_EXEC_PREFIX. linking with GCC also checks these directories for ordinary libraries when you use the -l option, though directories given with -L come first ๐Ÿซถ.


GCC_EXTRA_DIAGNOSTIC_OUTPUT ๐Ÿ”ฅ

if this is set to one of the values below, extra text gets printed to stderr whenever fix-it hints get emitted ๐Ÿ’ฌ. -fdiagnostics-parseable-fixits and -fno-diagnostics-parseable-fixits take precedence over this env var, so they win if you use them.

  • fixits-v1 โ€” emits parseable fix-it hints, same as -fdiagnostics-parseable-fixits. columns are counted as a number of bytes, starting at byte 1 for the initial column ๐Ÿ”ข.
  • fixits-v2 โ€” same as fixits-v1, except columns are display columns, as per -fdiagnostics-column-unit=display ๐Ÿ“.

Some more environment variables affect the preprocessor's behavior ๐Ÿงš.


CPATH, C_INCLUDE_PATH, CPLUS_INCLUDE_PATH, OBJC_INCLUDE_PATH ๐Ÿ“‚

each of these is a list of directories, separated by a special character, kinda like PATH, and they're where GCC looks for header files ๐Ÿ’œ. that special character is called "PATH_SEPARATOR" and it's decided when GCC gets built. on Microsoft Windows-based targets it's a semicolon, and on almost every other target it's a colon.

CPATH is searched as if you'd passed -I, but after any -I paths on the command line ๐ŸŒธ. this one gets used no matter which language is being preprocessed.

the other three only apply when preprocessing the particular language they're named for ๐ŸŽ€. each one gets searched as if you'd passed -isystem, but 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 show up at the beginning or end of a path. for example, if the value of CPATH is ":/special/include", that has the same effect as -I. -I/special/include ๐Ÿฆ‹.


DEPENDENCIES_OUTPUT ๐Ÿงพ

if this is set, its value says how to output Make dependencies based on the non-system header files the compiler processed ๐Ÿ› ๏ธ. 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 have the form file target, in which case the rules get written to file using target as the target name ๐ŸŽฏ.

basically this env var is the same as combining -MM and -MF, with an optional -MT switch too ๐Ÿ’….


SUNPRO_DEPENDENCIES ๐ŸŒ™

this is the same as DEPENDENCIES_OUTPUT, except system header files are not ignored. so 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 that replaces the current date and time in the __DATE__ and __TIME__ macros ๐Ÿ•ฐ๏ธ. that way the embedded timestamps are reproducible ๐Ÿ’–.

the value has to be a UNIX timestamp, which is the number of seconds (not counting leap seconds) since 01 Jan 1970 00:00:00, written in ASCII. it's the same output as date +%s on GNU/Linux and other systems whose date command supports the %s extension โŒš.

the value should be a known timestamp, like the last modification time of the source or package, and it should be set by the build process ๐Ÿ› ๏ธ.


โœจ BUGS โœจ

for instructions on reporting bugs, check out <file:///usr/share/doc/gcc-12/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 โœจ

ok the reading list ๐Ÿ“–: 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 <https://gcc.gnu.org/onlinedocs/gcc/Contributors.html>, for all the contributors to GCC ๐Ÿซถ.


Copyright (c) 1988-2022 Free Software Foundation, Inc. ๐ŸŒˆ

permission is granted 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." ๐Ÿ’–


bestie, that's the whole ENVIRONMENT page ๐ŸŽ€ from gcc-12, dated 2022-02-22. you're literally so ready for compiling now ๐Ÿ’…โœจ

๐Ÿ“ฆ where this page comes from