GCC(1)

๐Ÿ“ฆ
version 10.5.0 ยท 3 versions
, in ubuntu jammy

๐ŸŒธ GCC(1) ยท GNU ๐ŸŒธ

Part 1 of 107. Bestie, this is the opening chunk, so the rest is coming! ๐Ÿ’–

โœจ NAME โœจ

gcc - GNU project C and C++ compiler. This is the GNU project's C and C++ compiler, the main character of this whole page ๐Ÿ‘‘.

โœจ SYNOPSIS โœจ

Okay, here's how the command is shaped:

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 here, so check below for the rest ๐Ÿ™ˆ. g++ accepts mostly the same options as gcc. ๐Ÿงš

โœจ DESCRIPTION โœจ

Okay so when you run GCC, it normally goes through the whole glow-up: preprocessing, compilation, assembly and linking ๐Ÿ’…. The "overall options" let you stop the process at an intermediate stage. For example, -c tells it not to run the linker, so the output is just the object files spat out by the assembler ๐Ÿฆ‹.

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

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

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

The gcc program takes options and file names as operands. Lots of options have multi-letter names, so you can't bunch up single-letter options together. -dv is very different from -d -v, so don't get it twisted ๐Ÿ’€.

You can mix options and other arguments, and for the most part the order doesn't matter. Order does matter when you use several options of the same kind. For example, if you specify -L more than once, the directories get searched in the order you gave them. The placement of the -l option is also significant ๐ŸŒˆ.

Lots of options have long names that start with -f or with -W---for. 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 is not the default ๐Ÿ”ฅ.

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

Arguments to options that set some kind 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 ๐ŸŒธ. The text calls these arguments byte-size from here on. For the full list and the actual 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 full tea on every option, grouped by type. The explanations come in the following sections ๐Ÿ’œ.

๐ŸŒธ Overall Options ๐ŸŒธ

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

๐ŸŒˆ C Language Options ๐ŸŒˆ

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

๐Ÿ’œ C++ Language Options ๐Ÿ’œ

-fabi-version=n  -fno-access-control -faligned-new=n
-fargs-in-order=n  -fchar8_t  -fcheck-new -fconstexpr-depth=n
-fconstexpr-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
-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 -Wabi-tag  -Wcatch-value  -Wcatch-value=n
-Wno-class-conversion  -Wclass-memaccess -Wcomma-subscript
-Wconditionally-supported -Wno-conversion-null  -Wctor-dtor-privacy
-Wno-delete-incomplete -Wdelete-non-virtual-dtor  -Wdeprecated-copy
-Wdeprecated-copy-dtor -Weffc++  -Wextra-semi
-Wno-inaccessible-base -Wno-inherited-variadic-ctor
-Wno-init-list-lifetime -Wno-invalid-offsetof  -Wno-literal-suffix
-Wmismatched-tags -Wmultiple-inheritance  -Wnamespaces  -Wnarrowing
-Wnoexcept  -Wnoexcept-type  -Wnon-virtual-dtor -Wpessimizing-move
-Wno-placement-new  -Wplacement-new=n -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  -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  -Wselector
-Wstrict-selector-match -Wundeclared-selector

๐Ÿซง Diagnostic Message Formatting Options ๐Ÿซง

-fmessage-length=n -fdiagnostics-show-location=[once|every-line]
-fdiagnostics-color=[auto|never|always]
-fdiagnostics-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

โœจ Warning Options โœจ

Okay bestie, this is the whole warning squad ๐Ÿšจ Every flag is kept whole and copy-paste ready ๐Ÿ’…

-fsyntax-only -fmax-errors=n -Wpedantic -pedantic-errors -w
-Wextra -Wall -Wabi=n -Waddress -Wno-address-of-packed-member
-Waggregate-return -Walloc-size-larger-than=byte-size -Walloc-zero
-Walloca -Walloca-larger-than=byte-size
-Wno-aggressive-loop-optimizations -Warith-conversion -Warray-bounds
-Warray-bounds=n -Wno-attributes -Wattribute-alias=n
-Wno-attribute-alias -Wno-attribute-warning -Wbool-compare
-Wbool-operation -Wno-builtin-declaration-mismatch
-Wno-builtin-macro-redefined -Wc90-c99-compat -Wc99-c11-compat
-Wc11-c2x-compat -Wc++-compat -Wc++11-compat -Wc++14-compat
-Wc++17-compat -Wc++20-compat -Wcast-align -Wcast-align=strict
-Wcast-function-type -Wcast-qual -Wchar-subscripts -Wclobbered
-Wcomment -Wconversion -Wno-coverage-mismatch -Wno-cpp
-Wdangling-else -Wdate-time -Wno-deprecated
-Wno-deprecated-declarations -Wno-designated-init
-Wdisabled-optimization -Wno-discarded-array-qualifiers
-Wno-discarded-qualifiers -Wno-div-by-zero -Wdouble-promotion
-Wduplicated-branches -Wduplicated-cond -Wempty-body
-Wno-endif-labels -Wenum-compare -Wenum-conversion -Werror
-Werror=* -Wexpansion-to-defined -Wfatal-errors -Wfloat-conversion
-Wfloat-equal -Wformat -Wformat=2 -Wno-format-contains-nul
-Wno-format-extra-args -Wformat-nonliteral -Wformat-overflow=n
-Wformat-security -Wformat-signedness -Wformat-truncation=n
-Wformat-y2k -Wframe-address -Wframe-larger-than=byte-size
-Wno-free-nonheap-object -Wno-hsa -Wno-if-not-aligned
-Wno-ignored-attributes -Wignored-qualifiers
-Wno-incompatible-pointer-types -Wimplicit -Wimplicit-fallthrough
-Wimplicit-fallthrough=n -Wno-implicit-function-declaration
-Wno-implicit-int -Winit-self -Winline -Wno-int-conversion
-Wint-in-bool-context -Wno-int-to-pointer-cast
-Wno-invalid-memory-model -Winvalid-pch -Wjump-misses-init
-Wlarger-than=byte-size -Wlogical-not-parentheses -Wlogical-op
-Wlong-long -Wno-lto-type-mismatch -Wmain -Wmaybe-uninitialized
-Wmemset-elt-size -Wmemset-transposed-args -Wmisleading-indentation
-Wmissing-attributes -Wmissing-braces -Wmissing-field-initializers
-Wmissing-format-attribute -Wmissing-include-dirs
-Wmissing-noreturn -Wno-missing-profile -Wno-multichar
-Wmultistatement-macros -Wnonnull -Wnonnull-compare
-Wnormalized=[none|id|nfc|nfkc] -Wnull-dereference -Wno-odr
-Wopenmp-simd -Wno-overflow -Woverlength-strings
-Wno-override-init-side-effects -Wpacked
-Wno-packed-bitfield-compat -Wpacked-not-aligned -Wpadded
-Wparentheses -Wno-pedantic-ms-format -Wpointer-arith
-Wno-pointer-compare -Wno-pointer-to-int-cast -Wno-pragmas
-Wno-prio-ctor-dtor -Wredundant-decls -Wrestrict
-Wno-return-local-addr -Wreturn-type -Wno-scalar-storage-order
-Wsequence-point -Wshadow -Wshadow=global -Wshadow=local
-Wshadow=compatible-local -Wno-shadow-ivar -Wno-shift-count-negative
-Wno-shift-count-overflow -Wshift-negative-value
-Wno-shift-overflow -Wshift-overflow=n -Wsign-compare
-Wsign-conversion -Wno-sizeof-array-argument -Wsizeof-pointer-div
-Wsizeof-pointer-memaccess -Wstack-protector -Wstack-usage=byte-size
-Wstrict-aliasing -Wstrict-aliasing=n -Wstrict-overflow
-Wstrict-overflow=n -Wstring-compare -Wstringop-overflow=n
-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
-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 ๐Ÿ”

Ooh, the static analyzer squad ๐Ÿ•ต๏ธโ€โ™€๏ธ Here's the full lineup, no cuts:

-fanalyzer -fanalyzer-call-summaries -fanalyzer-checker=name
-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-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-null-argument
-Wno-analyzer-null-dereference -Wno-analyzer-possible-null-argument
-Wno-analyzer-possible-null-dereference
-Wno-analyzer-stale-setjmp-buffer -Wno-analyzer-tainted-array-index
-Wanalyzer-too-complex
-Wno-analyzer-unsafe-call-within-signal-handler
-Wno-analyzer-use-after-free
-Wno-analyzer-use-of-pointer-in-stale-stack-frame
-Wno-analyzer-use-of-uninitialized-value

๐ŸŒธ C and Objective-C-only Warning Options ๐ŸŒธ

Next up, the C and Objective-C-only crew ๐ŸŒท These are kept exactly as they are:

-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 ๐Ÿ›

And last but not least, the debugging options ๐Ÿงš Bug hunting era, let's go ๐Ÿ”ฅ

-g -glevel -gdwarf -gdwarf-version -ggdb -grecord-gcc-switches
-gno-record-gcc-switches -gstabs -gstabs+ -gstrict-dwarf
-gno-strict-dwarf -gas-loc-support -gno-as-loc-support
-gas-locview-support -gno-as-locview-support -gcolumn-info
-gno-column-info -gstatement-frontiers -gno-statement-frontiers
-gvariable-location-views -gno-variable-location-views
-ginternal-reset-location-views -gno-internal-reset-location-views
-ginline-points -gno-inline-points -gvms -gxcoff -gxcoff+
-gz[=type] -gsplit-dwarf -gdescribe-dies -gno-describe-dies
-fdebug-prefix-map=old=new -fdebug-types-section
-fno-eliminate-unused-debug-types -femit-struct-debug-baseonly
-femit-struct-debug-reduced -femit-struct-debug-detailed[=spec-list]
-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 list is HUGE ๐Ÿ˜ญ๐Ÿ”ฅ the page just drops the names here with no notes, so these are the flags in their full glory ๐Ÿ’…

-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-cp  -fipa-cp-clone -fipa-bit-cp
-fipa-vrp  -fipa-pta  -fipa-profile  -fipa-pure-const
-fipa-reference  -fipa-reference-addressable -fipa-stack-alignment
-fipa-icf  -fira-algorithm=algorithm -flive-patching=level
-fira-region=region  -fira-hoist-pressure -fira-loop-pressure
-fno-ira-share-save-slots -fno-ira-share-spill-slots
-fisolate-erroneous-paths-dereference
-fisolate-erroneous-paths-attribute -fivopts
-fkeep-inline-functions  -fkeep-static-functions
-fkeep-static-consts  -flimit-function-alignment
-flive-range-shrinkage -floop-block  -floop-interchange
-floop-strip-mine -floop-unroll-and-jam  -floop-nest-optimize
-floop-parallelize-all  -flra-remat  -flto  -flto-compression-level
-flto-partition=alg  -fmerge-all-constants -fmerge-constants
-fmodulo-sched  -fmodulo-sched-allow-regmoves -fmove-loop-invariants
-fno-branch-count-reg -fno-defer-pop  -fno-fp-int-builtin-inexact
-fno-function-cse -fno-guess-branch-probability  -fno-inline
-fno-math-errno  -fno-peephole -fno-peephole2
-fno-printf-return-value  -fno-sched-interblock -fno-sched-spec
-fno-signed-zeros -fno-toplevel-reorder  -fno-trapping-math
-fno-zero-initialized-in-bss -fomit-frame-pointer
-foptimize-sibling-calls -fpartial-inlining  -fpeel-loops
-fpredictive-commoning -fprefetch-loop-arrays -fprofile-correction
-fprofile-use  -fprofile-use=path -fprofile-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
-fthread-jumps  -ftracer  -ftree-bit-ccp -ftree-builtin-call-dce
-ftree-ccp  -ftree-ch -ftree-coalesce-vars  -ftree-copy-prop
-ftree-dce  -ftree-dominator-opts -ftree-dse  -ftree-forwprop
-ftree-fre  -fcode-hoisting -ftree-loop-if-convert  -ftree-loop-im
-ftree-phiprop  -ftree-loop-distribution
-ftree-loop-distribute-patterns -ftree-loop-ivcanon
-ftree-loop-linear  -ftree-loop-optimize -ftree-loop-vectorize
-ftree-parallelize-loops=n  -ftree-pre  -ftree-partial-pre
-ftree-pta -ftree-reassoc  -ftree-scev-cprop  -ftree-sink
-ftree-slsr  -ftree-sra -ftree-switch-conversion  -ftree-tail-merge
-ftree-ter  -ftree-vectorize  -ftree-vrp  -funconstrained-commons
-funit-at-a-time  -funroll-all-loops  -funroll-loops
-funsafe-math-optimizations  -funswitch-loops -fipa-ra
-fvariable-expansion-in-unroller  -fvect-cost-model  -fvpt -fweb
-fwhole-program  -fwpa  -fuse-linker-plugin --param name=value -O
-O0  -O1  -O2  -O3  -Os  -Ofast  -Og

โœจ Program Instrumentation Options โœจ

the instrumentation crew is up next ๐Ÿงš same deal, just the names, served fresh ๐Ÿ“

-p  -pg  -fprofile-arcs  --coverage  -ftest-coverage
-fprofile-abs-path -fprofile-dir=path  -fprofile-generate
-fprofile-generate=path -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] -fstack-protector
-fstack-protector-all  -fstack-protector-strong
-fstack-protector-explicit  -fstack-check -fstack-limit-register=reg
-fstack-limit-symbol=sym -fno-stack-limit  -fsplit-stack
-fvtable-verify=[std|preinit|none] -fvtv-counts  -fvtv-debug
-finstrument-functions
-finstrument-functions-exclude-function-list=sym,sym,...
-finstrument-functions-exclude-file-list=file,file,...

โœจ Preprocessor Options โœจ

the preprocessor is giving main character energy ๐ŸŽ€ here's the whole cast:

-Aquestion=answer -A-question[=answer] -C  -CC  -Dmacro[=defn] -dD
-dI  -dM  -dN  -dU -fdebug-cpp  -fdirectives-only
-fdollars-in-identifiers -fexec-charset=charset
-fextended-identifiers -finput-charset=charset
-fmacro-prefix-map=old=new -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
-no-integrated-cpp  -P  -pthread  -remap -traditional
-traditional-cpp  -trigraphs -Umacro  -undef -Wp,option
-Xpreprocessor option

โœจ Assembler Options โœจ

short and sweet, the assembler only has two ๐Ÿซถ

-Wa,option  -Xassembler option

โœจ Linker Options โœจ

the linker is the final boss ๐Ÿ‘‘ and it has a LOT of options ๐Ÿ’€

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

โœจ Directory Options โœจ

where the compiler goes looking for stuff ๐Ÿฆ‹ the search-path squad:

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

โœจ Code Generation Options โœจ

this is where the code gets dressed up for the machine ๐Ÿ’–๐ŸŒˆ

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

for the debugging nerds ๐Ÿค“๐Ÿ’œ this section is absolutely packed, no cap:

-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 on the tour ๐ŸŒธ these ones depend on the target machine, so they vary by platform ๐Ÿงš

โœจ 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 bestie, this part is basically the roster of target-specific flags, grouped by chip. No explanations here, just the full lineup. ๐Ÿ’…

  • -mhalf-reg-file โ€” half-size register file ๐Ÿงš
  • -mprefer-short-insn-regs โ€” short-insn regs, please ๐Ÿ’…
  • -mbranch-cost=num โ€” branch cost with a number ๐Ÿ’–
  • -mcmove โ€” cmove, iconic โœจ
  • -mnops=num โ€” nops with a count ๐Ÿซถ
  • -msoft-cmpsf โ€” soft compare, single float ๐ŸŒธ
  • -msplit-lohi โ€” split lo and hi ๐Ÿฆ‹
  • -mpost-inc โ€” post-increment ๐Ÿ’œ
  • -mpost-modify โ€” post-modify ๐Ÿ”ฅ
  • -mstack-offset=num โ€” stack offset, numbered ๐Ÿงš
  • -mround-nearest โ€” round to nearest ๐Ÿ“
  • -mlong-calls โ€” long calls ๐Ÿ“ž
  • -mshort-calls โ€” short calls โญ
  • -msmall16 โ€” small16 vibes ๐Ÿ’…
  • -mfp-mode=mode โ€” FP mode, pick one ๐ŸŒˆ
  • -mvect-double โ€” vectorised doubles ๐Ÿ‘‘
  • -max-vect-align=num โ€” max vector alignment ๐ŸŽ€
  • -msplit-vecmove-early โ€” split vector moves early โฉ
  • -m1reg-reg โ€” one reg-reg ๐Ÿฆ‹

๐ŸŒˆ AMD GCN Options ๐ŸŒˆ

  • -march=gpu โ€” pick your GPU arch ๐Ÿ”ฅ
  • -mtune=gpu โ€” tune for a GPU ๐Ÿ’…
  • -mstack-size=bytes โ€” stack size, in bytes ๐Ÿ“

๐ŸŒธ ARC Options ๐ŸŒธ

  • -mbarrel-shifter โ€” barrel shifter ๐Ÿ›ž
  • -mjli-always โ€” JLI always โœจ
  • -mcpu=cpu โ€” pick a CPU ๐Ÿ’–
  • -mA6 โ€” A6 energy ๐Ÿงš
  • -mARC600 โ€” ARC600 ๐Ÿฆ‹
  • -mA7 โ€” A7 ๐ŸŒธ
  • -mARC700 โ€” ARC700 ๐Ÿ‘‘
  • -mdpfp โ€” double-precision FP ๐Ÿ”ฅ
  • -mdpfp-compact โ€” compact DPFP ๐Ÿ’œ
  • -mdpfp-fast โ€” fast DPFP โšก
  • -mno-dpfp-lrsr โ€” no DPFP LR/SR ๐Ÿ™ˆ
  • -mea โ€” extension aux ๐Ÿซถ
  • -mno-mpy โ€” no multiply ๐Ÿ’€
  • -mmul32x16 โ€” 32x16 multiply ๐ŸŒˆ
  • -mmul64 โ€” 64-bit multiply ๐Ÿ“
  • -matomic โ€” atomics ๐Ÿ’…
  • -mnorm โ€” normalise instruction ๐ŸŒธ
  • -mspfp โ€” single-precision FP ๐Ÿฆ‹
  • -mspfp-compact โ€” compact SPFP ๐Ÿ’–
  • -mspfp-fast โ€” fast SPFP โšก
  • -msimd โ€” SIMD ๐ŸŽ€
  • -msoft-float โ€” soft float ๐Ÿงš
  • -mswap โ€” swap instruction ๐Ÿ”„
  • -mcrc โ€” CRC ๐Ÿงฎ
  • -mdsp-packa โ€” DSP pack ๐Ÿ“ฆ
  • -mdvbf โ€” DVBF ๐ŸŒŸ
  • -mlock โ€” lock ๐Ÿ”’
  • -mmac-d16 โ€” MAC D16 ๐Ÿ’œ
  • -mmac-24 โ€” MAC 24 ๐Ÿ’œ
  • -mrtsc โ€” RTSC โฑ๏ธ
  • -mswape โ€” swap-and-escape vibes ๐ŸŒ€
  • -mtelephony โ€” telephony ๐Ÿ“ž
  • -mxy โ€” XY memory ๐Ÿ—บ๏ธ
  • -misize โ€” instruction size ๐Ÿ“
  • -mannotate-align โ€” annotate alignment ๐Ÿท๏ธ
  • -marclinux โ€” ARC Linux ๐Ÿง
  • -marclinux_prof โ€” ARC Linux, with profiling ๐Ÿ“Š
  • -mlong-calls โ€” long calls ๐Ÿ“ž
  • -mmedium-calls โ€” medium calls ๐Ÿ“ฑ
  • -msdata โ€” small data ๐Ÿ—ƒ๏ธ
  • -mirq-ctrl-saved โ€” IRQ control saved ๐Ÿ›ก๏ธ
  • -mrgf-banked-regs โ€” banked RGF regs ๐Ÿฆ
  • -mlpc-width=width โ€” LPC width, set it ๐Ÿ“
  • -G num โ€” small data threshold, numbered ๐Ÿ”ข
  • -mvolatile-cache โ€” volatile cache ๐ŸงŠ
  • -mtp-regno=regno โ€” TP register number ๐Ÿ”ข
  • -malign-call โ€” align calls ๐ŸŽฏ
  • -mauto-modify-reg โ€” auto-modify reg โœ๏ธ
  • -mbbit-peephole โ€” bbit peephole ๐Ÿ”
  • -mno-brcc โ€” no BRcc ๐Ÿ™…
  • -mcase-vector-pcrel โ€” PC-relative case vectors ๐Ÿงญ
  • -mcompact-casesi โ€” compact casesi ๐Ÿงฉ
  • -mno-cond-exec โ€” no conditional execution ๐Ÿ™…
  • -mearly-cbranchsi โ€” early cbranchsi โฉ
  • -mexpand-adddi โ€” expand adddi โž•
  • -mindexed-loads โ€” indexed loads ๐Ÿ“š
  • -mlra โ€” LRA ๐Ÿง 
  • -mlra-priority-none โ€” LRA priority: none ๐Ÿ™ˆ
  • -mlra-priority-compact โ€” LRA priority: compact ๐Ÿ—œ๏ธ
  • mlra-priority-noncompact โ€” LRA priority: noncompact ๐Ÿงท
  • -mmillicode โ€” millicode ๐Ÿœ
  • -mmixed-code โ€” mixed code ๐ŸŽญ
  • -mq-class โ€” q-class ๐Ÿท๏ธ
  • -mRcq โ€” Rcq ๐Ÿ…ฐ๏ธ
  • -mRcw โ€” Rcw ๐Ÿ…ฑ๏ธ
  • -msize-level=level โ€” size level, pick one ๐Ÿ“
  • -mtune=cpu โ€” tune for a CPU ๐ŸŽ›๏ธ
  • -mmultcost=num โ€” multiply cost, numbered ๐Ÿ’ฐ
  • -mcode-density-frame โ€” code density frame ๐Ÿ–ผ๏ธ
  • -munalign-prob-threshold=probability โ€” unaligned probability threshold ๐ŸŽฒ
  • -mmpy-option=multo โ€” MPY option, multo ๐Ÿงฎ
  • -mdiv-rem โ€” divide and remainder โž—
  • -mcode-density โ€” code density ๐Ÿ—œ๏ธ
  • -mll64 โ€” 64-bit long long ๐Ÿ”ข
  • -mfpu=fpu โ€” pick an FPU ๐Ÿง 
  • -mrf16 โ€” 16-register file ๐Ÿงบ
  • -mbranch-index โ€” branch index ๐Ÿงญ

๐Ÿฆ‹ ARM Options ๐Ÿฆ‹

  • -mapcs-frame โ€” APCS frame ๐Ÿ–ผ๏ธ
  • -mno-apcs-frame โ€” no APCS frame ๐Ÿ™…
  • -mabi=name โ€” pick an ABI ๐Ÿท๏ธ
  • -mapcs-stack-check โ€” APCS stack check ๐Ÿ›‘
  • -mno-apcs-stack-check โ€” no APCS stack check ๐Ÿ™…
  • -mapcs-reentrant โ€” APCS reentrant ๐Ÿ”
  • -mno-apcs-reentrant โ€” no APCS reentrant ๐Ÿ™…
  • -mgeneral-regs-only โ€” general regs only ๐Ÿงบ
  • -msched-prolog โ€” scheduled prolog ๐Ÿ“…
  • -mno-sched-prolog โ€” no scheduled prolog ๐Ÿ™…
  • -mlittle-endian โ€” little endian ๐Ÿ’œ
  • -mbig-endian โ€” big endian ๐Ÿ’™
  • -mbe8 โ€” BE8 ๐Ÿงฉ
  • -mbe32 โ€” BE32 ๐Ÿงฉ
  • -mfloat-abi=name โ€” float ABI, pick one ๐Ÿ”ข
  • -mfp16-format=name โ€” FP16 format, pick one ๐Ÿท๏ธ
  • -mthumb-interwork โ€” Thumb interwork ๐Ÿค
  • -mno-thumb-interwork โ€” no Thumb interwork ๐Ÿ™…
  • -mcpu=name โ€” pick a CPU ๐Ÿ’–
  • -march=name โ€” pick an arch ๐Ÿ—๏ธ
  • -mfpu=name โ€” pick an FPU ๐Ÿง 
  • -mtune=name โ€” tune for a name ๐ŸŽ›๏ธ
  • -mprint-tune-info โ€” print tune info ๐Ÿ–จ๏ธ
  • -mstructure-size-boundary=n โ€” structure size boundary, numbered ๐Ÿ“
  • -mabort-on-noreturn โ€” abort on noreturn ๐Ÿšจ
  • -mlong-calls โ€” long calls ๐Ÿ“ž
  • -mno-long-calls โ€” no long calls ๐Ÿ™…
  • -msingle-pic-base โ€” single PIC base ๐ŸŽฏ
  • -mno-single-pic-base โ€” no single PIC base ๐Ÿ™…
  • -mpic-register=reg โ€” PIC register, pick one ๐Ÿ“Œ
  • -mnop-fun-dllimport โ€” nop for dllimport functions ๐Ÿ’ค
  • -mpoke-function-name โ€” poke function name ๐Ÿ‘‰
  • -mthumb โ€” Thumb ๐Ÿงต
  • -marm โ€” ARM mode ๐Ÿ’ช
  • -mflip-thumb โ€” flip Thumb ๐Ÿ”€
  • -mtpcs-frame โ€” TPCS frame ๐Ÿ–ผ๏ธ
  • -mtpcs-leaf-frame โ€” TPCS leaf frame ๐Ÿƒ
  • -mcaller-super-interworking โ€” caller super interworking ๐Ÿค
  • -mcallee-super-interworking โ€” callee super interworking ๐Ÿค
  • -mtp=name โ€” TP, pick a name ๐Ÿงต
  • -mtls-dialect=dialect โ€” TLS dialect, pick one ๐Ÿ—ฃ๏ธ
  • -mword-relocations โ€” word relocations ๐Ÿงฉ
  • -mfix-cortex-m3-ldrd โ€” fix Cortex-M3 LDRD ๐Ÿฉน
  • -munaligned-access โ€” unaligned access ๐Ÿซจ
  • -mneon-for-64bits โ€” NEON for 64-bit ops ๐ŸŽถ
  • -mslow-flash-data โ€” slow flash data ๐Ÿข
  • -masm-syntax-unified โ€” unified assembler syntax ๐Ÿ“œ
  • -mrestrict-it โ€” restrict IT ๐Ÿšง
  • -mverbose-cost-dump โ€” verbose cost dump ๐Ÿ—’๏ธ
  • -mpure-code โ€” pure code ๐Ÿงผ
  • -mcmse โ€” CMSE ๐Ÿ”
  • -mfix-cmse-cve-2021-35465 โ€” fix CMSE CVE-2021-35465 ๐Ÿฉน
  • -mfdpic โ€” FDPIC ๐Ÿงฉ

๐Ÿ AVR Options ๐Ÿ

  • -mmcu=mcu โ€” pick an MCU ๐Ÿ”Œ
  • -mabsdata โ€” absolute data ๐Ÿ“
  • -maccumulate-args โ€” accumulate args ๐Ÿงบ
  • -mbranch-cost=cost โ€” branch cost, with a value ๐Ÿ’ฐ
  • -mcall-prologues โ€” call prologues ๐Ÿ“ž
  • -mgas-isr-prologues โ€” GAS ISR prologues โšก
  • -mint8 โ€” 8-bit int ๐Ÿ”ข
  • -mdouble=bits โ€” double width, in bits ๐Ÿ“
  • -mlong-double=bits โ€” long double width, in bits ๐Ÿ“
  • -mn_flash=size โ€” flash size, set it ๐Ÿ’พ
  • -mno-interrupts โ€” no interrupts ๐Ÿ™…
  • -mmain-is-OS_task โ€” main is an OS task ๐Ÿง 
  • -mrelax โ€” relax ๐Ÿง˜
  • -mrmw โ€” read-modify-write ๐Ÿ”
  • -mstrict-X โ€” strict X register ๐Ÿ…ง
  • -mtiny-stack โ€” tiny stack ๐Ÿค
  • -mfract-convert-truncate โ€” fract convert truncate โœ‚๏ธ
  • -mshort-calls โ€” short calls โญ
  • -nodevicelib โ€” no device library ๐Ÿšซ
  • -nodevicespecs โ€” no device specs ๐Ÿšซ
  • -Waddr-space-convert โ€” warn on address-space convert โš ๏ธ
  • -Wmisspelled-isr โ€” warn on misspelled ISR โš ๏ธ

๐Ÿ’™ Blackfin Options ๐Ÿ’™

  • -mcpu=cpu[-sirevision] โ€” CPU, with optional SI revision ๐Ÿ”ข
  • -msim โ€” simulator ๐ŸŽฎ
  • -momit-leaf-frame-pointer โ€” omit leaf frame pointer ๐Ÿƒ
  • -mno-omit-leaf-frame-pointer โ€” keep leaf frame pointer ๐Ÿ™…
  • -mspecld-anomaly โ€” specld anomaly ๐Ÿฉน
  • -mno-specld-anomaly โ€” no specld anomaly ๐Ÿ™…
  • -mcsync-anomaly โ€” csync anomaly ๐Ÿฉน
  • -mno-csync-anomaly โ€” no csync anomaly ๐Ÿ™…
  • -mlow-64k โ€” low 64K ๐Ÿงฑ
  • -mno-low64k โ€” no low 64K ๐Ÿ™…
  • -mstack-check-l1 โ€” stack check L1 ๐Ÿ›‘
  • -mid-shared-library โ€” ID shared library ๐Ÿ“š
  • -mno-id-shared-library โ€” no ID shared library ๐Ÿ™…
  • -mshared-library-id=n โ€” shared library ID, numbered ๐Ÿ”ข
  • -mleaf-id-shared-library โ€” leaf ID shared library ๐Ÿƒ
  • -mno-leaf-id-shared-library โ€” no leaf ID shared library ๐Ÿ™…
  • -msep-data โ€” separate data ๐Ÿ—‚๏ธ
  • -mno-sep-data โ€” no separate data ๐Ÿ™…
  • -mlong-calls โ€” long calls ๐Ÿ“ž
  • -mno-long-calls โ€” no long calls ๐Ÿ™…
  • -mfast-fp โ€” fast FP ๐Ÿš€
  • -minline-plt โ€” inline PLT ๐Ÿงต
  • -mmulticore โ€” multicore ๐Ÿงฉ
  • -mcorea โ€” core A ๐Ÿ…ฐ๏ธ
  • -mcoreb โ€” core B ๐Ÿ…ฑ๏ธ
  • -msdram โ€” SDRAM ๐Ÿง 
  • -micplb โ€” ICPLB ๐Ÿงท

๐ŸŒŸ C6X Options ๐ŸŒŸ

  • -mbig-endian โ€” big endian ๐Ÿ’™
  • -mlittle-endian โ€” little endian ๐Ÿ’œ
  • -march=cpu โ€” pick an arch ๐Ÿ—๏ธ
  • -msim โ€” simulator ๐ŸŽฎ
  • -msdata=sdata-type โ€” small data type, pick one ๐Ÿ—ƒ๏ธ

๐Ÿงš CRIS Options ๐Ÿงš

  • -mcpu=cpu โ€” pick a CPU ๐Ÿ’–
  • -march=cpu โ€” pick an arch ๐Ÿ—๏ธ
  • -mtune=cpu โ€” tune for a CPU ๐ŸŽ›๏ธ
  • -mmax-stack-frame=n โ€” max stack frame, numbered ๐Ÿ“
  • -melinux-stacksize=n โ€” Linux stack size, numbered ๐Ÿ“š
  • -metrax4 โ€” ETRAX 4 ๐Ÿง“
  • -metrax100 โ€” ETRAX 100 ๐Ÿ’ฏ
  • -mpdebug โ€” debug ๐Ÿ›
  • -mcc-init โ€” CC init ๐Ÿงน
  • -mno-side-effects โ€” no side effects ๐Ÿ™…
  • -mstack-align โ€” stack align ๐Ÿ“
  • -mdata-align โ€” data align ๐Ÿ“
  • -mconst-align โ€” const align ๐Ÿ“
  • -m32-bit โ€” 32-bit ๐Ÿ”ข
  • -m16-bit โ€” 16-bit ๐Ÿ”ข
  • -m8-bit โ€” 8-bit ๐Ÿ”ข
  • -mno-prologue-epilogue โ€” no prologue or epilogue ๐Ÿ™…
  • -mno-gotplt โ€” no GOTPLT ๐Ÿ™…
  • -melf โ€” ELF ๐Ÿงฉ
  • -maout โ€” a.out ๐Ÿ—ฟ
  • -melinux โ€” Linux ๐Ÿง
  • -mlinux โ€” Linux ๐Ÿง
  • -sim โ€” simulator ๐ŸŽฎ
  • -sim2 โ€” simulator 2 ๐ŸŽฎ
  • -mmul-bug-workaround โ€” multiply bug workaround ๐Ÿฉน
  • -mno-mul-bug-workaround โ€” no multiply bug workaround ๐Ÿ™…

๐ŸŽ€ CR16 Options ๐ŸŽ€

  • -mmac โ€” MAC ๐Ÿ’œ
  • -mcr16cplus โ€” CR16C+ ๐Ÿง 
  • -mcr16c โ€” CR16C ๐Ÿงฉ
  • -msim โ€” simulator ๐ŸŽฎ
  • -mint32 โ€” 32-bit int ๐Ÿ”ข
  • -mbit-ops โ€” bit ops ๐Ÿงฎ
  • -mdata-model=model โ€” data model, pick one ๐Ÿ—‚๏ธ

๐ŸŒฟ C-SKY Options ๐ŸŒฟ

  • -march=arch โ€” pick an arch ๐Ÿ—๏ธ
  • -mcpu=cpu โ€” pick a CPU ๐Ÿ’–
  • -mbig-endian โ€” big endian ๐Ÿ’™
  • -EB โ€” big endian, the short way ๐Ÿ’™
  • -mlittle-endian โ€” little endian ๐Ÿ’œ
  • -EL โ€” little endian, the short way ๐Ÿ’œ
  • -mhard-float โ€” hard float ๐Ÿ”ฅ
  • -msoft-float โ€” soft float ๐Ÿงš
  • -mfpu=fpu โ€” pick an FPU ๐Ÿง 
  • -mdouble-float โ€” double float ๐Ÿฆ‹
  • -mfdivdu โ€” FDIVDU โž—
  • -melrw โ€” ELRW ๐Ÿ”
  • -mistack โ€” ISTACK ๐Ÿ“š
  • -mmp โ€” MP ๐Ÿงต
  • -mcp โ€” CP ๐Ÿงฉ
  • -mcache โ€” cache ๐ŸงŠ
  • -msecurity โ€” security ๐Ÿ”
  • -mtrust โ€” trust ๐Ÿค
  • -mdsp โ€” DSP ๐ŸŽถ
  • -medsp โ€” EDSP ๐ŸŽถ
  • -mvdsp โ€” VDSP ๐ŸŽถ
  • -mdiv โ€” divide โž—
  • -msmart โ€” smart ๐Ÿง 
  • -mhigh-registers โ€” high registers ๐Ÿš€
  • -manchor โ€” anchor โš“
  • -mpushpop โ€” push and pop ๐Ÿ“ฅ
  • -mmultiple-stld โ€” multiple load/store ๐Ÿ“ฆ
  • -mconstpool โ€” constant pool ๐ŸŠ
  • -mstack-size โ€” stack size ๐Ÿ“
  • -mccrt โ€” CCRT ๐Ÿงฉ
  • -mbranch-cost=n โ€” branch cost, numbered ๐Ÿ’ฐ
  • -mcse-cc โ€” CSE CC ๐Ÿงน
  • -msched-prolog โ€” scheduled prolog ๐Ÿ“…

๐ŸŽ Darwin Options ๐ŸŽ

  • -all_load โ€” load everything ๐Ÿ“ฆ
  • -allowable_client โ€” allowable client ๐Ÿง‘โ€๐Ÿคโ€๐Ÿง‘
  • -arch โ€” arch ๐Ÿ—๏ธ
  • -arch_errors_fatal โ€” arch errors are fatal ๐Ÿ’€
  • -arch_only โ€” arch only ๐ŸŽฏ
  • -bind_at_load โ€” bind at load ๐Ÿ”—
  • -bundle โ€” bundle ๐Ÿงบ
  • -bundle_loader โ€” bundle loader ๐Ÿงบ
  • -client_name โ€” client name ๐Ÿท๏ธ
  • -compatibility_version โ€” compatibility version ๐Ÿ”ข
  • -current_version โ€” current version ๐Ÿ”ข
  • -dead_strip โ€” dead strip โœ‚๏ธ
  • -dependency-file โ€” dependency file ๐Ÿ“„
  • -dylib_file โ€” dylib file ๐Ÿ“š
  • -dylinker_install_name โ€” dylinker install name ๐Ÿท๏ธ
  • -dynamic โ€” dynamic โšก
  • -dynamiclib โ€” dynamic lib ๐Ÿ“š
  • -exported_symbols_list โ€” exported symbols list ๐Ÿ“œ
  • -filelist โ€” file list ๐Ÿ“ƒ
  • -flat_namespace โ€” flat namespace ๐Ÿ—บ๏ธ
  • -force_cpusubtype_ALL โ€” force CPU subtype ALL ๐Ÿ’ช
  • -force_flat_namespace โ€” force flat namespace ๐Ÿ—บ๏ธ
  • -headerpad_max_install_names โ€” header pad for max install names ๐Ÿงท
  • -iframework โ€” include framework ๐Ÿงฑ
  • -image_base โ€” image base ๐Ÿ–ผ๏ธ
  • -init โ€” init ๐ŸŒฑ
  • -install_name โ€” install name ๐Ÿท๏ธ
  • -keep_private_externs โ€” keep private externs ๐Ÿ”’
  • -multi_module โ€” multi module ๐Ÿงฉ
  • -multiply_defined โ€” multiply defined ๐ŸŒ€
  • -multiply_defined_unused โ€” multiply defined, unused ๐ŸŒ€
  • -noall_load โ€” no load-all ๐Ÿ™…
  • -no_dead_strip_inits_and_terms โ€” no dead strip for inits and terms ๐Ÿ™…
  • -nofixprebinding โ€” no fix prebinding ๐Ÿ™…
  • -nomultidefs โ€” no multidefs ๐Ÿ™…
  • -noprebind โ€” no prebind ๐Ÿ™…
  • -noseglinkedit โ€” no segment linkedit ๐Ÿ™…
  • -pagezero_size โ€” page zero size ๐Ÿ“
  • -prebind โ€” prebind ๐Ÿ”—
  • -prebind_all_twolevel_modules โ€” prebind all two-level modules ๐Ÿ”—
  • -private_bundle โ€” private bundle ๐Ÿ”’
  • -read_only_relocs โ€” read-only relocs ๐Ÿ“–
  • -sectalign โ€” section align ๐Ÿ“
  • -sectobjectsymbols โ€” section object symbols ๐Ÿงพ
  • -whyload โ€” why load โ“
  • -seg1addr โ€” seg1 address ๐Ÿ“
  • -sectcreate โ€” section create ๐Ÿ› ๏ธ
  • -sectobjectsymbols โ€” section object symbols ๐Ÿงพ
  • -sectorder โ€” section order ๐Ÿ“‹
  • -segaddr โ€” segment address ๐Ÿ“
  • -segs_read_only_addr โ€” read-only segment address ๐Ÿ“
  • -segs_read_write_addr โ€” read-write segment address ๐Ÿ“
  • -seg_addr_table โ€” segment address table ๐Ÿ—‚๏ธ
  • -seg_addr_table_filename โ€” segment address table filename ๐Ÿ“„
  • -seglinkedit โ€” segment linkedit ๐Ÿ”—
  • -segprot โ€” segment protection ๐Ÿ›ก๏ธ
  • -segs_read_only_addr โ€” read-only segment address ๐Ÿ“
  • -segs_read_write_addr โ€” read-write segment address ๐Ÿ“
  • -single_module โ€” single module ๐Ÿงฑ
  • -static โ€” static ๐ŸงŠ
  • -sub_library โ€” sub library ๐Ÿ“š
  • -sub_umbrella โ€” sub umbrella โ˜‚๏ธ
  • -twolevel_namespace โ€” two-level namespace ๐Ÿ—บ๏ธ
  • -umbrella โ€” umbrella โ˜‚๏ธ
  • -undefined โ€” undefined โ“
  • -unexported_symbols_list โ€” unexported symbols list ๐Ÿ“œ
  • -weak_reference_mismatches โ€” weak reference mismatches โš ๏ธ
  • -whatsloaded โ€” what's loaded ๐Ÿ”
  • -F โ€” framework path ๐Ÿ“‚
  • -gused โ€” debug, only used ๐Ÿ›
  • -gfull โ€” full debug ๐Ÿ›
  • -mmacosx-version-min=version โ€” minimum macOS version ๐Ÿ
  • -mkernel โ€” kernel ๐Ÿง 
  • -mone-byte-bool โ€” one-byte bool ๐Ÿ”ข

๐Ÿงก DEC Alpha Options ๐Ÿงก

  • -mno-fp-regs โ€” no FP regs ๐Ÿ™…
  • -msoft-float โ€” soft float ๐Ÿงš
  • -mieee โ€” IEEE ๐Ÿงฎ
  • -mieee-with-inexact โ€” IEEE with inexact ๐Ÿงฎ
  • -mieee-conformant โ€” IEEE conformant โœ…
  • -mfp-trap-mode=mode โ€” FP trap mode, pick one ๐Ÿชค
  • -mfp-rounding-mode=mode โ€” FP rounding mode, pick one ๐Ÿ”
  • -mtrap-precision=mode โ€” trap precision, pick one ๐ŸŽฏ
  • -mbuild-constants โ€” build constants ๐Ÿงฑ
  • -mcpu=cpu-type โ€” pick a CPU type ๐Ÿ’–
  • -mtune=cpu-type โ€” tune for a CPU type ๐ŸŽ›๏ธ
  • -mbwx โ€” BWX ๐Ÿ”ข
  • -mmax โ€” MAX ๐Ÿ“ˆ
  • -mfix โ€” FIX ๐Ÿฉน
  • -mcix โ€” CIX ๐Ÿ”ข
  • -mfloat-vax โ€” VAX float ๐Ÿฆ•
  • -mfloat-ieee โ€” IEEE float ๐Ÿงฎ
  • -mexplicit-relocs โ€” explicit relocs ๐Ÿงฉ
  • -msmall-data โ€” small data ๐Ÿ—ƒ๏ธ
  • -mlarge-data โ€” large data ๐Ÿ—„๏ธ
  • -msmall-text โ€” small text ๐Ÿ“
  • -mlarge-text โ€” large text ๐Ÿ“š
  • -mmemory-latency=time โ€” memory latency, set the time โฑ๏ธ

๐Ÿš eBPF Options ๐Ÿš

  • -mbig-endian โ€” big endian ๐Ÿ’™
  • -mlittle-endian โ€” little endian ๐Ÿ’œ
  • -mkernel=version โ€” kernel version ๐Ÿง 
  • -mframe-limit=bytes โ€” frame limit, in bytes ๐Ÿ“
  • -mxbpf โ€” XBPF ๐Ÿงฉ

๐ŸŒ™ FR30 Options ๐ŸŒ™

  • -msmall-model โ€” small model ๐Ÿค
  • -mno-lsim โ€” no LSIM ๐Ÿ™…

๐Ÿช FT32 Options ๐Ÿช

  • -msim โ€” simulator ๐ŸŽฎ
  • -mlra โ€” LRA ๐Ÿง 
  • -mnodiv โ€” no divide ๐Ÿ™…
  • -mft32b โ€” FT32B ๐Ÿงฉ
  • -mcompress โ€” compress ๐Ÿ—œ๏ธ
  • -mnopm โ€” no PM ๐Ÿ™…

๐Ÿฆ„ FRV Options ๐Ÿฆ„

  • -mgpr-32 โ€” 32 GPRs ๐Ÿ”ข
  • -mgpr-64 โ€” 64 GPRs ๐Ÿ”ข
  • -mfpr-32 โ€” 32 FPRs ๐Ÿ”ข
  • -mfpr-64 โ€” 64 FPRs ๐Ÿ”ข
  • -mhard-float โ€” hard float ๐Ÿ”ฅ
  • -msoft-float โ€” soft float ๐Ÿงš
  • -malloc-cc โ€” allocate CC ๐Ÿง 
  • -mfixed-cc โ€” fixed CC ๐Ÿ“Œ
  • -mdword โ€” doubleword ๐Ÿ”ข
  • -mno-dword โ€” no doubleword ๐Ÿ™…
  • -mdouble โ€” double ๐Ÿฆ‹
  • -mno-double โ€” no double ๐Ÿ™…
  • -mmedia โ€” media ๐ŸŽถ
  • -mno-media โ€” no media ๐Ÿ™…
  • -mmuladd โ€” multiply-add โž•
  • -mno-muladd โ€” no multiply-add ๐Ÿ™…
  • -mfdpic โ€” FDPIC ๐Ÿงฉ
  • -minline-plt โ€” inline PLT ๐Ÿงต
  • -mgprel-ro โ€” GP-relative read-only ๐Ÿ“–
  • -multilib-library-pic โ€” multilib library PIC ๐Ÿ“š
  • -mlinked-fp โ€” linked FP ๐Ÿ”—
  • -mlong-calls โ€” long calls ๐Ÿ“ž
  • -malign-labels โ€” align labels ๐ŸŽฏ
  • -mlibrary-pic โ€” library PIC ๐Ÿ“š
  • -macc-4 โ€” 4 accumulators ๐Ÿ”ข
  • -macc-8 โ€” 8 accumulators ๐Ÿ”ข
  • -mpack โ€” pack ๐Ÿ“ฆ
  • -mno-pack โ€” no pack ๐Ÿ™…
  • -mno-eflags โ€” no eflags ๐Ÿ™…
  • -mcond-move โ€” conditional move ๐Ÿƒ
  • -mno-cond-move โ€” no conditional move ๐Ÿ™…
  • -moptimize-membar โ€” optimise membar ๐Ÿงน
  • -mno-optimize-membar โ€” no membar optimisation ๐Ÿ™…
  • -mscc โ€” SCC ๐Ÿง 
  • -mno-scc โ€” no SCC ๐Ÿ™…
  • -mcond-exec โ€” conditional execution ๐Ÿƒ
  • -mno-cond-exec โ€” no conditional execution ๐Ÿ™…
  • -mvliw-branch โ€” VLIW branch ๐Ÿงฉ
  • -mno-vliw-branch โ€” no VLIW branch ๐Ÿ™…
  • -mmulti-cond-exec โ€” multi conditional execution ๐Ÿƒ
  • -mno-multi-cond-exec โ€” no multi conditional execution ๐Ÿ™…
  • -mnested-cond-exec โ€” nested conditional execution ๐Ÿช†
  • -mno-nested-cond-exec โ€” no nested conditional execution ๐Ÿ™…
  • -mtomcat-stats โ€” Tomcat stats ๐Ÿ“Š
  • -mTLS โ€” TLS ๐Ÿงต
  • -mtls โ€” TLS ๐Ÿงต
  • -mcpu=cpu โ€” pick a CPU ๐Ÿ’–

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

  • -mglibc โ€” glibc ๐Ÿ“š
  • -muclibc โ€” uClibc ๐Ÿ“š
  • -mmusl โ€” musl ๐Ÿ“š
  • -mbionic โ€” Bionic ๐Ÿค–
  • -mandroid โ€” Android ๐Ÿค–
  • -tno-android-cc โ€” no Android CC ๐Ÿ™…
  • -tno-android-ld โ€” no Android LD ๐Ÿ™…

๐ŸŒบ H8/300 Options ๐ŸŒบ

  • -mrelax โ€” relax ๐Ÿง˜
  • -mh โ€” H ๐Ÿ…ท
  • -ms โ€” S ๐Ÿ…ข
  • -mn โ€” N ๐Ÿ…
  • -mexr โ€” EXR ๐Ÿงฉ
  • -mno-exr โ€” no EXR ๐Ÿ™…
  • -mint32 โ€” 32-bit int ๐Ÿ”ข
  • -malign-300 โ€” align 300 ๐Ÿ“

๐Ÿฐ HPPA Options ๐Ÿฐ

  • -march=architecture-type โ€” pick an architecture type ๐Ÿ—๏ธ
  • -mcaller-copies โ€” caller copies ๐Ÿ“‹
  • -mdisable-fpregs โ€” disable FP regs ๐Ÿšซ
  • -mdisable-indexing โ€” disable indexing ๐Ÿšซ
  • -mfast-indirect-calls โ€” fast indirect calls ๐Ÿš€
  • -mgas โ€” GAS ๐Ÿงต
  • -mgnu-ld โ€” GNU LD ๐Ÿƒ
  • -mhp-ld โ€” HP LD ๐Ÿข
  • -mfixed-range=register-range โ€” fixed register range ๐Ÿ“Œ
  • -mjump-in-delay โ€” jump in delay slot ๐Ÿฆ˜
  • -mlinker-opt โ€” linker optimisation ๐Ÿงน
  • -mlong-calls โ€” long calls ๐Ÿ“ž
  • -mlong-load-store โ€” long load and store ๐Ÿ“ฆ
  • -mno-disable-fpregs โ€” don't disable FP regs ๐Ÿ™…
  • -mno-disable-indexing โ€” don't disable indexing ๐Ÿ™…
  • -mno-fast-indirect-calls โ€” no fast indirect calls ๐Ÿ™…
  • -mno-gas โ€” no GAS ๐Ÿ™…
  • -mno-jump-in-delay โ€” no jump in delay slot ๐Ÿ™…
  • -mno-long-load-store โ€” no long load and store ๐Ÿ™…
  • -mno-portable-runtime โ€” no portable runtime ๐Ÿ™…
  • -mno-soft-float โ€” no soft float ๐Ÿ™…
  • -mno-space-regs โ€” no space regs ๐Ÿ™…
  • -msoft-float โ€” soft float ๐Ÿงš
  • -mpa-risc-1-0 โ€” PA-RISC 1.0 ๐Ÿง“
  • -mpa-risc-1-1 โ€” PA-RISC 1.1 ๐Ÿง“
  • -mpa-risc-2-0 โ€” PA-RISC 2.0 ๐Ÿง 
  • -mportable-runtime โ€” portable runtime ๐Ÿงณ
  • -mschedule=cpu-type โ€” schedule for a CPU type ๐Ÿ—“๏ธ
  • -mspace-regs โ€” space regs ๐ŸŒŒ
  • -msio โ€” SIO ๐Ÿ”Œ
  • -mwsio โ€” WSIO ๐Ÿ”Œ
  • -munix=unix-std โ€” UNIX standard ๐Ÿง
  • -nolibdld โ€” no libdld ๐Ÿšซ
  • -static โ€” static ๐ŸงŠ
  • -threads โ€” threads ๐Ÿงต

๐Ÿ”๏ธ IA-64 Options ๐Ÿ”๏ธ

  • -mbig-endian โ€” big endian ๐Ÿ’™
  • -mlittle-endian โ€” little endian ๐Ÿ’œ
  • -mgnu-as โ€” GNU as ๐Ÿงต
  • -mgnu-ld โ€” GNU LD ๐Ÿƒ
  • -mno-pic โ€” no PIC ๐Ÿ™…
  • -mvolatile-asm-stop โ€” volatile asm stop ๐Ÿ›‘
  • -mregister-names โ€” register names ๐Ÿท๏ธ
  • -msdata โ€” small data ๐Ÿ—ƒ๏ธ
  • -mno-sdata โ€” no small data ๐Ÿ™…
  • -mconstant-gp โ€” constant GP ๐Ÿ“Œ
  • -mauto-pic โ€” auto PIC ๐Ÿค–
  • -mfused-madd โ€” fused multiply-add โž•
  • -minline-float-divide-min-latency โ€” inline float divide, min latency โฑ๏ธ
  • -minline-float-divide-max-throughput โ€” inline float divide, max throughput ๐Ÿšš
  • -mno-inline-float-divide โ€” no inline float divide ๐Ÿ™…
  • -minline-int-divide-min-latency โ€” inline int divide, min latency โฑ๏ธ
  • -minline-int-divide-max-throughput โ€” inline int divide, max throughput ๐Ÿšš
  • -mno-inline-int-divide โ€” no inline int divide ๐Ÿ™…
  • -minline-sqrt-min-latency โ€” inline sqrt, min latency โฑ๏ธ
  • -minline-sqrt-max-throughput โ€” inline sqrt, max throughput ๐Ÿšš
  • -mno-inline-sqrt โ€” no inline sqrt ๐Ÿ™…
  • -mdwarf2-asm โ€” DWARF2 asm ๐Ÿ›
  • -mearly-stop-bits โ€” early stop bits โน๏ธ
  • -mfixed-range=register-range โ€” fixed register range ๐Ÿ“Œ
  • -mtls-size=tls-size โ€” TLS size ๐Ÿ“
  • -mtune=cpu-type โ€” tune for a CPU type ๐ŸŽ›๏ธ
  • -milp32 โ€” ILP32 ๐Ÿ”ข
  • -mlp64 โ€” LP64 ๐Ÿ”ข
  • -msched-br-data-spec โ€” scheduling branch data speculation ๐Ÿ—“๏ธ
  • -msched-ar-data-spec โ€” scheduling AR data speculation ๐Ÿ—“๏ธ
  • -msched-control-spec โ€” scheduling control speculation ๐Ÿ—“๏ธ
  • -msched-br-in-data-spec โ€” scheduling branch in data speculation ๐Ÿ—“๏ธ
  • -msched-ar-in-data-spec โ€” scheduling AR in data speculation ๐Ÿ—“๏ธ
  • -msched-in-control-spec โ€” scheduling in control speculation ๐Ÿ—“๏ธ
  • -msched-spec-ldc โ€” scheduling spec LDC ๐Ÿ—“๏ธ
  • -msched-spec-control-ldc โ€” scheduling spec control LDC ๐Ÿ—“๏ธ
  • -msched-prefer-non-data-spec-insns โ€” prefer non-data-spec insns ๐Ÿ—“๏ธ
  • -msched-prefer-non-control-spec-insns โ€” prefer non-control-spec insns ๐Ÿ—“๏ธ
  • -msched-stop-bits-after-every-cycle โ€” stop bits after every cycle โน๏ธ
  • -msched-count-spec-in-critical-path โ€” count spec in critical path ๐Ÿงฎ
  • -msel-sched-dont-check-control-spec โ€” selective scheduling, skip control spec checks ๐Ÿ—“๏ธ
  • -msched-fp-mem-deps-zero-cost โ€” FP memory deps at zero cost ๐Ÿ’ธ
  • -msched-max-memory-insns-hard-limit โ€” max memory insns, hard limit ๐Ÿ›‘
  • -msched-max-memory-insns=max-insns โ€” max memory insns, set the max ๐Ÿ”ข

๐Ÿ’œ LM32 Options ๐Ÿ’œ

  • -mbarrel-shift-enabled โ€” barrel shift enabled ๐Ÿ›ž
  • -mdivide-enabled โ€” divide enabled โž—
  • -mmultiply-enabled โ€” multiply enabled โœ–๏ธ
  • -msign-extend-enabled โ€” sign extend enabled ๐Ÿ”ข
  • -muser-enabled โ€” user enabled ๐Ÿ‘ค

๐ŸŒท M32R/D Options ๐ŸŒท

  • -m32r2 โ€” M32R2 ๐Ÿงฉ
  • -m32rx โ€” M32RX ๐Ÿงฉ
  • -m32r โ€” M32R ๐Ÿงฉ
  • -mdebug โ€” debug ๐Ÿ›
  • -malign-loops โ€” align loops ๐ŸŽฏ
  • -mno-align-loops โ€” no loop alignment ๐Ÿ™…
  • -missue-rate=number โ€” issue rate, numbered ๐Ÿ”ข
  • -mbranch-cost=number โ€” branch cost, numbered ๐Ÿ’ฐ
  • -mmodel=code-size-model-type โ€” code size model type ๐Ÿ“
  • -msdata=sdata-type โ€” small data type ๐Ÿ—ƒ๏ธ
  • -mno-flush-func โ€” no flush function ๐Ÿ™…
  • -mflush-func=name โ€” flush function, pick a name ๐Ÿงน
  • -mno-flush-trap โ€” no flush trap ๐Ÿ™…
  • -mflush-trap=number โ€” flush trap, numbered ๐Ÿชค
  • -G num โ€” small data threshold, numbered ๐Ÿ”ข

๐ŸŒป M32C Options ๐ŸŒป

  • -mcpu=cpu โ€” pick a CPU ๐Ÿ’–
  • -msim โ€” simulator ๐ŸŽฎ
  • -memregs=number โ€” emregs, numbered ๐Ÿ”ข

๐Ÿฆ– M680x0 Options ๐Ÿฆ–

  • -march=arch โ€” pick an arch ๐Ÿ—๏ธ
  • -mcpu=cpu โ€” pick a CPU ๐Ÿ’–
  • -mtune=tune โ€” tune for a target ๐ŸŽ›๏ธ
  • -m68000 โ€” 68000 ๐Ÿฆ•
  • -m68020 โ€” 68020 ๐Ÿฆ•
  • -m68020-40 โ€” 68020-40 ๐Ÿฆ•
  • -m68020-60 โ€” 68020-60 ๐Ÿฆ•
  • -m68030 โ€” 68030 ๐Ÿฆ•
  • -m68040 โ€” 68040 ๐Ÿฆ•
  • -m68060 โ€” 68060 ๐Ÿฆ•
  • -mcpu32 โ€” CPU32 ๐Ÿงฉ
  • -m5200 โ€” 5200 ๐Ÿงฉ
  • -m5206e โ€” 5206e ๐Ÿงฉ
  • -m528x โ€” 528x ๐Ÿงฉ
  • -m5307 โ€” 5307 ๐Ÿงฉ
  • -m5407 โ€” 5407 ๐Ÿงฉ
  • -mcfv4e โ€” ColdFire V4e ๐Ÿงฉ
  • -mbitfield โ€” bitfield ๐Ÿงฎ
  • -mno-bitfield โ€” no bitfield ๐Ÿ™…
  • -mc68000 โ€” C68000 ๐Ÿฆ•
  • -mc68020 โ€” C68020 ๐Ÿฆ•
  • -mnobitfield โ€” no bitfield ๐Ÿ™…
  • -mrtd โ€” RTD ๐Ÿ“ž
  • -mno-rtd โ€” no RTD ๐Ÿ™…
  • -mdiv โ€” divide โž—
  • -mno-div โ€” no divide ๐Ÿ™…
  • -mshort โ€” short ๐Ÿ”ข
  • -mno-short โ€” no short ๐Ÿ™…
  • -mhard-float โ€” hard float ๐Ÿ”ฅ
  • -m68881 โ€” 68881 ๐Ÿง 
  • -msoft-float โ€” soft float ๐Ÿงš
  • -mpcrel โ€” PC-relative ๐Ÿงญ
  • -malign-int โ€” align int ๐ŸŽฏ
  • -mstrict-align โ€” strict align ๐Ÿ“
  • -msep-data โ€” separate data ๐Ÿ—‚๏ธ
  • -mno-sep-data โ€” no separate data ๐Ÿ™…
  • -mshared-library-id=n โ€” shared library ID, numbered ๐Ÿ”ข
  • -mid-shared-library โ€” ID shared library ๐Ÿ“š
  • -mno-id-shared-library โ€” no ID shared library ๐Ÿ™…
  • -mxgot โ€” XGOT ๐Ÿงฉ
  • -mno-xgot โ€” no XGOT ๐Ÿ™…
  • -mlong-jump-table-offsets โ€” long jump table offsets ๐Ÿชœ

๐Ÿ”ฅ MCore Options ๐Ÿ”ฅ

  • -mhardlit โ€” hard literals ๐Ÿงฑ
  • -mno-hardlit โ€” no hard literals ๐Ÿ™…
  • -mdiv โ€” divide โž—
  • -mno-div โ€” no divide ๐Ÿ™…
  • -mrelax-immediates โ€” relax immediates ๐Ÿง˜
  • -mno-relax-immediates โ€” no relaxed immediates ๐Ÿ™…
  • -mwide-bitfields โ€” wide bitfields ๐Ÿงฎ
  • -mno-wide-bitfields โ€” no wide bitfields ๐Ÿ™…
  • -m4byte-functions โ€” 4-byte functions ๐Ÿ”ข
  • -mno-4byte-functions โ€” no 4-byte functions ๐Ÿ™…
  • -mcallgraph-data โ€” callgraph data ๐Ÿ—บ๏ธ
  • -mno-callgraph-data โ€” no callgraph data ๐Ÿ™…
  • -mslow-bytes โ€” slow bytes ๐Ÿข
  • -mno-slow-bytes โ€” no slow bytes ๐Ÿ™…
  • -mno-lsim โ€” no LSIM ๐Ÿ™…
  • -mlittle-endian โ€” little endian ๐Ÿ’œ
  • -mbig-endian โ€” big endian ๐Ÿ’™
  • -m210 โ€” 210 ๐Ÿงฉ
  • -m340 โ€” 340 ๐Ÿงฉ
  • -mstack-increment โ€” stack increment ๐Ÿ“ˆ

๐ŸŒŠ MeP Options ๐ŸŒŠ

  • -mabsdiff โ€” absolute difference ๐Ÿงฎ
  • -mall-opts โ€” all the opts ๐ŸŽ
  • -maverage โ€” average ๐Ÿ“Š
  • -mbased=n โ€” based, numbered ๐Ÿ”ข
  • -mbitops โ€” bit ops ๐Ÿงฎ
  • -mc=n โ€” C, numbered ๐Ÿ”ข
  • -mclip โ€” clip โœ‚๏ธ
  • -mconfig=name โ€” config, pick a name โš™๏ธ
  • -mcop โ€” coprocessor ๐Ÿงฉ
  • -mcop32 โ€” 32-bit coprocessor ๐Ÿงฉ
  • -mcop64 โ€” 64-bit coprocessor ๐Ÿงฉ
  • -mivc2 โ€” IVC2 ๐Ÿงฉ
  • -mdc โ€” DC ๐Ÿงฉ
  • -mdiv โ€” divide โž—
  • -meb โ€” big endian ๐Ÿ’™
  • -mel โ€” little endian ๐Ÿ’œ
  • -mio-volatile โ€” volatile I/O ๐Ÿ”Œ
  • -ml โ€” L ๐Ÿ…ป
  • -mleadz โ€” leading zeros 0๏ธโƒฃ
  • -mm โ€” M ๐Ÿ…ผ
  • -mminmax โ€” min and max ๐Ÿ“
  • -mmult โ€” multiply โœ–๏ธ
  • -mno-opts โ€” no opts ๐Ÿ™…
  • -mrepeat โ€” repeat ๐Ÿ”
  • -ms โ€” S ๐Ÿ…ข
  • -msatur โ€” saturate ๐Ÿ”ฅ
  • -msdram โ€” SDRAM ๐Ÿง 
  • -msim โ€” simulator ๐ŸŽฎ
  • -msimnovec โ€” simulator, no vector ๐ŸŽฎ
  • -mtf โ€” TF ๐Ÿงฉ
  • -mtiny=n โ€” tiny, numbered ๐Ÿ”ข

๐Ÿฃ MicroBlaze Options ๐Ÿฃ

  • -msoft-float โ€” soft float ๐Ÿงš
  • -mhard-float โ€” hard float ๐Ÿ”ฅ
  • -msmall-divides โ€” small divides โž—
  • -mcpu=cpu โ€” pick a CPU ๐Ÿ’–
  • -mmemcpy โ€” memcpy ๐Ÿ“‹
  • -mxl-soft-mul โ€” XL soft multiply โœ–๏ธ
  • -mxl-soft-div โ€” XL soft divide โž—
  • -mxl-barrel-shift โ€” XL barrel shift ๐Ÿ›ž
  • -mxl-pattern-compare โ€” XL pattern compare ๐Ÿ”
  • -mxl-stack-check โ€” XL stack check ๐Ÿ›‘
  • -mxl-gp-opt โ€” XL GP opt ๐Ÿงน
  • -mno-clearbss โ€” no clear BSS ๐Ÿ™…
  • -mxl-multiply-high โ€” XL multiply high โœ–๏ธ
  • -mxl-float-convert โ€” XL float convert ๐Ÿ”„
  • -mxl-float-sqrt โ€” XL float sqrt ๐Ÿงฎ
  • -mbig-endian โ€” big endian ๐Ÿ’™
  • -mlittle-endian โ€” little endian ๐Ÿ’œ
  • -mxl-reorder โ€” XL reorder ๐Ÿ”€
  • -mxl-mode-app-model โ€” XL mode app model ๐Ÿงฉ
  • -mpic-data-is-text-relative โ€” PIC data is text-relative ๐Ÿงญ

OKAY bestie, the MIPS list is LONG and I'm not even sorry ๐Ÿ˜ญ Here are the machine-specific flags, grouped by target, with the page's list kept exactly as written ๐Ÿ’…

๐Ÿฆ‹ MIPS Options ๐Ÿฆ‹

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

๐Ÿงš MMIX Options ๐Ÿงš

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

๐Ÿ’œ MN10300 Options ๐Ÿ’œ

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

๐ŸŒธ Moxie Options ๐ŸŒธ

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

โœจ MSP430 Options โœจ

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

๐Ÿ“ NDS32 Options ๐Ÿ“

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

๐ŸŒˆ Nios II Options ๐ŸŒˆ

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

๐Ÿ’… Nvidia PTX Options ๐Ÿ’…

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

๐Ÿซถ OpenRISC Options ๐Ÿซถ

  • -mboard=name
  • -mnewlib
  • -mhard-mul
  • -mhard-div
  • -msoft-mul
  • -msoft-div
  • -msoft-float
  • -mhard-float
  • -mdouble-float
  • -munordered-float
  • -mcmov
  • -mror
  • -mrori
  • -msext
  • -msfimm
  • -mshftimm

๐Ÿ”ฅ PDP-11 Options ๐Ÿ”ฅ

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

๐Ÿงš picoChip Options ๐Ÿงš

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

๐Ÿฆ‹ PowerPC Options ๐Ÿฆ‹

This one's a little cross-reference moment, bestie. See RS/6000 and PowerPC Options. ๐Ÿงš

๐ŸŒธ PRU Options ๐ŸŒธ

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

๐Ÿ‘‘ RISC-V Options ๐Ÿ‘‘

  • -mbranch-cost=N-instruction
  • -mplt
  • -mno-plt
  • -mabi=ABI-string
  • -mfdiv
  • -mno-fdiv
  • -mdiv
  • -mno-div
  • -march=ISA-string
  • -mtune=processor-string
  • -mpreferred-stack-boundary=num
  • -msmall-data-limit=N-bytes
  • -msave-restore
  • -mno-save-restore
  • -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

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

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

๐Ÿฆ‹ RX Options ๐Ÿฆ‹

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

๐ŸŒธ S/390 and zSeries Options ๐ŸŒธ

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

๐Ÿงš Score Options ๐Ÿงš

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

๐Ÿ’œ SH Options ๐Ÿ’œ

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

๐Ÿซถ Solaris 2 Options ๐Ÿซถ

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

๐Ÿ”ฅ SPARC Options ๐Ÿ”ฅ

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

๐Ÿงš System V Options ๐Ÿงš

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

๐Ÿ’– TILE-Gx Options ๐Ÿ’–

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

๐ŸŒˆ TILEPro Options ๐ŸŒˆ

  • -mcpu=cpu
  • -m32

๐Ÿ“ V850 Options ๐Ÿ“

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

๐Ÿฆ‹ VAX Options ๐Ÿฆ‹

  • -mg
  • -mgnu
  • -munix

๐Ÿ’– Visium Options

okay bestie, these are the Visium flags ๐Ÿฆ‹

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

๐ŸŒธ VMS Options

the VMS crew has their own set โœจ

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

๐Ÿงš VxWorks Options

VxWorks gets its own little squad ๐Ÿซถ

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

๐Ÿ‘‘ x86 Options

the x86 list is literally massive, no cap ๐Ÿ’€ every single one is here, don't worry

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

๐ŸชŸ x86 Windows Options

the Windows corner of the x86 family ๐ŸŒˆ

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

๐Ÿฆ– Xstormy16 Options

just one little flag for the Xstormy16 folks ๐Ÿ’œ

-msim

๐ŸŽ€ Xtensa Options

the Xtensa list 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

โญ zSeries Options

for zSeries, you just gotta go look at S/390 and zSeries Options instead ๐Ÿ™ˆ


โœจ Options Controlling the Kind of Output โœจ

okay so compiling can have up to four stages: preprocessing, compilation proper, assembly, and linking, always in that order ๐Ÿ”ฅ GCC can preprocess and compile a bunch of files into either several assembler input files or one assembler input file. then each assembler input file becomes an object file, and linking mashes all the object files together (the newly compiled ones and the ones you gave it) into an executable file. it's giving teamwork ๐Ÿซถ

for any given input file, the file name suffix decides what kind of compilation happens ๐Ÿฆ‹

  • file.c โ€” C source code that has to be preprocessed first ๐Ÿ’–
  • file.i โ€” C source code that should NOT be preprocessed ๐ŸŒธ
  • file.ii โ€” C++ source code that should NOT be preprocessed ๐ŸŒธ
  • file.m โ€” Objective-C source code. heads up, you have to link with the libobjc library or your Objective-C program won't work ๐Ÿ’€
  • file.mi โ€” Objective-C source code that should NOT be preprocessed ๐ŸŒธ
  • file.mm, file.M โ€” Objective-C++ source code. same deal, you must link with libobjc for it to work. and yes, .M means a literal capital M ๐Ÿ”ฅ
  • file.mii โ€” Objective-C++ source code that should NOT be preprocessed ๐ŸŒธ
  • file.h โ€” a C, C++, Objective-C, or Objective-C++ header file that gets turned into a precompiled header (that's the default). or, if you use -fdump-ada-spec, a C or C++ header file gets turned into an Ada spec โœจ
  • file.cc, file.cp, file.cxx, file.cpp, file.CPP, file.c++, file.C โ€” C++ source code that has to be preprocessed. quick note: in .cxx, the last two letters have to be literally x, and .C means a literal capital C ๐Ÿงš
  • file.mm, file.M โ€” Objective-C++ source code that has to be preprocessed ๐Ÿ’œ
  • file.mii โ€” Objective-C++ source code that should NOT be preprocessed (yes, it's listed twice, the vibes are consistent ๐Ÿ˜ญ)
  • file.hh, file.H, file.hp, file.hxx, file.hpp, file.HPP, file.h++, file.tcc โ€” C++ header files that get turned into a precompiled header or an 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, using 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, using the traditional preprocessor ๐Ÿ’…
  • file.go โ€” Go source code ๐Ÿซง
  • file.brig โ€” BRIG files, which are the binary representation of HSAIL ๐Ÿค–
  • file.d โ€” D source code ๐ŸŒ™
  • file.di โ€” D interface file ๐ŸŒ™
  • file.dd โ€” D documentation code (Ddoc) ๐ŸŒ™
  • file.ads โ€” an Ada source file with a library unit declaration (a declaration of a package, subprogram, or generic, or a generic instantiation), or a library unit renaming declaration (a package, generic, or subprogram renaming declaration). these are also called specs ๐Ÿ‘‘
  • file.adb โ€” an Ada source file containing a library unit body (a subprogram or package body). these are also called bodies ๐Ÿ‘‘
  • file.s โ€” assembler code ๐Ÿ”ง
  • file.S, file.sx โ€” assembler code that MUST be preprocessed ๐Ÿ”ง
  • other โ€” an object file that gets fed straight into linking. any file name with no recognized suffix gets treated this way ๐Ÿซถ

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

  • -x language โ€” tells GCC the language for the input files that come after it, instead of letting it guess from the file name suffix. this applies to every following input file until the next -x shows up. the possible values for language are:
c  c-header  cpp-output
c++  c++-header  c++-cpp-output
objective-c  objective-c-header  objective-c-cpp-output
objective-c++ objective-c++-header objective-c++-cpp-output
assembler  assembler-with-cpp
ada
d
f77  f77-cpp-input f95  f95-cpp-input
go
brig
  • -x none โ€” turns off any language setting, so the files after it get handled by their suffixes, just like they would if -x had never been used at all ๐Ÿงน

if you only want some of the stages, you can use -x (or the filename suffixes) to tell gcc where to start, and one of -c, -S, or -E to say where it should stop ๐Ÿ›‘ fair warning, some combos (like -x cpp-output -E) make gcc do absolutely nothing ๐Ÿ’€

  • -c โ€” compile or assemble the source files, but DON'T link ๐Ÿ™…โ€โ™€๏ธ the linking stage just isn't done. the final output is one object file per source file. by default, the object file name for a source file gets made by swapping the suffix .c, .i, .s, etc. for .o. unrecognized input files that don't need compilation or assembly get ignored.
  • -S โ€” stop after the compilation proper stage, so no assembling ๐Ÿช„ the output is an assembler code file for each non-assembler input file. by default, the assembler file name for a source file gets made by swapping the suffix .c, .i, etc. for .s. input files that don't need compilation get ignored.
  • -E โ€” stop after the preprocessing stage, and don't run the compiler proper ๐ŸŒท the output is preprocessed source code, which gets sent to standard output. input files that don't need preprocessing get ignored.
  • -o file โ€” put the output in file. this works for whatever you're making, whether it's an executable, an object file, an assembler file, or preprocessed C code ๐ŸŽ if you don't specify -o, the default is: 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 goes in source.suffix.gch, and all the preprocessed C source goes to standard output.
  • -v โ€” prints the commands that get run for each stage of compilation (to standard error). it also prints the version number of the compiler driver, the preprocessor, and the compiler proper ๐Ÿ“ฃ
  • -### โ€” like -v, except the commands DON'T actually run ๐Ÿ™ˆ arguments get quoted unless they only contain alphanumeric characters or "./-_". this is super handy for shell scripts that want to capture the command lines the driver generates ๐Ÿš
  • --help โ€” prints a description of the command-line options gcc understands (to standard output) ๐Ÿ“– if -v is also specified, --help gets passed on to the various processes gcc invokes, so they can show the options they accept. and if -Wextra was specified before --help, options with no documentation get displayed too ๐Ÿ”
  • --target-help โ€” prints a description of the target-specific command-line options for each tool (to standard output) ๐ŸŽฏ some targets might print extra target-specific info too โœจ
  • --help={class|[^]qualifier}[,...] โ€” okay so this one prints (on the standard output) a rundown of every command-line option the compiler understands that fits all the classes and qualifiers you pick. Here are the classes:
    • optimizers โ€” every optimization option the compiler supports ๐Ÿ”ฅ
    • warnings โ€” every option that controls warning messages the compiler produces โš ๏ธ
    • target โ€” target-specific options ๐ŸŽฏ Unlike --target-help, this one does NOT show the target-specific options of the linker and assembler, because those tools don't currently support the extended --help= syntax ๐Ÿ™ˆ
    • params โ€” the values the --param option recognizes ๐Ÿ’…
    • language โ€” options for a language, where language is the name of one of the languages supported in this GCC version. If an option is supported by all languages, you need to pick the common class ๐ŸŒˆ
    • common โ€” the options that are common to all languages โœจ

These are the qualifiers:

  • undocumented โ€” only the options that are undocumented ๐Ÿซฃ
  • joined โ€” options that take an argument appearing after an equal sign in the same continuous piece of text, like --help=target ๐Ÿฆ‹
  • separate โ€” options that take an argument appearing as a separate word following the original option, like -o output-file ๐Ÿ“

So if you wanna see all the undocumented target-specific switches the compiler supports, just use:

--help=target,undocumented

The sense of a qualifier can be flipped by putting the ^ character in front of it. So if you want all the binary warning options (the ones that are either on or off and don't take an argument) that have a description, use:

--help=warnings,^joined,^undocumented
The argument to --help= should not consist solely of inverted qualifiers. Don't be that person ๐Ÿ’€

Combining several classes is possible, but it usually restricts the output so much that there's literally nothing to display. One case where it does work is when one of the classes is target. For example, to display all the target-specific optimization options, use:

--help=target,optimizers

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

If the -Q option appears on the command line before the --help= option, the descriptive text displayed by --help= changes! Instead of describing the options, it gives an indication of whether each option is enabled, disabled, or set to a specific value (assuming the compiler knows this at the point where the --help= option is used). Main character energy ๐Ÿ’–

Here is 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

Alternatively, 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 โ€” okay so normally the gcc program exits with the code of 1 if any phase of the compiler returns a non-success return code. If you specify -pass-exit-codes, though, gcc instead returns with 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, to override the defaults the gcc driver uses when deciding which switches to pass to cc1, cc1plus, as, ld, etc. ๐Ÿงš You can specify more than one -specs=file on the command line, and they're processed in order, from left to right.
  • -wrapper โ€” invokes all subcommands under a wrapper program. The name of the wrapper program and its parameters are passed as a comma separated list. 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 result of the compilation get recorded as if the files lived in directory new instead ๐Ÿฆ„ Specifying this is equivalent to specifying all the individual -f*-prefix-map options, and it can be used to make reproducible builds that are location independent. See also -fmacro-prefix-map and -fdebug-prefix-map.
  • -fplugin=name.so โ€” loads the plugin code in file name.so, which is assumed to be a shared object to be dlopen'd by the compiler ๐Ÿ”Œ 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 corresponding Ada specs ๐Ÿ’œ
  • -fada-spec-parent=unit โ€” used together with -fdump-ada-spec[-slim] above, this generates Ada specs as child units of the parent unit ๐ŸŒธ
  • -fdump-go-spec=file โ€” for input files in any language, generates corresponding Go declarations in file ๐Ÿน This makes Go const, type, var, and func declarations, which can be a super useful way to start writing a Go interface to code written in some other language.
  • @file โ€” reads command-line options from file ๐Ÿ“œ The options read are inserted in place of the original @file option. If file doesn't exist or can't be read, the option gets treated literally and isn't removed.
    • Options in file are separated by whitespace. 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 may itself contain additional @file options, and any such options will be processed recursively ๐Ÿ”

โœจ Compiling C++ Programs โœจ

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

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

When you compile C++ programs, you may specify many of the same command-line options you use for compiling programs in any language, or command-line options meaningful for C and related languages, or options that are meaningful only for C++ programs ๐Ÿฆ‹


๐ŸŒธ Options Controlling C Dialect ๐ŸŒธ

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

  • -ansi โ€” in C mode, this is equivalent to -std=c90. In C++ mode, it's equivalent to -std=c++98 ๐Ÿ‘‘
    • It turns off certain GCC features that are incompatible with ISO C90 (when compiling C code) or standard C++ (when compiling C++ code), like the asm and typeof keywords, and predefined macros such as unix and vax that identify the type of system you're using. It also enables the undesirable and rarely used ISO trigraph feature. For the C compiler, it disables recognition of C++ style // comments as well as the inline keyword ๐Ÿ™ˆ
    • The alternate keywords __asm__, __extension__, __inline__ and __typeof__ keep working despite -ansi. You wouldn't want to use them in an ISO C program, of course, but they're useful to put in header files that might get included in compilations done with -ansi. Alternate predefined macros such as __unix__ and __vax__ are also available, with or without -ansi ๐ŸŒˆ
    • The -ansi option does not cause non-ISO programs to be rejected gratuitously. For that, -Wpedantic is required in addition to -ansi ๐Ÿ’€
    • The macro __STRICT_ANSI__ is predefined when the -ansi option is used. Some header files may notice this macro and refrain from declaring certain functions or defining certain macros that the ISO standard doesn't call for, which avoids interfering with any programs that might use those names for other things ๐Ÿงš
    • Functions that are normally built in but don't have semantics defined by ISO C (such as alloca and ffs) are not built-in functions when -ansi is used ๐Ÿ“
  • -std= โ€” determines the language standard ๐Ÿ’– This option is currently only supported when compiling C or C++.

Okay so bestie, the -std= flag is where you tell GCC which rulebook to follow ๐Ÿ“–โœจ GCC can take a base standard like c90 or c++98, or a GNU dialect of one like gnu90 or gnu++98. ๐Ÿ’…

With a base standard, GCC accepts every program that follows that standard, plus any GNU extensions that don't clash with it. For example, -std=c90 switches off GCC features that don't fit ISO C90, like the asm and typeof keywords ๐Ÿ™ˆ, but keeps other GNU extras that mean nothing in ISO C90, like leaving out the middle term of a ?: expression. โœจ

With a GNU dialect, every feature the compiler supports gets turned on, even if that changes what the base standard means ๐ŸŒˆ Lowkey this means some strict-conforming programs might get rejected ๐Ÿ’€

-Wpedantic uses the chosen standard to decide which features count as GNU extensions. So -std=gnu90 -Wpedantic warns about C++ style // comments, but -std=gnu99 -Wpedantic doesn't. It's giving precision ๐ŸŽ€

You must give this option a value. These are the possible values:

  • c90, c89, iso9899:1990 โ€” Supports all ISO C90 programs. Certain GNU extensions that clash with ISO C90 get disabled. Same as -ansi for C code. ๐ŸŒธ
  • iso9899:199409 โ€” ISO C90 with amendment 1 added in โœจ
  • c99, c9x, iso9899:1999, iso9899:199x โ€” ISO C99 ๐Ÿฆ‹ This one is basically fully supported, aside from bugs and floating-point stuff (mostly, but not entirely, the optional C99 features from Annexes F and G). For more info check http://gcc.gnu.org/c99status.html. The names c9x and iso9899:199x are deprecated, so maybe don't use them anymore ๐Ÿ™…โ€โ™€๏ธ
  • c11, c1x, iso9899:2011 โ€” ISO C11, the 2011 revision ๐Ÿ’œ Also basically fully supported, aside from bugs and floating-point issues (mostly Annexes F and G again) plus 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 (published in 2018) ๐ŸŒˆ It's the same as C11 except for defect corrections (all of which also get 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 being worked on ๐Ÿšง Support is experimental and incomplete, so be careful bestie.
  • gnu90, gnu89 โ€” GNU dialect of ISO C90, which includes 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 ISO C standard plus GNU extensions, still in development ๐Ÿงš 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. This is the default for C++ code โœจ The name gnu++1y is deprecated.
  • c++17, c++1z โ€” The 2017 ISO C++ standard plus amendments. The name c++1z is deprecated.
  • gnu++17, gnu++1z โ€” GNU dialect of -std=c++17. The name gnu++1z is deprecated.
  • c++20, c++2a โ€” The next revision of ISO C++, planned for 2020 ๐Ÿ˜ญ Support is highly experimental and will almost certainly change in incompatible ways in future releases. > Proceed with extreme caution, this one is unstable ๐Ÿ’€
  • gnu++20, gnu++2a โ€” GNU dialect of -std=c++20. Support is highly experimental and will almost certainly change in incompatible ways in future releases. ๐Ÿ”ฅ

๐ŸŽ€ -fgnu89-inline

The -fgnu89-inline flag tells GCC to use the old-school GNU rules for inline functions when you're in C99 mode ๐Ÿ•ฐ๏ธ

Using it is roughly the same as slapping the gnu_inline function attribute onto every inline function ๐Ÿ’…

-fno-gnu89-inline tells GCC to use the C99 rules for inline when you're in C99 or gnu99 mode. That's the default behavior anyway, so it's kinda redundant lol. This option is not supported in -std=c90 or -std=gnu90 mode.

The preprocessor macros __GNUC_GNU_INLINE__ and __GNUC_STDC_INLINE__ can be used to check which inline semantics are in effect ๐Ÿ”


๐Ÿฆ‹ -fpermitted-flt-eval-methods=style

ISO/IEC TS 18661-3 adds new permissible values for FLT_EVAL_METHOD ๐ŸŒธ These say that operations and constants with a semantic type that's an interchange or extended format should be evaluated to the precision and range of that type. The new values are a superset of what C99/C11 allows, and C99/C11 doesn't define what any other positive values mean. So code that's C11-conforming might not have been written with the new values in mind ๐Ÿ‘€

-fpermitted-flt-eval-methods decides whether the compiler allows only the FLT_EVAL_METHOD values from C99/C11, or the extended set from ISO/IEC TS 18661-3.

style is either c11 or ts-18661-3, whichever fits ๐Ÿซถ

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


๐Ÿ“ -aux-info filename

This dumps prototyped declarations for all functions declared and/or defined in a translation unit into the given filename ๐Ÿ—‚๏ธ That includes functions in header files too. It's silently ignored in any language other than C, so don't stress if you're doing C++ ๐Ÿ˜Œ

Besides the declarations, the file uses comments to show where each declaration came from (source file and line). It also shows whether the declaration was implicit, prototyped or unprototyped. That's marked by I for new (implicit), N for new (prototyped), or O for old (unprototyped), in the first character after the line number and colon. The following character tells you whether it came from a declaration (C) or a definition (F). For function definitions, a K&R-style list of arguments followed by their declarations is also included, inside comments, right after the declaration ๐ŸŒˆ

Heads up: the I, N and O markers are described in the original as "I, N for new or O for old", so I and N both count as "new" and O is "old." Read it carefully bestie ๐Ÿค“

โœจ -fallow-parameterless-variadic-functions

This lets you accept variadic functions without named parameters ๐Ÿฆ„

You can define one of these, but it's not super useful because you can't read the arguments. This is only supported for C, because C++ allows this construct already ๐Ÿ’œ


๐Ÿ™ˆ -fno-asm

This stops GCC from treating asm, inline or typeof as keywords, so your code can use those words as identifiers ๐Ÿงš Instead, you use the keywords __asm__, __inline__ and __typeof__. -ansi implies -fno-asm.

In C++, this switch only affects the typeof keyword, since asm and inline are standard keywords there. You might want to use -fno-gnu-keywords instead, which has the same effect ๐ŸŽ€

In C99 mode (-std=c99 or -std=gnu99), this switch only affects the asm and typeof keywords, because inline is a standard keyword in ISO C99 ๐ŸŒธ


๐Ÿงฎ -fno-builtin, -fno-builtin-function

This means "don't recognize built-in functions that don't start with the prefix __builtin_" ๐Ÿ™…โ€โ™€๏ธ

Normally GCC generates special code for certain built-in functions so they run faster. For example, calls to alloca might turn into single instructions that adjust the stack directly, and calls to memcpy might become inline copy loops ๐Ÿ”ฅ The result is usually smaller and faster, BUT the function calls don't show up as calls anymore. So you can't set a breakpoint on them, and you can't change what they do by linking against a different library ๐Ÿ’€ Also, when GCC recognizes a built-in, it might use what it knows about that function to warn you about problems with calls to it, or to generate more efficient code, even if the code still has calls to that function in it. For example, you get warnings with -Wformat for bad calls to printf when printf is built in and strlen is known not to modify global memory ๐Ÿง 

With -fno-builtin-function, only that one built-in function gets disabled. The function name must not begin with __builtin_. If you name a function that isn't built in for this version of GCC, the option is just ignored ๐Ÿซ  There's no matching -fbuiltin-function option. If you want to enable built-in functions selectively while using -fno-builtin or -ffreestanding, you can define macros like this:

#define abs(n)          __builtin_abs ((n))
#define strcpy(d, s)    __builtin_strcpy ((d), (s))

๐Ÿงช -fgimple

This enables parsing of function definitions marked with __GIMPLE. It's an experimental feature that lets you unit test GIMPLE passes ๐Ÿ”ฌ


๐Ÿ  -fhosted

This asserts that compilation targets a hosted environment, and it implies -fbuiltin. A hosted environment is one where the entire standard library is available, and where main has a return type of int ๐Ÿ‘‘ Examples are basically everything except a kernel. This is equivalent to -fno-freestanding.


๐Ÿš€ -ffreestanding

This asserts that compilation targets a freestanding environment, and it implies -fno-builtin. In a freestanding environment, the standard library may not exist, and program startup may not necessarily be at main ๐ŸŒŒ The most obvious example is an OS kernel. This is equivalent to -fno-hosted.

  • -fopenacc โ€” okay so this one switches on handling of OpenACC directives, #pragma acc in C/C++ and !$acc in Fortran ๐Ÿ’– With it on, the compiler generates accelerated code following the OpenACC Application Programming Interface v2.6 (https://www.openacc.org) โœจ It also implies -pthread, so it only works on targets that support -pthread ๐ŸŽ€
  • -fopenacc-dim=geom โ€” sets default compute dimensions for parallel offload regions that don't specify their own ๐Ÿฆ‹ geom is a triple of sizes separated by ':', in the order gang, worker and vector. You can leave any size out to use a target-specific default ๐ŸŒธ
  • -fopenmp โ€” enables OpenMP directives, #pragma omp in C/C++ and !$omp in Fortran ๐ŸŒˆ With it on, the compiler generates parallel code according to the OpenMP Application Program Interface v4.5 (https://www.openmp.org). It implies -pthread, so it's only supported on targets with -pthread support. It also implies -fopenmp-simd ๐Ÿ‘‘
  • -fopenmp-simd โ€” handles only OpenMP's SIMD directives, written as #pragma omp in C/C++ and !$omp in Fortran. Every other OpenMP directive gets ignored ๐Ÿ™ˆ
  • -fgnu-tm โ€” when this is specified, the compiler generates code for the Linux variant of Intel's current Transactional Memory ABI specification document (Revision 1.1, May 6 2009). It's an experimental feature, so its interface may change in future GCC versions as the official specification changes ๐Ÿงช Also, not every architecture supports it, so check before you rely on it ๐Ÿ’…

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

๐Ÿ’€ Heads up: the transactional memory feature is not supported with non-call exceptions (-fnon-call-exceptions).
  • -fms-extensions โ€” accepts some non-standard constructs used in Microsoft header files ๐ŸŽ€ In C++ code, this lets member names in structures match previous type declarations, like this:
typedef int UOW;
struct ABC {
  UOW UOW;
};

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

  • -fplan9-extensions โ€” accepts some non-standard constructs used in Plan 9 code ๐Ÿงš This turns on -fms-extensions and lets you pass pointers to structures with anonymous fields to functions that expect pointers to elements of the field's type. It also lets you refer to anonymous fields declared using a typedef. This is only supported for C, not C++ ๐Ÿฆ‹
  • -fcond-mismatch โ€” allows conditional expressions with mismatched types in the second and third arguments. The value of such an expression is void ๐Ÿ’œ This option isn't supported for C++.
  • -flax-vector-conversions โ€” allows implicit conversions between vectors with differing numbers of elements and/or incompatible element types. Please don't use this for new code ๐Ÿ˜ญ
  • -funsigned-char โ€” makes the type char unsigned, like unsigned char ๐ŸŒธ Every kind of machine has a default for what char should be, and it's either like unsigned char or like signed char. Ideally a portable program always uses signed char or unsigned char when it depends on signedness, but lots of programs were written to use plain char and expect it to be signed or unsigned depending on the machine they were written for. This option, and its inverse, let you make those programs work with the opposite default ๐Ÿ” Also, char is always a distinct type from both signed char and unsigned char, even though it behaves exactly like one of those two.
  • -fsigned-char โ€” makes the type char signed, like signed char ๐Ÿ’– This is equivalent to -fno-unsigned-char, which is the negative form of -funsigned-char. Likewise, -fno-signed-char is equivalent to -funsigned-char.
  • -fsigned-bitfields, -funsigned-bitfields, -fno-signed-bitfields, -fno-unsigned-bitfields โ€” 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 too โœจ
  • -fsso-struct=endianness โ€” sets the default scalar storage order of structures and unions to the endianness you pick ๐ŸŒˆ The accepted values are big-endian, little-endian and native. native is the native endianness of the target and is the default. This option isn't 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. Be careful with this one, bestie ๐Ÿ˜ญ

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

This section covers the command-line options that only mean something for C++ programs ๐Ÿ’… You can still use most 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 is a 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 that conforms most closely to the C++ ABI specification, so the ABI you get from version 0 will change in different versions of G++ as ABI bugs get fixed ๐Ÿ”ง
    • Version 1 โ€” the version of the C++ ABI that first appeared in G++ 3.2.
    • Version 2 โ€” 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 appeared in G++ 4.5 and implements a standard mangling for vector types.
    • Version 5 โ€” first appeared in G++ 4.6 and corrects the mangling of attribute const/volatile on function pointer types, decltype of a plain decl, and use of a function parameter in the declaration of another parameter.
    • Version 6 โ€” first appeared in G++ 4.7 and corrects the promotion behavior of C++11 scoped enums and the mangling of template argument packs, const/static_cast, prefix ++ and --, and a class scope function used as a template argument.
    • Version 7 โ€” first appeared in G++ 4.8 and treats nullptr_t as a builtin type and corrects the mangling of lambdas in default argument scope.
    • Version 8 โ€” first appeared in G++ 4.9 and corrects the substitution behavior of function types with function-cv-qualifiers.
    • Version 9 โ€” first appeared in G++ 5.2 and corrects the alignment of "nullptr_t".
    • Version 10 โ€” first appeared in G++ 6.1 and adds mangling of attributes that affect type identity, such as ia32 calling convention attributes (e.g. stdcall).
    • Version 11 โ€” first appeared in G++ 7 and corrects the mangling of sizeof... expressions and operator names. For multiple entities with the same name within a function, declared in different scopes, the mangling now changes starting with the twelfth occurrence. It also implies -fnew-inheriting-ctors.
    • Version 12 โ€” first appeared in G++ 8 and corrects the calling conventions for empty classes on the x86_64 target and for classes with only deleted copy/move constructors. It accidentally changes the calling convention for classes with a deleted copy constructor and a trivial move constructor.
    • Version 13 โ€” first appeared in G++ 8.2 and fixes the accidental change in version 12 ๐Ÿฉน
    • Version 14 โ€” first appeared in G++ 10 and corrects the mangling of the nullptr expression.

See also -Wabi.

  • -fabi-compat-version=n โ€” on targets that support strong aliases, G++ works around mangling changes by creating an alias with the correct mangled name when it defines a symbol with an incorrect mangled name ๐Ÿชž This switch picks which ABI version to use for that alias.
    • With -fabi-version=0 (the default), this defaults to 11 (GCC 7 compatibility). If another ABI version is explicitly selected, this defaults to 0. For compatibility with GCC versions 3.2 through 4.9, use -fabi-compat-version=2.
    • If this option isn't provided but -Wabi=n is, that version is used for compatibility aliases. If this option is provided along with -Wabi (without the version), the version from this option is used for the warning.
  • -fno-access-control โ€” turns off all access checking ๐Ÿ™ˆ This switch is mainly useful for working around bugs in the access control code.
  • -faligned-new โ€” enables support for C++17 "new" of types that need more alignment than void* ::operator new(std::size_t) provides โœจ A numeric argument like -faligned-new=32 can specify 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++2a ๐ŸŒ This includes a new char8_t fundamental type, changes to the types of UTF-8 string and character literals, new signatures for user-defined literals, associated standard library updates, and new __cpp_char8_t and __cpp_lib_char8_t feature test macros.

This option lets functions be overloaded for ordinary and UTF-8 strings, like so:

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

It also introduces new signatures for user-defined literals:

int operator""_udl1(char8_t);
int v3 = u8'x'_udl1;
int operator""_udl2(const char8_t*, std::size_t);
int v4 = u8"text"_udl2;
template<typename T, T...> int operator""_udl3();
int v5 = u8"text"_udl3;

Okay so bestie, -fchar8_t is where things get a little messy ๐Ÿ˜ญ Switching the types of UTF-8 string and character literals causes incompatibilities with ISO C++11 and later standards. Code that is totally fine under ISO C++11 becomes ill-formed once -fchar8_t is specified. Check out these little heartbreakers ๐Ÿ’€

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

โœจ OPTIONS โœจ

  • -fcheck-new โ€” ๐ŸŽ€ Checks that the pointer returned by operator new is non-null before you touch the storage it allocated. Honestly this check is usually unnecessary, because the C++ standard says operator new only returns 0 if it's declared throw(), and in that case the compiler always checks the return value even without this option. In every other case, when operator new has a non-empty exception specification, memory exhaustion is signalled by throwing std::bad_alloc. See also new (nothrow). ๐Ÿ’…
  • -fconcepts, -fconcepts-ts โ€” ๐Ÿฆ‹ Below -std=c++2a, -fconcepts turns on support for the C++ Extensions for Concepts Technical Specification, ISO 19217 (2015).
    • With -std=c++2a and above, Concepts are part of the language standard, so -fconcepts defaults to on. But the standard version of Concepts is very different 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. We need a limit so endless recursion can be caught during constant expression evaluation. The minimum the standard requires is 512.
  • -fconstexpr-cache-depth=n โ€” ๐Ÿ“ Sets the maximum level of nested evaluation depth for C++11 constexpr functions that get cached, to n. It's a heuristic that trades compilation speed (when the cache avoids repeated calculations) against memory use (when the cache gets huge from super recursive evaluations). The default is 8. Very few people need to change it, but if your code does heavy constexpr calculations, feel free to experiment and see which value works best for you. ๐Ÿซถ
  • -fconstexpr-loop-limit=n โ€” ๐Ÿ” Sets the maximum number of iterations for a loop in C++14 constexpr functions to n. The limit exists so infinite loops can be caught 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 if one loop's iterations are capped by the limit above, you can still get trouble. If there are several nested loops that each run a lot of times but stay under that limit, or if a loop body (or code outside any loop) needs way too many expressions evaluated, the constexpr evaluation might take forever. The default is 33554432 (1<<25).
  • -fcoroutines โ€” ๐Ÿงช Enables support for the C++ coroutines extension. It's experimental, so handle with care, bestie โœจ
  • -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 turns that optimization off and forces G++ to call the copy constructor in every case. It also makes G++ call trivial member functions that would otherwise get expanded inline.
    • In C++17 the compiler is required to skip these temporaries, but this option still affects trivial member functions. ๐Ÿ‘€
  • -fno-enforce-eh-specs โ€” ๐Ÿ™ˆ Doesn't generate code that checks for violations of exception specifications at run time. This option breaks the C++ standard, but it can be handy for shrinking code size in production builds, kind of like defining NDEBUG.
This does NOT give your code permission to throw exceptions that break the exception specifications. The compiler still optimizes based on those specs, so throwing an unexpected exception causes undefined behavior at run time. Not it. ๐Ÿ’€
  • -fextern-tls-init, -fno-extern-tls-init โ€” ๐Ÿงต The C++11 and OpenMP standards let thread_local and threadprivate variables have dynamic (runtime) initialization. To make that work, any use of such a variable goes through a wrapper function that does the necessary initialization. When the use and the definition are in the same translation unit, that overhead can be optimized away. But when the use is in a different translation unit, there's a lot of overhead even if the variable never actually needs dynamic initialization. If you can be sure that no use of the variable in a non-defining TU needs to trigger dynamic initialization (either because the variable is statically initialized, or because a use in the defining TU will run before any uses in another TU), 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 don't support symbol aliases, the default is -fno-extern-tls-init. ๐ŸŒˆ
  • -fno-gnu-keywords โ€” ๐Ÿ”ค Stops typeof from being treated as a keyword, so you can use that word as an identifier. You can use the keyword __typeof__ instead. This option is implied by the strict ISO C++ dialects: -ansi, -std=c++98, -std=c++11, etc.
  • -fno-implicit-templates โ€” ๐Ÿ™…โ€โ™€๏ธ Never emits code for non-inline templates that get instantiated implicitly (i.e. by use). 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 end up with undefined symbols at link time.
  • -fno-implicit-inline-templates โ€” ๐Ÿซง Doesn't emit code for implicit instantiations of inline templates either. By default, inlines are handled differently so that builds with and without optimization need the same set of explicit instantiations.
  • -fno-implement-inlines โ€” ๐Ÿ“ฆ To save space, doesn't emit out-of-line copies of inline functions controlled by #pragma implementation. Heads up: this causes linker errors if those functions aren't inlined everywhere they're called.
  • -fms-extensions โ€” ๐ŸชŸ Disables Wpedantic warnings about constructs used in MFC, like implicit int and getting a pointer to a member function via non-standard syntax.
  • -fnew-inheriting-ctors โ€” ๐Ÿงฌ Enables the P0136 adjustment to the semantics of C++11 constructor inheritance. 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 -fabi-version=10 or lower is specified.
  • -fnew-ttp-matching โ€” ๐ŸŽญ Enables the P0522 resolution to Core issue 150, which covers template template parameters and default arguments. It allows a template with default template arguments to be passed as an argument for a template template parameter with 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. These include ffs, alloca, _exit, index, bzero, conjf, and other related functions.
  • -fnothrow-opt โ€” โšก Treats a throw() exception specification as if it were a noexcept specification, which can reduce or remove the text size overhead compared to a function with no exception specification. If the function has local variables of types 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 kind of exception specification results in a call to terminate rather than unexpected. ๐Ÿ˜ฌ
  • -fno-operator-names โ€” โž— Doesn't treat the operator name keywords and, bitand, bitor, compl, not, or and xor as synonyms as keywords.
  • -fno-optional-diags โ€” ๐Ÿ”• Disables diagnostics that the standard says a compiler doesn't need to issue. Right now, the only one G++ issues in this category is the one for a name having multiple meanings within a class.
  • -fpermissive โ€” ๐Ÿ˜Œ Downgrades some diagnostics about nonconformant code from errors to warnings. So using -fpermissive lets some nonconforming code compile. Lowkey a cheat code, but use it wisely ๐Ÿซถ
  • -fno-pretty-templates โ€” ๐Ÿ–๏ธ When an error message points at 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 (e.g. void f(T) [with T = int] rather than void f(int)). That way it's clear which template is involved. When an error message points at 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 these behaviors makes the error message harder to understand instead of easier, you can use -fno-pretty-templates to turn them off. ๐Ÿง 
  • -fno-rtti โ€” ๐Ÿช„ Disables generating the info for every class with virtual functions that the C++ run-time type identification features use (dynamic_cast and typeid). If you don't use those parts of the language, this flag can save you some space. Exception handling uses the same information, but G++ generates it as needed. The dynamic_cast operator can still be used for casts that don't need run-time type information, i.e. casts to void * or to unambiguous base classes.
Mixing code compiled with -frtti with 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. Be careful, bestie ๐Ÿšจ

โœจ OPTIONS โœจ (continued) ๐Ÿ’…

  • -fsized-deallocation โ€” okay, this one is giving "upgrade your delete" ๐Ÿ—‘๏ธโœจ It switches on the built-in global declarations below, which showed up in C++14:
void operator delete (void *, std::size_t) noexcept;
void operator delete[] (void *, std::size_t) noexcept;

This is super useful if you write your own replacement deallocation functions that use the object's size to make freeing stuff faster ๐ŸŽ๏ธ๐Ÿ’จ. It's enabled by default under -std=c++14 and above. And -Wsized-deallocation will warn you about spots that might want to add a definition ๐Ÿ‘€.

  • -fstrict-enums โ€” this lets the compiler optimize based on the assumption that an enum value can only be one of its enumerators ๐Ÿง . (Per the C++ standard, basically: a value that fits in the minimum number of bits needed to represent all the enumerators.) โš ๏ธ That assumption may not hold if your program casts some random integer into the enumerated type, so be careful, bestie.
  • -fstrong-eval-order โ€” evaluates member access, array subscripting, and shift expressions left-to-right, and assignment right-to-left, the way it was adopted for C++17 ๐ŸŽ€. It's enabled by default with -std=c++17. Then there's -fstrong-eval-order=some, which only orders member access and shift expressions. That one is the default without -std=c++17 ๐ŸŒธ.
  • -ftemplate-backtrace-limit=n โ€” sets how many template instantiation notes you get for a single warning or error to n. The default is 10 ๐Ÿ“.
  • -ftemplate-depth=n โ€” sets the max instantiation depth for template classes to n. This limit is what catches endless recursion during template class instantiation ๐Ÿ”. ANSI/ISO C++ conforming programs must not rely on a depth greater than 17 (it went up 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 โ€” skips 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 can shave a bit off the code size ๐Ÿฆ‹.
  • -fuse-cxa-atexit โ€” registers destructors for objects with static storage duration with the "__cxa_atexit" function instead of "atexit" โœจ. This is required for fully standards-compliant handling of static destructors, but it only works if your C library supports "__cxa_atexit".
  • -fno-use-cxa-get-exception-ptr โ€” tells GCC not to use the "__cxa_get_exception_ptr" runtime routine ๐Ÿ™…โ€โ™€๏ธ. This makes "std::uncaught_exception" incorrect, but it's necessary if that runtime routine isn't available.
  • -fvisibility-inlines-hidden โ€” this switch is you telling GCC that you don't compare pointers to inline functions or methods when the two functions' addresses are taken in different shared objects ๐Ÿค.

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

It's not exactly the same as marking methods hidden directly, though. 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 explicit visibility to cancel out the switch for that method. For example, if you do want to compare pointers to a particular inline method, 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 one tries to use visibility settings to make GCC's C++ linkage model match Microsoft Visual Studio's ๐Ÿ’œ. It makes these changes to GCC's linkage model:
  1. It sets the default visibility to hidden, like -fvisibility=hidden.
  2. Types, but not their members, are not hidden by default.
  3. The One Definition Rule gets relaxed for types without explicit visibility specifications that are defined in more than one shared object. Those declarations are permitted if they'd be permitted without this option.

In new code, it's better to use -fvisibility=hidden and export only the classes you actually want externally visible ๐Ÿ’–. Unfortunately, code might rely (perhaps accidentally) on the Visual Studio behavior ๐Ÿ˜ฌ.

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

โš ๏ธ Heads up: when this flag is given, defining types with the same name differently is a violation of the ODR. Don't do it!
  • -fno-weak โ€” tells G++ not to use weak symbol support, even if the linker provides it ๐Ÿ™…โ€โ™€๏ธ. By default, G++ uses weak symbols when they're available. This option exists only for testing and should not be used by end-users. It results in inferior code and has no benefits ๐Ÿ’€. It may be removed in a future release of G++.
  • -fext-numeric-literals (C++ and Objective-C++ only) โ€” accepts imaginary, fixed-point, or machine-defined literal number suffixes as GNU extensions ๐ŸŽ€. When this option is turned off, those 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++ โ€” skips the standard directories specific to C++ when searching for header files ๐Ÿ™ˆ, but still searches the other standard directories. (This option is used when building the C++ library.)

In addition, these warning options have meanings only 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 info about ABI tags.
  • -Wcomma-subscript (C++ and Objective-C++ only) โ€” warns about uses of a comma expression inside a subscripting expression ๐Ÿ‘€. This usage was deprecated in C++2a. However, a comma expression wrapped in ( ) is not deprecated. Example:
void f(int *a, int b, int c) {
    a[b,c];     // deprecated
    a[(b,c)];   // OK
}

It's enabled by default with -std=c++2a.

  • -Wctor-dtor-privacy (C++ and Objective-C++ only) โ€” warns when a class seems unusable because all 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 a derived class instance through a base class pointer when 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 when the class has a user-provided copy constructor or copy assignment operator, in C++11 and up ๐Ÿ“‹. This warning is enabled by -Wextra. With -Wdeprecated-copy-dtor, it also deprecates the implicit copy if the class has a user-provided destructor.
  • -Wno-init-list-lifetime (C++ and Objective-C++ only) โ€” turns off the warning 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 really 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 only lives until the end of the full-expression. So at the next statement, the initializer_list variable has a dangling pointer.
// li's initial underlying array lives as long as li
std::initializer_list<int> li = { 1,2,3 };
// assignment changes li to point to a temporary array
li = { 4, 5 };
// now the temporary is gone and li has a dangling pointer
int i = li.begin()[0] // undefined behavior
  • When a list constructor stores the begin pointer from the initializer_list argument, that doesn't extend the lifetime of the array. So if a class variable is constructed from a temporary initializer_list, the pointer is left dangling by the end of the variable declaration statement ๐Ÿ’”.
  • -Wno-literal-suffix (C++ and Objective-C++ only) โ€” stops the warning when a string or character literal is followed by a ud-suffix that doesn't begin with an underscore ๐Ÿงƒ. As a conforming extension, GCC treats those suffixes as separate preprocessing tokens so that old code using formatting macros from <inttypes.h> keeps working. For example:
#define __STDC_FORMAT_MACROS
#include <inttypes.h>
#include <stdio.h>

The first part is the PRId64 example, so this one starts just after that. Here's what comes next. Keep those bits in mind, bestie ๐Ÿ’–

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

Okay so in this case, PRId64 gets treated as its own separate preprocessing token ๐Ÿงš no cap, it's giving very specific vibes.

This option also keeps an eye on user-defined literal operators that get declared with a literal suffix identifier which doesn't start with an underscore. Those suffixes are reserved for future standardization, so the warning is literally there to protect you ๐Ÿ›ก๏ธโœจ

These warnings are enabled by default. ๐Ÿ’…


๐ŸŽ€ -Wno-narrowing (C++ and Objective-C++ only)

Okay so for C++11 and later, narrowing conversions are diagnosed by default, because the standard says so ๐Ÿ˜ญ A narrowing conversion from a constant throws an error, and a narrowing conversion from a non-constant throws a warning. -Wno-narrowing is the one that mutes that diagnostic ๐Ÿ™ˆ Just know it doesn't change what well-formed code means. Narrowing conversions are still ill-formed in SFINAE contexts, so don't get it twisted.

With -Wnarrowing in C++98, you get a warning 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)

Warn when a noexcept-expression evaluates to false because of a call to a function that doesn't have a non-throwing exception specification (so, throw() or noexcept), but the compiler still knows for sure that it never throws. It's giving "technically not promised, but actually fine" energy ๐Ÿ’€

๐ŸŒธ -Wnoexcept-type (C++ and Objective-C++ only)

Warn 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 example, it's so iconic:

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

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

๐Ÿงš -Wclass-memaccess (C++ and Objective-C++ only)

Warn when the destination of a call to a raw memory function, like memset or memcpy, is an object of class type. This also covers writing into such an object in a way that 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 the invariants the member functions rely on, which is so not it ๐Ÿ˜ญ

Here's the main offender. The memset below is undefined because it modifies a non-trivial class object, so it gets flagged:

std::string str = "abc";
memset (&str, 0, sizeof str);

The safe way to initialize or clear storage for these types is to use the appropriate constructor or assignment operator, if one exists ๐Ÿซถ The -Wclass-memaccess option is enabled by -Wall. If you explicitly cast the pointer to the class object to void *, or to a type that the raw memory function can safely access, the warning goes away.

๐Ÿ’œ -Wnon-virtual-dtor (C++ and Objective-C++ only)

Warn when a class has virtual functions and an accessible non-virtual destructor, either on itself or on an accessible polymorphic base class. That means it's possible to delete a derived class instance through a pointer to the class or base class, but it's unsafe ๐Ÿ™ˆ This warning is automatically turned on if -Weffc++ is specified.

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

Warn about uses of the register storage class specifier, unless it's part of the GNU Explicit Register Variables extension. The register keyword was deprecated in C++11 and removed in C++17, so it's kinda dead now ๐Ÿ’€ It's enabled by default with -std=c++17.

๐Ÿซง -Wreorder (C++ and Objective-C++ only)

Warn when the order of member initializers in the code doesn't match the order they actually have to run in. For example:

struct A {
  int i;
  int j;
  A(): j (0), i (1) { }
};

The compiler rearranges the member initializers for i and j so they match the declaration order of the members, and it emits a warning about that. This warning is enabled by -Wall โœจ

๐Ÿ’… -Wno-pessimizing-move (C++ and Objective-C++ only)

This warning goes off when a call to std::move prevents copy elision. A typical case where copy elision can happen is when a function with a class return type returns the name of a non-volatile automatic object. That object can't be a function parameter, and it has to have the same type as the function's return type.

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

In this example, the std::move call is what stops copy elision from happening, which is a whole vibe check ๐Ÿ™…โ€โ™€๏ธ

This warning is enabled by -Wall.

๐ŸŒˆ -Wno-redundant-move (C++ and Objective-C++ only)

This warning goes off for redundant calls to std::move. That means a move would have happened even without the std::move call. This happens because the compiler is forced to treat an object as an rvalue in certain situations, like returning a local variable where copy elision doesn't apply. Consider:

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

Here, the std::move call is redundant ๐Ÿ™„ Because G++ implements Core Issue 1579, here's another 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 are different. Even so, G++ treats the return value as if it were designated by an rvalue, so yeah, it's still flagged ๐Ÿ’€

This warning is enabled by -Wextra.

๐ŸŒท -Wredundant-tags (C++ and Objective-C++ only)

Warn about redundant class-key and enum-key in references to class types and enumerated types, in places where the key can be dropped without causing 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

๐Ÿง -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, then defining it in multiple translation units would be an ODR violation, because the meaning of B differs in each translation unit. If A only appears in a single translation unit, the best way to silence the warning is to give it internal linkage by putting it in an anonymous namespace too. The compiler doesn't give this warning for types defined in the main .C file, since those are unlikely to have multiple definitions. -Wsubobject-linkage is enabled by default ๐ŸŒธ

๐Ÿ“š -Weffc++ (C++ and Objective-C++ only)

Warn about violations of these style guidelines from Scott Meyers' Effective C++ series of books ๐Ÿค“

  • Define a copy constructor and an assignment operator for classes with dynamically-allocated memory.
  • Prefer initialization to assignment in constructors.
  • Have operator= return a reference to *this.
  • Don't try to return a reference when you must return an object.
  • Distinguish between prefix and postfix forms of increment and decrement operators.
  • Never overload &&, ||, or ,.

This option also enables -Wnon-virtual-dtor, which is one of the effective C++ recommendations too. The check is extended to warn about a lack of virtual destructor in accessible non-polymorphic base classes as well.

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

๐ŸŽˆ -Wstrict-null-sentinel (C++ and Objective-C++ only)

Warn about using an uncasted NULL as a sentinel. When compiling only with GCC, this is a valid sentinel, because NULL is defined as __null. Even though it's a null pointer constant rather than a null pointer, it's guaranteed to be the same size as a pointer. Still, this usage isn't portable across different compilers, so be careful ๐Ÿ™ˆ

๐Ÿฃ -Wno-non-template-friend (C++ and Objective-C++ only)

Disable warnings when non-template friend functions are declared within a template. In very old versions of GCC that predate the ISO standard, declarations like friend int foo(int), where the friend's name is an unqualified-id, could be interpreted as a particular specialization of a template function. The warning exists to diagnose compatibility problems, and it's enabled by default.

๐ŸŒŸ -Wold-style-cast (C++ and Objective-C++ only)

Warn if an old-style (C-style) cast to a non-void type is used in a C++ program. The new-style casts (dynamic_cast, static_cast, reinterpret_cast, and const_cast) are less vulnerable to unintended effects and way easier to search for ๐Ÿ”

๐Ÿฆ„ -Woverloaded-virtual (C++ and Objective-C++ only)

Warn when a function declaration hides virtual functions from a base class. For example:

struct A {
  virtual void f();
};

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

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

B* b;
b->f();

fails to compile ๐Ÿ˜ญ

๐Ÿฌ -Wno-pmf-conversions (C++ and Objective-C++ only)

Disable the diagnostic for converting a bound pointer to member function to a plain pointer โœจ

  • -Wsign-promo (C++ and Objective-C++ only) โ€” okay so this one flags it 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 says the current behavior is the way, so that's just the vibe now ๐Ÿ’…

  • -Wtemplates (C++ and Objective-C++ only) โ€” warns whenever a primary template declaration shows up ๐Ÿฆ‹. Some coding rules ban templates, so this is how you enforce that rule. It stays quiet inside system headers like the STL, so you can still use the STL, and you can still instantiate or specialize templates โœจ

  • -Wmismatched-tags (C++ and Objective-C++ only) โ€” warns on declarations of structs, classes, and class templates (plus their specializations) whose class-key doesn't match the definition, or the first declaration if there's no definition ๐ŸŽ€ Ngl this one is so specific but also kind of iconic.

Here's the example. The struct Object in the argument list of draw triggers the warning:

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

To fix it, either drop the redundant class-key struct, or swap it for class so it matches the definition ๐Ÿซถ Using struct to declare a class isn't wrong, as the example shows. This option is just here to keep your class declarations looking consistent. If your code is meant to be portable to Windows-based compilers, the warning also helps prevent unresolved references, because symbols declared with different class-keys get mangled differently ๐Ÿ˜ญ You can use this option on its own or together with -Wredundant-tags.


  • -Wmultiple-inheritance (C++ and Objective-C++ only) โ€” warns when a class is defined with multiple direct base classes ๐ŸŒธ Same deal as before: some coding rules ban multiple inheritance, so this helps enforce that. It's inactive inside system headers like the STL, and you're still allowed to 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, so this can enforce that rule. Also inactive inside system headers like the STL, and you can still define classes that indirectly use virtual inheritance โœจ
  • -Wno-virtual-move-assign โ€” silences warnings about inheriting from a virtual base with a non-trivial C++11 move assignment operator. Be careful though, this one is dangerous ๐Ÿ’€ If the virtual base is reachable 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 so it never moves from a moved-from object, then you can turn this warning off safely ๐Ÿซถ
  • -Wnamespaces โ€” warns when a namespace definition is opened ๐ŸŒˆ Some coding rules ban namespaces, and this helps enforce that. It's inactive inside system headers 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-class-conversion (C++ and Objective-C++ only) โ€” doesn't warn when a conversion function converts an object to the same type, to a base class of that type, or to void. Those conversion functions will never be called, so the warning is skipped ๐Ÿ“
  • -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
    • compound assignments where the left operand is a volatile-qualified non-class type
    • a volatile-qualified function return type
    • a volatile-qualified parameter type
    • structured bindings of a volatile-qualified type

This usage was deprecated in C++20 ๐Ÿ˜ญ It's enabled by default with -std=c++2a.

  • -Wzero-as-null-pointer-constant (C++ and Objective-C++ only) โ€” warns when a literal 0 is used as a null pointer constant. This can be super helpful when you're converting over to nullptr in C++11 ๐ŸŒธ

  • -Waligned-new โ€” warns about a new-expression of a type that needs greater alignment than alignof(std::max_align_t), but uses an allocation function without an explicit alignment parameter ๐Ÿ”ฅ This option is enabled by -Wall. Normally it only warns about global allocation functions, but -Waligned-new=all also warns about class member allocation functions ๐Ÿ’–
  • -Wno-placement-new, -Wplacement-new=n โ€” warns about placement new expressions with undefined behavior, like constructing an object in a buffer that's smaller than the object's type ๐Ÿงš For example, this placement new gets diagnosed because it tries to construct an array of 64 integers in a buffer that's only 64 bytes:
char buf [64];
new (buf) int[64];

This warning is enabled by default โœจ

  • -Wplacement-new=1 โ€” this is the default level ๐ŸŒˆ At this level, the warning skips some strictly undefined constructs that GCC allows as extensions for compatibility with legacy code. For example, this new expression isn't diagnosed at this level, even though it's undefined according to the C++ standard, because it writes past the end of the one-element array:
struct S { int n, a[1]; };
S *s = (S *)malloc (sizeof *s + 31 * sizeof s->a[0]);
new (s->a)int [32]();
  • -Wplacement-new=2 โ€” at this level you get all the same diagnostics as level 1, plus one more ๐Ÿ’… It also warns about placement new expressions that construct an object in the last member of a structure, where that member is an array of a single element and the object is bigger than that array. The previous example would get flagged here, but this version uses the flexible member array extension to 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) โ€” warns about catch handlers that don't catch via reference ๐ŸŽ€ Here's how the levels break down:
    • -Wcatch-value=1 (or just -Wcatch-value) warns about polymorphic class types that are caught by value
    • -Wcatch-value=2 warns about all class types that are caught by value
    • -Wcatch-value=3 warns about all types that are not caught by reference

-Wcatch-value is enabled by -Wall ๐Ÿซถ

  • -Wconditionally-supported (C++ and Objective-C++ only) โ€” warns for conditionally-supported constructs (C++11 [intro.defs]) ๐Ÿฆ‹
  • -Wno-delete-incomplete (C++ and Objective-C++ only) โ€” doesn't warn when you delete a pointer to an incomplete type, which can cause undefined behavior at runtime. This warning is enabled by default, so this flag is how you turn it off ๐Ÿ™ˆ
  • -Wextra-semi (C++, Objective-C++ only) โ€” warns about redundant semicolons after in-class function definitions ๐Ÿ“
  • -Wno-inaccessible-base (C++, Objective-C++ only) โ€” controls warnings for when a base class is inaccessible in a derived class because of ambiguity ๐Ÿ’œ This warning is enabled by default. Heads up that the warning for ambiguous virtual bases is turned on by the -Wextra option instead. Here's the example:
struct A { int a; };

struct B : A { };

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

The restrictions on offsetof might get relaxed in a future version of the C++ standard ๐Ÿ‘€

  • -Wsized-deallocation (C++ and Objective-C++ only) โ€” warns about a definition of an unsized deallocation function, like these:
void operator delete (void *) noexcept;
void operator delete[] (void *) noexcept;

...without a definition of the matching sized deallocation function:

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

...or vice versa ๐Ÿ”ฅ It's enabled by -Wextra along with -fsized-deallocation.

  • -Wsuggest-final-types โ€” warns about types with virtual methods where the code would be better off if the type were declared with the C++11 final specifier, or, if possible, declared in an anonymous namespace ๐Ÿ’– That lets GCC devirtualize polymorphic calls more aggressively. This warning works better with link-time optimization, since the class hierarchy graph info is more complete then โญ
  • -Wsuggest-final-methods โ€” warns about virtual methods that would benefit from the C++11 final specifier, or, if possible, having their type declared in an anonymous namespace or with the final specifier ๐ŸŒˆ Like the one above, this is more effective with link-time optimization, where the class hierarchy graph is more complete. It's recommended to look at the -Wsuggest-final-types suggestions first, then rebuild with the new annotations ๐Ÿซถ
  • -Wsuggest-override โ€” warns about overriding virtual functions that aren't marked with the override keyword ๐ŸŽ€
  • -Wuseless-cast (C++ and Objective-C++ only) โ€” warns when an expression is cast to its own type ๐Ÿ’…โœจ
  • -Wno-conversion-null (C++ and Objective-C++ only) โ€” okay so this one tells GCC to stop yelling about conversions between NULL and non-pointer types ๐Ÿ™ˆ Heads up that -Wconversion-null is already on by default, so this is how you opt out ๐Ÿ’…

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

๐Ÿ“ข NOTE: This manual does not describe the Objective-C and Objective-C++ languages themselves. We're here for the flags, bestie ๐Ÿซถ

This section covers 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, so you could compile a file called some_class.m like this:

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

In that example, -fgnu-runtime is an Objective-C-only option ๐ŸŒธ The other options work with any language GCC supports.

Objective-C is an extension of C, so Objective-C compilations can also use options specific to the C front-end (e.g., -Wtraditional). Same energy for Objective-C++, which can use C++-specific options (e.g., -Wabi) ๐Ÿ’œ

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

  • -fconstant-string-class=class-name โ€” Use class-name as the class to instantiate for each literal string written as @"...". The default 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 โ€” Generate object code compatible with the standard GNU Objective-C runtime. This is the default for most types of systems ๐ŸŒˆ
  • -fnext-runtime โ€” Generate output compatible with the NeXT runtime. This is the default for NeXT-based systems, including Darwin and Mac OS X. The macro __NEXT_RUNTIME__ is predefined if (and only if) this option is used ๐Ÿ“
  • -fno-nil-receivers โ€” Assume that every Objective-C message dispatch ([receiver message:arg]) in this translation unit makes sure the receiver is not nil. This lets the runtime use more efficient entry points. It's only available alongside the NeXT runtime and ABI version 0 or 1 ๐Ÿงš
  • -fobjc-abi-version=n โ€” Use version n of the Objective-C ABI for the selected runtime. Right now this is only supported for the NeXT runtime ๐Ÿ‘‘
    • Version 0 is the traditional (32-bit) ABI, without support for properties and 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 โ€” For each Objective-C class, GCC checks whether any of its instance variables is a C++ object with a non-trivial default constructor. If so, it synthesizes a special - (id) .cxx_construct instance method that runs those non-trivial default constructors on the instance variables, in order, and then returns self ๐Ÿซถ It also checks whether any instance variable is a C++ object with a non-trivial destructor, and if so, synthesizes a special - (void) .cxx_destruct method that runs all of those default destructors in reverse order ๐Ÿ’…
    • The generated - (id) .cxx_construct and - (void) .cxx_destruct methods only operate on instance variables declared in the current Objective-C class, not the ones inherited from superclasses. It's the Objective-C runtime's job to invoke all of these methods across an object's inheritance hierarchy.
    • The runtime calls - (id) .cxx_construct immediately after a new object instance is allocated, and calls - (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 invoke the - (id) .cxx_construct and - (void) .cxx_destruct methods ๐Ÿ™ˆ
  • -fobjc-direct-dispatch โ€” Allow fast jumps to the message dispatcher. On Darwin, this is accomplished via the comm page โšก
  • -fobjc-exceptions โ€” Enable syntactic support for structured exception handling in Objective-C, similar to what C++ offers. This option is required to use the Objective-C keywords @try, @throw, @catch, @finally and @synchronized ๐ŸŽ€ It's available with both the GNU runtime and the NeXT runtime, but not with the NeXT runtime on Mac OS X 10.2 and earlier ๐Ÿ’€
  • -fobjc-gc โ€” Enable garbage collection (GC) in Objective-C and Objective-C++ programs. This option is only available with the NeXT runtime. The GNU runtime has a different garbage collection implementation that doesn't need special compiler flags โœจ
  • -fobjc-nilcheck โ€” For the NeXT runtime with version 2 of the ABI, check for a nil receiver in method invocations before doing the actual method call. This is the default, and you can turn it off with -fno-objc-nilcheck ๐Ÿฆ‹ Class methods and super calls are never checked for nil this way, no matter what this flag is set to. Right now this flag does nothing when the GNU runtime, or an older version of the NeXT runtime ABI, is used ๐Ÿฅ€
  • -fobjc-std=objc1 โ€” Conform to the language syntax of Objective-C 1.0, the language recognized by GCC 4.0. This only affects the Objective-C additions to the C/C++ language. It doesn't change conformance to C/C++ standards, which the separate C/C++ dialect option flags control. With this option, any Objective-C syntax that GCC 4.0 doesn't recognize gets rejected. It's super useful if you need to make sure your Objective-C code still compiles with older versions of GCC ๐Ÿงธ
  • -freplace-objc-classes โ€” Emit a special marker that tells ld(1) not to statically link the resulting object file, and lets dyld(1) load it at run time instead. This goes hand in hand with the Fix-and-Continue debugging mode, where the object file might get recompiled and dynamically reloaded during execution, no restart needed ๐Ÿ”ฅ Right now, Fix-and-Continue is only available alongside the NeXT runtime on Mac OS X 10.3 and later ๐ŸŒธ
  • -fzero-link โ€” When compiling for the NeXT runtime, the compiler normally swaps calls to objc_getClass("...") (when the class name is known at compile time) for static class references that get initialized at load time, which boosts run-time performance ๐Ÿš€ This flag stops that and keeps the objc_getClass("...") calls. It's handy in Zero-Link debugging mode, since you can modify individual class implementations while the program is running. The GNU runtime always keeps calls to objc_get_class("...") no matter which command-line options you pass ๐Ÿ’œ
  • -fno-local-ivars โ€” By default, instance variables in Objective-C can be accessed as if they were local variables inside the methods of the class they're declared in. That can cause shadowing between instance variables and other variables with the same name, either declared locally inside a class method or globally. Specifying -fno-local-ivars turns this behavior off, so you avoid those shadowing issues ๐Ÿ™…โ€โ™€๏ธ
  • -fivar-visibility=[public|protected|private|package] โ€” Sets the default instance variable visibility to the option you pick, so instance variables declared outside the scope of any access modifier directive default to that visibility ๐Ÿ‘€
  • -gen-decls โ€” Dump the interface declarations for all classes seen in the source file to a file named sourcename.decl ๐Ÿ“
  • -Wassign-intercept (Objective-C and Objective-C++ only) โ€” Warn whenever an Objective-C assignment is intercepted by the garbage collector ๐Ÿšจ
  • -Wno-property-assign-default (Objective-C and Objective-C++ only) โ€” Don't warn if a property for an Objective-C object has no assign semantics specified ๐Ÿคทโ€โ™€๏ธ
  • -Wno-protocol (Objective-C and Objective-C++ only) โ€” If a class is declared to implement a protocol, GCC warns about every method in that protocol the class doesn't implement. By default, it warns for every method not explicitly implemented in the class, even when the implementation is inherited from the superclass. With -Wno-protocol, methods inherited from the superclass count as implemented, so no warning gets issued for them ๐Ÿงƒ
  • -Wselector (Objective-C and Objective-C++ only) โ€” Warn if multiple methods of different types for the same selector are found during compilation. This check runs on the list of methods in the final stage of compilation. It also checks each selector that appears in a @selector(...) expression, if a matching method for that selector was found during compilation. Since these checks only scan the method table at the very end, the warnings won't show up if the final stage of compilation isn't reached, for example because an error was found during compilation, or because -fsyntax-only is being used ๐Ÿ˜ญ
  • -Wstrict-selector-match (Objective-C and Objective-C++ only) โ€” Warn if multiple methods with differing argument and/or return types are found for a given selector when you try to send a message with that selector to a receiver of type id or Class. When this flag is off (which is the default), the compiler skips these warnings if the differences are confined to types that share the same size and alignment ๐ŸŒท
  • -Wundeclared-selector (Objective-C and Objective-C++ only) โ€” okay bestie, this one's for Objective-C and Objective-C++ only ๐Ÿ“ It warns you when a @selector(...) expression points at a selector that hasn't been declared yet ๐Ÿ‘€. A selector counts as undeclared if no method with that name was declared before the @selector(...) shows up. That declaration can be explicit, in an @interface or @protocol declaration, or implicit, in an @implementation section. This option runs its checks the moment it spots a @selector(...) expression, while -Wselector waits until the final stage of compilation. It also enforces the style rule that methods and selectors must be declared before you use them ๐Ÿ’…
  • -print-objc-runtime-info โ€” Generates a C header describing the largest structure that gets passed by value, if any ๐Ÿงš

โœจ Options to Control Diagnostic Messages Formatting โœจ

Traditionally, diagnostic messages got formatted without caring about the output device's aspect (e.g. its width, ...) ๐Ÿ™„ These options let you control the formatting algorithm, like how many characters go on a line and how often source location info gets reported. Heads up: some language front ends may not honor these options ๐Ÿ’€

  • -fmessage-length=n โ€” Tries to format error messages so they fit on lines of about n characters. If n is zero, no line-wrapping happens and each error message sits on a single line. This is the default for all front ends โœจ
Note: this option also affects the display of the #error and #warning pre-processor directives, and the deprecated function/type/variable attribute. It does not however affect the pragma GCC warning and pragma GCC error pragmas.
  • -fdiagnostics-show-location=once โ€” Only meaningful in line-wrapping mode ๐ŸŒธ This tells the diagnostic reporter to emit source location info once. If a message is too long and has to be wrapped, the location prefix won't get stamped again and again on each continuation line. This is the default behavior.
  • -fdiagnostics-show-location=every-line โ€” Only meaningful in line-wrapping mode ๐Ÿฆ‹ This tells the reporter to emit the same source location info as a prefix for every physical line that comes from breaking up a message that's too long to fit on one line.
  • -fdiagnostics-color[=WHEN], -fno-diagnostics-color โ€” Uses color in diagnostics ๐ŸŒˆ WHEN is never, always, or auto. The default depends on how the compiler was configured. It can be any of the WHEN options above, or never if the GCC_COLORS environment variable isn't present in the environment, and auto otherwise. auto makes GCC use color only when standard error is a terminal, and when it's not running in an emacs shell. The forms -fdiagnostics-color and -fno-diagnostics-color are aliases for -fdiagnostics-color=always and -fdiagnostics-color=never, respectively.

The colors are controlled by the GCC_COLORS environment variable ๐ŸŽจ Its value is a colon-separated list of capabilities and Select Graphic Rendition (SGR) substrings. SGR commands are interpreted by your terminal or terminal emulator, so check 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 stuck together with semicolons. The common ones you'll see are: 1 for bold, 4 for underline, 5 for blink, 7 for inverse, 39 for the 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 mode foreground colors, 49 for the default background color, 40 to 47 for background colors, 100 to 107 for 16-color mode background colors, and 48;5;0 to 48;5;255 for 88-color and 256-color mode 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

Here's the decoder ring ๐Ÿ’– 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 capabilities you can set:

  • error= โ€” SGR substring for error: markers.
  • warning= โ€” SGR substring for warning: markers.
  • note= โ€” SGR substring for note: markers.
  • path= โ€” SGR substring for colorizing paths of control-flow events printed via -fdiagnostics-path-format=, like the identifiers of individual events and the lines showing interprocedural calls and returns ๐Ÿงญ
  • range1= โ€” 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] โ€” Uses escape sequences to embed URLs in diagnostics ๐Ÿ”— For example, when -fdiagnostics-show-option shows the command-line option controlling a diagnostic, it embeds a URL pointing to that option's docs.

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. It can be any of the WHEN options above.

GCC can also be configured (via the --with-diagnostics-urls=auto-if-env configure-time option) so the default is affected by environment variables. Under that configuration, GCC defaults to auto if either the GCC_URLS or TERM_URLS environment variables are present and non-empty in the 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 don't get embedded in diagnostics. If it's set to st, URLs use ST escape sequences. If it's set to bel, which is the default, URLs use BEL escape sequences. Any other non-empty value enables the feature. If GCC_URLS isn't set, TERM_URLS is used as a fallback.

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

GCC also tries to detect a few terminals that are known to not implement the URL feature, or that have bugs (or had bugs in versions still in use), where URL escapes are likely to misbehave and 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, but do it at your own risk ๐Ÿ’€

  • -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 this flag suppresses that behavior ๐Ÿ™ˆ
  • -fno-diagnostics-show-caret โ€” By default, each diagnostic includes the original source line and a caret ^ indicating the column. This option suppresses that info ๐ŸŽ€ The source line is truncated to n characters if -fmessage-length=n is given. When the output goes to the terminal, the width is limited to the width given by the COLUMNS environment variable or, if that isn't set, 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 those labels (in the example above, 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 that metadata for some -fanalyzer diagnostics, and GCC plugins may also provide diagnostics with it. By default, if the info is present, it gets printed with the diagnostic. This option suppresses printing that metadata.
  • -fno-diagnostics-show-line-numbers โ€” By default, when printing source code (via -fdiagnostics-show-caret), a left margin showing line numbers is printed. This option suppresses that left margin ๐Ÿƒ
  • -fdiagnostics-minimum-margin-width=width โ€” Controls the minimum width of the left margin printed by -fdiagnostics-show-line-numbers. It defaults to 6.
  • -fdiagnostics-parseable-fixits โ€” Emits fix-it hints in a machine-parseable format, perfect for IDEs ๐Ÿงšโ€โ™€๏ธ For each fix-it, a line gets printed after the relevant diagnostic, starting with the string fix-it:. For example:
fix-it:"test.c":{45:3-45:21}:"gtk_widget_show_all"

The location is a half-open range ๐ŸŽ€ counted in bytes, and the initial column is byte 1, not 0 ๐Ÿ™ˆ. In the example up there, bytes 3 through 20 of line 45 of "test.c" get swapped out for the new string:

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

Filenames and replacement strings get escaped ๐Ÿ’…. A backslash becomes "\\", a tab becomes "\t", a newline becomes "\n", double quotes become "\"", and non-printable characters get written in octal, so a vertical tab turns into "\013" ๐ŸŒธ.

An empty replacement string means the range gets removed ๐Ÿ—‘๏ธ. An empty range like "45:3-45:3" means the string gets inserted right at that spot โœจ.

๐Ÿฉน -fdiagnostics-generate-patch

Okay, this one prints fix-it hints to stderr in unified diff format, after all the diagnostics are printed ๐Ÿ–จ๏ธ. It looks like this:

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

So in the C++ frontend ๐Ÿ’ป, when diagnostics show mismatching template types, you'll see something like:

  could not convert 'std::map<int, std::vector<double> >()'
    from 'map<[...],vector<double>>' to 'map<[...],vector<float>>

With -fdiagnostics-show-template-tree, you get a tree-like structure showing the common and differing parts of the types, like so:

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

The parts that differ are highlighted with color, so "double" and "float" pop in this case ๐Ÿ”ฅ.

๐Ÿ™…โ€โ™€๏ธ -fno-elide-type

By default, when the C++ frontend prints mismatching template types ๐Ÿ™ƒ, the common parts get squished into "[...]" so the error message isn't a whole novel. For example:

  could not convert 'std::map<int, std::vector<double> >()'
    from 'map<[...],vector<double>>' to 'map<[...],vector<float>>

Specifying -fno-elide-type suppresses that behavior ๐Ÿšซ. It also affects the output of -fdiagnostics-show-template-tree.

๐Ÿ›ค๏ธ -fdiagnostics-path-format=KIND

This one specifies how to print paths of control-flow events for diagnostics that have a path attached to them ๐Ÿงญ.

KIND can be none, separate-events, or inline-events, and inline-events is the default โญ.

none means don't print diagnostic paths at all ๐Ÿฅ€.

separate-events means each event within the diagnostic gets its own separate "note" diagnostic ๐Ÿ“. For example:

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

inline-events means the events get printed "inline" right inside the source code ๐Ÿ’ซ. This view tries to consolidate events into runs of events that are close together, then prints them as labelled ranges within the source.

For example, the same events as above might be printed as:

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

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

  'test': events 1-2
    |
    |  133 | {
    |      | ^
    |      | |
    |      | (1) entering 'test'
    |  134 |   boxed_int *obj = make_boxed_int (i);
    |      |                    ~~~~~~~~~~~~~~~~~~
    |      |                    |
    |      |                    (2) calling 'make_boxed_int'
    |
    +--> 'make_boxed_int': events 3-4
           |
           |  120 | {
           |      | ^
           |      | |
           |      | (3) entering 'make_boxed_int'
           |  121 |   boxed_int *result = (boxed_int *)wrapped_malloc (sizeof (boxed_int));
           |      |                                    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
           |      |                                    |
           |      |                                    (4) calling 'wrapped_malloc'
           |
           +--> 'wrapped_malloc': events 5-6
                  |
                  |    7 | {
                  |      | ^
                  |      | |
                  |      | (5) entering 'wrapped_malloc'
                  |    8 |   return malloc (size);
                  |      |          ~~~~~~~~~~~~~
                  |      |          |
                  |      |          (6) calling 'malloc'
                  |
    <-------------+
    |
 'test': event 7
    |
    |  138 |   free_boxed_int (obj);
    |      |   ^~~~~~~~~~~~~~~~~~~~
    |      |   |
    |      |   (7) calling 'free_boxed_int'
    |
(etc)

๐Ÿ” -fdiagnostics-show-path-depths

This option gives you extra info when printing control-flow paths tied to a diagnostic ๐Ÿ•ต๏ธโ€โ™€๏ธ.

If this option is provided, the stack depth gets printed for each run of events within -fdiagnostics-path-format=separate-events ๐Ÿ“.

This one is meant for GCC developers and plugin developers ๐Ÿง‘โ€๐Ÿ’ป when they're debugging diagnostics that report interprocedural control flow.

๐Ÿ™ˆ -fno-show-column

Don't print column numbers in diagnostics. This may be necessary if diagnostics are being scanned by a program that doesn't understand the column numbers, such as dejagnu ๐Ÿซถ.

๐Ÿงพ -fdiagnostics-format=FORMAT

This 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 containing JSON objects that represent the diagnostics ๐Ÿงƒ.

The JSON gets emitted as one line with no formatting ๐Ÿ˜ต, so the examples below have been formatted to make them readable.

Diagnostics can have child diagnostics ๐Ÿ‘ถ. For example, this error and note:

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

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

[
    {
        "kind": "warning",
        "locations": [
            {
                "caret": {
                    "column": 3,
                    "file": "misleading-indentation.c",
                    "line": 15
                },
                "finish": {
                    "column": 4,
                    "file": "misleading-indentation.c",
                    "line": 15
                }
            }
        ],
        "message": "this \u2018if\u2019 clause does not guard...",
        "option": "-Wmisleading-indentation",
        "option_url": "https://gcc.gnu.org/onlinedocs/gcc/Warning-Options.html#index-Wmisleading-indentation",
        "children": [
            {
                "kind": "note",
                "locations": [
                    {
                        "caret": {
                            "column": 5,
                            "file": "misleading-indentation.c",
                            "line": 17
                        }
                    }
                ],
                "message": "...this statement, but the latter is ..."
            }
        ]
    },
    ...
]

where the "note" is a child of the "warning" ๐Ÿงธ.

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


A diagnostic can contain zero or more locations ๐Ÿ“. Each location has up to three positions within it: a "caret" position and optional "start" and "finish" positions. A location can also have an optional "label" string. For example, this error:

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

has three locations, bestie ๐ŸŽ€ Its main spot is the + token at column 23 โœจ. It also has two secondary spots for the left and right sides of the expression, and those two get labels ๐Ÿท๏ธ. If you ask for JSON, it might look 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}"
        }
    ],
    "message": "invalid operands to binary + ..."
}

Okay, next up: fix-it hints ๐Ÿ’… If a diagnostic has them, it gets a "fixits" array made of half-open intervals, kinda like what you'd get from -fdiagnostics-parseable-fixits. 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

And here's how that might look in JSON form ๐Ÿฆ‹:

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

So the fix-it hint means: replace the text from "start" up to but not including "next" with the value of "string". Deletions are written with an empty "string" value, and insertions are written by having "start" equal "next" โœจ.

Control-flow paths ๐ŸŒธ If the diagnostic has a path of control-flow events attached, it gets a "path" array of event objects. Each event has a "description" string and a "location" object, plus a "function" string and a "depth" number for showing interprocedural paths. 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= could have this JSON for its path:

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

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

Okay, so warnings are diagnostic messages about constructions that aren't straight-up erroneous but are risky, or that suggest there may have been a mistake ๐Ÿ‘€.

These language-independent options don't turn on any specific warnings. Instead, they control the kinds of diagnostics GCC produces ๐Ÿ’–.

  • -fsyntax-only โ€” checks your code for syntax errors and stops right there. Nothing extra ๐Ÿ™…โ€โ™€๏ธ.
  • -fmax-errors=n โ€” caps the number of error messages at n, and then GCC bails instead of trying to keep going through the source code ๐Ÿ›‘. If n is 0 (the default), there's no limit on how many errors get printed. If -Wfatal-errors is also specified, then -Wfatal-errors takes precedence over this one ๐Ÿ‘‘.
  • -w โ€” inhibits all warning messages ๐Ÿคซ.
  • -Werror โ€” turns every warning into an error ๐Ÿ˜ค.
  • -Werror= โ€” turns one specific warning into an error. You append the warning's name, so for example -Werror=switch makes the warnings controlled by -Wswitch into errors ๐Ÿ”ฅ. It also has a negative form, which negates -Werror for specific warnings. For example, -Wno-error=switch means -Wswitch warnings are not errors, even when -Werror is in effect ๐Ÿซถ.
    • Every controllable warning's message includes the option that controls it, and you can use that option with -Werror= and -Wno-error= like we just talked about. (Printing that option in the message can be turned off with the -fno-diagnostics-show-option flag ๐Ÿ™ˆ.)
    • Heads up: specifying -Werror=foo automatically implies -Wfoo. However, -Wno-error=foo does not imply anything ๐Ÿง.
  • -Wfatal-errors โ€” makes the compiler abort on the very first error instead of trying to keep going and printing more error messages ๐Ÿ’€.

You can request a ton of specific warnings with options that begin with -W. For example, -Wimplicit asks for warnings on implicit declarations ๐Ÿ“. Every one of these specific warning options also has a negative form that starts with -Wno- to turn the warnings off. For example, -Wno-implicit ๐ŸŒˆ. This manual only lists one of the two forms, whichever one isn't the default. For more language-specific options, also check out C++ Dialect Options and Objective-C and Objective-C++ Dialect Options ๐Ÿ“–. Additional warnings can be produced by enabling the static analyzer;

Some options, like -Wall and -Wextra, switch on other options, like -Wunused, which might switch on even more options, like -Wunused-value ๐Ÿงš. When you mix positive and negative forms, the more specific option wins over the less specific one, no matter where it sits on the command line. For options with the same specificity, the last one takes effect ๐Ÿ. Options turned on or off via pragmas act as if they appeared at the very end of the command line ๐Ÿ“Œ.

When you request an unrecognized warning option (like -Wunknown-warning), GCC emits a diagnostic saying the option isn't recognized ๐Ÿค”. But if you use the -Wno- form, it's a little different: no diagnostic is produced for -Wno-unknown-warning unless other diagnostics are also being produced. This lets you use new -Wno- options with old compilers ๐Ÿฆ‹. The catch is that if something goes wrong, the compiler will warn you that an unrecognized option is present โš ๏ธ.

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

  • -Wpedantic, -pedantic โ€” issues all the warnings demanded by strict ISO C and ISO C++, and 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 ISO C standard you specify with any -std option you used.
    • 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 specifying the required version of ISO C. Without this option, certain GNU extensions and traditional C and C++ features are supported too. With this option, they get rejected ๐Ÿ™…โ€โ™€๏ธ.
    • -Wpedantic doesn't cause warnings for the alternate keywords whose names begin and end with __. That alternate format can also disable warnings for non-ISO __intN types, i.e. __intN__. Pedantic warnings are also disabled in the expression that follows __extension__. Only system header files should use these escape routes, though. Application programs should avoid them ๐Ÿšซ.

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

A feature that reports every failure to conform to ISO C would be useful sometimes, bestie, but it would be a LOT of extra work and totally different from -Wpedantic ๐Ÿ˜ญ No plans to add it anytime soon.

Where the standard set with -std is a GNU extended dialect like gnu90 or gnu99, there's a matching base standard, the version of ISO C that dialect is built on ๐ŸŒธ -Wpedantic warnings show up wherever that base standard requires them. It wouldn't make sense for warnings to appear only for features outside the GNU dialect you picked, because the GNU dialects already include every feature the compiler supports with that option, so there'd be nothing left to warn about ๐Ÿ™ˆ

๐Ÿ’… -pedantic-errors

This one turns the base standard's required diagnostics into full-on errors ๐Ÿ”ฅ It also covers some cases with undefined behavior at compile time, plus some other cases that don't stop compilation of programs that are valid under the standard.

Not the same as -Werror=pedantic! This option enables some errors the other one doesn't, and the other way around too ๐Ÿ’€

๐Ÿ‘‘ -Wall

This turns on every warning about constructions some users find questionable, the ones that are easy to avoid (or easy to tweak so the warning goes away), even when macros are involved โœจ It also switches on some language-specific warnings from the C++ Dialect Options and Objective-C and Objective-C++ Dialect Options sections.

-Wall turns on these warning flags:

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

Heads up ๐Ÿฆ‹ Some warning flags are not included in -Wall. A few of them flag stuff most people don't think is sus, but you might still want to check for it sometimes. Others flag stuff that's necessary or really hard to avoid in certain cases, with no easy code change to shut them up. Some are turned on by -Wextra, but lots of them have to be enabled one by one.

๐ŸŽ€ -Wextra

This enables some extra warning flags that -Wall doesn't ๐Ÿงš (This option used to be called -W. The older name still works, but -Wextra is more descriptive, so use that one bestie ๐Ÿ’–)

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

-Wextra also prints warnings for these cases:

  • A pointer gets compared against integer zero with <, <=, >, or >=.
  • (C++ only) An enumerator and a non-enumerator both show up in a conditional expression.
  • (C++ only) Ambiguous virtual bases.
  • (C++ only) Subscripting an array that's been declared "register".
  • (C++ only) Taking the address of a variable that's been declared "register".
  • (C++ only) A base class doesn't get initialized in the copy constructor of a derived class.

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

This warns about code affected by ABI changes ๐ŸŒˆ That includes code that might not be compatible with the vendor-neutral C++ ABI, plus the psABI for the particular target.

Since G++ now updates the ABI with every major release by default, -Wabi usually only warns about C++ ABI compatibility problems when a check was added later in a release series for an ABI issue found after the initial release. -Wabi warns about more stuff if you pick an older ABI version (with -fabi-version=n).

You can also give -Wabi an explicit version number to check C++ ABI compatibility against a specific -fabi-version level, like -Wabi=2 to warn about changes relative to -fabi-version=2.

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

Even though a lot of effort went into warning about every case, there are probably some cases that slip through, even though G++ is generating incompatible code. There can also be cases where warnings pop up even though the generated code is actually compatible ๐Ÿ™ˆ

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

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

  • A template with a non-type template parameter of reference type got 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 with __attribute ((vector_size)) were mangled in a non-standard way that didn't allow overloading functions that take vectors of different sizes.

The mangling changed in -fabi-version=4.

  • __attribute ((const)) and noreturn were mangled as type qualifiers, and decltype of a plain declaration got folded away โœ‚๏ธ

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

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

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

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

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

These issues got 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, which led to unaligned accesses. This didn't affect the ABI of a function with a nullptr_t parameter, since parameters have a minimum alignment.

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

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

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

This option also enables 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 as the psABI specifies. Before GCC 4.4, this wasn't the case. For example:
union U {
  long double ld;
  int i;
};

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

๐Ÿ“ -Wchar-subscripts

This warns if an array subscript has type char. It's a super common source of bugs, since programmers often forget this type is signed on some machines ๐Ÿ™ˆ This warning is enabled by -Wall.

๐ŸŒธ -Wno-coverage-mismatch

This warns if feedback profiles don't match when you use -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 profile feedback info.

By default this warning is on and gets treated as an error. You can use -Wno-coverage-mismatch to turn off the warning, or -Wno-error=coverage-mismatch to turn off the error.

Turning off the error can lead to poorly optimized code, and it's only useful for really minor changes, like bug fixes to an existing codebase. Completely disabling the warning is not recommended ๐Ÿ’€

๐Ÿงš -Wno-cpp

(C, Objective-C, C++, Objective-C++ and Fortran only) This suppresses the warning messages emitted by #warning directives ๐Ÿซถ

  • -Wdouble-promotion (C, C++, Objective-C and Objective-C++ only) โ€” okay bestie, this one yells whenever a float gets quietly promoted to a double ๐Ÿ‘€. Some CPUs have a 32-bit single-precision FPU that handles float in hardware but has to fake double in software, and that fake version is SO expensive. Doing math with double on those machines means paying a whole overhead tax ๐Ÿ’€. The sneaky part is that floating-point literals are implicitly double, so it's super easy to do it by accident ๐Ÿ™ˆ. Check this out:
float area(float radius)
{
   return 3.14159 * radius * radius;
}

The compiler does the entire computation in double because that little 3.14159 literal is a double ๐Ÿ˜ญ not it, bestie.

  • -Wduplicate-decl-specifier (C and Objective-C only) โ€” warns if a declaration repeats a const, volatile, restrict or _Atomic specifier ๐Ÿ’…. This one is turned on by -Wall โœจ.
  • -Wformat, -Wformat=n โ€” the big one ๐ŸŽ€ This checks calls to printf and scanf, etc., to make sure the arguments you pass match the types the format string wants, and that the conversions in the format string actually make sense. It covers the standard functions plus anything with format attributes, in the printf, scanf, strftime and strfmon families (strfmon is an X/Open extension, not in the C standard) or other target-specific families ๐ŸŒธ. Which functions get checked without format attributes depends on the standard version you picked, and those checks get switched 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 stuff from the Single Unix Specification and some BSD and GNU extensions. Other library implementations might not support all of these, and GCC doesn't warn about features that go beyond a particular library's limits ๐Ÿ’œ. BUT if you use -Wpedantic along with -Wformat, you'll get warnings about format features that aren't in your 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 for several functions, it also implies -Wnonnull ๐Ÿ‘‘. Some parts of this level can be turned off with -Wno-format-contains-nul, -Wno-format-extra-args, and -Wno-format-zero-length ๐Ÿ™ˆ. -Wformat is enabled by -Wall ๐Ÿ’–.
  • -Wformat=2 โ€” turns on -Wformat plus some extra format checks ๐Ÿ”ฅ. Right now that's the same as -Wformat -Wformat-nonliteral -Wformat-security -Wformat-y2k ๐Ÿ’….
  • -Wno-format-contains-nul โ€” if -Wformat is on, don't warn about format strings that contain NUL bytes ๐Ÿฆ‹.
  • -Wno-format-extra-args โ€” if -Wformat is on, don't warn about extra arguments to a printf or scanf format function ๐ŸŒˆ. The C standard says those extra args just get ignored, so this is the no-drama option ๐Ÿ’…. Now, if the unused arguments sit between used arguments that use $ operand number specs, you'll still get warnings by default, because the implementation can't know what type to hand va_arg to skip them ๐Ÿ˜ญ. But for scanf formats, this option does suppress that warning when all the unused arguments are pointers, since the Single Unix Specification says those are allowed ๐Ÿซถ.
  • -Wformat-overflow, -Wformat-overflow=level โ€” warns about calls to formatted output functions like sprintf and vsprintf that might overflow the destination buffer ๐ŸŒธ. When the exact number of bytes a format directive writes can't be figured out at compile time, GCC estimates it with 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 ๐Ÿ™ˆ. Here's how the levels work:
  • -Wformat-overflow, -Wformat-overflow=1 โ€” level 1 is enabled by -Wformat and is super conservative ๐Ÿซถ. It only warns about calls that most likely overflow the buffer ๐Ÿ’€. At this level, numeric args with unknown values are assumed to be one, and strings of unknown length are assumed to be empty ๐Ÿงš. Numeric args known to be bounded to a subrange of their type, or string args whose output is bounded by their directive's precision or by a finite set of string literals, are assumed to take whichever value in that range gives the most bytes of output ๐Ÿ‘‘. In the example below, the call to sprintf gets diagnosed because even with both a and b equal to 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 actually avoid the overflow ๐ŸŽ€.
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 all of that plus calls that might overflow the buffer given an argument of big enough length or magnitude ๐Ÿ”ฅ. At level 2, unknown numeric args are assumed to have the minimum representable value for signed types with a precision greater than 1, and the maximum representable value otherwise ๐Ÿ’œ. Unknown string args that can't be assumed bounded by the directive's precision, a finite set of string literals they might evaluate to, or 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 writes some of its digits past the end of the destination buffer ๐Ÿ˜ญ. To make the call safe no matter what the two variables are, the destination buffer has to be at least 34 bytes โœจ. GCC includes that minimum buffer size in an informational note right after the warning ๐Ÿฆ‹.

You can also shrink the problem instead of growing the buffer: constrain the range of the formatted values ๐Ÿ’…. You can bound the max length of string args by giving a precision in the format directive ๐ŸŒธ. And when numeric args can be assumed to be bounded by less than the precision of their type, picking an appropriate length modifier in the format specifier (or casting the argument) will reduce the required buffer size ๐Ÿงš. In the example below, if a and b are within the precision of short int, then using the %hi directive or casting the argument to short drops the max 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 on, don't warn about zero-length formats ๐Ÿ“. The C standard says zero-length formats are allowed, so GCC won't yell about them ๐Ÿ’–.
  • -Wformat-nonliteral โ€” if -Wformat is on, also warn if the format string isn't a string literal, since then it can't be checked ๐Ÿ‘€. The exception is when the format function takes its format arguments as a va_list ๐ŸŒธ.
  • -Wformat-security โ€” if -Wformat is on, also warn about uses of format functions that could be security problems ๐Ÿ”. Right now this warns about calls to printf and scanf where the format string isn't a string literal and there are no format arguments, like printf (foo); ๐Ÿ˜ฌ. That can be a security hole if the format string came from untrusted input and contains %n ๐Ÿ’€. (Currently this is a subset of what -Wformat-nonliteral warns about, but future warnings might get added to -Wformat-security that aren't in -Wformat-nonliteral ๐Ÿ”ฎ.)
  • -Wformat-signedness โ€” if -Wformat is on, also warn if the format string needs an unsigned argument but you pass a signed one, and vice versa ๐Ÿงš.
  • -Wformat-truncation, -Wformat-truncation=level โ€” warns about calls to formatted output functions like snprintf and vsnprintf that might result in output truncation โœ‚๏ธ. The same heuristics apply: when the exact number of bytes isn't known at compile time, GCC estimates it based on the level argument and on optimization ๐ŸŒˆ. Optimization usually makes this more accurate, but it can also give false positives โญ. Except where noted otherwise, this option uses the same logic as -Wformat-overflow ๐Ÿ’….
    • -Wformat-truncation, -Wformat-truncation=1 โ€” level 1 is enabled by -Wformat and is conservative ๐Ÿซถ. It only warns about calls to bounded functions whose return value is unused and that will most likely result in truncation ๐Ÿฅบ.
    • -Wformat-truncation=2 โ€” level 2 also warns about calls to bounded functions whose return value is used, and that might truncate given an argument of sufficient length or magnitude ๐Ÿ”ฅ.
  • -Wformat-y2k โ€” if -Wformat is on, also warn about strftime formats that may only yield a two-digit year ๐Ÿ“…. Y2K is NOT the vibe ๐Ÿ’€.
  • -Wnonnull โ€” warns about passing a null pointer for arguments that the nonnull function attribute says must be non-null ๐Ÿšซ. -Wnonnull is included in -Wall and -Wformat ๐Ÿ’–. You can turn it off with -Wno-nonnull ๐Ÿ™….
  • -Wnonnull-compare โ€” warns when you compare an argument marked with the nonnull function attribute against null inside the function ๐Ÿ‘€. It's included in -Wall โœจ, and you can disable it with -Wno-nonnull-compare ๐Ÿฆ‹.
  • -Wnull-dereference โ€” the compiler gets suspicious here ๐Ÿ‘€ It warns when it finds code paths that lead to erroneous or undefined behaviour because a null pointer got dereferenced. This only kicks in while -fdelete-null-pointer-checks is active, and optimizations switch that on for most targets ๐Ÿ”ฅ How precise the warnings are depends on which optimization options you're using โœจ
  • -Winit-self (C, C++, Objective-C and Objective-C++ only) โ€” warns about uninitialized variables that get initialized with themselves ๐Ÿ™ˆ Heads up, this one only works together with -Wuninitialized ๐Ÿ’…

GCC only warns about i being uninitialized in this snippet when -Winit-self is on:

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

And it's enabled by -Wall in C++ ๐ŸŒธ

  • -Wno-implicit-int (C and Objective-C only) โ€” controls the warnings for when a declaration doesn't specify a type ๐Ÿงš It's on by default in C99 and later dialects of C, and -Wall turns it on too ๐Ÿ’–
  • -Wno-implicit-function-declaration (C and Objective-C only) โ€” controls the warnings for when a function gets used before it's declared ๐Ÿ‘€ It's on by default in C99 and later dialects of C, and -Wall enables it as well. Heads up: -pedantic-errors turns this one into a full error ๐Ÿ˜ญ
  • -Wimplicit (C and Objective-C only) โ€” same as -Wimplicit-int and -Wimplicit-function-declaration put together ๐Ÿซถ Enabled by -Wall.
  • -Wimplicit-fallthrough โ€” -Wimplicit-fallthrough is the same as -Wimplicit-fallthrough=3, and -Wno-implicit-fallthrough is the same as -Wimplicit-fallthrough=0 ๐Ÿฆ‹
  • -Wimplicit-fallthrough=n โ€” this one warns when a switch case falls through ๐Ÿ˜ญ Like this:
switch (cond)
  {
  case 1:
    a = 1;
    break;
  case 2:
    a = 2;
  case 3:
    a = 3;
    break;
  }

It doesn't warn when the last statement of a case can't fall through, like a return or a call to a function declared with the noreturn attribute ๐ŸŒˆ It also understands control flow statements like if, so it only warns when it actually makes sense ๐Ÿง  For example:

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

Sometimes a fallthrough is exactly what you want, so GCC gives you an attribute, __attribute__ ((fallthrough)), to use with a null statement. That suppresses the warning that would otherwise pop up ๐Ÿ’…

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

C++17 has a standard way to silence -Wimplicit-fallthrough using [[fallthrough]]; instead of the GNU attribute. In C++11 or C++14, you can use [[gnu::fallthrough]];, which is a GNU extension โœจ You can also add a fallthrough comment instead of any of these attributes to silence the warning. The whole body of the C or C++ style comment has to match the regular expressions listed below. The option argument n decides what kinds of comments count:

  • -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, so only attributes disable the warning.

The comment needs to come right after optional whitespace and other comments, followed by a case or default keyword, or by a user label that sits in front of some case or default label ๐Ÿซง Like so:

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 get issued ๐ŸŽ€ These are enabled by default.
  • -Wignored-qualifiers (C and C++ only) โ€” warns if a function's return type has a type qualifier like const ๐Ÿ’… In ISO C, that qualifier does nothing, because a function's returned value isn't an lvalue. In C++, the warning only shows up for scalar types or void. ISO C doesn't allow 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 for when an attribute gets ignored ๐Ÿฆ‹ It's different from -Wattributes: this one warns whenever the compiler decides to drop an attribute, not when the attribute is unknown, used in the wrong place, and so on. It's enabled by default.
  • -Wmain โ€” warns if the type of main looks sus ๐Ÿ‘€ main should be a function with external linkage, returning int, and taking either zero arguments, two, or three arguments of appropriate types. It's enabled by default in C++, and by either -Wall or -Wpedantic.
  • -Wmisleading-indentation (C and C++ only) โ€” warns when the indentation doesn't match the block structure ๐Ÿซฃ Specifically, it warns for if, else, while, and for clauses with a guarded statement that has no braces, followed by an unguarded statement with the same indentation. Like here, the call to bar is indented as if the if guards it, but it isn't:
if (some_condition ())
  foo ();
  bar ();  /* Gotcha: this is not guarded by the "if".  */

If you mix tabs and spaces, the warning uses -ftabstop= to figure out whether statements line up. It defaults to 8 ๐Ÿ“

It isn't issued for code involving multiline preprocessor logic, like this:

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

It also isn't issued after a #line directive, since that usually means autogenerated code, and no assumptions can be made about the layout of the file that the directive references ๐ŸŒˆ This warning is enabled by -Wall in C and C++.

  • -Wmissing-attributes โ€” warns when a function declaration is missing one or more attributes that a related function is declared with, where the absence could hurt the correctness or efficiency of the generated code ๐Ÿงš For example, it fires for alias declarations that use attributes to set less restrictive requirements than their targets. That's usually a potential optimization opportunity โœจ By contrast, -Wattribute-alias=2 controls the warnings for when the alias is more restrictive than the target, which 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 is issued when an explicit specialization of a primary template is declared without one of these attributes that the primary template was declared with: "alloc_align", "alloc_size", "assume_aligned", "format", "format_arg", "malloc", or "nonnull". The attributes "deprecated", "error", and "warning" suppress the warning.

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

-Wmissing-attributes is enabled by -Wall ๐Ÿ’œ

Since the primary function template below uses both the "malloc" and "alloc_size" attributes, the explicit specialization of that template gets diagnosed for missing one of them ๐Ÿ™ˆ

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

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

This warning is enabled by -Wall.

  • -Wmissing-include-dirs (C, C++, Objective-C and Objective-C++ only) โ€” warns if a user-supplied include directory doesn't exist ๐ŸŒธ

-Wno-missing-profile ๐Ÿ’–

okay so this one is about the profile feedback warnings when you use -fprofile-use ๐Ÿ”ฅ. It basically catches the cases where you added a new function or a new file between -fprofile-generate and -fprofile-use and didn't regenerate your profiles. The profile feedback data files don't have any info for that new function or file, so it's giving missing data ๐Ÿ˜ญ. Same deal if the profile count data (.gcda) files got deleted, because then GCC can't use any profile feedback at all. In all of these cases you get a warning telling you it's time for a profile generation step, and ignoring it can leave you with poorly optimized code ๐Ÿ’€. -Wno-missing-profile turns the warning off, but tbh that's not recommended. Only use it when having no profile data is actually justified ๐Ÿ™ˆ.

-Wmultistatement-macros ๐ŸŽ€

this one is for unsafe macros that have multiple statements and look like they're guarded by an if, else, for, switch, or while. The catch is that after expansion, only the first statement is actually guarded. Like, the bug is so sneaky ๐Ÿ˜ญ:

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

see how y gets incremented unconditionally, not just when c holds? That's the moment this warning saves your life โœจ. 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 ๐Ÿฆ‹

this warns when you skip parentheses in spots where people usually get confused. Think an assignment where a truth value is expected, or operators nested in a way that precedence trips everyone up ๐Ÿ™ƒ. It also warns if you write a comparison like x<=y<=z, which is equivalent to (x<=y ? 1 : 0) <= z. That is NOT what your math teacher meant, bestie ๐Ÿ’€.

It also warns about dangerous uses of the GNU extension to ?: with the middle operand left out. When the condition is a boolean expression, the omitted value is always 1 ๐ŸŒˆ. Programmers often expect it to be a value computed inside the conditional expression instead, so this is a major vibe check ๐Ÿšฉ.

For C++, this also warns about some unnecessary parentheses in declarations, which can mean you were trying to make 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 this one is a whole saga and I'm obsessed ๐Ÿ˜ญ. It warns about code that may have undefined semantics because of violations of the sequence point rules in the C and C++ standards.

So sequence points are like little checkpoints in the evaluation order of your program: things executed before the checkpoint, and things executed after it ๐Ÿงš. They show up after a full expression is evaluated, after the first operand of &&, ||, ? :, or , (comma) is evaluated, before a function is called (but after its arguments and the expression naming the called function are evaluated), and in a few other places. Outside of those checkpoints, the order of evaluating subexpressions isn't specified at all ๐ŸŒธ. Even function calls within one expression, with no sequence point between them, can happen in any order. The standards committee did rule that function calls don't overlap, though ๐Ÿ’œ.

Here's the scary part. It's not specified when modifications to object values take effect between sequence points. Programs that depend on this have undefined behavior. The standards say:

"Between the previous and next sequence point an object shall have its stored value modified at most once by the evaluation of an expression. Furthermore, the prior value shall be read only to determine the value to be stored."

If a program breaks these rules, the results on any particular implementation are entirely unpredictable ๐Ÿ’€๐Ÿ’€. Examples of undefined behavior include a = a++;, a[n] = b[n++], and a[i++] = i;. Some more complicated cases won't get flagged, and it might give an occasional false positive, but it's been found pretty effective at catching this kind of problem in real programs ๐Ÿ”ฅ.

The C++17 standard defines the order of evaluation in more cases. Specifically, the right-hand side of an assignment gets evaluated before the left-hand side, so the examples above aren't undefined anymore ๐Ÿซถ. But this option will still warn about them anyway, 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 <http://gcc.gnu.org/readings.html> ๐Ÿ“š.

This warning is enabled by -Wall for C and C++ ๐ŸŽ€.

-Wno-return-local-addr ๐ŸŒท

this turns off the warning about returning a pointer (or a reference, in C++) to a variable that goes out of scope once the function returns. Use with caution, bestie, because that pointer is pointing at nothing ๐Ÿ˜ฌ.

-Wreturn-type ๐Ÿ“

this one 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 too, so no sneaking past it ๐Ÿ‘€.

For C only, it warns about a return statement with an expression in a function whose return type is void, unless the expression's type is also void. As a GNU extension, that last case is accepted without a warning unless -Wpedantic is used ๐Ÿ’…. Using the return value of a non-void function other than main that flows off the end by reaching the closing curly brace is undefined.

Unlike in C, in C++, flowing off the end of a non-void function other than main results in undefined behavior even when the value of the function is not used. Not a vibe ๐Ÿ’€.

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

-Wno-shift-count-negative ๐Ÿงš

this controls warnings for a negative shift count. It's enabled by default, so you'd only use this option to turn it off ๐Ÿ™ˆ.

-Wno-shift-count-overflow ๐Ÿฆ‹

this controls warnings if a shift count is greater than or equal to the bit width of the type. It's enabled by default too ๐Ÿ’–.

-Wshift-negative-value ๐ŸŒˆ

this warns if you left shift a negative value. It's enabled by -Wextra in C99 (and newer) and in C++11 to C++17 modes โญ.

-Wno-shift-overflow, -Wshift-overflow=n ๐Ÿ”ฅ

these options control warnings about left shift overflows. There are two levels, and it's giving layers ๐Ÿ˜ญ.

  • -Wshift-overflow=1 โ€” this is the level you get from -Wshift-overflow, and it's enabled by default in C99 and C++11 modes (and newer) โœจ. It doesn't warn about left-shifting 1 into the sign bit. (In C, though, that kind of overflow is still rejected in contexts where an integer constant expression is required.) There's no warning in C++2A mode (and newer), because signed left shifts always wrap now ๐Ÿซถ.
  • -Wshift-overflow=2 โ€” this level also warns about left-shifting 1 into the sign bit, unless C++14 mode (or newer) is active ๐Ÿ‘‘.

-Wswitch ๐Ÿ’…

this warns whenever a switch statement has an index of enumerated type and is missing a case for one or more of the named codes in that enumeration. A default label prevents this warning, so you're covered if you have one ๐ŸŽ€. case labels outside the enumeration range also trigger warnings with this option, even if there's a default label. It's enabled by -Wall โœจ.

-Wswitch-default ๐ŸŒธ

this warns whenever a switch statement doesn't have a default case. Just a little reminder to be thorough ๐Ÿซถ.

-Wswitch-enum ๐Ÿ’œ

this warns whenever a switch statement has an index of enumerated type and lacks a case for one or more of the named codes of that enumeration. case labels outside the enumeration range also get warnings. The only difference between this and -Wswitch is that this one warns about an omitted enumeration code even when there's a default label ๐Ÿ”ฅ.

-Wno-switch-bool ๐Ÿ“

this turns off the warning for a switch statement whose index is boolean but whose case values are outside the range of a boolean type. If you want to shut it up without turning it off, cast 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 ๐Ÿงš

this controls warnings when a switch case has a value that's outside its respective type range. It's enabled by default for C and C++ programs โญ.

-Wno-switch-unreachable ๐Ÿ™ˆ

this turns off the warning about a switch statement that contains statements between the controlling expression and the first case label, which will never be executed. For example:

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

-Wswitch-unreachable doesn't warn if the statement between the controlling expression and the first case label is just a declaration:

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

This warning is enabled by default for C and C++ programs ๐Ÿ’–.

-Wsync-nand (C and C++ only) ๐Ÿ”ฅ

this warns when the __sync_fetch_and_nand and __sync_nand_and_fetch built-in functions get used. Heads up: these changed semantics in GCC 4.4, so old code might act different ๐Ÿ’€.

-Wunused-but-set-parameter โœจ

this warns whenever a function parameter gets assigned to but is otherwise unused (aside from its declaration). Assigned but never read? That's a main character who forgot their lines ๐ŸŽญ๐Ÿ‘‘.

To suppress this warning, use the "unused" attribute. ๐Ÿซถ

This warning is also enabled by -Wunused together with -Wextra. โœจ

  • -Wunused-but-set-variable โ€” okay so this one yells when a local variable gets assigned to but never actually used (apart from its declaration) ๐Ÿ‘€ It's enabled by -Wall.

To suppress this warning, use the "unused" attribute. ๐Ÿซถ

This warning is also enabled by -Wunused, which is enabled by -Wall. ๐Ÿ’…

  • -Wunused-function โ€” Warns whenever a static function is declared but not defined, or a non-inline static function is unused. ๐Ÿฆ‹ This warning is enabled by -Wall.
  • -Wunused-label โ€” Warns whenever a label is declared but never used. ๐Ÿท๏ธ This warning is 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 defined locally inside a function goes unused. ๐Ÿงš This warning is enabled by -Wall.
  • -Wunused-parameter โ€” Warns whenever a function parameter is unused, aside from its declaration. ๐ŸŒธ

To suppress this warning, use the "unused" attribute. ๐Ÿซถ

  • -Wno-unused-result โ€” no drama here ๐Ÿ™ˆ Stops the warning for when a caller of a function marked with the attribute "warn_unused_result" doesn't use its return value. The default is -Wunused-result.
  • -Wunused-variable โ€” Warns whenever a local or static variable is unused, aside from its declaration. ๐Ÿ’œ This option implies -Wunused-const-variable=1 for C, but not for C++. This warning is enabled by -Wall.

To suppress this warning, 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 gets turned on 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 "#define"s. ๐Ÿคทโ€โ™€๏ธ

To suppress this warning, use the "unused" attribute. ๐Ÿซถ

  • -Wunused-const-variable=1 โ€” This is the warning level that -Wunused-variable turns on for C. ๐ŸŒˆ It only warns about unused static const variables defined in the main compilation unit, and not about static const variables declared in any header that's included.
  • -Wunused-const-variable=2 โ€” This level also warns about unused constant static variables in headers (excluding system headers). ๐Ÿง This is the warning level of -Wunused-const-variable, and you have to explicitly ask for it, since in C++ this isn't an error and in C it might be harder to clean up all the headers that get included.
  • -Wunused-value โ€” Warns whenever a statement computes a result that's explicitly not used. ๐Ÿ’… To shush it, cast the unused expression to "void". This includes an expression-statement, or the left-hand side of a comma expression that has no side effects. For example, an expression such as x[i,j] causes a warning, while x[(void)i,j] does not. ๐Ÿ’–

This warning is enabled by -Wall.

  • -Wunused โ€” all the above -Wunused options, combined ๐Ÿ‘‘

In order 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 automatic variable is used before it's ever initialized. ๐Ÿฅบ In C++, it also warns if a non-static reference or a non-static "const" member shows up in a class without constructors.

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 happen for individual uninitialized elements of structure, union or array variables, as well as for variables that are uninitialized as a whole. They do not happen for variables or elements declared "volatile". Because these warnings depend on optimization, the exact variables or elements that get warnings depend on the precise optimization options and the version of GCC you're using. ๐Ÿ“

Note that there may be no warning about a variable that's only used to compute a value that's itself never used, because data flow analysis might delete those computations before the warnings are printed. ๐Ÿซ 

  • -Wno-invalid-memory-model โ€” This option controls warnings for invocations of __atomic builtins, __sync builtins, and the C11 atomic generic functions, when they have a memory consistency argument that's either invalid for the operation or outside the range of values in the memory_order enumeration. ๐Ÿง  For example, since __atomic_store and __atomic_store_n are only defined for the relaxed, release, and sequentially consistent memory orders, the following code gets diagnosed:
void store (int *i)
{
  __atomic_store_n (i, 0, memory_order_consume);
}

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

  • -Wmaybe-uninitialized โ€” For an automatic (aka local) variable, if there's a path from the function entry to a use of the variable that's initialized, but some other paths leave it uninitialized, the compiler emits a warning if it can't prove the uninitialized paths never run at runtime. ๐Ÿ•ต๏ธโ€โ™€๏ธ

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

These warnings are optional because GCC might not be able to tell when code is correct even though 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 suppress the warning, you need to provide a default case with assert(0) or similar code. ๐Ÿ›ก๏ธ

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

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

This warning is enabled by -Wall or -Wextra. ๐Ÿ”ฅ

  • -Wunknown-pragmas โ€” Warns when a #pragma directive shows up that GCC doesn't understand. ๐Ÿ”ฎ If this command-line option is used, warnings are even issued for unknown pragmas in system header files. That's not the case if the warnings are only enabled by the -Wall command-line option.
  • -Wno-pragmas โ€” Doesn't warn about misuses of pragmas, like incorrect parameters, invalid syntax, or conflicts between pragmas. ๐ŸŒท See also -Wunknown-pragmas.
  • -Wno-prio-ctor-dtor โ€” Doesn't warn if a priority from 0 to 100 is used for a constructor or destructor. ๐Ÿ—๏ธ The constructor and destructor attributes let you assign a priority to control their order of execution before main is called or after it returns. The priority values must be greater than 100, since the compiler reserves priority values 0--100 for itself. ๐Ÿšซ
  • -Wstrict-aliasing โ€” This option is only active when -fstrict-aliasing is active. ๐ŸŽฏ It warns about code that might break the strict aliasing rules the compiler uses for optimization. It doesn't catch every case, but it does try to catch the more common pitfalls. It's included in -Wall. It's equivalent to -Wstrict-aliasing=3.
  • -Wstrict-aliasing=n โ€” Also only active when -fstrict-aliasing is active. ๐Ÿง It warns about code that might break the strict aliasing rules the compiler uses for optimization. Higher levels mean higher accuracy (fewer false positives). Higher levels also take more effort, kind of like how -O works. -Wstrict-aliasing is equivalent to -Wstrict-aliasing=3.
    • Level 1 โ€” Most aggressive, quick, and least accurate. ๐Ÿฃ It's possibly useful when higher levels don't warn but -fstrict-aliasing still breaks 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 the pointer is never dereferenced. It runs in the front end only.
    • Level 2 โ€” Aggressive, quick, and not too precise. ๐ŸŒ€ It may still have many false positives (not as many as level 1, though), and few false negatives (but possibly more than level 1). Unlike level 1, it only warns when an address is taken. It warns about incomplete types. It runs in the front end only.
    • Level 3 (default for -Wstrict-aliasing) โ€” Should have very few false positives and few false negatives. ๐Ÿ‘‘ It's slightly slower than levels 1 or 2 when optimization is enabled. It takes care of the common pun+dereference pattern in the front end: *(int*)&some_float. If optimization is enabled, it also runs in the back end, where it deals with multiple-statement cases using flow-sensitive points-to information. It only warns when the converted pointer is dereferenced. It 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 case where the code might overflow: it only warns about cases where the compiler actually implements some optimization. So this warning depends on the optimization level. ๐Ÿค“

Okay so, assuming signed overflow never happens is totally safe as long as the numbers in your code never actually overflow ๐Ÿ’…. That means this warning can give a false positive, which is a warning about code that isn't actually a problem ๐Ÿ™ˆ. To help you focus on what matters, GCC has several warning levels โœจ. No warnings get issued for undefined signed overflow when the compiler is estimating how many iterations a loop needs, especially when it's figuring out whether a loop runs at all ๐Ÿ”.

  • -Wstrict-overflow=1 โ€” Warns about stuff that's both questionable and easy to avoid ๐Ÿ™ƒ. For example, the compiler turns x + 1 > x into 1. This level is turned on by -Wall, but the higher levels aren't, so you have to ask for them yourself ๐ŸŽ€.
  • -Wstrict-overflow=2 โ€” Also warns about other spots where a comparison gets simplified to a constant, like abs (x) >= 0 ๐Ÿ‘€. This one only works because signed integer overflow is undefined, since abs (INT_MIN) overflows to INT_MIN, which is less than zero. Also, -Wstrict-overflow with no level is the same as -Wstrict-overflow=2 ๐Ÿฆ‹.
  • -Wstrict-overflow=3 โ€” Also warns about other comparisons that get simplified, like x + 1 > 1 becoming x > 0 ๐ŸŒธ.
  • -Wstrict-overflow=4 โ€” Also warns about other simplifications that aren't covered above, like (x * 10) / 5 becoming x * 2 โœจ.
  • -Wstrict-overflow=5 โ€” Also warns when the compiler reduces the magnitude of a constant in a comparison, like x + 2 > y becoming x + 1 >= y. This only gets reported at the highest level because this simplification applies to so many comparisons that it gives a very large number of false positives ๐Ÿ˜ญ.

-Wstring-compare

Warns for calls to strcmp and strncmp whose result is determined to be either zero or non-zero in equality tests, because the length of one argument is bigger than the size of the array the other argument is stored in (or the bound, for strncmp). These 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 ๐Ÿ’œ.

-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. This argument only matters for functions that work 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 bigger than the largest possible object, or at most SIZE_MAX / 2 bytes ๐Ÿงฎ. It gives the best results with optimization turned on, but it can catch a small subset of simple buffer overflows even without optimization, in calls to GCC built-ins like __builtin_memcpy that match the standard functions. Either way, it only warns about a subset of the buffer overflows that the matching overflow checking built-ins catch ๐Ÿซถ. For example, this option warns 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
}

Heads up: -Wstringop-overflow=2 is enabled by default ๐Ÿ’–.

-Wstringop-overflow, -Wstringop-overflow=1

This one uses type-zero Object Size Checking to figure out the sizes of destination objects ๐Ÿง. It's the default setting of the option. At this setting, it doesn't warn for writes past the end of subobjects of larger objects accessed through pointers, unless the size of the largest surrounding object is known. When the destination might 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 that gets warned about when the _FORTIFY_SOURCE macro is defined to a non-zero value ๐Ÿง.

-Wstringop-overflow=2

This uses type-one Object Size Checking for destination sizes ๐Ÿ“. At this setting, the option 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 those pointers might point to arrays with an unknown number of elements ๐Ÿคทโ€โ™€๏ธ.

-Wstringop-overflow=3

This uses type-two Object Size Checking ๐Ÿ”. At this setting, the option warns about overflowing the smallest object or data member. It's the most restrictive setting that can still warn for safe code ๐Ÿ˜ฌ.

-Wstringop-overflow=4

This uses type-three Object Size Checking ๐Ÿงฉ. At this setting, the option warns about overflowing any data members. When the destination is one of several objects, it uses the size of the largest of them to decide whether to warn. Just like -Wstringop-overflow=3, this setting may result in warnings for benign code ๐Ÿ™ˆ.

-Wno-stringop-truncation

Do not warn for calls to bounded string manipulation functions like strncat, strncpy, and stpncpy that might either truncate the copied string or leave the destination unchanged ๐Ÿ™…โ€โ™€๏ธ.

In the following example, the call to strncat specifies a bound that's less 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);
}

Here's another one. The following call to strncpy copies only the characters before the terminating NUL into d, without appending 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 avoid the warning when the result isn't expected to be NUL-terminated, call memcpy instead ๐ŸŒˆ.

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

In this example, the call to strncpy uses the size of the destination buffer as the bound. If the length of the source string is equal to or greater than that size, the result won't be NUL-terminated, so the call is also diagnosed โš ๏ธ. 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);
  ...
}
Heads up: if a character array is meant to store a sequence of bytes with no terminating NUL, you can annotate it with the attribute nonstring to avoid this warning ๐ŸŽ€. But these arrays aren't suitable arguments for functions that expect NUL-terminated strings. To help catch accidental misuse of them, GCC issues warnings unless it can prove the use is safe ๐Ÿ›ก๏ธ.

-Wsuggest-attribute=pure, -Wsuggest-attribute=const, -Wsuggest-attribute=noreturn, -Wmissing-noreturn, -Wsuggest-attribute=malloc

Warns about functions that might be candidates for the attributes pure, const, noreturn, or malloc ๐Ÿช„. The compiler only warns for functions that are visible in other compilation units, or (for pure and const) if it can't prove that the function returns normally. A function returns normally if it doesn't contain an infinite loop and doesn't return abnormally by throwing, calling abort, or trapping โ™พ๏ธ. This analysis needs the option -fipa-pure-const, which is enabled by default at -O and higher. Higher optimization levels make the analysis more accurate ๐Ÿ“ˆ.

-Wsuggest-attribute=format, -Wmissing-format-attribute

Warns about function pointers that might be candidates for format attributes ๐Ÿ’ซ. 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 also have a matching format attribute in the resulting type ๐Ÿง . That means the left-hand side of the assignment or initialization, the type of the parameter variable, or the return type of the containing function, respectively, should also have a format attribute to avoid the warning ๐ŸŒธ.

GCC also yells about function definitions that might be candidates for format attributes ๐Ÿ‘€. Again, these are only possible candidates, not sure things ๐Ÿซถ. GCC guesses a format attribute might fit any function that calls something like vprintf or vscanf, but that's not always true ๐Ÿ’…, and some functions that really do need format attributes might slip past the detection ๐Ÿ™ˆ.

  • -Wsuggest-attribute=cold โ€” warns about functions that might be candidates for the cold attribute โ„๏ธ. This is based on static detection and generally only fires for functions that always lead to a call to another cold function, like wrappers around C++ throw or fatal error reporting functions that lead to abort.
  • -Walloc-zero โ€” warns about calls to allocation functions decorated with the alloc_size attribute that ask for zero bytes ๐Ÿซ . That includes the built-in forms of aligned_alloc, alloca, calloc, malloc, and realloc. The behavior at zero size differs between implementations (and realloc has been deprecated for it), so relying on it can cause sneaky portability bugs and should be avoided.
  • -Walloc-size-larger-than=byte-size โ€” warns about calls to functions decorated with the alloc_size attribute that try to allocate objects bigger than the number of bytes you specify ๐Ÿ“. It also warns when the size computation, done in an integer type with infinite precision, would go past PTRDIFF_MAX on the target. -Walloc-size-larger-than=PTRDIFF_MAX is enabled by default. You can turn these warnings off by giving a byte-size of SIZE_MAX or more, or by using -Wno-alloc-size-larger-than.
  • -Wno-alloc-size-larger-than โ€” disables -Walloc-size-larger-than= warnings. It's the same as -Walloc-size-larger-than=SIZE_MAX or larger ๐ŸŒธ.
  • -Walloca โ€” warns on all uses of alloca in the source ๐Ÿšจ.
  • -Walloca-larger-than=byte-size โ€” warns on calls to alloca whose integer argument is either zero, or isn't bounded by a controlling predicate that limits it to at most byte-size ๐Ÿง. It also warns for calls to alloca where the bound is unknown. Arguments of non-integer types count as unbounded, even if they look like they're in the expected range.

A bounded case of alloca could look like this:

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

In the example above, passing -Walloca-larger-than=1000 would not warn, 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 are the opposite: alloca calls with no controlling predicate constraining their 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, this time because there's no bounds checking at all ๐Ÿ’€.

Note that even seemingly correct code using signed integers can cause a warning:

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

In that example, n could be negative, which would cause a larger-than-expected argument to be implicitly cast into the alloca call ๐Ÿซฃ.

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 (which is 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 โ€” warns about implicit conversions coming 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 โ€” this option is only active when -ftree-vrp is active (the default for -O2 and above) ๐Ÿ“. It warns about subscripts to arrays that are always out of bounds ๐Ÿ™…. This warning is enabled by -Wall.
    • -Warray-bounds=1 โ€” this is the warning level of -Warray-bounds and it's enabled by -Wall โœจ. Higher levels aren't enabled by -Wall, so you have to ask for them explicitly.
    • -Warray-bounds=2 โ€” this level also warns about out-of-bounds access for arrays at the end of a struct, and for arrays accessed through pointers ๐Ÿ‘€. It may give a bigger pile of false positives, so it's deactivated by default ๐Ÿ™ƒ.
  • -Wattribute-alias=n, -Wno-attribute-alias โ€” warns about declarations using the alias and similar attributes whose target is incompatible with the type of the alias ๐Ÿฆ‹.
    • -Wattribute-alias=1 โ€” this is the default warning level, and it diagnoses incompatibilities between the type of the alias declaration and the type of its target. Those incompatibilities are usually a sign of bugs ๐Ÿ›.
    • -Wattribute-alias=2 โ€” at this level, -Wattribute-alias also diagnoses cases where the alias declaration's attributes are more restrictive than the attributes on its target ๐Ÿง. These mismatches can lead to incorrect code generation โš ๏ธ. In other cases they might be harmless, and could be fixed just by adding the missing attribute to the target. For comparison, see -Wmissing-attributes, which covers the opposite situation, where the alias declaration is less restrictive than the target.

The attributes considered include "alloc_align", "alloc_size", "cold", "const", "hot", "leaf", "malloc", "nonnull", "noreturn", "nothrow", "pure", "returns_nonnull", and "returns_twice" ๐Ÿ“‹.

-Wattribute-alias is equivalent to -Wattribute-alias=1, and that's the default ๐Ÿ’–. You can disable these warnings with either -Wno-attribute-alias or -Wattribute-alias=0.

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

This warning is enabled by -Wall.

  • -Wbool-operation โ€” warns about suspicious operations on expressions of a boolean type ๐Ÿซข. For instance, bitwise negation of a boolean is very likely a bug in the program. For C, this warning also covers 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 warning 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 covers conditional operators:

int i = x ? *p : *p;
  • -Wduplicated-cond โ€” warns about duplicated conditions in an if-else-if chain ๐Ÿ”. For instance, it warns on 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 ๐Ÿ . Such 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 ๐Ÿ™ˆ. Typically the compiler warns if a const char * variable is passed to a function that takes a char * parameter. Use this option to suppress 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 ๐ŸŽ€. Typically the compiler warns if a const int (*)[] variable is 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 when there's a conversion between pointers with incompatible types ๐Ÿงท. This covers cases not handled by -Wno-pointer-sign, which warns about pointer argument passing or assignment with different signedness.
  • -Wno-int-conversion (C and Objective-C only) โ€” stops the warnings 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 accesses to them are undefined.
Accesses to interior zero-length arrays are undefined, so please don't go poking around in them. See

For example, the first two stores in the function bad are diagnosed, because those array elements overlap the subsequent members b and c ๐Ÿ˜ญ. The third store is diagnosed 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
}

Option -Wzero-length-bounds is enabled by -Warray-bounds ๐Ÿ’œ.

  • -Wno-div-by-zero โ€” okay so this one turns off the warning for compile-time integer division by zero ๐Ÿ™ˆ Floating-point division by zero doesn't get warned about either, bc it can be a legit way to get infinities and NaNs โœจ
  • -Wsystem-headers โ€” prints warnings for constructs found in system header files ๐Ÿ’… Those get hushed by default bc they usually aren't real problems and would just make the output harder to read. This flag tells GCC to treat system header warnings like they came from your own code ๐Ÿซถ Heads up tho: using -Wall with this doesn't warn about unknown pragmas in system headers---for that, you ALSO need -Wunknown-pragmas ๐Ÿ’€
  • -Wtautological-compare โ€” warns if a self-comparison always evaluates to true or false ๐Ÿ‘‘ It catches mistakes like this:
int i = 1;
...
if (i > i) { ... }

It also warns about bitwise comparisons that always come out true or false, like this one, which is always false, no cap ๐Ÿ’€

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

This warning is enabled by -Wall.

  • -Wtrampolines โ€” warns about trampolines generated for pointers to nested functions ๐Ÿฆ‹ A trampoline is a little piece of data or code that gets created at run time on the stack when the address of a nested function is taken, and it's used to call that nested function indirectly. Some targets only use data, so they need no special treatment. But most targets use code, which means the stack has to be made executable for the program to work properly.
  • -Wfloat-equal โ€” warns if floating-point values are used in equality comparisons ๐ŸŒธ The idea is that sometimes it's convenient to treat floats as approximations of infinitely precise real numbers. If you're doing that, you need to figure out the maximum (or likely maximum) error the computation introduces, and allow for it when comparing (and when producing output, but that's a different problem). So instead of testing for equality, check whether the two values have ranges that overlap. That's done with the relational operators, so equality comparisons are probably a mistake ๐Ÿ˜ญ
  • -Wtraditional (C and Objective-C only) โ€” warns about constructs that behave differently in traditional C and ISO C ๐Ÿงš It also warns about ISO C constructs with no traditional C equivalent, and problematic constructs you should avoid. Here's the lineup:
    • Macro parameters that show up inside string literals in the macro body. Traditional C does macro replacement inside string literals, but ISO C doesn't.
    • Some preprocessor directives didn't exist in traditional C. Traditional preprocessors only considered a line a directive if the # was in column 1. So -Wtraditional warns about directives that traditional C understands but ignores because the # isn't the first character on the line. It also suggests hiding directives like #pragma that traditional C doesn't understand by indenting them. Some traditional implementations don't recognize #elif, so this option suggests avoiding it altogether.
    • A function-like macro that shows up without arguments.
    • The unary plus operator.
    • The U integer constant suffix, or the F or L floating-point constant suffixes. (Traditional C does support the L suffix on integer constants.) These suffixes appear in macros defined in the system headers of most modern systems, e.g. the _MIN/_MAX macros in <limits.h>. Using those macros in user 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. Hexadecimal or octal values, which typically represent bit patterns, aren't warned about.
    • Usage of ISO string concatenation is detected.
    • Initialization of automatic aggregates.
    • Identifier conflicts with labels. Traditional C lacks a separate namespace for labels.
    • Initialization of unions. If the initializer is zero, the warning is omitted. This is done under the assumption that a zero initializer in user code appears conditioned on something like __STDC__ to avoid missing-initializer warnings, and relies on default initialization to zero in the traditional C case.
    • Conversions by prototypes between fixed-point and floating-point values, and vice versa. The absence of these prototypes when compiling with traditional C causes serious problems. This is a subset of the possible conversion warnings; for the full set, use -Wtraditional-conversion.
    • Use of ISO C style function definitions. This warning intentionally isn't issued for prototype declarations or variadic functions, because those ISO C features show up in your code when using libiberty's traditional C compatibility macros, PARAMS and VPARAMS. The warning is also bypassed for nested functions, because that feature is already a GCC extension and thus not relevant to traditional C compatibility.
  • -Wtraditional-conversion (C and Objective-C only) โ€” warns if a prototype causes a type conversion that's different from what would happen to the same argument without a prototype ๐Ÿ”ฅ This includes conversions of fixed point to floating 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 borrowed from C++, was introduced with ISO C99, and is allowed by default in GCC. It is not supported by ISO C90.
  • -Wshadow โ€” warns whenever a local variable or type declaration shadows another variable, parameter, type, class member (in C++), or instance variable (in Objective-C), or whenever a built-in function gets shadowed ๐Ÿ‘€ In C++, the compiler warns if a local variable shadows an explicit typedef, but not if it shadows a struct, class, or enum. If this warning is enabled, it also includes all instances of local shadowing. That means -Wno-shadow=local and -Wno-shadow=compatible-local are ignored when -Wshadow is used. Same as -Wshadow=global.
  • -Wno-shadow-ivar (Objective-C only) โ€” don't warn when a local variable shadows an instance variable in an Objective-C method ๐Ÿ™…โ€โ™€๏ธ
  • -Wshadow=global โ€” warns for any shadowing. Same as -Wshadow.
  • -Wshadow=local โ€” warns when a local variable shadows another local variable or parameter.
  • -Wshadow=compatible-local โ€” warns when a local variable shadows another local variable or parameter whose type is compatible with the type of the shadowing variable. In C++, type compatibility here means the type of the shadowing variable can be converted to that of the shadowed variable. This flag exists bc the idea is that when a local variable shadows another one of incompatible type, it's most likely intentional and not a bug or typo, like in this example โœจ
for (SomeIterator i = SomeObj.begin(); i != SomeObj.end(); ++i)
{
  for (int i = 0; i < N; ++i)
  {
    ...
  }
  ...
}

Since the two variable i in the example above have incompatible types, enabling only -Wshadow=compatible-local does not emit a warning. Bc 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 reduce the number of warnings triggered by intentional shadowing. Note that this also means shadowing const char *i by char *i does not emit a warning.

This warning is also enabled by -Wshadow=local.

  • -Wlarger-than=byte-size โ€” warns whenever an object is defined whose size exceeds byte-size ๐Ÿ“ -Wlarger-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-larger-than.
  • -Wno-larger-than โ€” disables -Wlarger-than= warnings. The option is 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 used to determine 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 included by the compiler when deciding whether to warn. -Wframe-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-frame-larger-than.
  • -Wno-frame-larger-than โ€” disables -Wframe-larger-than= warnings. The option is equivalent to -Wframe-larger-than=SIZE_MAX or larger.
  • -Wno-free-nonheap-object โ€” don't warn when attempting to free an object that was not allocated on the heap ๐ŸŒˆ
  • -Wstack-usage=byte-size โ€” okay so this one screams if a function's stack usage might go past byte-size ๐Ÿ“š The math is on the cautious side ๐Ÿง , and any room grabbed with alloca, variable-length arrays, or similar constructs gets counted too ๐Ÿ’… The messages match the vibe of -fstack-usage โœจ
    • if the stack usage is fully static but goes over your limit, it's: warning: stack usage is 1120 bytes
    • if it's (partly) dynamic but bounded, it's: warning: stack usage might be 1648 bytes
    • if it's (partly) dynamic and not bounded, it's: warning: stack usage might be unbounded
    • heads up ๐Ÿ™ˆ -Wstack-usage=PTRDIFF_MAX is on by default. You can silence these by passing a byte-size of SIZE_MAX or more, or by using -Wno-stack-usage ๐Ÿ’–
  • -Wno-stack-usage โ€” no more -Wstack-usage= warnings ๐Ÿซถ This is the same as -Wstack-usage=SIZE_MAX or anything bigger
  • -Wunsafe-loop-optimizations โ€” this one 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're using -Wformat and -pedantic without GNU extensions, this turns off the warnings about non-ISO printf / scanf width specifiers I32, I64, and I ๐ŸชŸ Those work on Windows targets because they depend on the MS runtime, so they're not technically ISO, but they're valid there ๐ŸŒธ
  • -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 when you're doing math with void * pointers and pointers to functions. In C++, it also warns when an arithmetic operation involves NULL ๐Ÿ™…โ€โ™€๏ธ This warning is also enabled by -Wpedantic
  • -Wno-pointer-compare โ€” don't warn when a pointer gets compared with a zero character constant ๐Ÿ™„ That usually means the pointer was supposed to be dereferenced. Here's the classic oops:
const char *p = foo ();
if (p == '\0')
  return 42;

Note that the code above is invalid in C++11 ๐Ÿ’€ This warning is enabled by default


  • -Wtype-limits โ€” warns if a comparison is always true or always false because of the limited range of the data type, but it won't warn for constant expressions ๐Ÿง For example, it'll flag an unsigned variable being compared against zero with < or >=. This one is also enabled by -Wextra ๐Ÿ”ฅ
  • -Wabsolute-value (C and Objective-C only) โ€” warns when you call a standard absolute-value function and there's a more appropriate standard function available ๐Ÿซง For example, calling abs(3.14) triggers it, because the right function for a double is fabs. It also warns when the argument to such a function has an unsigned type. You can suppress it with an explicit type cast, and it's 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 what the program means ๐Ÿ” Trigraphs inside comments don't get warned about, except the ones that would form escaped newlines. This option is implied by -Wall. If -Wall isn't given, it's still enabled unless trigraphs are enabled. Want trigraph conversion without the warnings but still 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 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's redefined or undefined. Built-in macros, macros defined on the command line, and macros defined in include files are not warned about ๐Ÿ™…โ€โ™€๏ธ
Note: if a macro is used, but only inside skipped conditional blocks, the preprocessor still reports it as unused ๐Ÿ˜ญ To dodge the warning, you could 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:
#if defined the_macro_causing_the_warning
#endif
  • -Wno-endif-labels โ€” don't warn when an #else or an #endif is followed by text ๐Ÿ“œ This happens sometimes in older programs with code like this:
#if FOO
...
#else FOO
...
#endif FOO

The second and third FOO 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 gets cast to a pointer type
  • -Wc90-c99-compat (C and Objective-C only) โ€” warns about features that aren't in ISO C90 but are in ISO C99 ๐Ÿ“† Think variable length arrays, the long long type, the bool type, compound literals, designated initializers, and so on. This option doesn't care about the standards mode. Warnings are turned off in the expression that follows __extension__
  • -Wc99-c11-compat (C and Objective-C only) โ€” warns about features that aren't in ISO C99 but are in ISO C11 ๐Ÿฆ‹ That covers anonymous structures and unions, the _Atomic type qualifier, the _Thread_local storage-class specifier, the _Alignas specifier, the Alignof operator, the _Generic keyword, and so on. Again, it's independent of the standards mode, and warnings are disabled in the expression that follows __extension__
  • -Wc11-c2x-compat (C and Objective-C only) โ€” warns about features that aren't in ISO C11 but are in ISO C2X ๐Ÿ”ฎ For instance, it warns about omitting the string in _Static_assert, using [[]] attribute syntax, and using decimal floating-point types, plus more. Independent of the standards mode, and warnings are disabled in the expression that follows __extension__
  • -Wc++-compat (C and Objective-C only) โ€” warns about ISO C constructs that sit outside the common subset of ISO C and ISO C++ ๐Ÿงƒ For example, asking for an implicit conversion from void * to a pointer to 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 became keywords in ISO C++ 2011. This warning turns on -Wnarrowing and is enabled by -Wall
  • -Wc++14-compat (C++ and Objective-C++ only) โ€” warns about C++ constructs whose meaning differs between ISO C++ 2011 and ISO C++ 2014 ๐Ÿ’œ This warning is enabled by -Wall
  • -Wc++17-compat (C++ and Objective-C++ only) โ€” warns about C++ constructs whose meaning differs between ISO C++ 2014 and ISO C++ 2017 โญ This warning is enabled by -Wall
  • -Wc++20-compat (C++ and Objective-C++ only) โ€” warns about C++ constructs whose meaning differs between ISO C++ 2017 and ISO C++ 2020 ๐ŸŒ™ This warning is enabled by -Wall

  • -Wcast-qual โ€” warns whenever a pointer gets cast in a way that removes a type qualifier from the target type ๐Ÿซฃ For example, it warns if a const char * gets cast to an ordinary char *. It also warns when a cast adds a type qualifier in an unsafe way. Casting char ** to const char ** is unsafe, as you can see here:
/* p is char ** value.  */
const char **q = (const char **) p;
/* Assignment of readonly string to const char * is OK.  */
*q = "string";
/* Now char** pointer points to read-only memory.  */
**p = 'b';
  • -Wcast-align โ€” warns whenever a pointer gets cast so the required alignment of the target goes up ๐Ÿ“ For example, it warns if a char * gets cast to an int * on machines where integers can only be accessed at two- or four-byte boundaries
  • -Wcast-align=strict โ€” same deal, but it warns whenever the required alignment goes up, regardless of the target machine ๐Ÿงฑ So a char * cast to an int * gets flagged no matter what
  • -Wcast-function-type โ€” warns when a function pointer gets cast to an incompatible function pointer ๐ŸŽช For casts involving function types with a variable argument list, only the types of the initial arguments that are actually provided get considered. Any pointer-type parameter matches any other pointer-type. Benign differences in integral types get ignored, like int vs. long on ILP32 targets. Type qualifiers are ignored too. The function type void (*) (void) is special and matches everything, so you can use it to suppress this warning. For casts involving pointer to member types, the warning fires whenever the cast changes the pointer to member type. This warning is enabled by -Wextra ๐Ÿซถ
  • -Wwrite-strings โ€” when compiling C, this gives string constants the type const char[length], so copying the address of one into a non-const char * pointer produces a warning ๐Ÿงต These warnings help you find code at compile time that might try to write into a string constant, but only if you've been super careful with const in your declarations and prototypes. Otherwise, it's just a nuisance. That's why -Wall doesn't request these warnings. When compiling C++, it warns about the deprecated conversion from string literals to char *. This warning is enabled by default for C++ programs ๐Ÿ™ƒ
  • -Wclobbered โ€” warns about variables that might get changed by longjmp or vfork ๐ŸŒ€ This warning is also enabled by -Wextra
  • -Wconversion โ€” okay, the implicit-conversion police are HERE ๐Ÿ‘ฎโ€โ™€๏ธโœจ It warns when an implicit conversion might alter a value, like real-to-integer stuff such as abs (x) when x is double, signed-vs-unsigned chaos like unsigned ui = -1, or squishing a value into a smaller type like sqrtf (M_PI) ๐Ÿ’€. It's chill about explicit casts like abs ((int) x) and ui = (unsigned) -1 ๐Ÿซถ (you meant it, bestie), and it won't yell if the value doesn't actually change, like abs (2.0). If the signed/unsigned warnings are too much, you can turn just those off with -Wno-sign-conversion ๐Ÿ’…

For C++, it also flags confusing overload resolution for user-defined conversions ๐Ÿ”ฅ, plus conversions that never use a type conversion operator: conversions to void, the same type, a base class, or a reference to them ๐Ÿงš In C++, the signed/unsigned conversion warnings are off by default unless you explicitly enable -Wsign-conversion ๐Ÿ˜ญ

Warnings about arithmetic on a small type getting converted back to that same small type only show up with -Warith-conversion ๐ŸŒธ

  • -Wdangling-else โ€” this one is for the "wait, which if does this else belong to??" moments ๐Ÿ™ˆ Here's the classic example that gets people:
{
  if (a)
    if (b)
      foo ();
  else
    bar ();
}

In C/C++, every else belongs to the innermost possible if, which in this example is if (b) ๐Ÿ˜ญ That's usually NOT what the programmer meant, even though the indentation says otherwise. When there's a chance of this mix-up, GCC warns if you turn this flag on. To make the warning go away, add explicit braces around the innermost if so the else can't possibly belong to the outer one โœจ The fixed code looks like this:

{
  if (a)
    {
      if (b)
        foo ();
      else
        bar ();
    }
}
This warning is enabled by -Wparentheses ๐Ÿ‘€
  • -Wdate-time โ€” warns when the macros __TIME__, __DATE__ or __TIMESTAMP__ show up, because they can stop you from getting bit-wise-identical reproducible compilations ๐Ÿ•ฐ๏ธ๐Ÿ’œ
  • -Wempty-body โ€” warns if there's an empty body in an if, else or do while statement ๐Ÿซง This one's also turned on by -Wextra โœจ
  • -Wno-endif-labels โ€” stops GCC from fussing about stray tokens after #else and #endif ๐Ÿฆ‹
  • -Wenum-compare โ€” warns when you compare values from different enumerated types ๐Ÿ“ In C++, mismatched enum types in conditional expressions get flagged too, and this one is on by default there. In C, it's turned on by -Wall ๐Ÿ’…
  • -Wenum-conversion (C, Objective-C only) โ€” warns when a value of one enumerated type gets implicitly converted into a different enumerated type ๐Ÿ‘‘ Enabled by -Wextra ๐ŸŒˆ
  • -Wjump-misses-init (C, Objective-C only) โ€” this is about goto and switch statements that jump forward across a variable's initialization, or jump backward to a label after that variable's already been initialized ๐Ÿงš It only cares about variables that get initialized right when they're declared. This warning is only supported for C and Objective-C, because in C++ this kind of branch is an error anyway ๐Ÿ’€

-Wjump-misses-init is included in -Wc++-compat, and you can turn it off with -Wno-jump-misses-init ๐Ÿซถ

  • -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 one's enabled by -Wall. In C, it's enabled by -Wextra ๐Ÿ”ฅ
  • -Wsign-conversion โ€” warns for implicit conversions that might change the sign of an integer value, like assigning a signed integer expression to an unsigned integer variable ๐ŸŒธ An explicit cast silences the warning โœจ In C, this option is also turned on by -Wconversion ๐Ÿ’…
  • -Wfloat-conversion โ€” warns for implicit conversions that reduce the precision of a real value ๐Ÿ’– That includes going from real to integer, and going from a higher precision real to a lower precision real. This option is also turned on by -Wconversion ๐Ÿฆ‹
  • -Wno-scalar-storage-order โ€” tells GCC to chill about suspicious constructs involving reverse scalar storage order ๐ŸŒˆ
  • -Wsizeof-pointer-div โ€” warns about suspicious divisions of two sizeof expressions that divide the pointer size by the element size ๐Ÿ™ˆ That's the usual way people try to compute an array size, but it won't work right with pointers. For example, this warns about sizeof (ptr) / sizeof (ptr[0]) if ptr is a pointer and not an array ๐Ÿ˜ญ Enabled by -Wall โœจ
  • -Wsizeof-pointer-memaccess โ€” warns about sketchy length parameters passed to certain string and memory built-in functions when the argument uses sizeof ๐Ÿงš It triggers for things like memset (ptr, 0, sizeof (ptr)); if ptr is a pointer and not an array (and it even suggests a possible fix), or memcpy (&foo, ptr, sizeof (&foo)); ๐Ÿ’œ It also warns about bounded string copy functions like strncat or strncpy that use the sizeof of the source array as their bound. Here's a super relatable example where the strncat call uses the size of the source string as the bound. That's almost certainly a mistake, so the call gets diagnosed ๐Ÿ’€
void make_file (const char *name)
{
  char path[PATH_MAX];
  strncpy (path, name, sizeof path - 1);
  strncat (path, ".text", sizeof ".text");
  ...
}
The -Wsizeof-pointer-memaccess option is enabled by -Wall ๐Ÿ‘€
  • -Wno-sizeof-array-argument โ€” doesn't warn when sizeof gets 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. It triggers when the first argument references an array, and the third argument is a number equal to the number of elements, but not equal to the size of the array in memory ๐Ÿ˜ญ That usually means you forgot to multiply by the element size. This warning is enabled by -Wall โœจ
  • -Wmemset-transposed-args โ€” warns about suspicious memset calls where the second argument isn't zero and the third argument is zero ๐Ÿ™ƒ For example, memset (buf, sizeof buf, 0) gets diagnosed, because memset (buf, 0, sizeof buf) was what you meant ๐Ÿ’… The diagnostic only fires if the third argument is a literal zero. If it's an expression that folds to zero, or a cast of zero to some type, the arguments are a lot less likely to have been mixed up by accident, so no warning is emitted ๐Ÿซถ This warning is enabled by -Wall ๐Ÿ”ฅ
  • -Waddress โ€” warns about suspicious uses of memory addresses ๐Ÿ‘€ This includes using the address of a function in a conditional expression, like void func(void); if (func), and comparing against the memory address of a string literal, like if (x == "abc"). These usually mean a programmer error. The address of a function always evaluates to true, so using it in a conditional usually means you forgot the parentheses in a function call ๐Ÿ’€ And comparing against string literals gives unspecified behavior and isn't portable in C, so you probably meant to use strcmp ๐Ÿงš This warning is enabled by -Wall โœจ
  • -Wno-address-of-packed-member โ€” doesn't warn when the address of a packed member of a struct or union is taken, which usually results in an unaligned pointer value ๐Ÿฆ‹ This is enabled by default ๐Ÿ’–
  • -Wlogical-op โ€” warns about suspicious uses of logical operators in expressions ๐ŸŒˆ That includes using logical operators where a bit-wise operator is likely expected. It also warns when both operands of a logical operator are the same. Like this one:
extern int a;
if (a < 0 && a < 0) { ... }
  • -Wlogical-not-parentheses โ€” warns about a logical not used on the left-hand operand of a comparison ๐Ÿ™ˆ It doesn't warn if the right operand is considered a boolean expression. The point is to catch sketchy code like this:
int a;
...
if (!a > 1) { ... }

If you want to shut the warning up, wrap the left-hand side in parentheses:

if ((!a) > 1) { ... }
This warning is enabled by -Wall ๐Ÿ‘€
  • -Waggregate-return โ€” warns if any functions that return structures or unions are defined or called ๐Ÿ“ In languages where you can return an array, this also gets a warning ๐Ÿ’…
  • -Wno-aggressive-loop-optimizations โ€” warns if, inside 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 โ€” doesn't warn if an unexpected __attribute__ is used, like unrecognized attributes, function attributes applied to variables, and so on ๐Ÿงš This doesn't stop errors for incorrect use of supported attributes though, so don't get too comfy ๐Ÿ’€
  • -Wno-builtin-declaration-mismatch โ€” warns if a built-in function is declared with an incompatible signature or as a non-function ๐Ÿ‘‘ It also warns when a built-in function 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 on, 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 prototypes of built-in functions are in scope โœจ

Here's an example. The call to memset below gets diagnosed because the function expects a value of type size_t as its argument, but the type of 32 is int ๐Ÿ˜ญ With -Wextra, the declaration of the function gets diagnosed too:

extern void* memset ();
void f (void *d)
{
  memset (d, '\0', 32);
}
  • -Wno-builtin-macro-redefined: okay bestie, this is the chill button ๐Ÿ˜Œ It stops GCC from freaking out when you redefine certain built-in macros. Specifically, it quiets the warnings for redefining __TIMESTAMP__, __TIME__, __DATE__, __FILE__, and __BASE_FILE__ ๐Ÿ•ฐ๏ธ
  • -Wstrict-prototypes (C and Objective-C only): GCC will call you out if a function gets declared or defined without spelling out its argument types ๐Ÿ’… An old-style definition gets a pass with no warning, though, as long as an earlier declaration already lists the argument types. no cap, that's a fair deal ๐Ÿซถ
  • -Wold-style-declaration (C and Objective-C only): this one hunts for obsolescent stuff in declarations, based on the C Standard ๐Ÿ“œ For example, it warns if storage-class specifiers like static aren't the very first things in a declaration. This warning is also enabled by -Wextra โœจ
  • -Wold-style-definition (C and Objective-C only): warns whenever you use an old-style function definition, and it does this even if there's a previous prototype ๐Ÿ™ƒ Quick tea โ˜•: a definition using () isn't treated as old-style in C2X mode, since it means the same thing as (void) there. For older standards, though, it still counts as old-style.
  • -Wmissing-parameter-type (C and Objective-C only): this catches a parameter that gets declared with no type specifier in K&R-style functions, like this ๐Ÿ‘‡
void foo(bar) { }

This warning is also enabled by -Wextra ๐ŸŒธ

  • -Wmissing-prototypes (C and Objective-C only): warns if a global function is defined without a previous prototype declaration ๐Ÿฆ‹ It fires even when the definition itself has a prototype. Use it to sniff out global functions that don't have a matching prototype in a header file. This option isn't valid for C++, because every function declaration there already provides a prototype, and a non-matching one just declares an overload instead of conflicting with an earlier declaration. For C++, use -Wmissing-declarations instead ๐Ÿ’œ
  • -Wmissing-declarations: warns if a global function is defined without a previous declaration ๐Ÿงš Same deal, it does this even if the definition provides a prototype. Use it to find global functions that aren't declared in header files. In C, there are no warnings for functions with previous non-prototype declarations, so use -Wmissing-prototypes for those. In C++, there are no warnings for function templates, inline functions, or functions in anonymous namespaces ๐ŸŒˆ
  • -Wmissing-field-initializers: warns if a structure's initializer is missing some fields ๐Ÿ“ In this example, x.h is implicitly zero, so it gets flagged:
struct s { int f, g, h; };
struct s x = { 3, 4 };

This option does not warn about designated initializers, so this one slides right through โœจ

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

In C, this option also doesn't warn about the universal zero initializer { 0 } ๐Ÿ’–

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

Likewise, in C++, the empty { } initializer gets a pass too ๐Ÿซถ

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

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

  • -Wno-multichar: turns off the warning for multicharacter constants like 'FOOF' ๐Ÿ™ˆ These are usually typos, since they have implementation-defined values, so they don't belong in portable code ๐Ÿ’€
  • -Wnormalized=[none|id|nfc|nfkc]: okay, this one is a whole saga, so buckle up ๐ŸŽข In ISO C and ISO C++, two identifiers are different if they're different sequences of characters. But when characters outside basic ASCII show up, you can end up with two different sequences that look exactly the same ๐Ÿ‘€ To stop that confusion, the ISO 10646 standard has normalization rules that turn look-alike sequences into the same sequence. GCC can warn you if your identifiers haven't been normalized, and this option controls that warning.

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

Here's the tea: some characters that ISO C and ISO C++ allow in identifiers can't be allowed after converting to NFC. That means there's no way to use those symbols in portable ISO C or C++ and still have every identifier in NFC ๐Ÿ˜ญ -Wnormalized=id suppresses the warning for those characters. The standards folks are hoping future versions will fix this, which is exactly why this option isn't the default โœจ

You can switch the warning off for all characters with -Wnormalized=none or -Wno-normalized.

Only do this if you're using some other normalization scheme (like "D"). Otherwise you can easily create bugs that are literally impossible to see ๐Ÿ’€

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


  • -Wno-attribute-warning: stops GCC from warning about usage of functions declared with the "warning" attribute ๐Ÿฆ‹ By default, this warning is enabled. You can use -Wno-attribute-warning to disable the warning, or -Wno-error=attribute-warning to disable the error when compiling with the -Werror flag ๐Ÿซถ
  • -Wno-deprecated: no warnings about usage of deprecated features ๐Ÿงƒ
  • -Wno-deprecated-declarations: no warnings about uses of functions, variables, and types marked as deprecated with the "deprecated" attribute ๐ŸŒˆ
  • -Wno-overflow: no warnings about compile-time overflow in constant expressions ๐Ÿ™ˆ
  • -Wno-odr: this one warns about One Definition Rule violations during link-time optimization ๐Ÿง  It's enabled by default โœจ
  • -Wopenmp-simd: warns if the vectorizer cost model overrides the OpenMP simd directive that you set ๐Ÿ‘‘ If you want to relax the cost model, you can use -fsimd-cost-model=unlimited ๐Ÿ’…
  • -Woverride-init (C and Objective-C only): warns if an initialized field without side effects gets overridden when you use designated initializers ๐ŸŽ€ This warning is included in -Wextra. To get the other -Wextra warnings without this one, use -Wextra -Wno-override-init ๐Ÿ“
  • -Wno-override-init-side-effects (C and Objective-C only): no warnings if an initialized field with side effects gets overridden when you use designated initializers. This warning is enabled by default ๐Ÿ’œ
  • -Wpacked: warns if a structure gets the packed attribute, but packed has no effect on the layout or size of the structure ๐Ÿงš Those structures can end up misaligned for little benefit, which is a bit of a mood ๐Ÿ˜ฌ 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: okay, history lesson time ๐Ÿ“š The 4.1, 4.2, and 4.3 series of GCC ignored the packed attribute on bit-fields of type char. That got fixed in GCC 4.4, but the change can lead to differences in structure layout. GCC tells you when the offset of such a field has changed in GCC 4.4. For example, there's no longer a 4-bit padding between field a and b in this structure:
struct foo
{
  char a:4;
  char b:8;
} __attribute__ ((packed));

This warning is enabled by default. Use -Wno-packed-bitfield-compat to disable this warning ๐ŸŒธ

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

This warning is enabled by -Wall ๐Ÿ”ฅ

  • -Wpadded: warns if padding is included in a structure, either to align one of its elements or to align the whole structure ๐Ÿซง Sometimes you can rearrange the fields to reduce the padding and make the structure smaller, so this one is kind of a helpful nudge ๐Ÿฆ‹
  • -Wredundant-decls: warns if anything gets declared more than once in the same scope ๐Ÿ™ƒ It does this even in cases where multiple declarations are valid and change nothing ๐Ÿ’…
  • -Wrestrict: warns when an object referenced by a restrict-qualified parameter (or a __restrict-qualified parameter in C++) is aliased by another argument, or when copies between those objects overlap ๐Ÿ˜ฑ In the strcpy example below, the call 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 detects some instances of simple overlap even without optimization, but it works best at -O2 and above โšก It's included in -Wall ๐Ÿ’–

  • -Wnested-externs (C and Objective-C only): warns if an extern declaration is encountered within a function ๐ŸŒˆ
  • -Winline โ€” okay so this one yells at you if a function you marked inline can't actually get inlined ๐Ÿ‘€ Even with it on, GCC won't warn about failed inlining in functions from system headers ๐Ÿซถ The compiler juggles a bunch of heuristics to decide, like how big the function is and how much inlining it's already done in the current function. So tiny changes in your source can make -Winline warnings pop up or vanish, and that's just the vibe ๐Ÿฆ‹
  • -Wint-in-bool-context โ€” warns about sus integer stuff where a boolean is expected ๐Ÿง Think conditional expressions (?:) using non-boolean integer constants in a boolean context, like "if (a <= b ? 2 : 3)". Or left shifting signed integers in a boolean context, like "for (a = 0; 1 << a; a++);". It also covers all kinds of multiplications, no matter the data type ๐Ÿ’€ This one is enabled by -Wall โœจ
  • -Wno-int-to-pointer-cast โ€” this suppresses the warnings for casts to a pointer type from an integer of a different size ๐Ÿ™ˆ In C++, casting to a pointer type of a smaller size is an error, so keep that in mind bestie. Wint-to-pointer-cast is enabled by default ๐Ÿ’…
  • -Wno-pointer-to-int-cast (C and Objective-C only) โ€” silences warnings for casts from a pointer to an integer type of a different size ๐ŸŒธ
  • -Winvalid-pch โ€” warns if a precompiled header is found in the search path but can't actually be used ๐Ÿฅฒ
  • -Wlong-long โ€” warns when the "long long" type shows up ๐Ÿ‘‘ It's enabled by either -Wpedantic or -Wtraditional in ISO C90 and C++98 modes. To make the warnings go away, use -Wno-long-long ๐Ÿ“
  • -Wvariadic-macros โ€” warns if variadic macros are used in ISO C90 mode, or if the GNU alternate syntax is used in ISO C99 mode ๐Ÿงš It's enabled by either -Wpedantic or -Wtraditional. To shush it, use -Wno-variadic-macros ๐Ÿซถ
  • -Wno-varargs โ€” don't warn about questionable usage of the macros for handling variable arguments, like "va_start" ๐Ÿ’– These warnings are on by default, so this is how you turn them off ๐Ÿ™…โ€โ™€๏ธ
  • -Wvector-operation-performance โ€” warns if a vector operation isn't implemented using the architecture's SIMD capabilities ๐Ÿ”ฅ It's mainly useful for performance tuning. A vector operation can be done three ways: "piecewise", where the scalar operation runs on every vector element; "in parallel", where it's implemented with scalars of a wider type (which is usually more performance efficient); and "as a single scalar", where the vector fits into a scalar type โœจ
  • -Wvla โ€” warns if a variable-length array is used in the code ๐Ÿฆ‹ -Wno-vla stops the -Wpedantic warning about variable-length arrays ๐ŸŒˆ
  • -Wvla-larger-than=byte-size โ€” if you use this, the compiler warns about declarations of variable-length arrays whose size is either unbounded, or bounded by an argument that lets the array size go past byte-size bytes ๐Ÿ˜ญ It's kinda like how -Walloca-larger-than=byte-size works, just for variable-length arrays ๐Ÿ’œ
Heads up: GCC may optimize small variable-length arrays with a known value into plain arrays, so this warning might not trigger for those ๐Ÿ‘€

-Wvla-larger-than=PTRDIFF_MAX is enabled by default, but it's typically only effective when -ftree-vrp is active (which is the default for -O2 and above) ๐Ÿงš See also -Walloca-larger-than=byte-size โญ

  • -Wno-vla-larger-than โ€” disables the -Wvla-larger-than= warnings ๐Ÿ™…โ€โ™€๏ธ This is the same as -Wvla-larger-than=SIZE_MAX or larger ๐ŸŒธ
  • -Wvolatile-register-var โ€” warns if a register variable is declared volatile ๐Ÿซ  Here's the tea: volatile doesn't stop every optimization that might eliminate reads and/or writes to register variables. This warning is enabled by -Wall ๐Ÿ’…
  • -Wdisabled-optimization โ€” warns if a requested optimization pass is disabled ๐Ÿฅน This doesn't usually mean your code is wrong. It just means GCC's optimizers can't handle it efficiently. Often the code is just too big or too complex, and GCC refuses to optimize programs when the optimization would likely take inordinate amounts of time ๐Ÿข
  • -Wpointer-sign (C and Objective-C only) โ€” warns about pointer argument passing or assignment with different signedness ๐ŸŽ€ This option is only supported for C and Objective-C. It's implied by -Wall and by -Wpedantic, and you can disable it with -Wno-pointer-sign ๐Ÿ’–
  • -Wstack-protector โ€” this one is only active when -fstack-protector is active ๐Ÿ›ก๏ธ It warns about functions that aren't protected against stack smashing ๐Ÿ’€
  • -Woverlength-strings โ€” warns about string constants longer than the "minimum maximum" length the C standard specifies ๐Ÿ“ Modern compilers are chill with way longer strings, but very portable programs should avoid them ๐Ÿซถ The limit applies after string constant concatenation and doesn't count the trailing NUL. In C90 the limit was 509 characters, and in C99 it got bumped to 4095. C++98 doesn't specify 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 without a suffix ๐Ÿง If you pair it with -Wsystem-headers, it also warns about those constants in system header files. This is super handy when you're getting code ready for the "FLOAT_CONST_DECIMAL64" pragma from the decimal floating-point extension to C99 ๐Ÿ’œ
  • -Wno-lto-type-mismatch โ€” during link-time optimization, this stops warnings about type mismatches in global declarations from different compilation units ๐Ÿ”— It requires -flto to be enabled, and it's on by default ๐Ÿฆ‹
  • -Wno-designated-init (C and Objective-C only) โ€” suppresses warnings when a positional initializer is used to initialize a structure marked with the "designated_init" attribute ๐Ÿ™ˆ
  • -Wno-hsa โ€” no warnings when HSAIL can't be emitted for the compiled function or OpenMP construct ๐ŸŒธ These warnings are on by default, so this is how you quiet them ๐Ÿ˜Œ

โœจ Options That Control Static Analysis โœจ

  • -fanalyzer โ€” okay this one is the main character of static analysis ๐Ÿ•ต๏ธโ€โ™€๏ธ It looks for "interesting" interprocedural paths through the code and warns you about problems it finds on them. Just a heads up, it's way more expensive than other GCC warnings ๐Ÿ˜ญ Turning it on effectively turns on all of these:
-Wanalyzer-double-fclose -Wanalyzer-double-free
-Wanalyzer-exposure-through-output-file -Wanalyzer-file-leak
-Wanalyzer-free-of-non-heap -Wanalyzer-malloc-leak
-Wanalyzer-possible-null-argument
-Wanalyzer-possible-null-dereference -Wanalyzer-null-argument
-Wanalyzer-null-dereference -Wanalyzer-stale-setjmp-buffer
-Wanalyzer-tainted-array-index
-Wanalyzer-unsafe-call-within-signal-handler
-Wanalyzer-use-after-free
-Wanalyzer-use-of-pointer-in-stale-stack-frame
This option is only available if GCC was configured with analyzer support enabled, so check your build first ๐Ÿ‘€
  • -Wanalyzer-too-complex โ€” the analyzer uses a bunch of heuristics to explore the control flow and data flow in your program, but sufficiently complicated code can totally defeat them ๐ŸŒ€ By default, if the code is too complicated and the analysis hits an internal limit, it just silently stops ๐Ÿคทโ€โ™€๏ธ This option makes it warn you when that happens ๐Ÿ”ฅ
  • -Wno-analyzer-double-fclose โ€” this warning needs -fanalyzer to be on, since that's what enables it ๐Ÿ’… Use -Wno-analyzer-double-fclose to turn it off. It warns about paths through the code where a "FILE *" can have "fclose" called on it more than once ๐Ÿ“
  • -Wno-analyzer-double-free โ€” again, this needs -fanalyzer to enable it, and you can use -Wno-analyzer-double-free to disable it ๐Ÿซถ It warns about paths where a pointer can have "free" called on it more than once ๐Ÿงน
  • -Wno-analyzer-exposure-through-output-file โ€” needs -fanalyzer to be enabled, and -Wno-analyzer-exposure-through-output-file turns it off ๐Ÿ™ˆ It warns about paths where a security-sensitive value gets written to an output file, like writing a password to a log file ๐Ÿ” (no thank you ๐Ÿ’€)
  • -Wno-analyzer-file-leak โ€” requires -fanalyzer, and you can disable it with -Wno-analyzer-file-leak ๐ŸŒธ It warns about paths where a "<stdio.h>" "FILE *" stream object gets leaked ๐Ÿ’ง
  • -Wno-analyzer-free-of-non-heap โ€” needs -fanalyzer to be on, and -Wno-analyzer-free-of-non-heap disables it ๐Ÿงš It warns about paths where "free" is called on a non-heap pointer, like an on-stack buffer or a global ๐Ÿ™…โ€โ™€๏ธ
  • -Wno-analyzer-malloc-leak โ€” -fanalyzer enables this one, and -Wno-analyzer-malloc-leak turns it off โœจ It warns about paths where a pointer allocated via "malloc" gets leaked ๐Ÿซ 
  • -Wno-analyzer-possible-null-argument โ€” requires -fanalyzer, and -Wno-analyzer-possible-null-argument disables it ๐ŸŽ€ It warns about paths where a possibly-NULL value is passed to a function argument marked with "__attribute__((nonnull))" as needing a non-NULL value ๐Ÿฅบ
  • -Wno-analyzer-possible-null-dereference โ€” needs -fanalyzer to be enabled, and -Wno-analyzer-possible-null-dereference turns it off ๐Ÿ’… It warns about paths where a possibly-NULL value gets dereferenced ๐Ÿ˜ฌ
  • -Wno-analyzer-null-argument โ€” -fanalyzer enables this, and -Wno-analyzer-null-argument disables it ๐ŸŒˆ It warns about paths where a value known to be NULL is passed to a function argument marked with "__attribute__((nonnull))" as needing a non-NULL value ๐Ÿ’€
  • -Wno-analyzer-null-dereference โ€” requires -fanalyzer, and you can use -Wno-analyzer-null-dereference to disable it ๐Ÿซถ

okay bestie, this one is the alarm for when a path through your code dereferences a value that's known to be NULL ๐Ÿ’€ rip to every null pointer that snuck through unnoticed ๐Ÿซ 

  • -Wno-analyzer-stale-setjmp-buffer โ€” this warning needs -fanalyzer to be on, and that flag turns it on for you โœจ if you want it gone, use -Wno-analyzer-stale-setjmp-buffer ๐Ÿ’…

okay so this one warns when longjmp gets used to rewind to a jmp_buf tied to a setjmp call, but the function that made that setjmp call has already returned ๐Ÿ˜ญ

when setjmp is called on a jmp_buf to save a rewind spot, it also records the stack frame. that frame goes invalid the second the function with the setjmp call returns. if you longjmp back to it anyway, you're referencing a stack frame that doesn't exist anymore, which will likely lead to a crash (or worse ๐Ÿ™ˆ)

  • -Wno-analyzer-tainted-array-index โ€” this warning needs both -fanalyzer and -fanalyzer-checker=taint to be enabled ๐Ÿ” use -Wno-analyzer-tainted-array-index to switch it off

this one is giving security vibes ๐Ÿ›ก๏ธ it warns when a value an attacker could control gets used as the index of an array access without being sanitized first

  • -Wno-analyzer-unsafe-call-within-signal-handler โ€” this warning needs -fanalyzer, which enables it ๐Ÿ”ฅ use -Wno-analyzer-unsafe-call-within-signal-handler to disable it

it warns when a function that's known to be async-signal-unsafe (like fprintf) gets called from inside a signal handler ๐Ÿ’€

  • -Wno-analyzer-use-after-free โ€” this warning needs -fanalyzer, which enables it โœจ use -Wno-analyzer-use-after-free to disable it

this one is the drama queen ๐Ÿ‘‘ it warns when a pointer gets used after free has already been called on it

  • -Wno-analyzer-use-of-pointer-in-stale-stack-frame โ€” this warning needs -fanalyzer, which enables it ๐ŸŒธ use -Wno-analyzer-use-of-pointer-in-stale-stack-frame to disable it

it warns when a pointer gets dereferenced and it points to a variable in a stale stack frame ๐Ÿฆ‹

okay so the knobs you can twist to control how the analyzer explores your code 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 ๐ŸŽ›๏ธ

these options control the analyzer, so let's get into them ๐Ÿ’–

  • -fanalyzer-call-summaries โ€” 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 enabled, call summaries are only 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 run just the named checker, and enables it ๐ŸŽฏ

some checkers are off by default (even with -fanalyzer), like the "taint" checker that implements -Wanalyzer-tainted-array-index. this option is required to turn them on ๐Ÿ”“

  • -fanalyzer-fine-grained โ€” this one is intended for analyzer developers ๐Ÿง‘โ€๐Ÿ’ป

internally the analyzer builds an "exploded graph" that combines control flow graphs with data flow information. by default, an edge in this graph can hold the effects of a whole run of multiple statements within a basic block. with -fanalyzer-fine-grained, each statement gets its own edge ๐Ÿฆ‹

  • -fanalyzer-show-duplicate-count โ€” another developer-only one ๐Ÿ› ๏ธ if multiple diagnostics get flagged as duplicates of each other, it emits a note when reporting the best diagnostic, giving the number of extra diagnostics the deduplication logic suppressed ๐Ÿ’…
  • -fno-analyzer-state-merge โ€” developer territory ๐ŸŒˆ by default the analyzer tries to simplify things by merging sufficiently similar states at each program point as it builds its "exploded graph". with -fno-analyzer-state-merge this merging gets suppressed, which is handy for debugging state-handling issues ๐Ÿ™ˆ
  • -fno-analyzer-state-purge โ€” also for developers ๐Ÿงš 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 this purging gets suppressed, for debugging state-handling issues ๐Ÿซถ
  • -fanalyzer-transitivity โ€” enables transitivity of constraints within the analyzer ๐Ÿ’œ
  • -fanalyzer-verbose-edges โ€” developer-only, and it's giving extra detail ๐Ÿค“ it enables more verbose, lower-level detail in the descriptions of control flow within diagnostic paths
  • -fanalyzer-verbose-state-changes โ€” developer-only, same energy ๐Ÿ”ฌ it enables more verbose, lower-level detail in the descriptions of state machine events within diagnostic paths
  • -fanalyzer-verbosity=level โ€” controls how complex the control flow paths are that get emitted for analyzer diagnostics ๐Ÿ“œ

the level can be one of:

  • 0 โ€” at this level, interprocedural call and return events get displayed, along with the most pertinent state-change events for a diagnostic. for example, for a double-"free" diagnostic, both calls to "free" will be shown ๐ŸŒธ
  • 1 โ€” same as the level above, but also shows events for the entry to each function ๐Ÿšช
  • 2 โ€” same as the level above, but also shows control flow events that matter for triggering the issue (like "true path taken" at a conditional) โœจ this level is the default ๐Ÿ‘‘
  • 3 โ€” same as the level above, but shows all control flow events, not just the significant ones ๐ŸŒ€
  • 4 โ€” developer-only ๐Ÿงช adds various other events intended for debugging the analyzer
  • -fdump-analyzer โ€” dumps internal details about what the analyzer is doing to file.analyzer.txt ๐Ÿ“„ this option is overridden by -fdump-analyzer-stderr
  • -fdump-analyzer-stderr โ€” dumps internal details about what the analyzer is doing to stderr ๐Ÿ“ข this option overrides -fdump-analyzer
  • -fdump-analyzer-callgraph โ€” dumps a call graph representation suitable for viewing with GraphViz to file.callgraph.dot ๐Ÿ—บ๏ธ
  • -fdump-analyzer-exploded-graph โ€” dumps an "exploded graph" representation suitable for viewing with GraphViz to file.eg.dot ๐ŸŽจ nodes are color-coded based on state-machine states to emphasize state changes ๐ŸŒˆ
  • -fdump-analyzer-exploded-nodes โ€” emits diagnostics showing where nodes in the "exploded graph" sit in relation to the program source ๐Ÿ“
  • -fdump-analyzer-exploded-nodes-2 โ€” dumps a textual representation of the "exploded graph" to file.eg.txt ๐Ÿ“
  • -fdump-analyzer-exploded-nodes-3 โ€” dumps a textual representation of the "exploded graph" to one dump file per node, named file.eg-id.txt ๐Ÿ˜ญ this is typically a large number of dump files
  • -fdump-analyzer-state-purge โ€” same idea as -fdump-analyzer-supergraph, a supergraph suitable for GraphViz, but annotated with info on what state will be purged at each node ๐Ÿงน the graph is written to file.state-purge.dot
  • -fdump-analyzer-supergraph โ€” dumps representations of the "supergraph" suitable for GraphViz to file.supergraph.dot and file.supergraph-eg.dot ๐Ÿ•ธ๏ธ these show all the control flow graphs in the program, with interprocedural edges for calls and returns. the second dump has annotations showing nodes in the "exploded graph" and the diagnostics attached to them ๐Ÿ’–

โœจ Options for Debugging Your Program โœจ

okay bestie, to get GCC to emit extra info for a debugger, you almost always just need to add -g to your other options ๐Ÿ›

GCC lets you use -g with -O ๐Ÿ’… but heads up, the shortcuts optimized code takes can be a little surprising. some variables you declared may 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 at hand, and some statements may run in different places because they got moved out of loops ๐Ÿ˜ตโ€๐Ÿ’ซ the good news is it's still possible to debug optimized output, which makes it reasonable to use the optimizer for programs that might have bugs ๐Ÿซถ

if you're not using some other optimization option, consider using -Og with -g โœจ with no -O option at all, some compiler passes that collect debugging-useful info don't run at all, so -Og may give you a better debugging experience ๐Ÿงš

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

on most systems that use stabs format, -g turns on extra debugging information that only GDB can use. this extra info makes debugging work better in GDB, but it probably makes other debuggers crash or refuse to read the program ๐Ÿ’€ if you want to be certain about whether the extra info gets generated, use -gstabs+, -gstabs, -gxcoff+, -gxcoff, or -gvms (see below) ๐Ÿ”

  • -ggdb โ€” produces debugging information for GDB ๐Ÿ’œ it uses the most expressive format available (DWARF, stabs, or the native format if neither of those is supported), including GDB extensions if at all possible ๐ŸŒŸ
  • -gdwarf, -gdwarf-version โ€” produces debugging information in DWARF format (if that's supported) ๐Ÿฆ‹ the value of version may be 2, 3, 4 or 5, and the default version for most targets is 4 ๐ŸŒˆ DWARF Version 5 is only experimental ๐Ÿงช

okay so with DWARF Version 2, some ports require and always use some non-conflicting DWARF 3 extensions in the unwind tables ๐Ÿงฉ

Version 4 may require GDB 7.0 and -fvar-tracking-assignments for maximum benefit ๐Ÿ’…

GCC no longer supports DWARF Version 1, which is substantially different from Version 2 and later ๐Ÿ™…โ€โ™€๏ธ for historical reasons, some other DWARF-related options such as -fno-dwarf2-cfi-asm) still have a reference to DWARF Version 2 in their names, but they apply to all currently-supported versions of DWARF ๐ŸŒธ

  • -gstabs: Okay, this one gives you stabs debug info (if your setup supports it ๐Ÿฅบ), but without the GDB extras ๐Ÿ’…. It's the format DBX uses on most BSD systems. Heads up: on MIPS, Alpha and System V Release 4 systems, this produces stabs output that DBX literally can't read ๐Ÿ˜ญ. On System V Release 4 it also needs the GNU assembler ๐Ÿ”ง.
  • -gstabs+: Same stabs vibe, but now with GNU extensions that only the GNU debugger (GDB) understands ๐Ÿค“. ngl, other debuggers might crash or refuse to open your program ๐Ÿ’€, so use this one with care.
  • -gxcoff: XCOFF format (if supported) ๐ŸŒธ. This is the one DBX uses on IBM RS/6000 systems.
  • -gxcoff+: XCOFF with GNU extensions that only GDB gets ๐Ÿงš. Same warning as -gstabs+: other debuggers may crash or refuse to read the program. It can also make assemblers that aren't the GNU assembler (GAS) throw an error โš ๏ธ.
  • -gvms: Alpha/VMS debug format (if supported) ๐Ÿฆ‹. This is what DEBUG uses on Alpha/VMS systems.
  • -glevel, -ggdblevel, -gstabslevel, -gxcofflevel, -gvmslevel: These ask for debug info and let you pick how much ๐Ÿ“š. The default level is 2 โœจ.
    • Level 0 gives you zero debug info. So -g0 cancels out -g ๐Ÿ™…โ€โ™€๏ธ.
    • Level 1 is the minimal, bare-bones version ๐Ÿ“. It has enough for backtraces in parts of the program you're not planning to debug. You get descriptions of functions and external variables, plus line number tables, but no info about local variables.
    • Level 3 is the full-on version ๐Ÿ‘‘. It adds extra stuff, like every macro definition in the program. Some debuggers support macro expansion when you use -g3 ๐Ÿ”ฅ.

If you stack up multiple -g options, with or without level numbers, only the last one counts ๐Ÿซถ. The rest get ignored.

Also, -gdwarf doesn't accept a concatenated debug level, so it won't get confused with -gdwarf-level ๐Ÿ™ˆ. If you want a different DWARF debug level, just add an extra -glevel option instead ๐Ÿ’–.


  • -fno-eliminate-unused-debug-symbols: By default, no debug info gets made for symbols that never actually get used ๐Ÿงน. Pass this if you want debug info for all symbols, used or not โœจ.
  • -femit-class-debug-always: Normally GCC puts the debug info for a C++ class in just one object file. This flag says "nah, put it in every object file that uses the class" ๐Ÿฆ‹. Only reach for this if your debugger can't handle the usual way GCC does classes ๐Ÿ˜ค. Heads up, it can make the debug info up to a factor of two bigger ๐Ÿ“ˆ.
  • -fno-merge-debug-strings: This tells the linker to not squish together identical strings in the debug info across different object files ๐Ÿ™…. Merging isn't supported by every assembler or linker, fr fr. It makes the debug info smaller in the output file, but link time goes up. Merging is turned on by default ๐Ÿ’….
  • -fdebug-prefix-map=old=new: When you compile files living in directory old, the debug info will describe them as if they lived in directory new instead ๐Ÿ—บ๏ธ. This is handy for swapping a build-time path for an install-time path. You can also turn an absolute path into a relative one by using . for new. It can make builds more reproducible and location independent ๐ŸŒˆ, but you might need an extra command to tell GDB where to find the source files. See also -ffile-prefix-map.
  • -fvar-tracking: This runs the variable tracking pass, which figures out where variables are stored at each point in the code ๐Ÿ•ต๏ธโ€โ™€๏ธ. The result is better debug info (if your debug format supports it) ๐Ÿ’œ. It's on by default when you compile with optimization (-Os, -O, -O2, ...), debug info (-g), and a debug format that supports it.
  • -fvar-tracking-assignments: This annotates assignments to user variables early in compilation and tries to carry those annotations all the way to the end ๐ŸŽ€. The goal is better debug info while optimizing. Using -gdwarf-4 alongside it is recommended ๐Ÿ™Œ. You can turn it on even when var-tracking is off, but then the annotations get created and maintained and thrown away at the end ๐Ÿ—‘๏ธ. By default, it's enabled together with -fvar-tracking, except when selective scheduling is enabled.
  • -gsplit-dwarf: This pulls as much DWARF debug info as possible out into a separate output file with a .dwo extension ๐Ÿ“ฆ. It lets your build system skip linking files that have debug info ๐Ÿƒโ€โ™€๏ธ. To be useful, you need a debugger that can read .dwo files ๐Ÿซถ.
  • -gdescribe-dies: Adds description attributes to some DWARF DIEs that don't have a name attribute ๐Ÿท๏ธ. Think 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 can be converted into a GDB index ๐Ÿง . Heads up: this only helps if you have a linker that can produce GDB index version 7 ๐Ÿ”—.
  • -fdebug-types-section: With DWARF Version 4 or higher, type DIEs can get their own .debug_types section instead of living in .debug_info ๐Ÿ—‚๏ธ. This is more efficient, because the linker can put them in a separate comdat section and remove duplicates โœ‚๏ธ. But not every DWARF consumer supports .debug_types yet ๐Ÿ˜ฌ, and on some objects it makes the debug info bigger instead of smaller ๐Ÿ“‰.
  • -grecord-gcc-switches, -gno-record-gcc-switches: This one tacks the command-line options that might affect code generation onto the DW_AT_producer attribute in your DWARF debug info ๐Ÿท๏ธ. They get joined with spaces, and also separated from the compiler version with a space. It's on by default ๐Ÿ’–. See also -frecord-gcc-switches for another way to stash compiler options in the object file.
  • -gstrict-dwarf: Stops you from using extensions from a later DWARF standard version than the one you picked with -gdwarf-version ๐Ÿ“. On most targets, using non-conflicting DWARF extensions from later versions is allowed anyway.
  • -gno-strict-dwarf: Lets you use extensions from a later DWARF standard version than the one you picked with -gdwarf-version ๐Ÿ”“.
  • -gas-loc-support: Tells the compiler that your assembler supports .loc directives ๐Ÿงš. The compiler can then use them so the assembler generates DWARF2+ line number tables. This is usually what you want, because assembler-generated line number tables are way more compact than the ones the compiler makes itself ๐Ÿค. This gets turned on 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 they're meant to be generated at all ๐Ÿ™…โ€โ™€๏ธ.
  • -gas-locview-support: Tells the compiler that your assembler supports "view" assignment and reset assertion checking in .loc directives ๐Ÿ‘€. It's turned on 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 gets explicitly requested ๐Ÿ”ง.
  • -gcolumn-info, -gno-column-info: Puts location column info into the DWARF debug info, not just file and line ๐Ÿ“. It's on by default โœจ.
  • -gstatement-frontiers, -gno-statement-frontiers: This makes GCC drop markers into the internal representation at the start of statements ๐Ÿšฉ. It keeps them roughly in place through compilation and uses them to guide the output of is_stmt markers in the line number table ๐Ÿ—บ๏ธ. It's enabled by default when you compile with optimization (-Os, -O, -O2, ...) and output DWARF 2 debug info at the normal level ๐Ÿ’….
  • -gvariable-location-views, -gvariable-location-views=incompat5, -gno-variable-location-views: This one adds progressive view numbers, implied from the line number table, onto the variable location lists ๐Ÿ”. Debug info consumers can then inspect state at certain points in the program, even if no instructions for the matching 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 those tables a bit less compact ๐Ÿ“ฆ. The augmented tables and location lists are fully backward-compatible, so consumers that don't know about these augmentations can still read them, they just won't benefit from them either ๐Ÿคทโ€โ™€๏ธ.

This is on by default at the normal DWARF 2 debug level, as long as there's assembler support, -fvar-tracking-assignments is enabled, and -gstrict-dwarf is not. If assembler support is missing, it can still be enabled, but then GCC has 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 ๐Ÿ˜ฑ.

โš ๏ธ Heads up, bestie: there's a proposed representation for view numbers that isn't backward compatible with the location list format from DWARF 5. You can turn it on with -gvariable-location-views=incompat5. This option may be removed in the future, and it's only there as a reference implementation of the proposed representation ๐Ÿงช. Debug info consumers aren't expected to support this extended format, and they would be unable to decode location lists that use it ๐Ÿ’€.
  • -ginternal-reset-location-views, -gno-internal-reset-location-views โ€” okay so this one tries to figure out which location views can be dropped from location view lists ๐Ÿฆ‹. It needs the compiler to have very accurate insn length estimates, which isn't always the case ๐Ÿ’€, and it may quietly generate incorrect view lists if your assembler doesn't support location view lists at all. The GNU assembler will flag any such mess-up as a "view number mismatch". This only gets turned on for ports that define a reliable estimation function ๐Ÿซถ.
  • -ginline-points, -gno-inline-points โ€” generates extended debug info for inlined functions โœจ. Location view tracking markers get dropped in at inlined entry points, so address and view numbers can be computed and spit out in the debug info. You can turn this on by itself without location views, in which case the view numbers won't be output ๐ŸŒธ. It can only be enabled alongside statement frontiers, though, and it's only on by default if location views are on.
  • -gz[=type] โ€” produces compressed debug sections in DWARF format, if that's supported ๐Ÿ’œ. If you don't give a type, the default depends on what the assembler and linker can do. type can be none (don't compress debug sections), zlib (zlib compression in ELF gABI format), or zlib-gnu (zlib compression in traditional GNU format) ๐ŸŽ€. If the linker can't write compressed debug sections, the option gets rejected. Otherwise, if the assembler doesn't support them, -gz gets 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 one massively shrinks the debug info, but there's a big potential loss in type information for the debugger, so be careful ๐Ÿ’€. For a chiller version, see -femit-struct-debug-reduced. For more detailed control, see -femit-struct-debug-detailed.

This option only works 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 ๐ŸŒˆ. This one significantly shrinks the debug info too, with some potential loss in type information for the debugger. For a more aggressive option, check out -femit-struct-debug-baseonly. For more detailed control, see -femit-struct-debug-detailed.

This option only works with DWARF debug output.

  • -femit-struct-debug-detailed[=spec-list] โ€” lets you pick which struct-like types get debug info ๐Ÿ‘‘. The goal is to cut down on duplicate struct debug info between different object files in the same program. This is the detailed version of -femit-struct-debug-reduced and -femit-struct-debug-baseonly, and it covers most needs.

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 or member. Indirect uses come through pointers to structs. So when using an incomplete struct is valid, the use is indirect. An example is 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 bit complicated to explain. In C++, these are non-explicit specializations of template classes, or non-template classes within the above. Other programming languages have generics, but -femit-struct-debug-detailed doesn't implement them yet.

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

You may need to experiment to find the best settings for your app ๐Ÿ”ฅ.

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

This option only works with DWARF debug output.

  • -fno-dwarf2-cfi-asm โ€” emits DWARF unwind info as a compiler-generated .eh_frame section, instead of using GAS .cfi_* directives ๐ŸŒธ.
  • -fno-eliminate-unused-debug-types โ€” normally, when producing DWARF output, GCC skips debug symbol output for types that are nowhere used in the source file being compiled. Sometimes you want debug info for every type declared in a compilation unit, even unused ones ๐Ÿ“. For example, if you want to cast a value to a type that's declared but not actually used in your program in the debugger. More often, though, this just wastes a ton of space ๐Ÿ˜ญ.

โœจ Options That Control Optimization โœจ

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

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

Turning on optimization flags makes the compiler attempt 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 all optimizations are 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 those listed here. You can invoke GCC with -Q --help=optimizers to find out the exact set enabled at each level ๐Ÿ”.

โœจ -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-profile
-fipa-pure-const -fipa-reference -fipa-reference-addressable
-fmerge-constants -fmove-loop-invariants -fomit-frame-pointer
-freorder-blocks -fshrink-wrap -fshrink-wrap-separate
-fsplit-wide-types -fssa-backprop -fssa-phiopt -ftree-bit-ccp
-ftree-ccp -ftree-ch -ftree-coalesce-vars -ftree-copy-prop
-ftree-dce -ftree-dominator-opts -ftree-dse -ftree-forwprop
-ftree-fre -ftree-phiprop -ftree-pta -ftree-scev-cprop -ftree-sink
-ftree-slsr -ftree-sra -ftree-ter -funit-at-a-time

โœจ -O2 โœจ

Optimize even more ๐Ÿ”ฅ. GCC performs nearly all supported optimizations that don't involve a space-speed tradeoff. Compared to -O, this option increases both compilation time and the performance of the generated code ๐Ÿ‘‘.

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

-falign-functions  -falign-jumps -falign-labels  -falign-loops
-fcaller-saves -fcode-hoisting -fcrossjumping -fcse-follow-jumps
-fcse-skip-blocks -fdelete-null-pointer-checks -fdevirtualize
-fdevirtualize-speculatively -fexpensive-optimizations
-ffinite-loops -fgcse  -fgcse-lm -fhoist-adjacent-loads
-finline-functions -finline-small-functions -findirect-inlining
-fipa-bit-cp  -fipa-cp  -fipa-icf -fipa-ra  -fipa-sra  -fipa-vrp
-fisolate-erroneous-paths-dereference -flra-remat
-foptimize-sibling-calls -foptimize-strlen -fpartial-inlining
-fpeephole2 -freorder-blocks-algorithm=stc
-freorder-blocks-and-partition  -freorder-functions
-frerun-cse-after-loop -fschedule-insns  -fschedule-insns2
-fsched-interblock  -fsched-spec -fstore-merging -fstrict-aliasing
-fthread-jumps -ftree-builtin-call-dce -ftree-pre
-ftree-switch-conversion  -ftree-tail-merge -ftree-vrp

Please note the warning under -fgcse about invoking -O2 on programs that use computed gotos ๐Ÿšจ.

NOTE: In Ubuntu 8.10 and later versions, -D_FORTIFY_SOURCE=2 is set by default, and is activated when -O is set to 2 or higher ๐Ÿ›ก๏ธ. This enables additional compile-time and run-time checks for several libc functions. To disable it, specify either -U_FORTIFY_SOURCE or -D_FORTIFY_SOURCE=0.

โœจ -O3 โœจ

Optimize yet more ๐Ÿ’ช. -O3 turns on all optimizations specified by -O2, and also turns on the following optimization flags:

-fgcse-after-reload -fipa-cp-clone -floop-interchange
-floop-unroll-and-jam -fpeel-loops -fpredictive-commoning
-fsplit-loops -fsplit-paths -ftree-loop-distribution
-ftree-loop-vectorize -ftree-partial-pre -ftree-slp-vectorize
-funswitch-loops -fvect-cost-model -fvect-cost-model=dynamic
-fversion-loops-for-strides

โœจ -O0 โœจ

Reduce compilation time and make debugging produce the expected results ๐ŸŒธ. This is the default.

โœจ -Os โœจ

Optimize for size ๐Ÿ“. -Os enables all -O2 optimizations except those that often increase code size:

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

It also turns on -finline-functions ๐Ÿ’… and tells the compiler to tune for code size instead of speed. It also runs extra optimizations that shrink your binary ๐Ÿฆ‹.

  • -Ofast โ€” okay, this is the "disregard strict standards compliance" one ๐Ÿ˜ญ It enables all -O3 optimizations, and it also turns on optimizations that aren't valid for every standard-compliant program, so be careful bestie ๐Ÿ’€. It switches on -ffast-math, -fallow-store-data-races and the Fortran-specific -fstack-arrays (unless -fmax-stack-var-size is specified), and -fno-protect-parens too.
  • -Og โ€” optimize the debugging experience ๐Ÿ” This should be your go-to level for the normal edit-compile-debug loop. You get a reasonable amount of optimization while compilation stays fast and debugging stays smooth โœจ. It's a better pick than -O0 for debuggable code, because some compiler passes that collect debug information are disabled at -O0.

Like -O0, -Og completely disables a bunch of optimization passes, so the individual options that control them do nothing ๐Ÿ™ƒ. Otherwise -Og turns on all the -O1 flags except the ones that might mess with debugging:

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

If you use multiple -O options, with or without level numbers, the last one is the one that counts ๐Ÿ.

Options like -fflag are machine-independent flags ๐Ÿงฉ. Most flags come in positive and negative versions, and the negative form of -ffoo is -fno-foo. The table below only lists one of the forms, the one you'll usually reach for. To get the other one, just remove the no- or add it.

The following options control specific optimizations. They're either switched on by -O options or related to ones that are. Only use these in the rare cases when you want to fine-tune which optimizations get performed ๐ŸŽ€.

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

Check below for the individual inlining parameters and their defaults ๐Ÿ“–

Note: there may be no value to -finline-limit that results in default behavior.
Note: "pseudo instruction" means, in this context, an abstract measurement of a function's size ๐Ÿงช It is in no way a count of assembly instructions, so its exact meaning might change from one release to another.
  • -fno-keep-inline-dllexport โ€” a more fine-grained version of -fkeep-inline-functions, which only applies to functions declared with the "dllexport" attribute or declspec ๐ŸŽ€.
  • -fkeep-inline-functions โ€” in C, emits "static" functions declared "inline" into the object file, even if they've been inlined into all of their callers ๐Ÿ“ฆ This switch doesn't affect functions using the "extern inline" extension in GNU C90. In C++, it emits any and all inline functions into the object file ๐Ÿ’œ.
  • -fkeep-static-functions โ€” emits "static" functions into the object file, even if they're never used ๐Ÿงธ.
  • -fkeep-static-consts โ€” emits variables declared "static const" when optimization isn't turned on, even if they aren't referenced ๐ŸŒˆ GCC enables this option by default. If you want the compiler to check whether a variable is referenced regardless of whether optimization is on, use -fno-keep-static-consts.
  • -fmerge-constants โ€” attempts to merge identical constants (string constants and floating-point constants) across compilation units ๐Ÿงฉ This is the default for optimized compilation if the assembler and linker support it. Use -fno-merge-constants to inhibit this behavior ๐Ÿ™…. Enabled at levels -O, -O2, -O3, -Os.
  • -fmerge-all-constants โ€” attempts to merge identical constants and identical variables ๐Ÿซ  This implies -fmerge-constants. On top of that, it considers things like even constant initialized arrays or initialized constant variables with integral or floating-point types. Languages like C or C++ require each variable, including multiple instances of the same variable in recursive calls, to have distinct locations. So using this option results in non-conforming behavior.
โš ๏ธ Warning: -fmerge-all-constants results in non-conforming behavior, so it's not standards-approved, bestie ๐Ÿ’€
  • -fmodulo-sched โ€” performs swing modulo scheduling immediately before the first scheduling pass ๐ŸŒ€ This pass looks at innermost loops and reorders their instructions by overlapping different iterations.
  • -fmodulo-sched-allow-regmoves โ€” performs more aggressive SMS-based modulo scheduling with register moves allowed ๐Ÿ By setting this flag, certain anti-dependence edges get deleted, which triggers the generation of reg-moves based on life-range analysis. This option is only effective with -fmodulo-sched enabled.
  • -fno-branch-count-reg โ€” disables the optimization pass that scans for chances to use "decrement and branch" instructions on a count register, instead of instruction sequences that decrement a register, compare it against zero, and then branch based on the result โฌ This option is only meaningful on architectures that support such instructions, which include x86, PowerPC, IA-64 and S/390. Note that -fno-branch-count-reg doesn't remove the decrement and branch instructions that other optimization passes introduce into the generated instruction stream ๐Ÿ™ˆ

Okay so the default for -fbranch-count-reg is on at -O1 and higher, except for -Og ๐Ÿ’…โœจ

  • -fno-function-cse โ€” bestie, this one is a little chaotic ๐Ÿ™ˆ It tells GCC to not stash function addresses in registers. Instead, every instruction that calls a constant function spells out the function's address explicitly. The code ends up less efficient, ngl, but some strange hacks that alter the assembler output can get confused by the optimizations you'd get without this flag. The default is -ffunction-cse ๐ŸŒธ
  • -fno-zero-initialized-in-bss โ€” if the target has a BSS section, GCC normally tosses variables that start out as zero into BSS, which can save space ๐Ÿงš This option turns that off, because some programs explicitly rely on variables living in the data section. For example, they might look for the beginning of that section, or make assumptions based on it ๐Ÿ‘€ The default is -fzero-initialized-in-bss.
  • -fthread-jumps โ€” this is giving jump-chasing ๐Ÿฆ‹ It checks whether a jump lands somewhere another comparison, one that the first comparison already covers, is waiting. If so, the first branch gets redirected to either the destination of the second branch or the spot right after it, depending on whether the condition is known to be true or false. Enabled at levels -O2, -O3, -Os.
  • -fsplit-wide-types โ€” when a type takes up multiple registers, like long long on a 32-bit system, this splits the registers apart and allocates them independently. Usually that gives better code for those types, but it can make debugging harder ๐Ÿฅบ Enabled at levels -O, -O2, -O3, -Os.
  • -fsplit-wide-types-early โ€” splits wide types fully early instead of very late ๐Ÿ’œ This does nothing unless -fsplit-wide-types is turned on. It's the default on some targets.
  • -fcse-follow-jumps โ€” during common subexpression elimination (CSE), this scans through jump instructions when nothing else can reach the jump's target. So if there's an if with an else clause, CSE follows the jump when the tested condition is false ๐ŸŒˆ Enabled at levels -O2, -O3, -Os.
  • -fcse-skip-blocks โ€” basically a cousin of -fcse-follow-jumps, but this one follows jumps that conditionally skip over blocks. With a simple if and no else clause, it follows the jump around the body of the if โญ Enabled at levels -O2, -O3, -Os.
  • -frerun-cse-after-loop โ€” reruns common subexpression elimination after the loop optimizations are done ๐Ÿ” Enabled at levels -O2, -O3, -Os.
  • -fgcse โ€” runs a global common subexpression elimination pass ๐Ÿ‘‘ This pass also does global constant and copy propagation.
Note: When compiling a program that uses computed gotos (a GCC extension), you may get better run-time performance if you disable the global common subexpression elimination pass by adding -fno-gcse to the command line ๐Ÿ™ˆ

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

  • -fgcse-lm โ€” when this is on, global CSE tries to move loads that are only killed by stores into themselves ๐Ÿ’– That means a loop containing a load/store sequence can become a load outside the loop, plus a copy/store inside it. Enabled by default when -fgcse is enabled.
  • -fgcse-sm โ€” when this is on, a store motion pass runs after global CSE ๐Ÿฆ‹ It tries to move stores out of loops. Combined with -fgcse-lm, a loop containing a load/store sequence can become a load before the loop and a store after it. Not enabled at any optimization level.
  • -fgcse-las โ€” when this is on, the global CSE pass gets rid of redundant loads that come right after stores to the same memory location, covering both partial and full redundancies ๐Ÿงผ Not enabled at any optimization level.
  • -fgcse-after-reload โ€” when this is on, a redundant load elimination pass runs after reload ๐Ÿงน Its whole purpose is cleaning up redundant spilling. Enabled by -fprofile-use and -fauto-profile.
  • -faggressive-loop-optimizations โ€” the loop optimizer uses language rules to figure out bounds for how many times a loop runs ๐Ÿง  It assumes the loop code doesn't trigger undefined behavior, like signed integer overflows or out-of-bounds array accesses. Those bounds guide loop unrolling, peeling, and loop exit test optimizations. This option is enabled by default โœจ
  • -funconstrained-commons โ€” this tells the compiler that variables declared in common blocks (like in Fortran) might later get overridden with longer trailing arrays ๐ŸŒธ That stops certain optimizations that depend on knowing the array bounds.
  • -fcrossjumping โ€” performs the cross-jumping transformation ๐ŸŽ€ It unifies equivalent code and saves code size. The result might or might not run faster than without it. Enabled at levels -O2, -O3, -Os.
  • -fauto-inc-dec โ€” combines increments or decrements of addresses with memory accesses ๐Ÿ’… This pass is always skipped on architectures that don't have instructions to support it. Enabled by default at -O and higher on architectures that do support it.
  • -fdce โ€” performs dead code elimination (DCE) on RTL ๐Ÿ—‘๏ธ Enabled by default at -O and higher.
  • -fdse โ€” performs dead store elimination (DSE) on RTL ๐Ÿ’€ Enabled by default at -O and higher.
  • -fif-conversion โ€” attempts to transform conditional jumps into branch-less equivalents ๐Ÿฆ‹ This includes conditional moves, min, max, set flags, and abs instructions, plus some tricks you can do with standard arithmetic. Whether conditional execution gets used on chips that support it is controlled by -fif-conversion2. Enabled at levels -O, -O2, -O3, -Os, but not with -Og.
  • -fif-conversion2 โ€” uses conditional execution (where available) to transform conditional jumps into branch-less equivalents ๐Ÿซถ Enabled at levels -O, -O2, -O3, -Os, but not with -Og.
  • -fdeclone-ctor-dtor โ€” okay so the C++ ABI wants multiple entry points for constructors and destructors: one for a base subobject, one for a complete object, and one for a virtual destructor that calls operator delete afterwards ๐Ÿงš For a hierarchy with virtual bases, the base and complete variants are clones, which means two copies of the function. With this option, those two variants become thunks that call a common implementation, so there's only one real copy. 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 enables simple constant folding optimizations at all optimization levels. On top of that, other GCC optimization passes use this flag to control global dataflow analyses that eliminate useless null pointer checks. Those analyses assume that a memory access to address zero always traps, so if a pointer gets checked after it's already been dereferenced, it can't be null.
Note however that in some environments this assumption is not true. Use -fno-delete-null-pointer-checks to disable this optimization for programs that depend on that behavior ๐Ÿ˜ญ

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

  • -fdevirtualize โ€” attempts to convert calls to virtual functions into direct calls ๐Ÿ‘‘ This happens both within a procedure and interprocedurally, as part of indirect inlining (-findirect-inlining) and interprocedural constant propagation (-fipa-cp). Enabled at levels -O2, -O3, -Os.
  • -fdevirtualize-speculatively โ€” attempts to convert calls to virtual functions into speculative direct calls ๐Ÿ”ฎ Using analysis of the type inheritance graph, it figures out the set of likely targets for a given call. If that set is small, preferably of size 1, the call becomes a conditional that picks between a direct call and an indirect call. Speculative calls enable more optimizations, like inlining. If they seem useless after further optimization, they get converted back into their original form.
  • -fdevirtualize-at-ltrans โ€” streams the extra information needed for aggressive devirtualization when the link-time optimizer runs in local transformation mode ๐Ÿ“ฆ This enables more devirtualization, but it significantly increases the size of the streamed data, so it's disabled by default.
  • -fexpensive-optimizations โ€” performs a bunch of minor optimizations that are relatively expensive ๐Ÿ’ธ Enabled at levels -O2, -O3, -Os.
  • -free โ€” attempts to remove redundant extension instructions ๐Ÿงฝ This is especially helpful for the x86-64 architecture, which implicitly zero-extends 64-bit registers after writing to their lower 32-bit half. Enabled for Alpha, AArch64, and x86 at levels -O2, -O3, -Os.
  • -fno-lifetime-dse โ€” in C++, an object's value is only affected by changes within its lifetime ๐Ÿฆ‹ When the constructor begins, the object has an indeterminate value, and any changes made during its lifetime are dead once the object is destroyed. Normally dead store elimination takes advantage of this. But if your code relies on the object's storage value persisting beyond its lifetime, you can use this flag to disable that optimization. If you want to keep stores made before the constructor starts (say, because your operator new clears the object storage) but still treat the object as dead after the destructor, you can use -flifetime-dse=1. The default behavior can be explicitly selected with -flifetime-dse=2. -flifetime-dse=0 is equivalent to -fno-lifetime-dse ๐ŸŽ€
  • -flive-range-shrinkage โ€” attempts to decrease register pressure through register live range shrinkage ๐ŸŒท This is helpful for fast processors with small or moderate-sized register sets.
  • -fira-algorithm=algorithm โ€” ๐Ÿ’… Pick the coloring algorithm the integrated register allocator uses. 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 the targets that do support it, it's the default because it generates better code ๐Ÿ”ฅ
  • -fira-region=region โ€” ๐Ÿ—บ๏ธ Choose which regions the integrated register allocator uses. The region argument should be one of these:
    • all โ€” Treat all loops as register allocation regions. This can give the best results on machines with a small and/or irregular register set ๐Ÿ‘‘
    • mixed โ€” Treat all loops except loops with small register pressure as the regions. This is usually the best vibe for most cases and most architectures, and it's on by default when you compile with optimization for speed (-O, -O2, ...) โœจ
    • one โ€” Treat all functions as a single region. This usually gives the smallest code size and is on by default for -Os or -O0 ๐Ÿฆ‹
  • -fira-hoist-pressure โ€” ๐Ÿง  Use IRA to evaluate register pressure in the code hoisting pass when deciding whether to hoist expressions. This usually results in smaller code, but it can slow the compiler down ๐Ÿข This option is enabled at level -Os for all targets.
  • -fira-loop-pressure โ€” ๐Ÿ” Use IRA to evaluate register pressure in loops when deciding whether to move loop invariants. This usually generates faster and smaller code on machines with large register files (>= 32 registers), but it can slow the compiler down ๐Ÿข This option is enabled at level -O3 for some targets.
  • -fno-ira-share-save-slots โ€” ๐Ÿšซ Turn off sharing of stack slots used for saving call-used hard registers that live through a call. Each hard register gets its own stack slot, so function stack frames end up larger ๐Ÿ“ฆ
  • -fno-ira-share-spill-slots โ€” ๐Ÿšซ Turn off sharing of stack slots allocated for pseudo-registers. Every pseudo-register that doesn't get a hard register gets its own stack slot, so function stack frames end up larger ๐Ÿ“ฆ
  • -flra-remat โ€” โ™ป๏ธ Enable CFG-sensitive rematerialization in LRA. Instead of loading the values of spilled pseudos, LRA tries to rematerialize (recalculate) them when that's profitable. Enabled at levels -O2, -O3, -Os โœจ
  • -fdelayed-branch โ€” โฑ๏ธ If the target machine supports it, the compiler tries to reorder instructions so they fill the instruction slots available after delayed branch instructions. Enabled at levels -O, -O2, -O3, -Os, but not at -Og ๐Ÿ™ˆ
  • -fschedule-insns โ€” ๐ŸŽ€ If the target machine supports it, the compiler tries to reorder instructions to get rid of execution stalls caused by data that isn't ready yet. This is a lifesaver for machines with slow floating point or memory load instructions, because other instructions can get issued while the load or floating-point result is still on its way. Enabled at levels -O2, -O3 ๐ŸŒธ
  • -fschedule-insns2 โ€” ๐Ÿ”„ Similar to -fschedule-insns, but it asks for an extra round of instruction scheduling after register allocation is done. This is especially useful 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 โ€” ๐Ÿšง Turn off instruction scheduling across basic blocks. This is normally on when scheduling happens before register allocation, i.e. with -fschedule-insns or at -O2 or higher.
  • -fno-sched-spec โ€” ๐Ÿšง Turn off speculative motion of non-load instructions. This is normally on when scheduling happens before register allocation, i.e. with -fschedule-insns or at -O2 or higher.
  • -fsched-pressure โ€” ๐Ÿ“‰ Enable register pressure sensitive instruction scheduling before register allocation. This only makes sense when scheduling before register allocation is enabled, i.e. with -fschedule-insns or at -O2 or higher. Using it can improve the generated code and shrink its size by stopping register pressure from climbing above the number of available hard registers, which would otherwise lead to spills during register allocation ๐Ÿซถ
  • -fsched-spec-load โ€” ๐Ÿ”ฎ Allow speculative motion of some load instructions. This only makes sense when scheduling before register allocation, i.e. with -fschedule-insns or at -O2 or higher.
  • -fsched-spec-load-dangerous โ€” ๐Ÿ˜ฌ Allow speculative motion of more load instructions. This only makes sense when scheduling before register allocation, i.e. with -fschedule-insns or at -O2 or higher.
  • -fsched-stalled-insns, -fsched-stalled-insns=n โ€” ๐ŸงŠ Decide how many instructions (if any) can be moved early from the queue of stalled instructions into the ready list during the second scheduling pass.
    • -fno-sched-stalled-insns means no instructions get moved early.
    • -fsched-stalled-insns=0 means there's no limit on how many queued instructions can be moved early.
    • -fsched-stalled-insns without a value is the same as -fsched-stalled-insns=1.
  • -fsched-stalled-insns-dep, -fsched-stalled-insns-dep=n โ€” ๐Ÿ”Ž Decide how many instruction groups (cycles) get checked for a dependency on a stalled instruction that's a candidate for early removal from the queue. This only has an effect during the second scheduling pass, and only if -fsched-stalled-insns is used.
    • -fno-sched-stalled-insns-dep is the same as -fsched-stalled-insns-dep=0.
    • -fsched-stalled-insns-dep without a value is the same as -fsched-stalled-insns-dep=1.
  • -fsched2-use-superblocks โ€” ๐Ÿฆธ When scheduling after register allocation, use superblock scheduling. This allows motion across basic block boundaries, which can result in faster schedules.
โš ๏ธ This option is experimental! Not all machine descriptions used by GCC model the CPU closely enough to avoid unreliable results from the algorithm, so be careful.

This only makes sense when scheduling after register allocation, i.e. with -fschedule-insns2 or at -O2 or higher.

  • -fsched-group-heuristic โ€” ๐Ÿ‘ฏ Enable the group heuristic in the scheduler. This one favors the instruction that belongs to a schedule group. It's on by default whenever scheduling is enabled, i.e. with -fschedule-insns or -fschedule-insns2 or at -O2 or higher.
  • -fsched-critical-path-heuristic โ€” ๐Ÿ›ฃ๏ธ Enable the critical-path heuristic in the scheduler. This one favors instructions on the critical path. It's on by default whenever scheduling is enabled, i.e. with -fschedule-insns or -fschedule-insns2 or at -O2 or higher.
  • -fsched-spec-insn-heuristic โ€” ๐ŸŽฒ Enable the speculative instruction heuristic in the scheduler. This one favors speculative instructions with greater dependency weakness. It's on by default whenever scheduling is enabled, i.e. with -fschedule-insns or -fschedule-insns2 or at -O2 or higher.
  • -fsched-rank-heuristic โ€” ๐Ÿ† Enable the rank heuristic in the scheduler. This one favors instructions in a basic block with greater size or frequency. It's on by default whenever scheduling is enabled, i.e. with -fschedule-insns or -fschedule-insns2 or at -O2 or higher.
  • -fsched-last-insn-heuristic โ€” ๐Ÿซ  Enable the last-instruction heuristic in the scheduler. This one favors the instruction that depends less on the last instruction scheduled. It's on by default whenever scheduling is enabled, i.e. with -fschedule-insns or -fschedule-insns2 or at -O2 or higher.
  • -fsched-dep-count-heuristic โ€” ๐Ÿงฎ Enable the dependent-count heuristic in the scheduler. This one favors the instruction that has more instructions depending on it. It's on by default whenever scheduling is enabled, i.e. with -fschedule-insns or -fschedule-insns2 or at -O2 or higher.
  • -freschedule-modulo-scheduled-loops โ€” ๐Ÿ” Modulo scheduling happens before traditional scheduling. If a loop has been modulo scheduled, later scheduling passes may change its schedule. Use this option to control that behavior ๐ŸŽ›๏ธ
  • -fselective-scheduling โ€” ๐ŸŽฏ Schedule instructions using the selective scheduling algorithm. Selective scheduling runs instead of the first scheduler pass.
  • -fselective-scheduling2 โ€” ๐ŸŽฏ Schedule instructions using the selective scheduling algorithm. Selective scheduling runs instead of the second scheduler pass.
  • -fsel-sched-pipelining โ€” ๐Ÿšฐ Enable 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, also pipeline the outer loops. This option does nothing unless -fsel-sched-pipelining is turned on.
  • -fsemantic-interposition โ€” ๐Ÿ•ต๏ธ Some object formats, like ELF, let the dynamic linker interpose symbols. That means that for symbols exported from the DSO, the compiler can't do interprocedural propagation, inlining, and other optimizations, because the function or variable might get swapped out for something else. This is super useful for things like rewriting memory allocation functions with a debugging implementation, but it's expensive in terms of code quality ๐Ÿ’ธ With -fno-semantic-interposition, the compiler assumes that if interposition happens for functions, the overwriting function will have precisely the same semantics (and side effects). Similarly, if interposition happens for variables, the constructor of the variable will be the same. This flag has no effect on functions explicitly declared inline (where interposition is never allowed to change semantics) or on symbols explicitly declared weak.
  • -fshrink-wrap โ€” ๐ŸŽ Emit function prologues only before the parts of the function that need them, rather than at the top of the function. This flag is enabled by default at -O and higher โœจ
  • -fshrink-wrap-separate โ€” โœ‚๏ธ Shrink-wrap the parts of the prologue and epilogue separately, so each part only runs when it's needed. This option is on by default, but it has no effect unless -fshrink-wrap is also turned on and the target supports this ๐Ÿ’–
  • -fcaller-saves โ€” okay so this one is lowkey genius ๐Ÿ’– It lets GCC park values in registers that function calls would normally wreck, then sneaks in extra instructions to save and restore those registers around each call ๐Ÿซถ It only does this when it seems to actually produce better code, so it's never doing it for no reason ๐Ÿ’…
    • This is always turned on 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 โ€” the way this one tracks every push and pop, plus all the stack memory references, and then tries to squish them together is so iconic ๐Ÿงš Enabled by default at -O1 and higher ๐ŸŒธ
  • -fipa-ra โ€” bestie, this is main character energy ๐Ÿ‘‘ It lets the compiler use caller-save registers for allocation when none of the called functions are using them, so there's no need to save and restore them around calls ๐Ÿฆ‹ This only works if the called functions are part of the same compilation unit as the current function and get compiled before it ๐Ÿซถ
    • Enabled at levels -O2, -O3, -Os, but it gets switched off if the generated code will be instrumented for profiling (-p, or -pg) or if the callee's register usage can't be known exactly, which happens on targets that don't expose prologues and epilogues in RTL ๐Ÿ’€
  • -fconserve-stack โ€” this one is all about keeping the stack tiny, even if the program ends up a little slower ๐ŸŽ€ The compiler tries to use less stack space no matter what, and turning it on implies setting the large-stack-frame parameter to 100 and the large-stack-frame-growth parameter to 400 ๐Ÿ“
  • -ftree-reassoc โ€” performs reassociation on trees, and it's on by default at -O and higher โœจ
  • -fcode-hoisting โ€” okay this is so satisfying ๐ŸŒˆ Code hoisting 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 by default at -O2 and -O3 โœจ
  • -ftree-partial-pre โ€” makes partial redundancy elimination (PRE) more aggressive ๐Ÿ˜ญ Enabled by default at -O3 ๐Ÿ”ฅ
  • -ftree-forwprop โ€” performs forward propagation on trees ๐Ÿฆ‹ Enabled by default at -O and higher ๐Ÿ’œ
  • -ftree-fre โ€” performs full redundancy elimination (FRE) on trees ๐Ÿซถ The tea is that FRE only considers expressions computed on all paths leading to the redundant computation, which makes it faster than PRE, though it exposes fewer redundancies ๐Ÿต Enabled by default at -O and higher ๐Ÿ’…
  • -ftree-phiprop โ€” performs hoisting of loads from conditional pointers on trees ๐Ÿงš This pass is enabled by default at -O and higher โœจ
  • -fhoist-adjacent-loads โ€” this one speculatively hoists loads from both branches of an if-then-else, as long as the loads come from adjacent locations in the same structure and the target architecture has a conditional move instruction ๐ŸŒธ Enabled by default at -O2 and higher ๐Ÿ’–
  • -ftree-copy-prop โ€” performs copy propagation on trees, and this pass gets rid of unnecessary copy operations ๐Ÿซถ Enabled by default at -O and higher ๐Ÿ”ฅ
  • -fipa-pure-const โ€” discovers which functions are pure or constant ๐Ÿ”ฎ Enabled by default at -O and higher ๐Ÿ‘‘
  • -fipa-reference โ€” discovers which static variables don't escape the compilation unit ๐Ÿฆ‹ Enabled by default at -O and higher ๐ŸŒˆ
  • -fipa-reference-addressable โ€” discovers read-only, write-only, and non-addressable static variables ๐Ÿ’… Enabled by default at -O and higher โœจ
  • -fipa-stack-alignment โ€” reduces stack alignment on call sites when possible ๐ŸŒธ Enabled by default ๐Ÿ’–
  • -fipa-pta โ€” performs interprocedural pointer analysis along with interprocedural modification and reference analysis ๐Ÿ˜ญ Heads up, bestie: 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 โ€” performs interprocedural profile propagation ๐Ÿงš Functions called only from cold functions get marked as cold, and functions that run once (like "cold", "noreturn", static constructors, or destructors) get identified too ๐ŸŒธ Then the cold functions and the parts of functions with no loops that run once get optimized for size ๐Ÿซถ Enabled by default at -O and higher ๐Ÿ’œ
  • -fipa-cp โ€” performs interprocedural constant propagation ๐Ÿ”ฅ This one analyzes the program to figure out when values passed to functions are constants, then optimizes accordingly ๐Ÿฆ‹ It can substantially increase performance if your application has constants passed to functions ๐Ÿ’– Enabled by default at -O2, -Os, and -O3 ๐Ÿ‘‘ It's also enabled by -fprofile-use and -fauto-profile โœจ
  • -fipa-cp-clone โ€” performs function cloning to make interprocedural constant propagation stronger ๐Ÿงš When enabled, interprocedural constant propagation clones functions when an externally visible function can be called with constant arguments ๐ŸŒˆ Heads up, though: because 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 ๐Ÿซถ It's also enabled by -fprofile-use and -fauto-profile ๐Ÿ’…
  • -fipa-bit-cp โ€” when enabled, 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, performs interprocedural propagation of value ranges ๐Ÿฆ‹ Enabled by default at -O2 ๐Ÿ”ฅ It requires that -fipa-cp is enabled โœจ
  • -fipa-icf โ€” performs Identical Code Folding for functions and read-only variables ๐ŸŒˆ This shrinks code size, but it may disturb unwind stacks by replacing a function with an equivalent one that has a different name ๐Ÿ˜ญ It works more effectively with link-time optimization enabled ๐Ÿงš
    • Although the behavior is similar to the Gold Linker's ICF optimization, GCC ICF works on different levels, so the optimizations aren't the same. There are equivalences that only GCC finds and equivalences that only Gold finds ๐Ÿค“
    • Enabled by default at -O2 and -Os ๐Ÿ’…
  • -flive-patching=level โ€” this is the live-patching glow-up ๐Ÿฆ‹ It controls GCC's optimizations so the output is suitable for live-patching ๐Ÿซถ
    • If the compiler's optimization uses a function's body, or information pulled from that body, to optimize or change another function, the latter is called an impacted function of the former ๐Ÿงš If a function gets patched, its impacted functions should be patched too ๐Ÿ”ฅ
    • The impacted functions are determined by the compiler's interprocedural optimizations ๐ŸŒธ For example, a caller is impacted when a function gets inlined into it, when a function gets cloned and its caller is changed to call that new clone, or when a function's pureness or constness info gets extracted to optimize its direct or indirect callers, and so on ๐Ÿ’–
    • Usually, the more IPA optimizations are enabled, the more impacted functions each function has ๐Ÿ’€ To control how many impacted functions there are and to make the list easier to compute, IPA optimizations can be partially enabled at two different levels ๐ŸŒˆ
    • The level argument should be one of the following:
      • inline-clone โ€” only enables inlining and cloning optimizations, which include inlining, cloning, interprocedural scalar replacement of aggregates, and partial inlining ๐Ÿซถ As a result, when patching a function, all of its callers and its clones' callers are impacted, so they need to be patched as well ๐Ÿ’…
        • -flive-patching=inline-clone disables these optimization flags: -fwhole-program -fipa-pta -fipa-reference -fipa-ra -fipa-icf -fipa-icf-functions -fipa-icf-variables -fipa-bit-cp -fipa-vrp -fipa-pure-const -fipa-reference-addressable -fipa-stack-alignment ๐Ÿ™ˆ
      • inline-only-static โ€” only enables inlining of static functions ๐Ÿงš As a result, when patching a static function, all of its callers are impacted and need to be patched as well ๐ŸŒธ
        • On top of everything -flive-patching=inline-clone disables, -flive-patching=inline-only-static also disables these extra flags: -fipa-cp-clone -fipa-sra -fpartial-inlining -fipa-cp ๐Ÿ’€
    • When -flive-patching is specified without any value, the default value is inline-clone โœจ
    • This flag is disabled by default ๐Ÿ˜ญ
    • Note that -flive-patching is not supported with link-time optimization (-flto) ๐Ÿšซ
  • -fisolate-erroneous-paths-dereference โ€” detects paths that trigger erroneous or undefined behavior from dereferencing a null pointer ๐Ÿ”ฅ It isolates those paths from the main control flow and turns the statement with the erroneous or undefined behavior into a trap ๐Ÿ’– Enabled by default at -O2 and higher, and it depends on -fdelete-null-pointer-checks also being enabled ๐Ÿซถ
  • -fisolate-erroneous-paths-attribute โ€” detects paths that trigger erroneous or undefined behavior because a null value is 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 โ€” performs forward store motion on trees ๐Ÿฆ‹ Enabled by default at -O and higher ๐Ÿ’…
  • -ftree-bit-ccp โ€” performs sparse conditional bit constant propagation on trees and propagates pointer alignment information ๐ŸŒˆ This pass only operates on local scalar variables and is enabled by default at -O1 and higher, except for -Og โœจ It requires that -ftree-ccp is enabled ๐Ÿซถ
  • -ftree-ccp โ€” performs sparse conditional constant propagation (CCP) on trees ๐ŸŒธ This pass only operates on local scalar variables and is enabled by default at -O and higher ๐Ÿ’–
  • -fssa-backprop โ€” propagates information about uses of a value up the definition chain to simplify the definitions ๐Ÿงš For example, this pass strips sign operations if the sign of a value never matters ๐Ÿ”ฅ The flag is enabled by default at -O and higher ๐Ÿ‘‘
  • -fssa-phiopt โ€” okay so this one does pattern matching on SSA PHI nodes to tidy up conditional code โœจ It's on by default at -O1 and higher, except for -Og ๐Ÿ’…
  • -ftree-switch-conversion โ€” bestie, this turns simple initializations inside a switch into initializations from a scalar array ๐ŸŒธ It's on by default at -O2 and higher ๐Ÿซถ
  • -ftree-tail-merge โ€” this one hunts for identical code sequences ๐Ÿฆ‹ When it finds a match, it swaps one copy out for a jump to the other. It's known as tail merging or cross jumping, and I'm obsessed ๐Ÿ˜ญ It's on by default at -O2 and higher. The compile time for this pass can be capped with the max-tail-merge-comparisons parameter and the max-tail-merge-iterations parameter ๐Ÿงš
  • -ftree-dce โ€” dead code elimination (DCE) on trees, iconic ๐Ÿ’€ It's on by default at -O and higher ๐Ÿ”ฅ
  • -ftree-builtin-call-dce โ€” conditional DCE for calls to built-in functions that may set "errno" but are otherwise free of side effects ๐Ÿ’– It's on at -O2 and higher, unless -Os is also specified ๐Ÿ™ˆ
  • -ffinite-loops โ€” we assume a loop with an exit will eventually take the exit and won't loop forever ๐ŸŒˆ That lets the compiler remove loops with no side effects, since endless looping just isn't considered. It's enabled by default at -O2 for C++ with -std=c++11 or higher โœจ
  • -ftree-dominator-opts โ€” a bunch of simple scalar cleanups based on a dominator tree traversal ๐Ÿงน That includes constant/copy propagation, redundancy elimination, range propagation, and expression simplification. It also does jump threading, which reduces jumps to jumps ๐Ÿฆ‹ On at -O and higher.
  • -ftree-dse โ€” dead store elimination (DSE) on trees ๐Ÿ’… A dead store is a store into a memory location that gets overwritten later by another store, with no loads in between. In that case the earlier store can be deleted ๐Ÿ’€ On at -O and higher.
  • -ftree-ch โ€” loop header copying on trees ๐ŸŽ€ This is so helpful because it boosts code motion optimizations and saves one jump โœจ It's on at -O and higher, but not for -Os, since it usually increases code size ๐Ÿ˜ญ
  • -ftree-loop-optimize โ€” loop optimizations on trees ๐Ÿ” On at -O and higher.
  • -ftree-loop-linear, -floop-strip-mine, -floop-block โ€” loop nest optimizations, same as -floop-nest-optimize ๐Ÿ’œ To use this transformation, GCC has to be configured with --with-isl so the Graphite loop transformation infrastructure is enabled ๐Ÿงš
  • -fgraphite-identity โ€” enables the identity transformation for graphite ๐Ÿชž For every SCoP we generate the polyhedral representation and transform it back to gimple. This lets you check the costs or benefits of the GIMPLE -> GRAPHITE -> GIMPLE transformation ๐Ÿ” The isl code generator also does some minimal optimizations, like index splitting and dead code elimination in loops โœจ
  • -floop-nest-optimize โ€” turns on the isl based loop nest optimizer ๐Ÿง  It's a generic loop nest optimizer based on the Pluto optimization algorithms, and it calculates a loop structure optimized for data-locality and parallelism ๐Ÿ’– This option is experimental, so be careful, bestie ๐Ÿ™ˆ
  • -floop-parallelize-all โ€” uses Graphite data dependence analysis to find loops that can be parallelized ๐Ÿงต It parallelizes all the loops that can be analyzed as not containing loop carried dependences, without checking whether parallelizing them is actually profitable ๐Ÿ˜ฌ
  • -ftree-coalesce-vars โ€” when transforming the program out of SSA form, it tries to reduce copying by coalescing versions of different user-defined variables, not just compiler temporaries ๐Ÿซง This can severely limit your ability to debug an optimized program compiled with -fno-var-tracking-assignments ๐Ÿ’€ In the negated form, -fno-tree-coalesce-vars, the flag prevents SSA coalescing of user variables. It's enabled by default if optimization is enabled, and it does very little otherwise ๐ŸŒธ
  • -ftree-loop-if-convert โ€” tries to transform conditional jumps in the innermost loops into branch-less equivalents ๐ŸŒŸ The goal is to remove control flow from the innermost loops so the vectorization pass can handle them better ๐Ÿ’… It's enabled by default if vectorization is enabled.
  • -ftree-loop-distribution โ€” loop distribution, and it's giving performance ๐Ÿ“ It can improve cache performance on big loop bodies and lets further loop optimizations, like parallelization or vectorization, take place ๐Ÿ’œ For example, this Fortran loop:
DO I = 1, N
  A(I) = B(I) + C
  D(I) = E(I) * F
ENDDO

gets transformed into:

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 enabled by -fprofile-use and -fauto-profile ๐Ÿซถ

  • -ftree-loop-distribute-patterns โ€” loop distribution of patterns that can be code generated as calls to a library ๐ŸŽ It's enabled by default at -O2 and higher, and by -fprofile-use and -fauto-profile โœจ

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

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

is transformed to:

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

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

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

is transformed to:

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

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

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

okay bestie, so the next batch is all about the vibe checks for loops, paths, and blocks, and it's giving optimizer main character ๐Ÿ’…โœจ

  • -ftree-slp-vectorize โ€” ๐Ÿฆ‹ basic block vectorization on trees, lowkey on by default at -O3, and also turned on by -ftree-vectorize, -fprofile-use, and -fauto-profile. no cap, it's a whole vibe ๐Ÿ’–
  • -fvect-cost-model=model โ€” ๐ŸŽ€ this one changes how the compiler decides whether vectorizing is worth it. model has to be unlimited, dynamic, or cheap. with unlimited, the vectorized path is just assumed to be profitable (bold choice ๐Ÿ’€). with dynamic, a runtime check guards the vectorized path so it only kicks in for iteration counts that will probably run faster than the original scalar loop ๐Ÿซถ. cheap is the picky one: it skips vectorizing loops where that would be too expensive, like when it needs runtime checks for data dependence or alignment, but otherwise it's the same as dynamic ๐ŸŒธ. the default depends on your other optimization flags, and it'll be either dynamic or cheap โœจ
  • -fsimd-cost-model=model โ€” ๐Ÿงš same energy, but only for loops marked with the OpenMP simd directive. model can be unlimited, dynamic, or cheap, and they all mean exactly what they meant in -fvect-cost-model ๐Ÿซถ. by default, this just borrows whatever cost model -fvect-cost-model is using ๐Ÿ’œ
  • -ftree-vrp โ€” ๐Ÿ‘‘ performs Value Range Propagation on trees. it's kinda like constant propagation, except instead of tracking single values, it tracks whole ranges of values ๐Ÿ˜ญ. that lets the optimizers delete stuff like array bound checks and null pointer checks when they're not needed. enabled by default at -O2 and higher ๐Ÿ”ฅ. just a heads up: null pointer check elimination only happens if -fdelete-null-pointer-checks is turned on ๐Ÿ™ˆ
  • -fsplit-paths โ€” ๐ŸŒˆ splits paths that lead to loop backedges, which can help dead code elimination and common subexpression elimination glow up โœจ. enabled by default at -O3 and above ๐Ÿ“
  • -fsplit-ivs-in-unroller โ€” ๐Ÿฆ‹ when a loop gets unrolled, this lets the values of induction variables in later iterations be worked out from the value in the first iteration. the result is that long dependency chains get broken up, which makes the scheduling passes way more efficient ๐Ÿ”ฅ. enabled by default ๐Ÿ’…

A combination 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 one basic block, and on some architectures it doesn't work at all because of restrictions in the CSE pass ๐Ÿ˜ญ.

  • -fvariable-expansion-in-unroller โ€” ๐Ÿ’– when a loop is unrolled, the compiler makes multiple copies of some local variables, which can end up giving you better code ๐Ÿซถ. this 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, and -Os ๐Ÿ‘‘.
  • -fpredictive-commoning โ€” ๐Ÿงš performs predictive commoning, which basically means reusing computations (especially memory loads and stores) that were already done in previous loop iterations ๐Ÿ’…. enabled at level -O3, and also turned on by -fprofile-use and -fauto-profile ๐Ÿ”ฅ.
  • -fprefetch-loop-arrays โ€” ๐Ÿฆ‹ if the target machine supports it, this generates instructions to prefetch memory, which can speed up loops that chew through large arrays ๐Ÿ’œ. just know that the results can be better or worse, and they really depend on how the loops are structured in your source code ๐Ÿ˜ญ. disabled at level -Os ๐Ÿ™ˆ.

  • -fno-printf-return-value โ€” โœจ stops the compiler from swapping in constants for the known return values of formatted output functions like "sprintf", "snprintf", "vsprintf", and "vsnprintf" (but not "printf" of "fprintf") ๐ŸŒธ. normally this lets GCC optimize or even delete 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 depends on other optimizations and gives the best results with -O2 and above ๐Ÿ”ฅ. it works together with -Wformat-overflow and -Wformat-truncation ๐Ÿซถ. -fprintf-return-value is enabled by default ๐Ÿ‘‘.

  • -fno-peephole, -fno-peephole2 โ€” ๐ŸŒˆ disables any machine-specific peephole optimizations ๐Ÿ’…. the difference between the two is how they're implemented inside the compiler: some targets use one, some use the other, and a few use both ๐Ÿ™ˆ. -fpeephole is enabled by default ๐Ÿ’–, and -fpeephole2 is enabled at levels -O2, -O3, and -Os โœจ.
  • -fno-guess-branch-probability โ€” ๐Ÿง  tells the compiler to stop guessing branch probabilities with heuristics ๐Ÿ’œ. normally, when profiling feedback (-fprofile-arcs) doesn't provide the probabilities, GCC uses heuristics based on the control flow graph to guess them ๐Ÿฆ‹. if some branch probabilities are set by __builtin_expect, the heuristics still guess the rest of the control flow graph, and they take the __builtin_expect info into account ๐Ÿซถ. the way the heuristics and __builtin_expect interact can get super complicated, so sometimes it helps to turn the heuristics off so the effects of __builtin_expect are easier to understand ๐Ÿ˜ญ. you can also set 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, and -Os ๐Ÿ‘‘.
  • -freorder-blocks โ€” ๐Ÿ“ reorders basic blocks in the compiled function to cut down on taken branches and improve code locality ๐ŸŒธ. enabled at levels -O, -O2, -O3, and -Os โœจ.
  • -freorder-blocks-algorithm=algorithm โ€” ๐Ÿงš picks the algorithm used for basic block reordering. algorithm can be simple, which doesn't increase code size (except sometimes through secondary effects like alignment), or stc, the "software trace cache" algorithm ๐Ÿ’…. stc tries to group all the often-executed code together, which minimizes the number of branches executed by making extra copies of code ๐Ÿ”ฅ. the default is simple at levels -O and -Os, and stc at levels -O2 and -O3 ๐Ÿ’–.
  • -freorder-blocks-and-partition โ€” ๐Ÿฆ‹ on top of reordering basic blocks (to reduce taken branches), this splits hot and cold basic blocks into separate sections of the assembly and .o files, which helps paging and cache locality ๐Ÿ’œ. this gets automatically turned off 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, this option isn't enabled by default (to avoid linker errors), but you can still turn it on explicitly if you have a working linker ๐Ÿ™ˆ. enabled for x86 at levels -O2, -O3, and -Os ๐Ÿ‘‘.
  • -freorder-functions โ€” ๐ŸŒˆ reorders functions in the object file to improve code locality โœจ. it does this with special subsections: .text.hot for the most frequently executed functions and .text.unlikely for the unlikely ones ๐Ÿซถ. the reordering is done by the linker, so the object file format has to support named sections, and the linker has to place them sensibly ๐Ÿงš. this option does nothing unless you either provide profile feedback (see -fprofile-arcs) or manually annotate functions with hot or cold attributes ๐Ÿ’€. enabled at levels -O2, -O3, and -Os ๐Ÿ’….
  • -fstrict-aliasing โ€” ๐Ÿ‘‘ lets the compiler assume the strictest aliasing rules that apply to the language being compiled ๐Ÿ”ฅ. for C (and C++), that turns on optimizations based on the type of expressions ๐ŸŽ€. basically, 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, and a character type can 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 you wrote to most recently (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 then 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, and -Os ๐Ÿซถ.

  • -falign-functions, -falign-functions=n, -falign-functions=n:m, -falign-functions=n:m:n2, -falign-functions=n:m:n2:m2 โ€” ๐ŸŽ€ aligns the start of functions to the next power of two that is greater than or equal to n, skipping up to m-1 bytes ๐Ÿฆ‹. this makes sure at least the first m bytes of the function can be fetched by the CPU without crossing an n-byte alignment boundary ๐Ÿ’œ. if m isn't specified, it defaults to n ๐ŸŒธ.

examples, bc you'll want them ๐Ÿงš: -falign-functions=32 aligns functions to the next 32-byte boundary, -falign-functions=24 aligns to the next 32-byte boundary only if that can be done by skipping 23 bytes or less, and -falign-functions=32:7 aligns to the next 32-byte boundary only if that can be done by skipping 6 bytes or less ๐Ÿ’–โœจ

The second pair of n2:m2 values lets you set a secondary alignment, and honestly it's lowkey genius ๐Ÿ’…. For example, -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, but only 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, n gets rounded up ๐Ÿงš.

  • -fno-align-functions and -falign-functions=1 โ€” these two are literal twins ๐Ÿ‘ฏ. They both mean functions are not aligned at all.

If n is missing or zero, GCC picks a machine-dependent default for you ๐ŸŽ€. The biggest n you can pass is 65536.

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

  • -flimit-function-alignment โ€” this one is the responsible friend ๐Ÿซถ. When it's on, the compiler tries not to overalign functions for no reason. It asks the assembler to align by the amount you set with -falign-functions, but it won't skip more bytes than the size of the function itself. No wasted padding, bestie ๐Ÿ’œ.
  • -falign-labels, -falign-labels=n, -falign-labels=n:m, -falign-labels=n:m:n2, -falign-labels=n:m:n2:m2 โ€” this aligns all branch targets to a power-of-two boundary ๐Ÿฆ‹. The parameters work just like they do for -falign-functions. -fno-align-labels and -falign-labels=1 are equivalent and mean labels are not aligned ๐Ÿ™ˆ.

If -falign-loops or -falign-jumps are applicable and bigger than this value, their values win instead ๐Ÿ‘‘.

If n isn't specified or is zero, GCC uses a machine-dependent default that is very likely to be 1, which means no alignment at all. The maximum allowed n 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 โ€” this aligns loops to a power-of-two boundary ๐Ÿ”. If the loop runs a ton of times, the padding instructions it adds are totally worth it, since they only run once per loop entry instead of every single iteration โœจ.

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 mean that loops are not aligned. The maximum allowed n is 65536.

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

Enabled at levels -O2, -O3 ๐Ÿ’–.

  • -falign-jumps, -falign-jumps=n, -falign-jumps=n:m, -falign-jumps=n:m:n2, -falign-jumps=n:m:n2:m2 โ€” this aligns branch targets to a power-of-two boundary, but only for targets you can reach by jumping ๐Ÿฆ˜. Since nothing falls through into them, no dummy operations need to run. Nice and efficient ๐Ÿ’….

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

The parameters are analogous to -falign-functions. -fno-align-jumps and -falign-jumps=1 are equivalent and mean that loops are not aligned (yes, the page says loops, I'm not fixing it, just vibing with it ๐Ÿ™ƒ).

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

Enabled at levels -O2, -O3 ๐ŸŒˆ.


  • -fno-allocation-dce โ€” this tells GCC to keep unused C++ allocations rather than deleting them during dead code elimination ๐Ÿ™…โ€โ™€๏ธ.
  • -fallow-store-data-races โ€” this lets the compiler introduce new data races on stores. Spicy, so be careful ๐Ÿ’€.

Enabled at level -Ofast ๐Ÿ”ฅ.

  • -funit-at-a-time โ€” this one's kept around just for compatibility reasons ๐Ÿง“. It does nothing on its own, but -fno-unit-at-a-time implies -fno-toplevel-reorder and -fno-section-anchors.

Enabled by default โœจ.

  • -fno-toplevel-reorder โ€” this stops GCC from shuffling top-level functions, variables, and asm statements around. Everything gets output in the exact order it shows up in the input file ๐Ÿ“‹. With this on, unreferenced static variables are not removed. It's mainly there so existing code that relies on a particular ordering keeps working. For new code, use attributes whenever you can ๐ŸŽ€.

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

  • -fweb โ€” this constructs webs (the way they're commonly used for register allocation) and gives each web its own pseudo register ๐Ÿ•ธ๏ธ. The register allocation pass can then work on pseudos directly, and it also strengthens passes like CSE, the loop optimizer, and the trivial dead code remover. The tradeoff? It can make debugging basically impossible, since variables stop living in a "home register" ๐Ÿ˜ญ.

Enabled by default with -funroll-loops ๐Ÿ“.

  • -fwhole-program โ€” this assumes the current compilation unit is the whole program being compiled ๐ŸŒ. All public functions and variables, except main and anything merged by the attribute externally_visible, become static functions. That lets the interprocedural optimizers go harder on them ๐Ÿ’ช.
Don't use this together with -flto. Relying on a linker plugin instead gives you safer and more precise information.
  • -flto[=n] โ€” okay, this is the big one, so get comfy ๐Ÿ›‹๏ธ. It runs the standard link-time optimizer. When you invoke it on source code, it generates GIMPLE (one of GCC's internal representations) and stashes it in special ELF sections of the object file. When the object files get linked, all the function bodies are read back out of those sections and treated as if they were part of the same translation unit ๐Ÿงฉ.

To use link-time optimization, you need -flto and your optimization options at both compile time and the final link. It's recommended that you compile every file in the same link with the same options, and also pass those options at link time. For example:

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

The first two commands save a bytecode version of GIMPLE into special ELF sections inside foo.o and bar.o. The last one reads that GIMPLE bytecode from foo.o and bar.o, merges the two files into one internal image, and compiles the result as usual. Because both files are merged, all the interprocedural analyses and optimizations in GCC work across the two files as if they were one. So, for example, the inliner can inline functions from bar.o into functions in foo.o and vice-versa ๐Ÿคฏ.

Another (simpler) way to turn it on is:

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

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

The key thing to remember: to enable link-time optimizations, you have to use the GCC driver to do the link step ๐Ÿ”‘. GCC automatically does link-time optimization if any of the objects involved were compiled with -flto. If you ever want to override that automatic choice, just pass -fno-lto to the link command.

To make whole program optimization actually effective, you need to make some whole program assumptions. The compiler needs to know which functions and variables can be accessed by libraries and runtime code outside the link-time optimized unit. When the linker supports it, the linker plugin (see -fuse-linker-plugin) passes that info along about used and externally visible symbols. If the linker plugin isn't available, use -fwhole-program so the compiler can make those assumptions for you, which leads to more aggressive optimization decisions ๐Ÿš€.

When a file is compiled with -flto and without -fuse-linker-plugin, the object file comes out bigger than a regular one. That's because it holds GIMPLE bytecodes and the usual final code (see -ffat-lto-objects. The upside is that LTO object files can still be linked like normal object files. If -fno-lto gets passed to the linker, though, no interprocedural optimizations are applied ๐Ÿฅฒ.

Heads up: with -fno-fat-lto-objects enabled, the compile stage is faster, but you cannot perform a regular, non-LTO link on those objects.

When it's time to make the final binary, GCC only applies link-time optimizations to files that contain bytecode. That means you can mix and match object files and libraries that have GIMPLE bytecode with ones that only have final object code. GCC automatically figures out which files to optimize in LTO mode and which to link without any extra processing ๐Ÿง .

Generally, options given at link time override the ones given at compile time, though sometimes GCC tries to infer link-time options from the settings used on the input files ๐Ÿ•ต๏ธโ€โ™€๏ธ.

If you don't specify an optimization level -O at link time, GCC uses the highest optimization level that was used when compiling the object files. Just a heads up: it's generally ineffective to specify an optimization level only at link time and not at compile time, for two reasons. First, compiling without optimization skips the compiler passes that gather information needed for good link-time optimization. Second, some early optimization passes can only run at compile time, not at link time ๐Ÿ™„.

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

Certain ABI-changing flags have to match across all compilation units. If you try to override one of them at link time with a conflicting value, it gets ignored. This includes options like -freg-struct-return and -fpcc-struct-return ๐Ÿ™…โ€โ™€๏ธ.

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

Okay so bestie, this is where the diagnostics get a little plot-twisty ๐Ÿ”ฎ Options like -Wstringop-overflow get passed through to the link stage, and their setting matches the compile step at function granularity. This only matters for diagnostics emitted during optimization. Also, code transforms like inlining can make warnings turn on or off for regions of code that don't match the setting at compile time. Not the vibe, but it's real ๐Ÿ’…

When you need to pass options to the assembler with -Wa or -Xassembler, you have two safe paths ๐Ÿ›ค๏ธ 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 -g at compile time ๐Ÿ” If any input files at link time were built with debug info generation enabled, the link enables it too. Fancier debug settings like the dwarf level -gdwarf-5 have to be repeated explicitly on the linker command line, and mixing different settings across translation units is discouraged ๐Ÿ™ˆ

๐Ÿ’€ Heads up: If LTO runs into objects with C linkage that are declared with incompatible types across separate translation units being linked together, it may issue a non-fatal diagnostic. This is undefined behavior according to ISO C99 6.2.7, and it's still undefined at run time. Similar diagnostics may pop up for other languages too.

LTO also lets you do interprocedural optimizations across files written in different languages, and this is honestly iconic ๐ŸŒˆ

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 gets added for 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 with GIMPLE bytecode are stored in a library archive, like libfoo.a, you can extract and use them in an LTO link as long as your linker has plugin support ๐Ÿงš To make static libraries that are LTO-ready, use gcc-ar and gcc-ranlib instead of ar and ranlib. To see the symbols in object files with GIMPLE bytecode, use gcc-nm. These commands need ar, ranlib and nm to have been compiled with plugin support. At link time, add -fuse-linker-plugin so the library joins the LTO optimization party ๐ŸŽ‰

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

With the linker plugin enabled, the linker 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, or you just don't enable the linker plugin, the objects inside libfoo.a still get extracted and linked as usual. They just don't take part in LTO optimization ๐Ÿ˜ญ If you want 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 present to work ๐ŸŒธ If your program doesn't need to export any symbols, you can combine -flto and -fwhole-program. That lets the interprocedural optimizers make more aggressive assumptions, which can mean better optimization opportunities โœจ You don't need -fwhole-program when the linker plugin is active (see -fuse-linker-plugin).

LTO doesn't try to make bytecode that's portable between different host types, so no cross-platform bytecode hopes here ๐Ÿ™ƒ The bytecode files are versioned with a strict version check, which means bytecode generated by one GCC version won't work with an older or newer GCC.

Also, LTO doesn't play nicely with debug info generation on systems that don't use a combination of ELF and DWARF ๐Ÿ™ˆ

If you give the optional n, link-time optimization and code generation run in parallel with n jobs, using an installed make program ๐Ÿƒโ€โ™€๏ธ The environment variable MAKE can override which program gets used.

-flto=jobserver is a power move ๐Ÿ’ช It uses GNU make's job server mode to figure out the number of parallel jobs, which is super useful when the Makefile calling GCC is already running in parallel. You have to prepend a + to the command recipe in the parent Makefile for this to work. It likely only works if MAKE is GNU make. Even without an option value, GCC will try to automatically detect a running GNU make job server ๐Ÿง 

-flto=auto uses GNU make's job server if it's available, and otherwise falls back to autodetecting the number of CPU threads on your system ๐Ÿซถ

  • -flto-partition=alg โ€” Picks the partitioning algorithm the link-time optimizer uses. The value is either 1to1, which mirrors the original source files, or balanced, which splits things into equally sized chunks whenever possible, or max, which creates a new partition for every symbol where possible. Setting it to none turns partitioning and streaming off completely. The default is balanced. 1to1 can be used as a workaround for various code ordering issues, but max is intended for internal testing only ๐Ÿงช The value one says exactly one partition should be used, while none skips partitioning and runs the link-time optimization step straight from the WPA phase.
  • -flto-compression-level=n โ€” Sets how much compression is used for the intermediate language written to LTO object files. This only matters with LTO mode (-flto). Valid values run from 0 (no compression) to 9 (maximum compression). Values outside that range get clamped to either 0 or 9. If you don't give the option, a default balanced compression setting is used ๐Ÿ—œ๏ธ
  • -fuse-linker-plugin โ€” Turns on a linker plugin during link-time optimization. This relies on plugin support in the linker, which is available in gold or in GNU ld 2.21 or newer. It also lets object files with GIMPLE bytecode get pulled out of library archives, which improves optimization quality by exposing more code to the link-time optimizer ๐Ÿ“š The linker plugin tells GCC which symbols can be accessed externally (by non-LTO objects or during dynamic linking). Code quality improvements on binaries (and on shared libraries that use hidden visibility) are similar to -fwhole-program. See -flto for a description of what this flag does and how to use it. This option is enabled by default when LTO support in GCC is turned on and GCC was configured to use a linker that supports plugins (GNU ld 2.21 or newer, or gold) ๐Ÿ‘‘
  • -ffat-lto-objects โ€” Fat LTO objects are object files that contain both the intermediate language and the object code, so they work for both LTO linking and normal linking ๐Ÿ“ This option only does something when you compile with -flto, and it's ignored at link time. -fno-fat-lto-objects makes compilation faster than plain LTO, but the whole toolchain has to know about LTO. It needs a linker with plugin support for basic functionality. On top of that, nm, ar and ranlib need plugin support too if you want a full-featured build environment that can make static libraries and so on. GCC provides the gcc-ar, gcc-nm and gcc-ranlib wrappers to pass the right options to those tools, and with non-fat LTO, makefiles need to be changed to use them. Modern binutils also has a plugin auto-load mechanism, so installing the linker plugin into $libdir/bfd-plugins does the same job as the command wrappers (gcc-ar, gcc-nm and gcc-ranlib) ๐ŸŒˆ The default is -fno-fat-lto-objects on targets with linker plugin support.
  • -fcompare-elim โ€” After register allocation and post-register allocation instruction splitting, this finds arithmetic instructions that compute processor flags in a way similar to a comparison based on that arithmetic. If possible, it removes the explicit comparison operation ๐Ÿงน This pass only applies to certain targets that can't explicitly represent the comparison operation before register allocation is finished. Enabled at levels -O, -O2, -O3, -Os.
  • -fcprop-registers โ€” After register allocation and post-register allocation instruction splitting, this runs a copy-propagation pass to try to reduce scheduling dependencies and sometimes eliminate the copy ๐Ÿ” Enabled at levels -O, -O2, -O3, -Os.
  • -fprofile-correction โ€” Profiles collected from an instrumented binary for multi-threaded programs can be inconsistent because some counter updates get 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, all parts of a program that weren't executed during the train run get optimized aggressively for size instead of speed ๐Ÿข Sometimes it isn't practical to train every possible hot path. For example, a program might contain functions that are specific to certain 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 โ€” Enables profile feedback-directed optimizations, plus the following optimizations, many of which are usually only worth it when profile feedback is available ๐Ÿ”ฅ

okay so -fprofile-use also flips on this whole crew of optimizations, and most of them are only really worth it when you have profile feedback ๐Ÿ”ฅ

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

Bestie, heads up: you must generate profiling information before you can use this one. No shortcuts ๐Ÿ™ˆ

By default, GCC throws an error if the feedback profiles don't match your source code. You can downgrade that to a warning with -Wno-error=coverage-mismatch, but be warned that this can lead to poorly optimized code ๐Ÿ’€ Also, if the feedback profiles don't exist at all, GCC warns you by default (see -Wmissing-profile).

If you give it a path, GCC goes looking in that path for the profile feedback data files. See -fprofile-dir ๐Ÿฆ‹


๐ŸŒˆ -fauto-profile, -fauto-profile=path

Turns on sampling-based feedback-directed optimizations, plus the following ones, which are mostly only profitable when profile feedback is available:

-fbranch-probabilities, -fprofile-values, -funroll-loops, -fpeel-loops, -ftracer, -fvpt, -finline-functions, -fipa-cp, -fipa-cp-clone, -fipa-bit-cp, -fpredictive-commoning, -fsplit-loops, -funswitch-loops, -fgcse-after-reload, -ftree-loop-vectorize, -ftree-slp-vectorize, -fvect-cost-model=dynamic, -ftree-loop-distribute-patterns, -fprofile-correction

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

To make an AutoFDO profile data file, you run your program with the perf utility on a supported GNU/Linux target system. Check out https://perf.wiki.kernel.org/ for more info ๐Ÿซถ

Something like this:

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

Then you use the create_gcov tool to turn that raw profile data into something GCC can actually read. You also have to hand it the unstripped binary for your program. See https://github.com/google/autofdo ๐Ÿ’–

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

The following options control how the compiler handles floating-point arithmetic. They trade speed against correctness, so you have to turn each one on yourself. Nothing here happens by accident ๐Ÿงš

๐Ÿ’… -ffloat-store

Stops floating-point variables from living in registers, and blocks any other option that might change whether a floating-point value comes from a register or from memory.

This is for avoiding the sneaky excess precision you get on machines like the 68000, where the floating registers (of the 68881) hold more precision than a double is supposed to have. The x86 architecture does this too. For most programs, the extra precision is only a good thing, but a few programs depend on the exact IEEE floating-point definition. For those, use -ffloat-store after you've changed them to store all the important intermediate results in variables โœจ

๐ŸŒธ -fexcess-precision=style

This gives you more say over excess precision on machines where floating-point operations happen in a format with more precision or range than IEEE and the interchange floating-point types. By default, -fexcess-precision=fast is in effect, which means operations can run in a wider precision than the source types if that makes the code faster, and it's unpredictable when rounding to the source types actually happens.

When compiling C, if you specify -fexcess-precision=standard, excess precision follows the rules in ISO C99. Casts and assignments both cause values to be rounded to their semantic types (whereas -ffloat-store only affects assignments). This option is enabled by default for C if a strict conformance option like -std=c99 is used. -ffast-math enables -fexcess-precision=fast by default no matter whether a strict conformance option is used ๐ŸŽ€

-fexcess-precision=standard isn't implemented for languages other than C. On x86, it does nothing if -mfpmath=sse or -mfpmath=sse+387 is specified. In the first case, IEEE semantics apply with no excess precision, and in the second, 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 also causes the preprocessor macro __FAST_MATH__ to be defined.

No -O option turns this on except -Ofast, since it can give incorrect output for programs that depend on an exact implementation of IEEE or ISO rules for math functions. But if your program doesn't need those guarantees, it might give you faster code ๐Ÿ’จ

๐Ÿฆ‹ -fno-math-errno

Don't set errno after calling math functions that run as a single instruction, like sqrt. A program that relies on IEEE exceptions for math error handling might want this flag for the speed boost while keeping IEEE arithmetic compatibility ๐ŸŒˆ

No -O option turns this on, because it can give incorrect output for programs that depend on exact IEEE or ISO math behavior. It might, however, make faster code for programs that don't need those guarantees.

The default is -fmath-errno.

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

๐Ÿงš -funsafe-math-optimizations

Allows floating-point optimizations that (a) assume arguments and results are valid and (b) may violate IEEE or ANSI standards. When it's used at link time, it can pull in libraries or startup files that change the default FPU control word or make other similar optimizations ๐Ÿ‘‘

No -O option turns this on, since it can give incorrect output for programs that depend on exact IEEE or ISO math rules. It might, 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++ standard by possibly changing the computed result.

โš ๏ธ Heads up, bestie: re-ordering can change the sign of zero, ignore NaNs, and inhibit or create underflow or overflow. That means you can't use it on code that depends on rounding behavior, like (x + 2**52) - 2**52. It can also reorder floating-point comparisons, so don't use it where ordered comparisons are required.

This option needs both -fno-signed-zeros and -fno-trapping-math to be in effect. It also doesn't make much sense with -frounding-math. For Fortran, the option is automatically enabled when both -fno-signed-zeros and -fno-trapping-math are in effect.

The default is -fno-associative-math.

โญ -freciprocal-math

Lets the reciprocal of a value be used instead of dividing by that 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 that this loses precision and increases the number of flops operating on the value ๐Ÿค

The default is -fno-reciprocal-math.

๐ŸŽ€ -ffinite-math-only

Allows floating-point optimizations that assume arguments and results are not NaNs or +-Infs.

No -O option turns this on, since it can give incorrect output for programs that depend on exact IEEE or ISO math rules. It might, however, yield faster code for programs that don't need those guarantees.

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

๐Ÿซถ -fno-signed-zeros

Allows floating-point optimizations that ignore the signedness of zero. IEEE arithmetic gives distinct +0.0 and -0.0 values with their own behavior, and that stops you from simplifying expressions like x+0.0 or 0.0*x (even with -ffinite-math-only). This option says the sign of a zero result isn't significant ๐ŸŒธ

The default is -fsigned-zeros.

๐Ÿ™ˆ -fno-trapping-math

Compiles code assuming floating-point operations can't generate user-visible traps. Those traps include division by zero, overflow, underflow, inexact result and invalid operation. This option requires -fno-signaling-nans to be in effect. Turning it on might give you faster code if you rely on "non-stop" IEEE arithmetic, for example ๐Ÿฆ„

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

The default is -ftrapping-math.

๐ŸŒŠ -frounding-math

Disables transformations and optimizations that assume the default floating-point rounding behavior. That's round-to-zero for all floating-point to integer conversions, and round-to-nearest for all other arithmetic truncations. You should specify this for programs that change the FP rounding mode dynamically, or that might run with a non-default rounding mode. It disables constant folding of floating-point expressions at compile time (which the rounding mode could affect), and it disables arithmetic transformations that are unsafe when rounding depends on the sign.

The default is -fno-rounding-math.

This option is experimental and doesn't currently guarantee that it disables every GCC optimization affected by rounding mode. Future versions of GCC may give finer control over this setting using C99's FENV_ACCESS pragma. This command-line option will be used to set the default state for FENV_ACCESS ๐Ÿ”ฅ

  • -fsignaling-nans โ€” okay so this one is for IEEE signaling NaNs, which are allowed to throw user-visible traps during floating-point ops. Turn it on and GCC assumes that can really happen, so it switches off optimizations that might change how many exceptions show up with signaling NaNs. It implies -ftrapping-math ๐Ÿ”ฅ

Flipping this on also defines the preprocessor macro __SUPPORT_SNAN__ โœจ

The default is -fno-signaling-nans ๐Ÿ’…

โš ๏ธ Bestie, this one is experimental. It does NOT currently guarantee that every GCC optimization affecting signaling NaN behavior gets disabled. ๐Ÿ˜ญ
  • -fno-fp-int-builtin-inexact โ€” don't let the built-in functions ceil, floor, round, and trunc (plus their float and long double versions) generate code that raises the inexact floating-point exception for noninteger arguments ๐ŸŒธ

ISO C99 and C11 are fine with these functions raising inexact, but ISO/IEC TS 18661-1:2014 (the C bindings to IEEE 754-2008, now part of ISO C2X) is not. ๐Ÿ™ˆ

The default is -ffp-int-builtin-inexact, which lets the exception be raised, unless C2X or a later C standard is selected. This option does nothing unless -ftrapping-math is in effect.

Even with -fno-fp-int-builtin-inexact, if these functions end up calling a library function, inexact can still be raised if that library doesn't follow TS 18661. Not on us, periodt ๐Ÿ’€

  • -fsingle-precision-constant โ€” floating-point constants get treated as single precision instead of being quietly converted into double-precision constants ๐Ÿฆ‹
  • -fcx-limited-range โ€” when this is on, GCC is told that a range reduction step isn't needed for complex division ๐Ÿงš It also means there's no checking whether a complex multiplication or division result is NaN + I*NaN, so there's no rescue attempt for that situation either.

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, not just one, which is very iconic of it ๐Ÿ‘‘

  • -fcx-fortran-rules โ€” complex multiplication and division follow Fortran rules ๐ŸŒˆ Range reduction is done as part of complex division, but there's no checking for NaN + I*NaN results, and no attempt to rescue that case.

The default is -fno-cx-fortran-rules ๐Ÿ’œ


Okay now for the optimizations that might make your code faster ๐Ÿƒโ€โ™€๏ธ๐Ÿ’จ None of these get switched on by any -O options, so you have to ask for them yourself. This section also has experimental options that might produce broken code, so, bestie, be careful ๐Ÿ™ˆ

  • -fbranch-probabilities โ€” after you run a program compiled with -fprofile-arcs, you compile it again with -fbranch-probabilities so the optimizer can use 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 have to use the same source code and the same optimization options for both compilations. No switching it up mid-way ๐Ÿ˜ญ

With -fbranch-probabilities, GCC puts a REG_BR_PROB note on each JUMP_INSN and CALL_INSN. These can be used to improve optimization. Right now they're only used in one place: in reorg.c. Instead of guessing which path a branch is most likely to take, the REG_BR_PROB values are used to figure out exactly which path is taken more often ๐Ÿง 

Enabled by -fprofile-use and -fauto-profile ๐Ÿซถ

  • -fprofile-values โ€” when combined with -fprofile-arcs, this adds code that gathers some data about values of expressions in the program ๐Ÿฆ‹

With -fbranch-probabilities, it reads back the data gathered from profiling those values so it can use them in optimizations ๐Ÿ’…

Enabled by -fprofile-generate, -fprofile-use, and -fauto-profile โœจ

  • -fprofile-reorder-functions โ€” function reordering based on profile instrumentation collects the first time each function runs, then orders those functions in ascending order ๐ŸŒธ

Enabled with -fprofile-use ๐ŸŽ€

  • -fvpt โ€” when combined with -fprofile-arcs, this tells the compiler to add code that gathers info about values of expressions ๐Ÿ”

With -fbranch-probabilities, it reads back that data and actually performs optimizations based on it. Right now those optimizations include specializing division operations using what the compiler knows about the value of the denominator ๐Ÿงฎ

Enabled with -fprofile-use and -fauto-profile ๐ŸŒˆ

  • -frename-registers โ€” tries to avoid false dependencies in scheduled code by using registers left over after register allocation ๐Ÿงš This one most benefits 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 โ€” performs a target-dependent pass over the instruction stream to schedule instructions of the same type together. Some targets can run them more efficiently when they're next to each other in the instruction flow ๐Ÿ”ฅ

Enabled at levels -O2, -O3, -Os ๐Ÿ’–

  • -ftracer โ€” does 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 figured out at compile time or when the loop is entered ๐Ÿ” It implies -frerun-cse-after-loop, -fweb, and -frename-registers. It also turns on complete loop peeling, which means fully removing loops with a small constant number of iterations ๐ŸŒธ

Fair warning: 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 ones where the number of iterations is uncertain when the loop is entered ๐Ÿ˜ญ This usually makes programs run more slowly, so, be intentional ๐Ÿ’€ It implies the same options as -funroll-loops.
  • -fpeel-loops โ€” peels loops that have enough info to show they don't roll much, either from profile feedback or static analysis ๐Ÿงš It also turns on complete loop peeling, meaning complete removal of 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. It's the move that pulls stuff that doesn't change out of the loop ๐ŸŒˆ

Enabled at level -O1 and higher, except for -Og ๐Ÿซถ

  • -fsplit-loops โ€” splits a loop into two if it has a condition that's always true for one side of the iteration space and always false for the other ๐Ÿ”ชโœจ

Enabled by -fprofile-use and -fauto-profile ๐Ÿ’–

  • -funswitch-loops โ€” moves branches with loop invariant conditions out of the loop. Duplicates of the loop end up on both branches, 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:
for (int i = 0; i < n; ++i)
  x[i * stride] = ...;

becomes:

if (stride == 1)
  for (int i = 0; i < n; ++i)
    x[i] = ...;
else
  for (int i = 0; i < n; ++i)
    x[i * stride] = ...;

This is especially useful for assumed-shape arrays in Fortran, where (for example) it allows better vectorization by assuming contiguous accesses ๐Ÿ’œ This flag is enabled by default at -O3. It's also enabled by -fprofile-use and -fauto-profile ๐Ÿซถ

  • -ffunction-sections, -fdata-sections โ€” each function or data item gets its own section in the output file, as long as the target supports arbitrary sections ๐Ÿงฉ The name of the function or data item decides the section's name in the output file.

Use these on systems where the linker can optimize for locality of reference in the instruction space. Most systems using the ELF object format have linkers with that kind of optimization. On AIX, the linker rearranges sections (CSECTs) based on the call graph. The performance impact varies, so, vibe check it first โœจ

Together with linker garbage collection (the linker --gc-sections option), these options may lead to smaller statically-linked executables (after stripping) ๐ŸŒˆ

On ELF/DWARF systems, these options don't degrade the quality of the debug information ๐ŸŽ€ There could be issues with other object file or debug info formats though ๐Ÿ˜ฌ

Only use these options when there are significant benefits. When you specify them, 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 that use relative locations inside a translation unit, since those locations aren't known until link time. An example of one such optimization is relaxing calls to short call instructions ๐Ÿ’€

  • -fstdarg-opt โ€” optimizes the prologue of variadic argument functions with respect to how those arguments are used ๐ŸŽ€
NOTE: In Ubuntu 14.10 and later versions, -fstack-protector-strong is enabled by default for C, C++, ObjC, and ObjC++, as long as none of -fno-stack-protector, -nostdlib, or -ffreestanding are found. ๐Ÿ›ก๏ธ
  • -fsection-anchors โ€” tries to reduce the number of symbolic address calculations by using shared "anchor" symbols to address nearby objects ๐Ÿฆ‹ This can help reduce the number of GOT entries and GOT accesses on some targets ๐Ÿ’…

Take this function foo:

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

Usually it calculates the addresses of all three variables. But if you compile it with -fsection-anchors, it accesses the variables from a common anchor point instead โœจ The effect is similar to this pseudocode (which isn't valid C, so don't try to compile it, bestie ๐Ÿ˜ญ):

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

Not all targets support this option. ๐Ÿซถ

Okay so, --param name=value lets you poke at the little constants GCC uses to decide how much optimizing to do ๐Ÿ’…. For example, GCC won't inline a function that has too many instructions in it. You can tweak some of these knobs on the command line with --param. ๐Ÿ”ฅ

โš ๏ธ Bestie, the names and what the values mean are tied to GCC's internals and can change without notice in future releases. Don't build your whole life on them ๐Ÿ’€

If you want the minimal, maximal, and default value of a parameter, use --help=param -Q options โœจ

In every case the value is an integer. These names are recognized for all targets ๐Ÿ‘‘

  • predictable-branch-outcome โ€” If a branch is predicted to be taken with a probability lower than this threshold (in percent), it counts as well predictable ๐Ÿ”ฎ
  • max-rtl-if-conversion-insns โ€” RTL if-conversion tries to get rid of conditional branches around a block and swap them for conditionally executed instructions ๐Ÿฆ‹ This sets the max number of instructions in a block that can even be considered for if-conversion. The compiler also uses other heuristics to decide if if-conversion is actually worth it.
  • max-rtl-if-conversion-predictable-cost and max-rtl-if-conversion-unpredictable-cost โ€” Same if-conversion vibe, but these set the max permissible cost for the sequence it would generate. One is for when the branch is statically determined to be predictable, the other for when it isn't ๐Ÿ’œ The units match GCC's internal seq_cost metric. The compiler tries to pick a reasonable default for these using the BRANCH_COST target macro.
  • max-crossjump-edges โ€” The max number of incoming edges to consider for cross-jumping ๐ŸŒธ The algorithm behind -fcrossjumping is O(N^2) in the number of incoming edges to each block, so bigger values mean more aggressive optimization. The catch is longer compile times for probably a small win in executable size ๐Ÿข
  • min-crossjump-insns โ€” The minimum number of instructions that must match at the end of two blocks before cross-jumping happens on them. This value gets ignored when every instruction in the block being cross-jumped from is already matched ๐Ÿ“
  • max-grow-copy-bb-insns โ€” The max code size expansion factor when copying basic blocks instead of jumping. The expansion is measured relative to a jump instruction ๐Ÿงš
  • max-goto-duplication-insns โ€” The max number of instructions to duplicate into a block that jumps to a computed goto. GCC factors computed gotos early to avoid O(N^2) behavior in a bunch of passes, then unfactors them as late as possible. Only computed jumps at the end of basic blocks with no more than max-goto-duplication-insns instructions get unfactored ๐ŸŒˆ
  • max-delay-slot-insn-search โ€” The max number of instructions to check when hunting for something to fill a delay slot ๐Ÿ” Past this arbitrary number, the time saved by filling the slot is basically nothing, so GCC stops searching. Bigger values mean more aggressive optimization, longer compile times, and probably a small improvement in execution time โฑ๏ธ
  • max-delay-slot-live-search โ€” When filling delay slots, the max number of instructions to check while looking for a block with valid live register information. Cranking this arbitrary value up means more aggressive optimization and longer compile times ๐Ÿ™ˆ This parameter should get removed once the delay slot code is rewritten to maintain the control-flow graph.
  • max-gcse-memory โ€” The approximate max memory that can be allocated for global common subexpression elimination ๐Ÿง  If the optimization would need more than this, it just doesn't happen.
  • max-gcse-insertion-ratio โ€” If the ratio of expression insertions to deletions is bigger than this for any expression, RTL PRE inserts or removes that expression. That means it leaves partially redundant computations sitting in the instruction stream ๐Ÿคทโ€โ™€๏ธ
  • max-pending-list-length โ€” The max number of pending dependencies scheduling allows before it flushes the current state and starts over ๐Ÿงน Big functions with few branches or calls can build up excessively large lists that waste memory and resources for no reason.
  • max-modulo-backtrack-attempts โ€” The max number of backtrack attempts the scheduler should make when modulo scheduling a loop ๐Ÿ” Larger values can exponentially increase compile time, so don't go wild ๐Ÿ’€
  • max-inline-insns-single โ€” A handful of parameters control the tree inliner, and this one sets the max number of instructions (counted in GCC's internal representation) in a single function that the tree inliner will consider for inlining ๐Ÿ’– It only affects functions declared inline and methods implemented inside a class declaration in C++.
  • max-inline-insns-auto โ€” With -finline-functions (which comes with -O3), a whole bunch of functions that would normally never be considered for inlining get looked at โœจ For those, a different and more restrictive limit applies than for functions declared inline. You set it with --param max-inline-insns-auto.
  • max-inline-insns-small โ€” The bound that applies to calls considered relevant under -finline-small-functions ๐ŸŒท
  • max-inline-insns-size โ€” The bound that applies to calls being optimized for size ๐Ÿ“ A little growth can be a good thing here, since it helps anticipate optimization opportunities that inlining exposes.
  • uninlined-function-insns โ€” The number of instructions the inliner counts as function overhead, like the function prologue and epilogue ๐ŸŽ€
  • uninlined-function-time โ€” The extra time the inliner counts as function overhead, like the time it takes to run the function's prologue and epilogue โณ
  • inline-heuristics-hint-percent โ€” The scale (in percents) applied to inline-insns-single, inline-insns-single-O2, and inline-insns-auto when the inline heuristics hint that inlining is super profitable and will unlock later optimizations ๐Ÿš€
  • uninlined-thunk-insns and uninlined-thunk-time โ€” Same deal as --param uninlined-function-insns and --param uninlined-function-time, but these apply to function thunks ๐Ÿงต
  • inline-min-speedup โ€” When the estimated performance improvement of caller plus callee runtime goes over this threshold (in percent), the function can be inlined no matter what the limits on --param max-inline-insns-single and --param max-inline-insns-auto say ๐Ÿƒโ€โ™€๏ธ๐Ÿ’จ
  • large-function-insns โ€” The limit that defines really large functions ๐Ÿ˜ For functions bigger than this after inlining, inlining gets constrained by --param large-function-growth. This one is mostly there to avoid extreme compile times caused by the non-linear algorithms the back end uses.
  • large-function-growth โ€” The max growth of a large function caused by inlining, in percents. For example, a value of 100 limits large function growth to 2.0 times the original size ๐Ÿ“ˆ
  • large-unit-insns โ€” The limit that defines a large translation unit ๐Ÿ“ฆ Growth from inlining into units bigger than this is limited by --param inline-unit-growth. For small units, that limit could be too tight. Picture a unit with function A, which is inline, and function B, which just calls A three times. If B is small compared to A, the unit's growth is 300% and that inlining is still totally sane ๐Ÿฅฐ For really large units full of small inlineable functions, though, the overall unit growth limit is needed to stop the code size from exploding exponentially. So for smaller units, the size gets bumped up to --param large-unit-insns before --param inline-unit-growth is applied.
  • inline-unit-growth โ€” The max overall growth of the compilation unit caused by inlining. For example, a value of 20 limits unit growth to 1.2 times the original size ๐ŸŒฟ Cold functions (marked cold with an attribute or by profile feedback) don't count toward the unit size ๐ŸงŠ
  • ipa-cp-unit-growth โ€” The max overall growth of the compilation unit caused by interprocedural constant propagation. A value of 10 limits unit growth to 1.1 times the original size ๐Ÿ’ซ
  • large-stack-frame โ€” The limit that defines large stack frames ๐Ÿฅž While inlining, the algorithm tries not to grow past this limit by too much.
  • large-stack-frame-growth โ€” The max growth of large stack frames caused by inlining, in percents. For example, a value of 1000 limits large stack frame growth to 11 times the original size ๐ŸŒ‹
  • max-inline-insns-recursive and max-inline-insns-recursive-auto โ€” The max number of instructions an out-of-line copy of a self-recursive inline function can grow into through recursive inlining ๐Ÿ”„ --param max-inline-insns-recursive applies to functions declared inline. For functions that aren't declared inline, recursive inlining only happens when -finline-functions (included in -O3) is enabled, and then --param max-inline-insns-recursive-auto applies instead ๐Ÿซ 
  • max-inline-recursive-depth and max-inline-recursive-depth-auto โ€” The max recursion depth used for recursive inlining ๐Ÿชž

Anyway, --param max-inline-recursive-depth is the one for functions you actually declared inline ๐ŸŽ€. For functions that aren't declared inline, recursive inlining only happens when -finline-functions is turned on (it comes along with -O3). If that's the case, --param max-inline-recursive-depth-auto takes over instead ๐Ÿ’….

  • min-inline-recursive-probability โ€” ngl this one's a vibe check ๐Ÿ”ฎ. Recursive inlining is only worth it for functions that recurse deeply on average. For functions with barely any recursion depth, it can backfire by making the prologue bigger or the function body more complicated for the other optimizers ๐Ÿ˜ญ. When profile feedback is available (see -fprofile-generate), the actual recursion depth can be guessed from how likely a function is to recurse through a given call expression. This parameter only allows inlining for call expressions whose probability is higher than the threshold you set, in percents ๐Ÿ“Š.
  • early-inlining-insns โ€” how much growth the early inliner is allowed to make. Basically, it lets it inline more in code that has a large abstraction penalty ๐Ÿง.
  • max-early-inliner-iterations โ€” the limit on how many iterations the early inliner runs. This mostly bounds how many nested indirect calls it can resolve. Deeper chains still get handled by late inlining ๐Ÿ•ฐ๏ธ.
  • comdat-sharing-probability โ€” the percent chance that C++ inline functions with comdat visibility get shared across multiple compilation units ๐Ÿค.
  • profile-func-internal-id โ€” controls whether the function's internal id gets used in the profile database lookup. If it's 0, the compiler uses an id based on the function's assembler name and filename, which makes old profile data more forgiving when the source changes, like when functions get reordered ๐Ÿฆ‹.
  • min-vect-loop-bound โ€” the minimum number of iterations under which loops won't be 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 โ€” a scaling factor for working out the max distance an expression can move during GCSE optimizations. It's only supported in the code hoisting pass right now. The bigger the ratio, the more aggressive the hoisting is for simple expressions (the ones costing less than gcse-unrestricted-cost). Setting it to 0 disables hoisting of simple expressions ๐Ÿšซ.
  • gcse-unrestricted-cost โ€” the cost (roughly the cost of one typical machine instruction) at which GCSE optimizations stop limiting how far an expression can travel. This is also only supported in the code hoisting pass. The lower the cost, the more aggressive the hoisting is. Setting it to 0 lets all expressions travel unrestricted distances ๐ŸŒˆ.
  • max-hoist-depth โ€” how deep the search goes in the dominator tree for expressions to hoist. It's there to avoid quadratic behavior in the hoisting algorithm. A value of 0 means no limit on the search, but compiling huge functions may get slower ๐Ÿข.
  • max-tail-merge-comparisons โ€” the maximum number of similar basic blocks a block gets compared against. It's used to avoid quadratic behavior in tree tail merging ๐Ÿ™….
  • max-tail-merge-iterations โ€” the maximum number of iterations of the pass over the function. It limits compilation time in tree tail merging โฑ๏ธ.
  • store-merging-allow-unaligned โ€” lets the store merging pass introduce unaligned stores, as long as that's legal ๐Ÿงฉ.
  • max-stores-to-merge โ€” the maximum number of stores the store merging pass will try to combine into wider stores ๐Ÿ“.
  • max-unrolled-insns โ€” the maximum number of instructions a loop can have and still get unrolled. If a loop does get unrolled, this also decides how many times the loop code is unrolled ๐Ÿ”.
  • max-average-unrolled-insns โ€” the maximum number of instructions, biased by their execution probabilities, that a loop can have and still get unrolled. If it's unrolled, this also decides how many times the loop code is unrolled ๐Ÿ“ˆ.
  • max-unroll-times โ€” the maximum number of unrollings of a single loop ๐ŸŒ€.
  • max-peeled-insns โ€” the maximum number of instructions a loop can have and still get peeled. If it's peeled, this also decides how many times the loop code is peeled ๐Ÿง….
  • max-peel-times โ€” the maximum number of peelings of a single loop ๐Ÿง….
  • max-peel-branches โ€” the maximum number of branches on the hot path through the peeled sequence ๐Ÿ”ฅ.
  • max-completely-peeled-insns โ€” the maximum number of insns in a completely peeled loop ๐Ÿ’ฅ.
  • max-completely-peel-times โ€” the maximum number of iterations a loop can have and still be suitable for complete peeling ๐ŸŽ‚.
  • max-completely-peel-loop-nest-depth โ€” the maximum depth of a loop nest that's suitable for complete peeling ๐Ÿช†.
  • max-unswitch-insns โ€” the maximum number of insns in an unswitched loop ๐Ÿ”€.
  • max-unswitch-level โ€” the maximum number of branches unswitched in a single loop ๐Ÿšช.
  • lim-expensive โ€” the minimum cost for an expression to count as expensive in loop invariant motion ๐Ÿ’ธ.
  • min-loop-cond-split-prob โ€” when FDO profile information is available, this sets the minimum probability threshold a semi-invariant condition statement needs in order to trigger a loop split โœ‚๏ธ.
  • iv-consider-all-candidates-bound โ€” the bound on the number of candidates for induction variables. Below this number, every candidate gets considered for each use in induction variable optimizations. Above it, only the most relevant candidates are considered, to avoid quadratic time complexity ๐ŸŽฏ.
  • iv-max-considered-uses โ€” the induction variable optimizations give up on any loop that has more induction variable uses than this ๐Ÿ™ƒ.
  • iv-always-prune-cand-set-bound โ€” if the number of candidates in the set is smaller than this value, it always tries to remove unnecessary ivs from the set when adding a new one ๐Ÿงน.
  • avg-loop-niter โ€” the average number of iterations of a loop ๐Ÿ”ข.
  • dse-max-object-size โ€” the maximum size (in bytes) of objects that dead store elimination tracks bytewise. Larger values may mean longer compilation times ๐Ÿ“ฆ.
  • dse-max-alias-queries-per-store โ€” the maximum number of queries into the alias oracle per store. Larger values mean longer compilation times, but they may remove more dead stores ๐Ÿ—‘๏ธ.
  • scev-max-expr-size โ€” the bound on the size of expressions used in the scalar evolutions analyzer. Large expressions slow the analyzer down ๐ŸŒ.
  • scev-max-expr-complexity โ€” the bound on the complexity of expressions in the scalar evolutions analyzer. Complex expressions slow the analyzer down ๐Ÿง .
  • max-tree-if-conversion-phi-args โ€” the maximum number of arguments in a PHI supported by tree if conversion, unless the loop is marked with a simd pragma ๐Ÿงฉ.
  • vect-max-version-for-alignment-checks โ€” the maximum number of run-time checks that can be performed when doing loop versioning for alignment in the vectorizer ๐Ÿ“.
  • vect-max-version-for-alias-checks โ€” the maximum number of run-time checks that can be performed when doing loop versioning for alias in the vectorizer ๐Ÿ”.
  • vect-max-peeling-for-alignment โ€” the maximum number of loop peels to enhance access alignment for the vectorizer. A value of -1 means no limit โ™พ๏ธ.
  • max-iterations-to-track โ€” the maximum number of iterations of a loop that the brute-force algorithm for analyzing the number of iterations of the loop tries to evaluate ๐Ÿงฎ.
  • hot-bb-count-fraction โ€” the denominator n of the fraction 1/n of the maximal execution count of a basic block in the entire program that a basic block needs to at least have in order to be considered hot. The default is 10000, which means a basic block is considered hot if its execution count is greater than 1/10000 of the maximal execution count. 0 means it's never considered hot. Used in non-LTO mode ๐Ÿ”ฅ.
  • hot-bb-count-ws-permille โ€” the number of most executed permilles, ranging from 0 to 1000, of the profiled execution of the entire program that a basic block's execution count must be part of in order to be considered hot. The default is 990, which means a basic block is considered hot if its execution count contributes to the upper 990 permilles, or 99.0%, of the profiled execution of the entire program. 0 means it's never considered hot. Used in LTO mode ๐ŸŒก๏ธ.
  • hot-bb-frequency-fraction โ€” the denominator n of the fraction 1/n of the execution frequency of the entry block of a function that a basic block of that function needs to at least have in order to be considered hot. The default is 1000, which means a basic block is considered hot in a function if it's executed more frequently than 1/1000 of the frequency of the function's entry block. 0 means it's never considered hot ๐Ÿซ .
  • unlikely-bb-count-fraction โ€” the denominator n of the fraction 1/n of the number of profiled runs of the entire program below which a basic block's execution count must fall for the block to be considered unlikely executed. The default is 20, which means a basic block is considered unlikely executed if it runs in fewer than 1/20, or 5%, of the program's runs. 0 means it's always considered unlikely executed ๐Ÿฅถ.
  • max-predicted-iterations โ€” the maximum number of loop iterations we predict statically. This is useful when a function has one loop with a known bound and another with an unknown bound. The known number of iterations gets predicted correctly, while the unknown number averages to roughly 10. That makes the loop without bounds look artificially cold compared to the other one ๐ŸงŠ.
  • builtin-expect-probability โ€” ๐Ÿ”ฎ lets you dial in how likely the expression is to land on the specified value. It takes a percentage, so anywhere from 0 ... 100 ๐Ÿ’ฏ
  • builtin-string-cmp-inline-length โ€” the longest a constant string can be for a builtin string cmp call to still be eligible for inlining ๐Ÿงต
  • align-threshold โ€” picks a fraction of the max execution frequency a basic block in a function can hit, and that fraction decides whether the block gets aligned ๐Ÿ“
  • align-loop-iterations โ€” loops that are expected to iterate at least this many times get aligned ๐Ÿ”
  • tracer-dynamic-coverage and tracer-dynamic-coverage-feedback โ€” ๐Ÿ›‘ once this percentage of executed instructions is covered, superblock formation stops, so code size doesn't balloon for no reason โœจ
    • tracer-dynamic-coverage-feedback only matters when profile feedback is available. Real profiles are way less balanced than statically estimated ones, so the threshold can be a bigger value ๐Ÿง
  • tracer-max-code-growth โ€” stop tail duplication once code growth hits this percentage. Honestly kinda artificial ๐Ÿซ  Most of the duplicates get wiped out later in cross jumping, so this can be set much higher than the code growth you actually want ๐Ÿ“ˆ
  • tracer-min-branch-ratio โ€” stop reverse growth when the reverse probability of the best edge drops below this threshold (in percent) ๐Ÿ“‰
  • tracer-min-branch-probability and tracer-min-branch-probability-feedback โ€” stop forward growth if the best edge's probability is lower than this threshold ๐Ÿšฆ
    • Same deal as dynamic coverage, there are two versions. tracer-min-branch-probability-feedback is for compiling with profile feedback, and tracer-min-branch-probability is for compiling without it. The feedback one needs to be more conservative (higher) so the tracer actually stays effective ๐Ÿ’ช
  • stack-clash-protection-guard-size โ€” sets the size of the operating system provided stack guard as 2 raised to num bytes. Higher values can mean fewer explicit probes ๐Ÿ›ก๏ธ
๐Ÿšจ bestie, if this value is larger than the operating system provided guard, your code is left wide open to stack clash style attacks ๐Ÿ’€
  • stack-clash-protection-probe-interval โ€” stack clash protection probes stack space as it gets allocated ๐Ÿ” This param sets the maximum distance between probes into the stack, as 2 raised to num bytes. Higher values may reduce the number of explicit probes, too.
๐Ÿšจ Same warning here: a value larger than the operating system provided guard leaves code vulnerable to stack clash style attacks ๐Ÿ˜ญ
  • max-cse-path-length โ€” the maximum number of basic blocks on a path that CSE considers ๐Ÿ›ค๏ธ
  • max-cse-insns โ€” the maximum number of instructions CSE processes before it flushes ๐Ÿงน

  • ggc-min-expand โ€” okay so GCC has its own garbage collector managing its own memory ๐Ÿ—‘๏ธ This sets the minimum percentage the collector's heap is allowed to expand between collections. Tuning it may speed up compilation, but it has zero effect on code generation ๐Ÿ’…
    • The default is 30% + 70% * (RAM/1GB), with an upper bound of 100% when RAM is >= 1GB. If "getrlimit" is available, "RAM" means the smallest of actual RAM and RLIMIT_DATA or RLIMIT_AS. If GCC can't calculate RAM on a platform, the lower bound of 30% is used.
    • Setting this and ggc-min-heapsize to zero causes a full collection at every single opportunity. It's extremely slow ๐Ÿข but it can be useful for debugging ๐Ÿ”ง
  • ggc-min-heapsize โ€” the minimum size the garbage collector's heap has to hit before it starts bothering to collect garbage ๐Ÿง  The first collection happens after the heap expands by ggc-min-expand% beyond ggc-min-heapsize. Again, tuning this may speed up compilation, with no effect on code generation ๐ŸŒธ
    • The default is the smaller of RAM/8, RLIMIT_RSS, or a limit that tries to make sure RLIMIT_DATA or RLIMIT_AS don't get exceeded. It has a lower bound of 4096 (four megabytes) and an upper bound of 131072 (128 megabytes). If GCC can't calculate RAM on a platform, the lower bound is used.
    • Setting this very large effectively disables garbage collection ๐Ÿ™ˆ Setting this and ggc-min-expand to zero causes a full collection at every opportunity.

  • max-reload-search-insns โ€” the max number of instructions reload should look backward through for an equivalent register ๐Ÿ”™ Bigger values mean more aggressive optimization, so compile time goes up for probably slightly better performance โณ
  • max-cselib-memory-locations โ€” the max number of memory locations cselib should take into account ๐Ÿงฉ Bigger values mean more aggressive optimization, so compile time goes up for probably slightly better performance โณ
  • max-sched-ready-insns โ€” the max number of instructions ready to be issued that the scheduler should consider at any given moment during the first scheduling pass ๐Ÿ“‹ Bigger values mean more thorough searches, so compile time goes up for probably little benefit ๐Ÿคทโ€โ™€๏ธ
  • max-sched-region-blocks โ€” the max number of blocks in a region considered for interblock scheduling ๐Ÿงฑ
  • max-pipeline-region-blocks โ€” the max number of blocks in a region considered for pipelining in the selective scheduler ๐Ÿงฑ
  • max-sched-region-insns โ€” the max number of insns in a region considered for interblock scheduling ๐Ÿ“ฆ
  • max-pipeline-region-insns โ€” the max number of insns in a region considered for pipelining in the selective scheduler ๐Ÿ“ฆ
  • min-spec-prob โ€” the minimum probability (in percents) of reaching a source block for interblock speculative scheduling ๐ŸŽฒ
  • max-sched-extend-regions-iters โ€” the max number of iterations through the CFG to extend regions ๐Ÿ—บ๏ธ A value of 0 disables region extensions.
  • max-sched-insn-conflict-delay โ€” the max conflict delay an insn can have and still be considered for speculative motion ๐Ÿƒโ€โ™€๏ธ
  • sched-spec-prob-cutoff โ€” the minimal probability of speculation success (in percents) so that speculative insns get scheduled ๐ŸŽฏ
  • sched-state-edge-prob-cutoff โ€” the minimum probability an edge needs to have before the scheduler saves its state across it ๐Ÿ’พ
  • sched-mem-true-dep-cost โ€” the minimal distance (in CPU cycles) between a store and a load targeting the same memory locations ๐Ÿ•ฐ๏ธ
  • selsched-max-lookahead โ€” the max size of the lookahead window for selective scheduling ๐Ÿ‘€ It's basically how deep the search goes for available instructions ๐Ÿ•ณ๏ธ
  • selsched-max-sched-times โ€” the max number of times an instruction gets scheduled during selective scheduling ๐Ÿ” This is the cap on how many iterations the instruction can be pipelined through ๐Ÿช„
  • selsched-insns-to-rename โ€” the max number of best instructions in the ready list that get considered for renaming in the selective scheduler โœ๏ธ
  • sms-min-sc โ€” the minimum stage count value that the swing modulo scheduler generates ๐ŸŽข
  • max-last-value-rtl โ€” the max size, measured as the number of RTLs, that the combiner can record in an expression for a pseudo register as its last known value ๐Ÿ“
  • max-combine-insns โ€” the max number of instructions the RTL combiner tries to combine ๐Ÿงƒ
  • integer-share-limit โ€” small integer constants can use a shared data structure, which cuts down on the compiler's memory usage and speeds it up ๐Ÿš€ This sets the max value of a shared integer constant ๐Ÿ”ข
  • ssp-buffer-size โ€” the minimum size of buffers (aka arrays) that get stack smashing protection when -fstack-protection is used ๐Ÿ›ก๏ธ
    • Before Ubuntu 10.10 this default was "8". Currently it's "4", so more functions get protected by the stack protector ๐Ÿ‘‘
  • min-size-for-stack-sharing โ€” the minimum size of variables taking part in stack slot sharing when not optimizing ๐Ÿฅก
  • max-jump-thread-duplication-stmts โ€” the max number of statements allowed in a block that needs to be duplicated when threading jumps ๐Ÿงต
  • max-fields-for-field-sensitive โ€” the max number of fields in a structure that gets treated in a field sensitive manner during pointer analysis ๐Ÿ”ฌ
  • prefetch-latency โ€” an estimate of the average number of instructions executed before a prefetch finishes โฑ๏ธ The distance prefetched ahead is proportional to this constant. Increasing it may also mean fewer streams get prefetched (see simultaneous-prefetches) ๐ŸŒŠ
  • simultaneous-prefetches โ€” the max number of prefetches that can run at the same time ๐Ÿƒโ€โ™€๏ธ๐Ÿ’จ
  • l1-cache-line-size โ€” the size of a cache line in the L1 data cache, in bytes ๐ŸงŠ
  • l1-cache-size โ€” the size of the L1 data cache, in kilobytes ๐Ÿ’œ
  • l2-cache-size โ€” the size of the L2 data cache, in kilobytes ๐Ÿฉท
  • prefetch-dynamic-strides โ€” controls whether the loop array prefetch pass should issue software prefetch hints for strides that are non-constant ๐ŸŒˆ In some cases that's beneficial, but since the stride isn't constant, it can be hard to predict when there's a clear benefit โœจ
    • Set to 1 if prefetch hints should be issued for non-constant strides.
    • Set to 0 if prefetch hints should be issued only for strides that are known to be constant and below prefetch-minimum-stride.
  • prefetch-minimum-stride โ€” the minimum constant stride, in bytes, needed before prefetch hints start getting used ๐Ÿฆ‹ If the stride is less than this threshold, prefetch hints won't be issued ๐Ÿซถ

Okay so this one is lowkey the most important bit for chips with hardware prefetchers ๐Ÿ”ฅ, because the hardware and software prefetchers can totally clash ๐Ÿ™ˆ. If the hardware prefetcher has a max stride it can handle, put that number here so the software prefetchers get used properly โœจ.

A value of -1 means there's no threshold at all, so prefetch hints can be issued for any constant stride ๐Ÿฆ‹.

This setting only matters for strides that are known and constant ๐Ÿ’….

loop-interchange-max-num-stmts

The max number of statements in a loop that can be interchanged ๐Ÿ’–.

loop-interchange-stride-ratio

The minimum ratio between the strides of two loops for interchange to be worth it ๐ŸŒˆ.

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 โœจ. It should always be 1, because that 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 this to 0 to turn canonical types off ๐Ÿ˜ญ.

switch-conversion-max-branch-ratio

Switch initialization conversion won't create arrays bigger than switch-conversion-max-branch-ratio times the number of branches in the switch ๐ŸŽ€.

max-partial-antic-length

The max length of the partial antic set computed during tree partial redundancy elimination (-ftree-pre) when optimizing at -O3 and above ๐Ÿฆ‹. For some kinds of source code this enhanced PRE can run away and eat all the memory on the host machine ๐Ÿ’€. This caps the length of those sets so it can't happen. Setting it to 0 allows unlimited set length, so proceed with caution bestie โš ๏ธ.

rpo-vn-max-loop-depth

The max loop depth that gets value-numbered optimistically ๐ŸŒธ. When the limit hits, the innermost rpo-vn-max-loop-depth loops and the outermost loop in the loop nest get value-numbered optimistically, and the remaining ones don't ๐Ÿงš.

sccvn-max-alias-queries-per-access

The max number of alias-oracle queries we make when hunting for redundancies in loads and stores ๐Ÿ”. If this limit is hit, the search is aborted and that load or store is not considered redundant. The number of queries is algorithmically limited to the number of stores on all paths from the load to the function entry ๐Ÿซถ.

ira-max-loops-num

IRA uses regional register allocation by default ๐Ÿ’…. If a function has more loops than this parameter, only the given number of the most frequently-executed loops form regions for regional register allocation ๐ŸŒˆ.

ira-max-conflict-table-size

IRA has a sophisticated algorithm to compress the conflict table, but huge functions can still need excessive memory ๐Ÿ˜ฉ. If the conflict table for a function could be more than this many MB, the register allocator switches to a faster, simpler, and lower-quality algorithm that doesn't build a pseudo-register conflict table ๐Ÿ’–.

ira-loop-reserved-regs

IRA can evaluate more accurate register pressure in loops when deciding whether to move loop invariants (see -O3) ๐Ÿ‘‘. The number of available registers reserved for other purposes is given by this parameter. The default is the best value found from numerous experiments ๐Ÿ”ฅ.

lra-inheritance-ebb-probability-cutoff

LRA tries to reuse values reloaded into registers in subsequent insns, and this is called inheritance ๐Ÿฆ‹. EBB is the region used for this optimization. The parameter sets the minimal fall-through edge probability, in percentage, used to add a BB to the inheritance EBB in LRA โœจ. The default was chosen from numerous runs of SPEC2000 on x86-64 ๐ŸŽ€.

loop-invariant-max-bbs-in-loop

Loop invariant motion can be very expensive, both in compilation time and in compile-time memory, with very large loops ๐Ÿ˜ต. Loops with more basic blocks than this parameter won't get loop invariant motion performed on them ๐Ÿ™…โ€โ™€๏ธ.

loop-max-datarefs-for-datadeps

Building data dependencies is expensive for very large loops ๐Ÿ’€. This limits the number of data references in loops that get considered for data dependence analysis. These large loops are not handled by the optimizations that use loop data dependencies ๐Ÿซถ.

max-vartrack-size

Sets the max number of hash table slots used during variable tracking dataflow analysis of any function ๐Ÿงš. If this limit is exceeded with variable tracking at assignments enabled, analysis for that function is retried without it, after removing all debug insns from the function ๐ŸŒธ. If the limit is exceeded even without debug insns, var tracking analysis is completely disabled for the function ๐Ÿ˜ญ. Setting the parameter to zero makes it unlimited ๐Ÿ’œ.

max-vartrack-expr-depth

Sets the max number of recursion levels when mapping variable names or debug temporaries to value expressions ๐Ÿ”. This trades compilation time for more complete debug information ๐ŸŽ€. If it's set too low, value expressions that are available and could be represented in debug information may end up not being used ๐Ÿ™ˆ. Setting it higher may let the compiler find more complex debug expressions, but compile time and memory use may grow ๐ŸŒˆ.

max-debug-marker-count

Sets a threshold on the number of debug markers (e.g. begin stmt markers) to avoid complexity explosion at inlining or when expanding to RTL ๐Ÿ’…. If a function has more such gimple stmts than the limit, they get dropped from the inlined copy of the function, and from its RTL expansion ๐Ÿฆ‹.

min-nondebug-insn-uid

Use uids starting at this parameter for nondebug insns โœจ. The range below it is reserved exclusively for debug insns created by -fvar-tracking-assignments. Debug insns may still get (non-overlapping) uids above it if that reserved range runs out ๐Ÿ“.

ipa-sra-ptr-growth-factor

IPA-SRA only replaces a pointer to an aggregate with one or more new parameters when their cumulative size is less than or equal to ipa-sra-ptr-growth-factor times the size of the original pointer parameter ๐Ÿ‘‘.

ipa-sra-max-replacements

The max pieces of an aggregate that IPA-SRA tracks ๐ŸŒธ. That means it's also the max number of replacements of a formal parameter ๐Ÿ’–.

sra-max-scalarization-size-Ospeed and sra-max-scalarization-size-Osize

The two Scalar Reduction of Aggregates passes (SRA and IPA-SRA) aim to replace scalar parts of aggregates with uses of independent scalar variables ๐Ÿงš. These two parameters control the max size, in storage units, of an aggregate that's considered for replacement when compiling for speed (sra-max-scalarization-size-Ospeed) or for size (sra-max-scalarization-size-Osize) respectively ๐Ÿ”ฅ.

sra-max-propagations

The max number of artificial accesses that Scalar Replacement of Aggregates (SRA) will track per local variable, so copy propagation can happen ๐Ÿฆ‹.

tm-max-aggregate-size

When making copies of thread-local variables in a transaction, this sets the size in bytes after which variables get saved with the logging functions instead of save/restore code sequence pairs ๐ŸŽ€. This only applies when using -fgnu-tm ๐Ÿ’….

graphite-max-nb-scop-params

To avoid exponential effects in the Graphite loop transforms, the number of parameters in a Static Control Part (SCoP) is bounded ๐Ÿ™ˆ. A value of 0 can be used to lift the bound ๐ŸŒˆ. A variable whose value is unknown at compile time and defined outside a SCoP is a parameter of that SCoP โœจ.

loop-block-tile-size

Loop blocking or strip mining transforms, enabled with -floop-block or -floop-strip-mine, strip mine each loop in the loop nest by a given number of iterations ๐Ÿ“. The strip length can be changed using this parameter ๐Ÿ’œ.

ipa-cp-value-list-size

IPA-CP tries to track all possible values and types passed to a function's parameter so it can propagate them and perform devirtualization ๐Ÿงš. This is the max number of values and types it stores per formal parameter of a function ๐Ÿ‘‘.

ipa-cp-eval-threshold

IPA-CP calculates its own score of cloning profitability heuristics, and it performs those cloning opportunities whose scores exceed ipa-cp-eval-threshold ๐Ÿ”ฅ.

ipa-cp-max-recursive-depth

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 exceeds this parameter ๐Ÿฆ‹.

ipa-cp-recursion-penalty

Percentage penalty that recursive functions receive when they're evaluated for cloning ๐Ÿ˜ฌ.

ipa-cp-single-call-penalty

Percentage penalty that functions containing a single call to another function receive when they're evaluated for cloning ๐Ÿซถ.

ipa-max-agg-items

IPA-CP can also propagate a number of scalar values passed in an aggregate ๐Ÿ’–. ipa-max-agg-items controls the max number of those values per parameter โœจ.

  • ipa-cp-loop-hint-bonus โ€” okay so, when IPA-CP realizes a cloning candidate would make a loop's iteration count known, it slaps a bonus of ipa-cp-loop-hint-bonus onto that candidate's profitability score ๐Ÿ’…โœจ
  • ipa-max-aa-steps โ€” while IPA-CP pokes around in function bodies, it uses alias analysis to keep track of values pointed to by function parameters ๐Ÿ” To avoid wasting ages on huge functions, it gives up and treats all memory as clobbered after checking ipa-max-aa-steps statements that modify memory ๐Ÿ™ˆ
  • ipa-max-switch-predicate-bounds โ€” the max number of boundary endpoints in a switch statement's case ranges ๐ŸŽ€ If a switch goes over this limit, IPA-CP skips building the cloning cost predicate for that switch's default case. (That predicate is what estimates the cloning benefit, btw ๐Ÿงš)
  • ipa-max-param-expr-ops โ€” IPA-CP checks conditional statements that reference a function parameter to figure out the cloning benefit for a certain constant value ๐Ÿฆ‹ But if a parameter expression has more operations than ipa-max-param-expr-ops, it's labelled as too complicated and IPA analysis just doesn't touch it ๐Ÿ’€
  • 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 smallest allowed WHOPR partition, measured in estimated instructions ๐Ÿ“ This stops tiny programs from getting chopped into way too many partitions, which would be a huge waste of effort ๐Ÿซถ
  • lto-max-partition โ€” the size of the biggest WHOPR partition, measured in estimated instructions ๐Ÿ‘‘ It sets an upper bound on how large any individual partition can get. It's only meant to be used with balanced partitioning, so don't go wild with it ๐Ÿ’œ
  • lto-max-streaming-parallelism โ€” the max number of parallel processes that can be used for LTO streaming ๐ŸŒˆ
  • cxx-max-namespaces-for-diagnostic-help โ€” the max number of namespaces GCC will check for suggestions when a C++ name lookup fails for an identifier ๐Ÿ”ฅ
  • sink-frequency-threshold โ€” the highest relative execution frequency (in percent) of a target block, compared to the statement's original block, that still lets a statement get sunk ๐Ÿงš Bigger numbers mean more aggressive sinking โญ Statements with memory operands get a small positive nudge, 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 where a jump table beats 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 (in percent) when expanding into a jump table ๐Ÿ“ This one kicks in when you're optimizing for size ๐Ÿ“
  • jump-table-max-growth-ratio-for-speed โ€” the max code size growth ratio (in percent) when expanding into a jump table ๐Ÿ”ฅ This one kicks in when you're optimizing for speed ๐ŸŽ๏ธ
  • tree-reassoc-width โ€” the max number of instructions that can execute in parallel in a reassociated tree ๐Ÿ’… If it has a nonzero value, it overrides the target-dependent heuristics that would normally be used by default ๐Ÿ‘‘
  • sched-pressure-algorithm โ€” picks one of the two available implementations of -fsched-pressure ๐Ÿง  Here's the tea:
    • Algorithm 1 โ€” the original implementation ๐Ÿ•ฐ๏ธ It's the more likely of the two to stop instructions from getting reordered ๐Ÿ”’
    • Algorithm 2 โ€” designed as a compromise between the pretty conservative vibes of algorithm 1 and the rather aggressive approach of the default scheduler ๐ŸŽข It leans harder on having a regular register file and accurate register pressure classes ๐Ÿซถ
    • The default choice depends on the target ๐ŸŽฏ
    • For more details, check out haifa-sched.c in the GCC sources ๐Ÿ“š
  • max-slsr-cand-scan โ€” the max number of existing candidates considered when hunting for a basis for a new straight-line strength reduction candidate ๐Ÿ”Ž
  • asan-globals โ€” turns on buffer overflow detection for global objects ๐ŸŒ This protection is on by default when you use -fsanitize=address ๐Ÿ’œ To turn off global objects protection, use --param asan-globals=0 ๐Ÿ™…โ€โ™€๏ธ
  • asan-stack โ€” turns on buffer overflow detection for stack objects ๐Ÿฅž It's on by default with -fsanitize=address โœจ To disable stack protection, use --param asan-stack=0 ๐Ÿ’…
  • asan-instrument-reads โ€” turns on buffer overflow detection for memory reads ๐Ÿ‘€ Also on by default with -fsanitize=address ๐ŸŒธ To turn off memory reads protection, use --param asan-instrument-reads=0 ๐Ÿซถ
  • asan-instrument-writes โ€” turns on buffer overflow detection for memory writes โœ๏ธ It's on by default when using -fsanitize=address ๐Ÿฆ‹ To disable memory writes protection, use --param asan-instrument-writes=0 ๐Ÿ™…โ€โ™€๏ธ
  • asan-memintrin โ€” turns on detection for built-in functions ๐Ÿงฉ On by default with -fsanitize=address ๐ŸŽ€ To disable built-in functions protection, use --param asan-memintrin=0 ๐Ÿซ 
  • asan-use-after-return โ€” turns on detection of use-after-return ๐Ÿ•ต๏ธโ€โ™€๏ธ It's enabled by default with the -fsanitize=address option ๐Ÿ”ฅ To turn it off, use --param asan-use-after-return=0 ๐Ÿ’€
Heads up, bestie: by default this check is disabled at run time ๐Ÿ˜ญ To turn it on, add "detect_stack_use_after_return=1" to the ASAN_OPTIONS environment variable ๐Ÿซถ
  • asan-instrumentation-with-call-threshold โ€” if the function being instrumented has a number of memory accesses greater than or equal to this value, ASan uses callbacks instead of inline checks ๐Ÿ“ž To turn off inline code completely, use --param asan-instrumentation-with-call-threshold=0 ๐Ÿงš
  • use-after-scope-direct-emission-threshold โ€” if a local variable is smaller than or equal to this many bytes, shadow memory gets poisoned (or unpoisoned) directly instead of going through run-time callbacks โšก
  • max-fsm-thread-path-insns โ€” the max number of instructions copied when duplicating blocks on a finite state automaton jump thread path ๐Ÿงต
  • max-fsm-thread-length โ€” the max number of basic blocks on a finite state automaton jump thread path ๐Ÿ›ค๏ธ
  • max-fsm-thread-paths โ€” the max number of new jump thread paths to create for a finite state automaton ๐ŸŒˆ
  • parloops-chunk-size โ€” the chunk size of the omp schedule for loops parallelized by parloops ๐Ÿฐ
  • parloops-schedule โ€” the schedule type of the omp schedule for loops parallelized by parloops ๐Ÿ—“๏ธ The options are static, dynamic, guided, auto, or runtime ๐Ÿ’–
  • parloops-min-per-thread โ€” the minimum number of iterations per thread for an innermost parallelized loop where the parallel version is preferred over the single-threaded one ๐Ÿงต 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 ๐Ÿ”—
  • hsa-gen-debug-stores โ€” enables emitting special debug stores inside HSA kernels, which the libgomp plugin then reads and reports ๐Ÿ› It's disabled by default, so use --param hsa-gen-debug-stores=1 to switch it on ๐Ÿซถ
  • 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 making a virtual call we might speculatively devirtualize ๐Ÿ”
  • max-vrp-switch-assertions โ€” the max number of assertions added along the default edge of a switch statement during VRP ๐Ÿง 
  • unroll-jam-min-percent โ€” the minimum percentage of memory references that have to get optimized away before unroll-and-jam is considered profitable ๐Ÿ“‰
  • unroll-jam-max-unroll โ€” the max number of times the outer loop can be unrolled by unroll-and-jam ๐Ÿ”
  • 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 an individual variable gets expanded during loop unrolling ๐ŸŒฑ
  • tracer-min-branch-probability-feedback โ€” stop growing forward if the probability of the best edge is below this threshold (in percent) ๐Ÿ›‘ It's used when profile feedback is available ๐Ÿ“Š
  • partial-inlining-entry-probability โ€” the max probability (in percent, relative to the function's entry BB) of the entry BB of a split region that still lets partial inlining happen ๐Ÿงฉ
  • max-tracked-strlens โ€” the max number of strings the strlen optimization pass will track lengths for ๐Ÿ“
  • gcse-after-reload-partial-fraction โ€” the threshold ratio for performing partial redundancy elimination after reload ๐Ÿ”
  • gcse-after-reload-critical-fraction โ€” the threshold ratio of the critical edges execution count that allows redundancy elimination after reload โš–๏ธ
  • max-loop-header-insns โ€” the max number of insns in a loop header that the copy loop headers pass is allowed to duplicate ๐Ÿงพ
  • vect-epilogues-nomask โ€” enables loop epilogue vectorization using a smaller vector size ๐Ÿช„
  • slp-max-insns-in-bb โ€” the max number of instructions in a basic block that gets considered for SLP vectorization ๐Ÿงบ
  • avoid-fma-max-bits โ€” the max number of bits for which GCC avoids creating FMAs ๐Ÿšซโœ–๏ธ
  • sms-loop-average-count-threshold โ€” okay so this is a threshold on the average loop count that the swing modulo scheduler pays attention to ๐Ÿ‘€
  • sms-dfa-history โ€” the number of cycles the swing modulo scheduler looks at when it's checking for conflicts using DFA ๐Ÿ”
  • max-inline-insns-recursive-auto โ€” the max number of instructions a non-inline function can grow to through recursive inlining ๐ŸŒธ
  • graphite-allow-codegen-errors โ€” decides whether codegen errors should be ICEs when -fchecking is on ๐Ÿ’€
  • sms-max-ii-factor โ€” a factor for tuning 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 maximum depth of sqrt chains you can use when synthesizing exponentiation by a real constant ๐Ÿฆ‹
  • max-dse-active-local-stores โ€” the maximum number of active local stores in RTL dead store elimination ๐Ÿซถ
  • asan-instrument-allocas โ€” enables asan allocas/VLAs protection ๐Ÿ›ก๏ธ
  • max-iterations-computation-cost โ€” the bound on how expensive an expression can be when computing the number of iterations ๐Ÿ’œ
  • max-isl-operations โ€” the maximum number of isl operations, where 0 means unlimited ๐ŸŒˆ
  • graphite-max-arrays-per-scop โ€” the maximum number of arrays per scop ๐ŸŽ€
  • max-vartrack-reverse-op-size โ€” the max size of a loc list where reverse ops get added, abbreviated as "max." in the original ๐Ÿ“
  • tracer-dynamic-coverage-feedback โ€” the percentage of a function, weighted by execution frequency, that trace formation has to cover. This one is used when profile feedback is available ๐Ÿ“ˆ
  • max-inline-recursive-depth-auto โ€” the maximum depth of recursive inlining for non-inline functions ๐ŸŒ€
  • fsm-scale-path-stmts โ€” a scale factor applied to the number of statements in a threading path when you compare it to the number of (scaled) blocks ๐Ÿงฎ
  • fsm-maximum-phi-arguments โ€” the max number of arguments a PHI can have before the FSM threader stops trying to thread through its block ๐Ÿšซ
  • uninit-control-dep-attempts โ€” the max number of nested calls used to search for control dependencies during uninitialized variable analysis ๐Ÿ”Ž
  • sra-max-scalarization-size-Osize โ€” the max size, in storage units, of an aggregate that should be considered for scalarization when you're compiling for size ๐Ÿ“ฆ
  • fsm-scale-path-blocks โ€” a scale factor applied to the number of blocks in a threading path when you compare it to 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 enables 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 max number of instructions an outer loop can have before the loop versioning pass decides it's too big to copy. Any instructions in inner loops that directly benefit from versioning don't count toward that total ๐Ÿ’…
  • ssa-name-def-chain-limit โ€” the max number of SSA_NAME assignments to follow when figuring out a property of a variable, like its value. This caps how many iterations or recursive calls GCC makes while optimizing certain statements or checking whether they're valid before it issues 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 for each element you search for ๐Ÿ”
  • 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 within the analyzer. Once that's hit, analysis of that point stops ๐Ÿ›‘
  • analyzer-min-snodes-for-call-summary โ€” the min number of supernodes within a function before the analyzer will think about summarizing its effects at call sites ๐Ÿ“š
  • analyzer-max-recursion-depth โ€” the max number of times a callsite can show up in a call stack within the analyzer. Once that's reached, analysis of a call that would recurse deeper is terminated ๐ŸŒช๏ธ
  • gimple-fe-computed-hot-bb-threshold โ€” the number of executions of a basic block that counts as hot. This parameter is only used in GIMPLE FE ๐Ÿ”ฅ
  • analyzer-bb-explosion-factor โ€” the max number of 'after supernode' exploded nodes per supernode within the analyzer, before analysis gets terminated ๐Ÿ’ซ

Also, these next ones are only for AArch64 targets ๐Ÿฆ‹:

  • aarch64-sve-compare-costs โ€” when you're vectorizing for SVE, this considers using "unpacked" vectors for smaller elements, and it 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. The precision of division is proportional to this param when division approximation is enabled. The default value is 1. ๐ŸŽ€
  • aarch64-double-recp-precision โ€” the number of Newton iterations used to calculate the reciprocal for the double type. The precision of division is proportional to this param when division approximation is enabled. The default value is 2. ๐Ÿ’–
  • aarch64-autovec-preference โ€” forces an ISA selection strategy for auto-vectorization. It accepts values from 0 to 4, inclusive. ๐ŸŒˆ
    • 0 โ€” use the default heuristics.
    • 1 โ€” use only Advanced SIMD for auto-vectorization.
    • 2 โ€” use only SVE for auto-vectorization.
    • 3 โ€” use both Advanced SIMD and SVE. Prefer Advanced SIMD when the costs are deemed equal.
    • 4 โ€” use both Advanced SIMD and SVE. Prefer SVE when the costs are deemed equal.

The default value is 0.


โœจ Program Instrumentation Options โœจ

okay so GCC has a bunch of command-line options that tell it to add run-time instrumentation to the code it normally generates ๐Ÿงš Instrumentation can be for collecting profiling stats so you can find program hot spots, doing code coverage analysis, or doing profile-guided optimizations ๐Ÿ“ˆ. It's also used for run-time checking that catches programming errors like invalid pointer dereferences or out-of-bounds array accesses, and it helps guard against deliberately hostile attacks like stack smashing or C++ vtable hijacking ๐Ÿ›ก๏ธ. There's also a general hook that can be used to implement other forms of tracing or function-level instrumentation for debugging or program analysis ๐Ÿ”

  • -p, -pg โ€” these generate extra code that writes profile information suitable for the analysis program prof (for -p) or gprof (for -pg). You have to use this option when compiling the source files you want data about, and you also have to use it when linking ๐Ÿ’…

You can use the function attribute "no_instrument_function" to skip 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 gets 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 a type of a global variable ๐Ÿซถ

When the compiled program exits, it saves this data to a file called auxname.gcda for each source file ๐Ÿ’พ. The data can be used for profile-directed optimizations (-fbranch-probabilities) or for test coverage analysis (-ftest-coverage). Each object file's auxname is generated from the name of the output file, if 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, you'd get foo.gcda for input file dir/foo.c, or dir/foo.gcda for output file specified as -o dir/foo.o ๐Ÿฆ‹

  • --coverage โ€” this is for compiling and linking code that's instrumented for coverage analysis. It's a synonym for -fprofile-arcs -ftest-coverage (when compiling) and -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 ๐ŸŒท
    • Compile the source files additionally with -fprofile-abs-path to create absolute path names in the .gcno files. This lets gcov find the correct sources in projects where compilations happen with different working directories ๐Ÿ—บ๏ธ
    • Link your object files with -lgcov or -fprofile-arcs (the latter implies the former) ๐Ÿ”—
    • Run the program on a representative workload to generate the arc profile information. You can do this any number of times. You can run concurrent instances of your program, and as long as the file system supports locking, the data files will be correctly updated ๐Ÿƒโ€โ™€๏ธ. Unless a strict ISO C dialect option is in effect, "fork" calls are detected and correctly handled without double counting ๐Ÿด
    • For profile-directed optimizations, compile the source files again with the same optimization and code generation options plus -fbranch-probabilities ๐Ÿ’œ
    • For test coverage analysis, use gcov to produce human readable information from the .gcno and .gcda files. Check the gcov documentation for further information ๐Ÿ“š

With -fprofile-arcs, GCC builds a program flow graph for every function in your program, then finds a spanning tree for it ๐Ÿฆ‹. Only the arcs that are not on that tree need instrumenting, so the compiler just adds code to count how many times those arcs run ๐Ÿ“Š. When an arc is the only exit or only entrance to a block, the counting code can go right inside that block. Otherwise GCC has to make a brand new basic block just to hold the instrumentation ๐Ÿงš

  • -ftest-coverage โ€” Produces a notes file that the gcov code-coverage utility can read to show program coverage ๐Ÿ“. Each source file's note file is called auxname.gcno. For what auxname means and how to generate test coverage data, check out -fprofile-arcs above ๐Ÿ’–. Coverage data lines up with your source files more closely if you do not optimize ๐Ÿ™ˆ.
  • -fprofile-abs-path โ€” Automatically converts relative source file names into absolute path names inside the .gcno files ๐Ÿ—บ๏ธ. This helps gcov find the correct sources in projects that compile from different working directories ๐Ÿซถ.
  • -fprofile-dir=path โ€” Sets the directory where profile data files get searched for, to path ๐Ÿ“‚. This only affects the profile data made by -fprofile-generate, -ftest-coverage, and -fprofile-arcs, plus the data used by -fprofile-use, -fbranch-probabilities, and their related options. Both absolute and relative paths work. By default GCC uses the current directory, so the profile data file lands in the same directory as the object file. To stop file names from clashing, 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 an executable runs in a massive parallel environment, it's recommended to save profiles to different folders ๐ŸŒˆ. You can do that with variables in path that get exported at run-time:

  • %p โ€” process ID.
  • %q{VAR} โ€” value of environment variable VAR.
  • -fprofile-generate, -fprofile-generate=path โ€” Turns on the options usually used for instrumenting an application, so it produces a profile for later recompilation with profile feedback based optimization ๐Ÿ”ฅ. You must use -fprofile-generate both when compiling and when linking your program ๐Ÿšจ. The following options are enabled: -fprofile-arcs, -fprofile-values, -finline-functions, and -fipa-bit-cp. If path is specified, GCC looks at that path to find the profile feedback data files. See -fprofile-dir. To optimize the program based on the collected profile information, use -fprofile-use.
  • -fprofile-note=path โ€” If path is specified, GCC saves the .gcno file into that location ๐Ÿ“ฆ. If you combine this with multiple source files, the .gcno file will get overwritten ๐Ÿ˜ฌ.
  • -fprofile-prefix-path=path โ€” Use this 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 profile-optimized binary, because the profile data won't be found during the optimized build ๐Ÿ˜ญ. In those setups, -fprofile-prefix-path=path with path pointing to 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-update=method โ€” Changes 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 great for single-threaded applications, while atomic prevents profile corruption by emitting thread-safe code ๐Ÿ›ก๏ธ. Using prefer-atomic becomes atomic when the target supports it, or single otherwise. The GCC driver automatically selects prefer-atomic when -pthread is in the command line ๐Ÿงต.
Warning: When an application doesn't properly join all threads (or creates a detached thread), a profile file can still get corrupted ๐Ÿ’€.
  • -fprofile-filter-files=regex โ€” Instruments only functions from files whose names match any of the regular expressions, separated by a semicolon ๐ŸŽฏ. For example, -fprofile-filter-files=main.c;module.*.c will instrument only main.c and all C files starting with 'module' ๐Ÿ’….
  • -fprofile-exclude-files=regex โ€” Instruments only functions from files where the names do not match all the regular expressions, separated by a semicolon ๐Ÿ™…. For example, -fprofile-exclude-files=/usr/* will stop instrumentation of every file located in the /usr/ folder ๐Ÿซฃ.
  • -fprofile-reproducible=[multithreaded|parallel-runs|serial] โ€” Controls how reproducible the profile gathered by -fprofile-generate is ๐Ÿ”. This lets you rebuild a program with the same outcome, which is super useful for things like distribution packages ๐Ÿ“ฆ.
    • serial โ€” The profile gathered by -fprofile-generate is reproducible as long as the trained program behaves the same on every invocation of the train run, it is not multi-threaded, and profile data streaming always happens in the same order ๐ŸงŠ. Note that profile streaming happens at the end of the program run, but also before the fork function is invoked.
    • parallel-runs โ€” The collected profile stays reproducible no matter what order the data gets streamed into gcda files ๐Ÿƒ. This makes it possible to run multiple instances of the instrumented program in parallel (such as with make -j), but it reduces the quality of the gathered data, particularly for indirect call profiling ๐Ÿ˜ต.

Heads up: it's pretty common for execution counts in some parts of a program to depend on things like the length of temporary file names or memory space randomization (which can affect hash-table collision rates) ๐ŸŽฒ. Those non-reproducible parts 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 ๐Ÿ”.

  • -fsanitize=address โ€” Enables AddressSanitizer, a fast memory error detector ๐Ÿ”. Memory access instructions get instrumented to catch out-of-bounds and use-after-free bugs ๐Ÿ’€. This option enables -fsanitize-address-use-after-scope. For more details, see https://github.com/google/sanitizers/wiki/AddressSanitizer. The run-time behavior can be influenced with the ASAN_OPTIONS environment variable ๐ŸŽ›๏ธ. When it's set to help=1, the available options get shown at startup of the instrumented program. For a list of supported options, see https://github.com/google/sanitizers/wiki/AddressSanitizerFlags#run-time-flags. This option cannot be combined with -fsanitize=thread.
  • -fsanitize=kernel-address โ€” Enables AddressSanitizer for the Linux kernel ๐Ÿง. For more details, see https://github.com/google/kasan/wiki.
  • -fsanitize=pointer-compare โ€” Instruments comparison operations (<, <=, >, >=) with pointer operands ๐Ÿ‘€. This option must be combined with either -fsanitize=kernel-address or -fsanitize=address. It cannot be combined with -fsanitize=thread. Note: by default the check is disabled at run time ๐Ÿ™ˆ. To turn it on, add detect_invalid_pointer_pairs=2 to the ASAN_OPTIONS environment variable. Using detect_invalid_pointer_pairs=1 only detects invalid operations when both pointers are non-null.
  • -fsanitize=pointer-subtract โ€” Instruments subtraction with pointer operands ๐Ÿงฎ. This option must be combined with either -fsanitize=kernel-address or -fsanitize=address. It cannot be combined with -fsanitize=thread. Note: by default the check is disabled at run time ๐Ÿ™ˆ. To turn it on, add detect_invalid_pointer_pairs=2 to the ASAN_OPTIONS environment variable. Using detect_invalid_pointer_pairs=1 only detects invalid operations when both pointers are non-null.
  • -fsanitize=thread โ€” Enables ThreadSanitizer, a fast data race detector ๐Ÿงต. Memory access instructions get instrumented to catch data race bugs. For more details, see https://github.com/google/sanitizers/wiki#threadsanitizer. The run-time behavior can be influenced with the TSAN_OPTIONS environment variable. For a list of supported options, see https://github.com/google/sanitizers/wiki/ThreadSanitizerFlags. This option cannot be combined with -fsanitize=address or -fsanitize=leak.
Note: sanitized atomic builtins cannot throw exceptions when operating on invalid memory addresses with non-call exceptions (-fnon-call-exceptions) ๐Ÿšซ.
  • -fsanitize=leak โ€” Enables LeakSanitizer, a memory leak detector ๐Ÿ’ง. This option only matters when linking executables, and only if the executable is linked against a library that overrides malloc and other allocator functions. For more details, see https://github.com/google/sanitizers/wiki/AddressSanitizerLeakSanitizer. The run-time behavior can be influenced with the LSAN_OPTIONS environment variable. This option cannot be combined with -fsanitize=thread.
  • -fsanitize=undefined โ€” Enables UndefinedBehaviorSanitizer, a fast undefined behavior detector ๐ŸŒ€. Various computations get instrumented to catch undefined behavior at runtime. See https://clang.llvm.org/docs/UndefinedBehaviorSanitizer.html for more details. The run-time behavior can be influenced with the UBSAN_OPTIONS environment variable. The current suboptions are:
    • -fsanitize=shift โ€” Enables checking that the result of a shift operation isn't undefined ๐Ÿซฃ. What counts as undefined differs slightly between C and C++, and between ISO C90 and C99, and so on. This option has two suboptions, -fsanitize=shift-base and -fsanitize=shift-exponent.
    • -fsanitize=shift-exponent โ€” Enables checking that the second argument of a shift operation isn't negative and is smaller than the precision of the promoted first argument ๐Ÿง.
  • -fsanitize=shift-base โ€” okay so when the second argument of a shift is in range, this checks that the shift result isn't undefined ๐Ÿ’… Heads up: what counts as undefined is slightly different between C and C++, and between ISO C90 and C99, etc. ๐ŸŒธ
  • -fsanitize=integer-divide-by-zero โ€” catches integer division by zero ๐Ÿ™…โ€โ™€๏ธ and also the "INT_MIN / -1" division, which is a sneaky one ๐Ÿ’€
  • -fsanitize=unreachable โ€” this one is giving "you should never be here" energy ๐Ÿงš With it on, the compiler swaps the "__builtin_unreachable" call for a diagnostics message call instead. Reaching that "__builtin_unreachable" call is undefined, so the behavior is undefined. ๐Ÿ™ˆ
  • -fsanitize=vla-bound โ€” checks that the size of a variable length array is positive ๐Ÿ“โœจ
  • -fsanitize=null โ€” pointer checking, bestie ๐Ÿซถ Apps built with this will throw an error when they try to dereference a NULL pointer, when a reference (possibly an rvalue reference) gets bound to a NULL pointer, or when a method gets invoked on an object pointed to by a NULL pointer.
  • -fsanitize=return โ€” return statement checking ๐Ÿ‘‘ Programs built with this will throw an error when the end of a non-void function gets reached without actually returning a value. This option works in C++ only.
  • -fsanitize=signed-integer-overflow โ€” signed integer overflow checking ๐Ÿ”ฅ It checks that the result of +, *, and both unary and binary - doesn't overflow in signed arithmetic. Also, integer promotion rules totally count here! So this is not an overflow:
signed char a = SCHAR_MAX;
a++;
  • -fsanitize=bounds โ€” array bounds instrumentation, 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 โ€” the stricter version ๐Ÿ’– Most out of bounds accesses get detected, including flexible array members and flexible array member-like arrays. Initializers of variables with static storage are still not instrumented.
  • -fsanitize=alignment โ€” checks pointer alignment when they're dereferenced ๐Ÿง It also checks when a reference is bound to an insufficiently aligned target, or when a method or constructor is invoked on an insufficiently aligned object.
  • -fsanitize=object-size โ€” instruments memory references using the "__builtin_object_size" function ๐ŸŒˆ Various out of bounds pointer accesses get detected.
  • -fsanitize=float-divide-by-zero โ€” detects floating-point division by zero ๐Ÿงฎ Unlike other similar options, this one is not turned on by -fsanitize=undefined, because floating-point division by zero can be a totally legit way to get infinities and NaNs. โญ
  • -fsanitize=float-cast-overflow โ€” floating-point type to integer conversion checking ๐Ÿ’œ It checks that the result of the conversion doesn't overflow. Unlike other similar options, this is not turned on by -fsanitize=undefined. Also, this option does not work well with "FE_INVALID" exceptions enabled, so keep that in mind ๐Ÿ™ƒ
  • -fsanitize=nonnull-attribute โ€” instruments calls to check that null values aren't passed to arguments marked as requiring a non-null value by the "nonnull" function attribute ๐Ÿ“
  • -fsanitize=returns-nonnull-attribute โ€” instruments return statements in functions marked with the "returns_nonnull" function attribute ๐ŸŽ€ This catches functions returning null values when they shouldn't.
  • -fsanitize=bool โ€” instruments loads from bool โœ… If a value other than 0/1 gets loaded, a run-time error is issued.
  • -fsanitize=enum โ€” instruments loads from an enum type ๐ŸŒธ If a value outside the range of values for the enum type gets loaded, a run-time error is issued.
  • -fsanitize=vptr โ€” C++ vibes ๐Ÿ’… It instruments C++ member function calls, member accesses, and some conversions between pointers to base and derived classes, so it can verify the referenced object has the correct dynamic type.
  • -fsanitize=pointer-overflow โ€” instruments pointer arithmetic ๐Ÿงšโ€โ™€๏ธ If the pointer arithmetic overflows, a run-time error is issued.
  • -fsanitize=builtin โ€” instruments arguments to selected builtin functions ๐Ÿ” If an invalid value gets passed to one of those arguments, a run-time error is issued. For example, passing 0 as the argument to "__builtin_ctz" or "__builtin_clz" invokes undefined behavior, and this option diagnoses it.

While -ftrapv causes traps for signed overflows to be emitted, -fsanitize=undefined gives a diagnostic message instead ๐Ÿฆ‹ Quick note: this currently works only for the C family of languages.

  • -fno-sanitize=all โ€” disables all previously enabled sanitizers ๐Ÿงน -fsanitize=all is not allowed, though, since some sanitizers can't be used together. ๐Ÿ™…โ€โ™€๏ธ
  • -fasan-shadow-offset=number โ€” forces GCC to use a custom shadow offset in AddressSanitizer checks ๐Ÿงช It's useful for experimenting with different shadow memory layouts in Kernel AddressSanitizer.
  • -fsanitize-sections=s1,s2,... โ€” sanitizes global variables in selected user-defined sections ๐ŸŒŸ si may contain wildcards.
  • -fsanitize-recover[=opts] โ€” controls the error recovery mode for the sanitizers listed in the comma-separated opts list ๐Ÿ’– When recovery is enabled for a sanitizer, it tries to keep running the program like no error happened. That means multiple runtime errors can get reported in one run, and the exit code might say success even though errors were reported. Use -fno-sanitize-recover= if you want to change this: only the first detected error gets reported, and then the program exits with a non-zero exit code.

Right now this only works for -fsanitize=undefined (and its suboptions, except for -fsanitize=unreachable and -fsanitize=return), -fsanitize=float-cast-overflow, -fsanitize=float-divide-by-zero, -fsanitize=bounds-strict, -fsanitize=kernel-address, and -fsanitize=address. For these sanitizers, error recovery is turned on by default, except for -fsanitize=address, where it's still experimental ๐Ÿงช You can also use -fsanitize-recover=all and -fno-sanitize-recover=all. The first enables recovery for every sanitizer that supports it, and the second disables recovery for every sanitizer that supports it.

Heads up, bestie: even if recovery is turned on at the compiler side, it also needs to be enabled on the runtime library side. Otherwise the failures are still fatal ๐Ÿ˜ญ The runtime library defaults to "halt_on_error=0" for ThreadSanitizer and UndefinedBehaviorSanitizer, while the default for AddressSanitizer is "halt_on_error=1". You can override this by setting the "halt_on_error" flag in the corresponding environment variable.

Syntax without an explicit opts parameter is deprecated ๐Ÿฅ€ It's equivalent to specifying this opts list:

undefined,float-cast-overflow,float-divide-by-zero,bounds-strict
  • -fsanitize-address-use-after-scope โ€” enables sanitization of 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 the "libubsan" library isn't needed and doesn't get linked in, so this is usable even in freestanding environments.
  • -fsanitize-coverage=trace-pc โ€” enables coverage-guided fuzzing code instrumentation ๐Ÿ› It inserts a call to "__sanitizer_cov_trace_pc" into every basic block.
  • -fsanitize-coverage=trace-cmp โ€” enables dataflow guided fuzzing code instrumentation ๐ŸŒˆ It inserts these calls:
    • "__sanitizer_cov_trace_cmp1", "__sanitizer_cov_trace_cmp2", "__sanitizer_cov_trace_cmp4", or "__sanitizer_cov_trace_cmp8" for integral comparisons where both operands are variables
    • "__sanitizer_cov_trace_const_cmp1", "__sanitizer_cov_trace_const_cmp2", "__sanitizer_cov_trace_const_cmp4", or "__sanitizer_cov_trace_const_cmp8" for integral comparisons where one operand is a constant
    • "__sanitizer_cov_trace_cmpf" or "__sanitizer_cov_trace_cmpd" for float or double comparisons
    • "__sanitizer_cov_trace_switch" for switch statements
  • -fcf-protection=[full|branch|return|none|check] โ€” instruments control-flow transfers to boost program security ๐Ÿ›ก๏ธ It checks that target addresses of control-flow transfer instructions (like indirect function calls, function returns, and indirect jumps) are valid, so the flow of control can't get diverted to an unexpected target. This is meant to guard against threats like Return-oriented Programming (ROP), and similar call/jmp-oriented programming (COP/JOP) ๐Ÿ˜ค
    • branch โ€” checks validity of control-flow transfers at indirect branch instructions, i.e. call/jmp instructions ๐ŸŒธ
    • return โ€” checks validity at the point of returning from a function ๐Ÿฆ‹
    • full โ€” an alias for specifying both branch and return ๐Ÿ‘‘
    • none โ€” turns off instrumentation ๐Ÿ™…โ€โ™€๏ธ
    • check โ€” used for the final link with link-time optimization (LTO) ๐Ÿ’… An error is issued if LTO object files were compiled with different -fcf-protection values. It's ignored at compile time.

The macro __CET__ is defined when -fcf-protection is used โœจ Its first bit is set to 1 for the value branch, and its second bit is set to 1 for return. ๐Ÿงš

You can also use the nocf_check attribute to tag which functions and calls should be skipped from instrumentation, bestie ๐Ÿซถ it's basically a VIP list for your code โœจ

Currently the x86 GNU/Linux target gets an implementation built on Intel Control-flow Enforcement Technology (CET), which works on i686 processors or newer ๐Ÿ’…

NOTE: In Ubuntu 19.10 and later versions, -fcf-protection is enabled by default for C, C++, ObjC, ObjC++, if none of -fno-cf-protection nor -fcf-protection=* are found ๐Ÿ˜ญ
  • -fstack-protector โ€” okay so this one 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, plus functions with buffers larger than or equal to 8 bytes. The guards get initialized when a function is entered and checked when it exits. If a guard check fails, an error message is printed and the program exits. Only variables that are actually allocated on the stack count, so optimized-away variables or variables allocated in registers don't ๐Ÿ™ˆ
  • -fstack-protector-all โ€” like -fstack-protector, except every single function gets protected ๐Ÿ‘‘
  • -fstack-protector-strong โ€” like -fstack-protector but with extra functions added to the protected squad ๐Ÿ’œ These are the ones with local array definitions, or ones that reference local frame addresses. Same rule as before: only variables actually allocated on the stack count, and optimized-away variables or variables allocated in registers don't.
  • -fstack-protector-explicit โ€” like -fstack-protector, but it only protects the functions that have the stack_protect attribute ๐ŸŽ€
  • -fstack-check โ€” generates code to verify that you don't go beyond the boundary of the stack ๐Ÿงฑ You should turn this on if you're running in an environment with multiple threads. You only rarely need it in a single-threaded environment, though, since stack overflow is automatically detected on nearly all systems when there's only one stack.

Note that this switch doesn't actually do the checking itself ๐Ÿ™ƒ The operating system or the language runtime has to do that. The switch just makes sure they see the stack being extended.

You can also add a string parameter:

  • no โ€” no checking at all
  • generic โ€” forces the use of old-style checking
  • specific โ€” uses the best checking method, and is equivalent to bare -fstack-check

Old-style checking is a generic mechanism that needs no specific target support in the compiler, but it comes with these drawbacks:

  1. Modified allocation strategy for large objects: they're always allocated dynamically if their size exceeds a fixed threshold. Note this may change the semantics of some code.
  2. Fixed limit on the size of the static frame of functions: when it is topped by a particular function, stack checking is not reliable and a warning is issued by the compiler.
  3. Inefficiency: because of both the modified allocation strategy and the generic implementation, code performance is hampered ๐Ÿข

Old-style stack checking is also the fallback method for specific if no target support has been added in the compiler.

-fstack-check= is designed for Ada's needs to detect infinite recursion and stack overflows. specific is an excellent choice when compiling Ada code. It's not generally sufficient to protect against stack-clash attacks, though. To protect against 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 is accessed immediately after allocation. That means allocations can't jump over any stack guard page the operating system provides ๐Ÿ›ก๏ธ

Most targets don't fully support stack clash protection. On those targets, though, -fstack-clash-protection will protect dynamic stack allocations. It may also provide limited protection for static stack allocations if the target supports -fstack-check=specific.

NOTE: In Ubuntu 19.10 and later versions, -fstack-clash-protection is enabled by default for C, C++, ObjC, ObjC++, unless -fno-stack-clash-protection is found.
  • -fstack-limit-register=reg, -fstack-limit-symbol=sym, -fno-stack-limit โ€” these make sure the stack doesn't grow beyond a certain value, either the value of a register or the address of a symbol ๐Ÿšง If a larger stack is needed, a signal is raised at run time. For most targets, the signal is raised before the stack overruns the boundary, so you can catch it without taking special precautions.

For instance, 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. Note that this may only work with the GNU linker.

You can locally override stack limit checking 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 is unable to allocate any more memory. This is most useful when running threaded programs, since you no longer need to calculate a good stack size to use for each thread. Right now it's only implemented for the x86 targets running GNU/Linux.

When code compiled with -fsplit-stack calls code compiled without it, there may not be much stack space left for the latter code to run. If compiling all code, including library code, with -fsplit-stack isn't an option, the linker can fix up these calls so that the code compiled without -fsplit-stack always gets a large stack. Support for this is implemented in the gold linker in GNU binutils release 2.21 and later ๐Ÿ”—


  • -fvtable-verify=[std|preinit|none] โ€” this is only available when compiling C++ code ๐Ÿฆ‹ It turns on the security feature that verifies at run time, for every virtual call, that the vtable pointer used for the call is valid for the type of the object and hasn't been corrupted or overwritten. Using -fvtable-verify=none turns it off instead. If an invalid vtable pointer is detected at run time, an error is reported and program execution is immediately halted ๐Ÿšจ

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

If this option appears multiple times on the command line with different values, none takes the highest priority over both std and preinit, and preinit takes priority over std ๐ŸŽ€

  • -fvtv-debug โ€” used together with -fvtable-verify=std or -fvtable-verify=preinit, this makes the compiler call debug versions of the runtime functions for the vtable verification feature ๐Ÿ” It also makes the compiler log info about 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 that's defined, or the current working directory otherwise.
Note: This feature appends data to the log file. If you want a fresh log file, be sure to delete any existing one ๐Ÿ—‘๏ธ
  • -fvtv-counts โ€” a debugging flag ๐Ÿงฎ When used together with -fvtable-verify=std or -fvtable-verify=preinit, the compiler keeps track of the total number of virtual calls it encounters and the number of verifications it inserts. It also counts the calls to certain run-time library functions that it inserts, and logs this info for each compilation unit. The compiler writes this to a file named vtv_count_data.log in the directory named by VTV_LOGS_DIR if that's defined, or the current working directory otherwise. It also counts the size of the vtable pointer sets for each class, and writes that info to vtv_class_set_sizes.log in the same directory.
Note: This feature appends data to the log files. To get fresh log files, be sure to delete any existing ones ๐Ÿงน
  • -finstrument-functions โ€” generates instrumentation calls for entry and exit to functions ๐Ÿ”ญ Just after function entry and just before function exit, the following profiling functions are 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 information may not be available to the profiling functions otherwise.
void __cyg_profile_func_enter (void *this_fn,
                               void *call_site);
void __cyg_profile_func_exit  (void *this_fn,
                               void *call_site);

The first argument is the address of the start of the current function, which can be looked up exactly in the symbol table ๐Ÿ—บ๏ธ

This instrumentation is also done for functions expanded inline in other functions. The profiling calls indicate where, conceptually, the inline function is entered and exited. This means that addressable versions of such functions must be available. If all your uses of a function are expanded inline, this may mean an additional expansion of code size. If you use extern inline in your C code, an addressable version of such functions must be provided. (This is normally the case anyway, but if you get lucky and the optimizer always expands the functions inline, you might have gotten away without providing static copies ๐Ÿ™ˆ)

A function can get the no_instrument_function attribute ๐Ÿฆ‹, which tells GCC to skip instrumenting it. This is perfect for the profiling functions listed above, high-priority interrupt routines, and any function that can't safely call the profiling functions (think signal handlers, especially if the profiling routines generate output or allocate memory ๐Ÿ’€).

  • -finstrument-functions-exclude-file-list=file,file,... โ€” Okay, this one is a whole vibe ๐Ÿ’…. It sets the list of files whose functions get left out of instrumentation (see -finstrument-functions). If the file holding a function definition matches any of the file entries, that function is skipped. The matching is by substring, so if your file value is a substring of the file name, it counts as a match ๐Ÿซถ

For example:

-finstrument-functions-exclude-file-list=/bits/stl,include/sys

This excludes any inline function defined in files whose pathnames contain /bits/stl or include/sys โœจ

If, for some reason, you need an actual comma inside one of your sym values, you type two commas, ,,. For example, -finstrument-functions-exclude-file-list=',,tmp' (note the single quotes around the whole option, bestie ๐Ÿ™ˆ).

  • -finstrument-functions-exclude-function-list=sym,sym,... โ€” This is basically the same energy as the file list, except it excludes by function name instead ๐ŸŒธ. The name it matches is the user-visible one, like vector<int> blah(const vector<int> &), not the internal mangled name like _Z4blahRSt6vectorIiSaIiEE ๐Ÿ‘€. Matching is also by substring: if your sym is a substring of the function name, it's a match. For C99 and C++ extended identifiers, you have to write the function name in UTF-8, not with universal character names ๐ŸŒˆ
  • -fpatchable-function-entry=N[,M] โ€” Okay, this one is giving "future-proof ๐Ÿงš". It generates N NOPs right at the start of each function, with the function entry point sitting before the Mth NOP. If you leave M out, it defaults to 0, so the entry point is the address right at the first NOP. Those NOPs reserve extra space that you can use to patch in instrumentation at run time, but only if the code segment is writable ๐Ÿ”ฅ. You control the size of that space indirectly through the number of NOPs. The NOP instruction used matches what the internal GCC back-end interface gen_nop emits. This behavior is target-specific and may also depend on the architecture variant and/or other compilation options, so it's not one-size-fits-all ๐Ÿ’–

For run-time identification, the starting addresses of these areas (which match each function entry minus M) also get collected in the __patchable_function_entries section of the final binary ๐ŸŽ€

Heads up: the value of __attribute__ ((patchable_function_entry (N,M))) takes precedence over the command-line option -fpatchable-function-entry=N,M. That means you can use it to bump the area size up or remove it entirely on one specific function ๐Ÿ’…. If N=0, no pad location gets recorded.

The NOP instructions go in at the function entry address (and maybe before it, depending on M), and that happens even before the prologue ๐Ÿฆ‹


โœจ Options Controlling the Preprocessor โœจ

Okay, these options control the C preprocessor, which runs on every C source file before the actual compilation happens ๐Ÿ’–

If you use -E, nothing gets done except preprocessing. Some of these options only make sense together with -E, because they make the preprocessor output unsuitable for actual compilation ๐Ÿ™ˆ

Also, there are a bunch of options for controlling the search paths for include files, which you can find in Directory Options ๐Ÿ—บ๏ธ. Options for controlling preprocessor diagnostics are listed in Warning Options ๐Ÿ”ฅ.

  • -D name โ€” Predefines name as a macro with the definition 1 ๐Ÿ“
  • -D name=definition โ€” The contents of definition get tokenized and processed as if they showed up during translation phase three in a #define directive. Heads up: the definition gets chopped off at any embedded newline characters โœ‚๏ธ

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

Wanna define a function-like macro on the command line? Write its argument list in parentheses before the equals sign (if there is one). Parentheses mean something to most shells, so you should quote the option. With sh and csh, -D'name(args...)=definition' works ๐Ÿ’…

-D and -U options are processed in the order you give them on the command line. All -imacros file and -include file options get processed after every -D and -U ๐Ÿฆ‹

  • -U name โ€” Cancels any previous definition of name, whether it was built in or provided with a -D option ๐Ÿงš
  • -include file โ€” Processes file as if #include "file" appeared as the first line of the primary source file. The difference is that the first directory searched for file is the preprocessor's working directory, not the directory containing the main source file. If it isn't found there, it's searched for in the rest of the #include "..." search chain like normal ๐ŸŒธ

If you give multiple -include options, the files get included in the order they appear on the command line โœจ

  • -imacros file โ€” Exactly like -include, except any output produced by scanning file gets thrown away. The macros it defines stay defined ๐Ÿ’œ. This lets you grab all the macros from a header without also processing its declarations ๐Ÿ“

All files specified by -imacros get processed before all files specified by -include ๐Ÿ‘‘

  • -undef โ€” Don't predefine any system-specific or GCC-specific macros. The standard predefined macros stay defined ๐ŸŒˆ
  • -pthread โ€” Defines the additional macros needed for using the POSIX threads library. Use this option consistently for both compilation and linking, bestie ๐Ÿซถ. It's supported on GNU/Linux targets, most other Unix derivatives, and also on x86 Cygwin and MinGW targets โญ
  • -M โ€” Instead of outputting the preprocessed result, this outputs a rule suitable for make that describes the dependencies of the main source file ๐ŸŽ€. The preprocessor outputs one make rule containing the object file name for that source file, a colon, and the names of all the included files. That includes any coming from -include or -imacros command-line options ๐Ÿงš

Unless you set it explicitly (with -MT or -MQ), the object file name is the source file's name with any suffix swapped for the object file suffix, and with any leading directory parts removed. If there are a lot of included files, the rule gets split across several lines using \-newline. The rule has no commands ๐Ÿ’…

This option does not suppress the preprocessor's debug output, like -dM. To avoid mixing that debug output with your dependency rules, specify the dependency output file explicitly with -MF, or use an environment variable like DEPENDENCIES_OUTPUT. The debug output still goes to the regular output stream as usual ๐Ÿ™ˆ

Passing -M to the driver implies -E, and it suppresses warnings with an implicit -w ๐Ÿ”ฅ

  • -MM โ€” Like -M, but it doesn't mention header files found in system header directories, or header files that get included, directly or indirectly, from one of those system headers ๐Ÿฆ‹

This also 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, this specifies a file to write the dependencies to. If you don't give a -MF switch, the preprocessor sends the rules to the same place it would send preprocessed output ๐ŸŒธ

When you use it with the driver options -MD or -MMD, -MF overrides the default dependency output file ๐Ÿซถ

If file is -, the dependencies get written to stdout โœจ

  • -MG โ€” Used together with an option like -M that requests dependency generation, -MG assumes missing header files are generated files. It adds them to the dependency list without raising an error ๐Ÿงš. The dependency filename is taken straight from the #include directive, without prepending any path ๐Ÿ“. -MG also suppresses preprocessed output, since a missing header makes that useless ๐Ÿ’€

This feature is used for automatically updating makefiles ๐Ÿ’œ

  • -MP โ€” This instructs CPP to add a phony target for each dependency other than the main file, so that each one depends on nothing ๐ŸŒˆ. These dummy rules work around the errors make throws if you delete 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 like .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 put them all in 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, except it quotes any characters that are special to Make ๐Ÿ’…. -MQ '$(objpfx)foo.o' gives:
$$(objpfx)foo.o: foo.c

The default target gets automatically quoted, as if it had been 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 that argument but with a .d suffix. Otherwise, it takes the input file's name, removes any directory components and suffix, and applies a .d suffix ๐ŸŒธ

If you use -MD together with -E, any -o switch is understood to specify the dependency output file. But if you use it 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, except it only mentions user header files, not system header files ๐Ÿ’–
  • -fpreprocessed โ€” ๐Ÿ’– okay so this one tells the preprocessor "hey, this file is already preprocessed, don't redo it!" It skips macro expansion, trigraph conversion, escaped newline splicing, and most directives. Comments still get recognized and removed, so you can pass it a file preprocessed with -C and it's totally fine ๐Ÿซถ. In this mode the integrated preprocessor is basically just a tokenizer for the front ends ๐Ÿงš. And it's switched on automatically if the input file ends in .i, .ii, or .mi, which are the extensions GCC uses for preprocessed files made by -save-temps โœจ.
  • -fdirectives-only โ€” ๐Ÿฆ‹ handle the directives but don't expand macros. What happens depends on -E and -fpreprocessed:
    • With -E, it only handles directives like #define, #ifdef, and #error. Stuff like macro expansion and trigraph conversion doesn't happen. Also, -dD gets turned on implicitly ๐Ÿ’….
    • With -fpreprocessed, predefining the command line and most builtin macros is disabled. Context-dependent macros like __LINE__ are handled normally. This lets you compile files that were preprocessed with -E -fdirectives-only ๐ŸŒธ.
    • With both -E and -fpreprocessed, the -fpreprocessed rules win. This gives you full preprocessing of files that were previously preprocessed with -E -fdirectives-only ๐Ÿ‘‘.
  • -fdollars-in-identifiers โ€” ๐Ÿ’… lets $ show up inside identifiers.
  • -fextended-identifiers โ€” ๐ŸŒˆ accepts universal character names and extended characters in identifiers. It's on by default for C99 (and later C standards) and C++, so you're already set ๐Ÿ˜ญ.
  • -fno-canonical-system-headers โ€” ๐Ÿ™ˆ when preprocessing, this stops system header paths from being shortened with canonicalization.
  • -fmax-include-depth=depth โ€” ๐Ÿงš sets the max depth of nested #includes. 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 when tabs are on the line ๐Ÿ“. If the value is less than 1 or greater than 100, the option gets ignored. The default is 8.
  • -ftrack-macro-expansion[=level] โ€” ๐Ÿ” tracks token locations across macro expansions. This lets the compiler print diagnostics about the current macro expansion stack when an error happens inside a macro. Heads up, though: it makes the preprocessor and compiler eat more memory ๐Ÿ’€. The level picks how precisely tokens get tracked, so you can dial down memory use if you need to:
    • 0 turns this option off.
    • 1 tracks token locations in a degraded mode to keep memory overhead minimal. In this mode, every token from expanding a function-like macro's argument shares the same location.
    • 2 tracks token locations completely. This is the most memory-hungry one ๐Ÿ”ฅ.

If you give the option with no argument, the level defaults to 2. Also, -ftrack-macro-expansion=2 is on by default, so it's already doing its thing ๐Ÿ‘€.

  • -fmacro-prefix-map=old=new โ€” ๐Ÿ—บ๏ธ when preprocessing files in directory old, __FILE__ and __BASE_FILE__ expand as if the files lived in directory new instead. You can use . for new to turn an absolute path into a relative one, which can make builds more reproducible and location independent ๐ŸŒฟ. This also affects __builtin_FILE() during compilation. See also -ffile-prefix-map.
  • -fexec-charset=charset โ€” ๐Ÿ’œ sets the execution character set for string and character constants. The default is UTF-8. charset can be any encoding the system's iconv library routine supports โœจ.
  • -fwide-exec-charset=charset โ€” ๐ŸŒธ sets the wide execution character set for wide string and character constants. The default is one of UTF-32BE, UTF-32LE, UTF-16BE, or UTF-16LE, whichever matches the width of wchar_t and the big-endian or little-endian byte order used for code generation. Like -fexec-charset, charset can be any encoding iconv supports, but you'll run into problems with encodings that don't fit exactly in wchar_t ๐Ÿ˜ฌ.
  • -finput-charset=charset โ€” ๐Ÿฆ‹ sets the input character set, which gets translated from the input file's character set into the source character set GCC uses. If the locale doesn't specify one, or GCC can't get it from the locale, the default is UTF-8. The locale or this command-line option can override it, but if they conflict, the command-line option wins ๐Ÿ‘‘. charset can be any encoding the system's iconv library routine supports.
  • -fpch-deps โ€” ๐Ÿง  when you're using precompiled headers, this makes the dependency-output flags also list the files from the precompiled header's dependencies. Without it, only the precompiled header gets listed, not the files used to create it, since those aren't consulted when a precompiled header is used ๐Ÿ™ƒ.
  • -fpch-preprocess โ€” ๐ŸŽ€ lets you use a precompiled header together with -E. It inserts a special #pragma into the output, #pragma GCC pch_preprocess "filename", to mark where the precompiled header was found and what its filename is. When -fpreprocessed is in use, GCC recognizes this #pragma and loads the PCH ๐Ÿซถ.

This option is off by default, since the preprocessed output is really only suitable as input to GCC. It gets switched on by -save-temps ๐ŸŒˆ.

You shouldn't write this #pragma in your own code. But it's safe to edit the filename if the PCH file lives somewhere else. 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 the working directory at preprocessing time. With this on, after the initial linemarker, the preprocessor emits a second linemarker with the current working directory followed by two slashes. GCC uses that directory, if it's in the preprocessed input, as the working directory in some debugging information formats โœจ. It's implicitly enabled when debugging info is on, but you can turn it off with the negated form -fno-working-directory. If -P is in the command line, this option does nothing, since no #line directives get emitted whatsoever ๐Ÿ™ˆ.
  • -A predicate=answer โ€” ๐Ÿ”ฎ makes an assertion with the predicate predicate and the answer answer. This form is preferred over the older -A predicate(answer) form, which is still supported. The new one is better because it doesn't use shell special characters ๐Ÿ’….
  • -A -predicate=answer โ€” ๐Ÿšซ cancels an assertion with the predicate predicate and the answer answer.
  • -C โ€” ๐Ÿ’ฌ don't throw away comments! All comments get passed through to the output file, except comments in processed directives, which get deleted along with the directive.
โš ๏ธ Be ready for side effects when you use -C. 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 โ€” ๐Ÿ’– don't throw away 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.

In addition to the -C side effects, -CC converts all C++-style comments inside a macro into C-style comments. This stops later uses of that macro from accidentally commenting out the rest of the source line ๐Ÿ™…โ€โ™€๏ธ. -CC is mostly used to support lint comments ๐Ÿงน.

  • -P โ€” ๐Ÿšซ inhibits linemarkers in the preprocessor output. This could be useful when you run the preprocessor on something that isn't C code and will get sent to a program that might get confused by linemarkers ๐ŸŒธ.
  • -traditional, -traditional-cpp โ€” ๐Ÿ•ฐ๏ธ try to imitate pre-standard C preprocessors instead of ISO C preprocessors. Check the GNU CPP manual for the details ๐Ÿ“–.

Also, GCC doesn't try to emulate a pre-standard C compiler otherwise, and these options only work with the -E switch or when you invoke CPP explicitly ๐Ÿ™ƒ.

  • -trigraphs โ€” ๐Ÿ”ค supports ISO C trigraphs. These are three-character sequences that all start with ?? and that ISO C defines as stand-ins for single characters. For example, ??/ stands for \, so '??/n' is a character constant for a newline ๐Ÿ“.

The nine trigraphs and their replacements are:

Trigraph:       ??(  ??)  ??<  ??>  ??=  ??/  ??'  ??!  ??-
Replacement:      [    ]    {    }    #    \    ^    |    ~

By default GCC ignores trigraphs, but in standard-conforming modes it converts them. Check out the -std and -ansi options for that ๐Ÿ‘‘.

  • -remap โ€” ๐Ÿ—‚๏ธ enables special code to work around file systems that only allow very short file names, like MS-DOS ๐Ÿ’พ.
  • -H โ€” ๐ŸŒณ prints the name of each header file used, along with all the other normal stuff. Each name is indented to show how deep it is in the #include stack ๐Ÿชœ. Precompiled header files get printed too, even if they turn out to be invalid. An invalid one gets printed with ...x, and a valid one with ...! โœจ.
  • -dletters โ€” ๐Ÿ”ฅ makes debugging dumps during compilation, as specified by letters. The flags documented here are the ones relevant to the preprocessor. Other letters get interpreted by the compiler proper, or are reserved for future GCC versions, so they're silently ignored ๐Ÿซฅ.
โš ๏ธ If you specify letters whose behavior conflicts, the result is undefined. Yikes ๐Ÿ˜ญ.
  • -dM โ€” ๐Ÿ“œ instead of the normal output, this generates a list of #define directives for all the macros defined during the preprocessor's execution, including predefined macros. It's a great way to find out what's predefined in your version of the preprocessor ๐Ÿซถ. Assuming you have no file foo.h, the command

Okay bestie, just run this and watch the magic โœจ

touch foo.h; cpp -dM foo.h

And boom, it shows you all the predefined macros ๐Ÿ’… Every single one, no cap.

๐Ÿ’€ If you use -dM without the -E option, -dM gets treated as a synonym for -fdump-rtl-mach. Not me being dramatic, that's just how it works.
  • -dD โ€” ๐ŸŽ€ This one's like -dM, but different in two ways. It skips the predefined macros, and it outputs both the #define directives and the result of preprocessing. Both kinds of output go to the standard output file ๐Ÿฆ‹
  • -dN โ€” Same energy as -dD, but it only gives you the macro names and skips their expansions ๐ŸŒธ
  • -dI โ€” Adds #include directives to the output, on top of the result of preprocessing ๐Ÿงš
  • -dU โ€” Like -dD, but way pickier ๐Ÿ™ˆ Only macros that get expanded, or whose definedness gets tested in preprocessor directives, make it into the output. The output is delayed until the macro is used or tested, and #undef directives also show up for macros that were tested but undefined at that moment.
  • -fdebug-cpp โ€” This one's only useful if you're debugging GCC itself, bestie ๐Ÿ”ง When it's 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 it's used from GCC without -E, this option has no effect ๐Ÿซ 

  • -Wp,option โ€” You can use this to skip the compiler driver and pass option straight through to the preprocessor ๐Ÿš€ If option has commas in it, it gets split into multiple options at those commas. Heads up though, because a lot 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 to the preprocessor ๐ŸŽ€ Use this for system-specific preprocessor options that GCC doesn't recognize. If the option you want takes an argument, you have to use -Xpreprocessor twice: once for the option and once for the argument.
  • -no-integrated-cpp โ€” By default, GCC does preprocessing as an integrated part of input tokenization and parsing, all smooth and built in ๐Ÿ’– With this option, preprocessing happens as a separate pass before compilation instead. The appropriate language front end (cc1, cc1plus, or cc1obj for C, C++, and Objective-C, respectively) gets invoked twice: once for preprocessing only, and once for the actual compilation of the preprocessed input. This can be handy with -B or -wrapper if you want an alternate preprocessor, or extra processing of your source between normal preprocessing and compilation ๐Ÿ“

โœจ Passing Options to the Assembler โœจ

You can pass options to the assembler ๐Ÿฆ‹

  • -Wa,option โ€” Passes option to the assembler. If option contains commas, it gets split into multiple options at the commas.
  • -Xassembler option โ€” Passes option to the assembler ๐Ÿ› ๏ธ Use this for system-specific assembler options that GCC doesn't recognize. If the option takes an argument, you have to use -Xassembler twice: once for the option and once for the argument.

โœจ Options for Linking โœจ

These options come into play when the compiler links object files into an executable output file ๐Ÿ”— They're meaningless if the compiler isn't doing a link step, so don't bother with them then.

  • 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 looking at the file contents.) If linking is done, these object files get used as input to the linker.
  • -c, -S, -E โ€” If any of these options is used, the linker doesn't run, so object file names should not be used as arguments ๐Ÿ™…
  • -flinker-output=type โ€” This option controls code generation for 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 set the type manually. Here's the lowdown on each type:
    • exec โ€” Code generation produces a static binary. In this case -fpic and -fpie are both disabled.
    • dyn โ€” Code generation produces a shared library. In this case -fpic or -fPIC is preserved, but not enabled automatically. This 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 results in similar optimizations as exec, except -fpie is not disabled if it was specified at compilation time.
    • rel โ€” The compiler assumes incremental linking is happening. The sections containing intermediate code for link-time optimization get merged, pre-optimized, and output to the resulting object file. If -ffat-lto-objects is specified, binary code is also produced for future non-LTO linking. The object file produced by incremental linking is smaller than a static library made from the same object files. At link time, the result also loads faster than a static library, assuming that most objects in the library are used.
    • nolto-rel โ€” Configures the compiler for incremental linking where code generation is forced, a final binary is produced, and the intermediate code for later link-time optimization is stripped. When multiple object files are linked together, the result is better optimized than with link-time optimizations disabled (cross-module inlining happens, for example), 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's 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 maintain whole program optimization, it's recommended to link such objects into a static library instead. Alternatively, it's possible to use H.J. Lu's binutils, which have support for mixed objects ๐ŸŒˆ

  • -fuse-ld=bfd โ€” Uses the bfd linker instead of the default linker ๐Ÿ’…
  • -fuse-ld=gold โ€” Uses the gold linker instead of the default linker โœจ
  • -fuse-ld=lld โ€” Uses the LLVM lld linker instead of the default linker ๐Ÿ’œ
  • -fuse-ld=mold โ€” Uses the Modern Linker (mold) instead of the default linker ๐Ÿ”ฅ
  • -llibrary, -l library โ€” Searches the library named library when linking ๐Ÿ” The second form, with the library as a separate argument, is only there for POSIX compliance and isn't recommended ๐Ÿ™ƒ

The -l option is passed directly to the linker by GCC, so check your linker's 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. Those directories include several standard system directories, plus any you specify with -L ๐Ÿ—บ๏ธ

Static libraries are archives of object files, and they have file names like liblibrary.a. Some targets also support shared libraries, which typically have names like liblibrary.so. If both static and shared libraries are found, the linker gives preference to linking with the shared library unless the -static option is used ๐Ÿ’–

Where you write this option in the command really matters ๐Ÿ‘€ 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 get loaded ๐Ÿ˜ฌ

  • -lobjc โ€” You need this special case of the -l option to link an Objective-C or Objective-C++ program ๐Ÿงš
  • -nostartfiles โ€” Don't use the standard system startup files when linking ๐Ÿšซ The standard system libraries are still used normally, unless -nostdlib, -nolibc, or -nodefaultlibs is used.
  • -nodefaultlibs โ€” Don't use the standard system libraries when linking. Only the libraries you specify are passed to the linker, and options specifying linkage of the system libraries, such as -static-libgcc or -shared-libgcc, are ignored. The standard startup files are used normally, unless -nostartfiles is used.

The compiler may generate calls to "memcmp", "memset", "memcpy" and "memmove". These entries are usually resolved by entries in libc. When this option is specified, these entry points should be supplied through some other mechanism ๐Ÿซถ

  • -nolibc โ€” Don't use the C library, or the system libraries tightly coupled with it, when linking. It still links with the startup files, libgcc, or toolchain-provided language support libraries such as libgnat, libgfortran, or libstdc++, unless options preventing their inclusion are used as well. This typically removes -lc from the link command line, along with 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. This is intended for bare-board targets where there is indeed no C library available ๐Ÿค–
  • -nostdlib โ€” Don't use the standard system startup files or libraries when linking. No startup files are used, and only the libraries you specify are passed to the linker. Options specifying linkage of the system libraries, such as -static-libgcc or -shared-libgcc, are ignored.

The compiler may generate calls to "memcmp", "memset", "memcpy" and "memmove". These entries are usually resolved by entries in libc. When this option is specified, these 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 ๐ŸŒธ

You almost always still need libgcc.a ๐Ÿ˜ญ, even when you're trying to ditch the other standard libraries ๐Ÿ™ˆ. So if you go with -nostdlib or -nodefaultlibs, you should usually throw -lgcc in there too ๐Ÿซถ. That way you won't end up with unresolved references to GCC's internal library subroutines ๐Ÿ’…. (__main is one of those internal helpers, and it's what makes sure C++ constructors get called โœจ.)

  • -e entry, --entry=entry โ€” Sets the program's entry point to entry ๐Ÿงš. The linker is the one reading this, and the GNU linker will happily take either a symbol name or an address.
  • -pie โ€” Makes a dynamically linked position independent executable on targets that support it ๐Ÿฆ‹. For predictable results, you also need to use the same options you compiled with (-fpie, -fPIE, or model suboptions) when you pass this linker option.
  • -no-pie โ€” Nope, no PIE for you. This makes a dynamically linked position independent executable not happen ๐Ÿ™…โ€โ™€๏ธ.
  • -static-pie โ€” Makes a static position independent executable on targets that support it ๐Ÿ’œ. It's basically a static executable, except it can be loaded at any address without needing a dynamic linker. Same deal as before: for predictable results, match your compile options (-fpie, -fPIE, or model suboptions) when you use this linker option.
  • -pthread โ€” Links with the POSIX threads library ๐Ÿงต. This works on GNU/Linux targets, most other Unix derivatives, and also on x86 Cygwin and MinGW targets. On some targets it also sets flags for the preprocessor, so use it consistently for both compiling and linking or it'll get messy ๐Ÿ’€.
  • -r โ€” Produces 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 to the dynamic symbol table, not only the ones that are used. It's needed for some uses of dlopen or to get backtraces from inside a program ๐Ÿ”ฅ.
  • -s โ€” Strips out all symbol table and relocation information from the executable ๐Ÿช„.
  • -static โ€” On systems that support dynamic linking, this overrides -pie and stops linking with shared libraries ๐Ÿšซ. On other systems it does absolutely nothing ๐Ÿคทโ€โ™€๏ธ.
  • -shared โ€” Makes a shared object that you can link with other objects to form an executable. Not every system supports this one ๐Ÿฅบ. For predictable results, match your compile options (-fpic, -fPIC, or model suboptions) when you use this linker option.[1]
  • -shared-libgcc, -static-libgcc โ€” On systems that ship libgcc as a shared library, these force the shared or static version, respectively ๐ŸŽ€. If no shared version of libgcc was built when the compiler was configured, these do nothing at all.

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, every one of those libraries and the app 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 use exceptions all the time, so this is the right move ๐Ÿ’….

If you use the GCC driver to make shared libraries instead, they might not always end up linked with the shared libgcc ๐Ÿ™ƒ. If GCC finds out at configuration time that you have a non-GNU linker, or a GNU linker that doesn't support the option --eh-frame-hdr, it links the shared version of libgcc into shared libraries by default. Otherwise, it takes advantage of the linker and skips linking with the shared libgcc, using the static version by default instead. This lets exceptions propagate through those shared libraries without paying relocation costs at library load time โœจ.

However, if a library or main executable is supposed to throw or catch exceptions, you must link it using the G++ driver, or use the option -shared-libgcc, so that it's linked with the shared libgcc. Don't skip this or your exceptions will be ghosting you ๐Ÿ’€.
  • -static-libasan โ€” When -fsanitize=address is used to link a program, the GCC driver automatically links against libasan ๐Ÿ”. If libasan is available as a shared library and -static isn't used, it links against the shared version. This option tells the GCC driver to link libasan statically, without necessarily linking other libraries statically.
  • -static-libtsan โ€” When -fsanitize=thread is used to link a program, the GCC driver automatically links against libtsan ๐Ÿงต. If libtsan is available as a shared library and -static isn't used, it links against the shared version. This option tells the GCC driver to link libtsan statically, without necessarily linking other libraries statically.
  • -static-liblsan โ€” When -fsanitize=leak is used to link a program, the GCC driver automatically links against liblsan ๐Ÿ•ต๏ธโ€โ™€๏ธ. If liblsan is available as a shared library and -static isn't used, it links against the shared version. This option tells the GCC driver to link liblsan statically, without necessarily linking other libraries statically.
  • -static-libubsan โ€” When -fsanitize=undefined is used to link a program, the GCC driver automatically links against libubsan ๐Ÿซ . If libubsan is available as a shared library and -static isn't used, it links against the shared version. This option tells the GCC driver to link libubsan statically, without necessarily linking other libraries statically.
  • -static-libstdc++ โ€” When the g++ program links a C++ program, it normally links against libstdc++ automatically ๐Ÿ“š. If libstdc++ is available as a shared library and -static isn't used, it links against the shared version, and that's usually totally fine ๐Ÿ’–. Sometimes, though, you want to freeze the libstdc++ version your program uses without going all the way to a fully static link. This option tells the g++ driver to link libstdc++ statically, without necessarily linking other libraries statically.
  • -symbolic โ€” Binds references to global symbols when building a shared object ๐Ÿ”—. It warns about any unresolved references (unless you override that with the link editor option -Xlinker -z -Xlinker defs). Only a few systems support this one, so it's a bit of a rare bird ๐Ÿฆœ.
  • -T script โ€” Uses script as the linker script ๐Ÿ“œ. This works on most systems that use the GNU linker. On some targets, like bare-board targets with no operating system, -T may be required when linking so you don't get references to undefined symbols ๐Ÿ˜ฌ.
  • -Xlinker option โ€” Passes option along to the linker as an option ๐Ÿš€. This is your escape hatch for system-specific linker options that GCC doesn't recognize.

If you want to pass an option that takes a separate argument, you have to use -Xlinker twice: once for the option and once for the argument. For example, to pass -assert definitions, you write -Xlinker -assert -Xlinker definitions. Writing -Xlinker "-assert definitions" does not work, because it passes the whole string as one single argument, and that's not what the linker expects ๐Ÿ™…โ€โ™€๏ธ.

When you're using the GNU linker, it's usually way more convenient to pass arguments with the option=value syntax instead of as separate arguments. For example, -Xlinker -Map=output.map is much nicer than -Xlinker -Map -Xlinker output.map. Other linkers might not support this syntax for command-line options, though ๐Ÿค“.

  • -Wl,option โ€” Passes option to the linker as an option ๐Ÿงƒ. If option has commas in it, it gets split into multiple options at each comma. This is how you pass an argument to an option: -Wl,-Map,output.map passes -Map output.map to the linker. With the GNU linker, you can also get the same effect with -Wl,-Map=output.map ๐Ÿ’….
NOTE: In Ubuntu 8.10 and later versions, for LDFLAGS, the option -Wl,-z,relro is used. To turn that off, use -Wl,-z,norelro ๐Ÿ“.
  • -u symbol โ€” Pretends the symbol symbol is undefined, which forces the linker to load library modules that define it ๐ŸŽญ. You can use -u multiple times with different symbols to force loading of extra library modules.
  • -z keyword โ€” Passes -z directly to the linker along with the keyword ๐ŸŽฏ. Check the documentation for your linker to see the permitted values and what they mean.

These options are how you tell GCC which directories to search for header files, libraries, and parts of the compiler ๐Ÿ—‚๏ธ:

  • -I dir โ€” Adds the directory dir to the list of directories searched for header files during preprocessing ๐Ÿ”. If dir begins with = or $SYSROOT, that = or $SYSROOT gets replaced by the sysroot prefix (see --sysroot and -isysroot).
  • -iquote dir โ€” Adds dir for the quote form only, which is #include "file" ๐Ÿ’ฌ.
  • -isystem dir โ€” Adds dir to the search list for both #include "file" and #include <file> ๐Ÿฐ.
  • -idirafter dir โ€” Adds dir to the search list for both #include "file" and #include <file>, but it gets searched last ๐Ÿ‘‹.

Quick note on those -iquote, -I, -isystem, and -idirafter lines: -iquote only applies to the quote form, while -I, -isystem, and -idirafter apply to both forms ๐Ÿ’–. Also, you can mix and match any number or combination of these on the command line to search several directories ๐ŸŒˆ. Here's the lookup order, bestie ๐Ÿ‘‘:

  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 given by -iquote options are searched left to right, in the order they appear on the command line โžก๏ธ.
  3. Directories given with -I options are scanned left to right ๐Ÿ‘€.
  4. Directories given with -isystem options are scanned left to right ๐Ÿซง.
  5. Standard system directories are scanned ๐Ÿ›๏ธ.
  6. Directories given with -idirafter options are scanned left to right, last of all ๐Ÿฆ‹.

You can use -I to override a system header file by swapping in your own version, since these directories get searched before the standard system header directories. ngl, though, don't use this to add directories full of vendor-supplied system headers. Use -isystem for that ๐Ÿซถ

-isystem and -idirafter also mark a directory as a system directory, so it gets the same special treatment as the standard system directories ๐Ÿ’…

If a standard system include directory, or one you gave with -isystem, also shows up in an -I, the -I gets ignored ๐Ÿ™ˆ The directory still gets searched, but as a system directory in its normal spot in the system include chain. This is so GCC's procedure for fixing buggy system headers and the ordering for the #include_next directive don't get messed up by accident. If you really need to change the search order for system directories, use -nostdinc and/or -isystem instead โœจ

  • -I- โ€” Splits the include path. This one is deprecated, so please switch to -iquote for any -I directories that come before the -I-, and then remove the -I- entirely ๐Ÿ’€

Any directories given with -I before the -I- only get searched for headers requested with #include "file". They're not searched for #include <file>. If you add more -I directories after the -I-, those get searched for every #include directive ๐Ÿงš

On top of that, -I- stops the directory of the current file from being used as the first search directory for #include "file". There's no way to undo this effect of -I-, so choose wisely bestie ๐Ÿ˜ญ

  • -iprefix prefix โ€” Sets prefix as the prefix for any -iwithprefix options that come after it. If the prefix is a directory, make sure you include the final / ๐ŸŒธ
  • -iwithprefix dir, -iwithprefixbefore dir โ€” Tacks dir onto the prefix you set earlier with -iprefix, then adds the resulting directory to the include search path. -iwithprefixbefore puts it in the same spot -I would, while -iwithprefix puts it where -idirafter would ๐Ÿฆ‹
  • -isysroot dir โ€” This is basically --sysroot, but it only applies to header files. The exception is Darwin targets, where it applies to both headers and libraries. Check out --sysroot for the full scoop ๐Ÿ“
  • -imultilib dir โ€” Uses dir as a subdirectory of the directory that holds the target-specific C++ headers ๐Ÿ’œ
  • -nostdinc โ€” Skips the standard system directories when hunting for header files. Only the directories you explicitly gave with -I, -iquote, -isystem, and/or -idirafter get searched, plus the directory of the current file if that's appropriate ๐Ÿ‘‘
  • -nostdinc++ โ€” Skips the C++-specific standard directories, but still searches the other standard directories. This one is used when building the C++ library ๐ŸŒˆ
  • -iplugindir=dir โ€” Sets the directory to search for plugins that get passed by -fplugin=name instead of -fplugin=path/name.so. This one isn't meant for you to use directly. Only the driver passes it along ๐Ÿ™ˆ
  • -Ldir โ€” Adds dir to the list of directories searched for -l โœจ
  • -Bprefix โ€” 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 each program it attempts to run, both with and without machine/version/ for the target machine and compiler version. It's giving organized ๐Ÿ’–

For each subprogram, the driver tries the -B prefix first, if you gave one. If that name isn't found, or if -B wasn't specified at all, the driver tries two standard prefixes: /usr/lib/gcc/ and /usr/local/lib/gcc/. If neither of those gets it a file that exists, the unmodified program name gets searched for in the directories listed in your PATH environment variable ๐Ÿง 

The compiler checks whether the path you gave with -B is a directory, and if it needs to, it adds a directory separator character to the end of the path ๐ŸŽ€

-B prefixes that effectively name directories also apply to libraries in the linker, because the compiler translates them into -L options for the linker. They also apply to include files in the preprocessor, since the compiler translates them into -isystem options for the preprocessor. In that case, the compiler appends include to the prefix ๐Ÿฆ‹

The runtime support file libgcc.a can also be searched for using the -B prefix, if needed. If it isn't found there, the two standard prefixes above get tried, and that's it. If it still isn't found by any of those means, the file gets left out of the link ๐Ÿ˜ญ

Another way to specify a prefix that's pretty much like the -B prefix is the environment variable GCC_EXEC_PREFIX ๐ŸŒธ

As a special kludge, if the path given with -B is [dir/]stageN/, where N is a number from 0 to 9, it gets replaced by [dir/]include. This is there to help with bootstrapping 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 โ€” Uses dir as the logical root directory for headers and libraries. For example, if the compiler normally searches for headers in /usr/include and libraries in /usr/lib, it'll instead search dir/usr/include and dir/usr/lib ๐ŸŒˆ

If you use both this option and -isysroot, then --sysroot applies to libraries, but -isysroot applies to header files ๐Ÿ‘‘

The GNU linker (version 2.16 and up) has the support it needs for this option. If your linker doesn't support it, the header file part of --sysroot still works, but the library part doesn't ๐Ÿ’€

  • --no-sysroot-suffix โ€” For some targets, a suffix gets tacked onto the root directory you specify with --sysroot, depending on the other options you used. That means headers might get 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 control the interface conventions used in code generation, and they're lowkey iconic ๐Ÿ’–

Most of them have both positive and negative forms. The negative form of -ffoo is -fno-foo. In the table below, only one of the forms gets listed, the one that isn't 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 that have names, and none disables stack reuse completely. The default value is all. This option is needed when a program extends the lifetime of a scoped local variable or a compiler-generated temporary beyond the end point the language defines. 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 lifetimes 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 doesn't overlap with it. However, some legacy code relies on the behavior of older compilers, where temporaries' stack space wasn't reused. Aggressive stack reuse can lead to runtime errors for that code ๐Ÿ˜ญ This option controls 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. Only active options override, though, 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. -ftrapv and -fwrapv override each other, so -ftrapv -fwrapv on the command line results in -fwrapv being effective. Only active options override, so -ftrapv -fwrapv -fno-wrapv on the command line results in -ftrapv being effective ๐Ÿ‘‘
  • -fwrapv-pointer โ€” okay so this tells the compiler to assume pointer arithmetic overflow on addition and subtraction just wraps around, using twos-complement representation ๐Ÿ”„. It also turns off some optimizations that assume pointer overflow is invalid, so it's a bit of a plot twist ๐ŸŽ€
  • -fstrict-overflow โ€” this one implies -fno-wrapv -fno-wrapv-pointer ๐Ÿ’…. When you negate it, it implies -fwrapv -fwrapv-pointer instead โœจ
  • -fexceptions โ€” enables exception handling and generates the extra code needed to propagate exceptions ๐Ÿ’ฅ. On some targets this also means GCC generates frame unwind information for all functions. That can add a lot of data size overhead, but it doesn't change how things execute ๐Ÿงš

If you don't specify this option, GCC turns it on by default for languages like C++ that normally need exception handling, and turns it off for languages like C that don't ๐Ÿ‘‘. Still, you might need to enable it when compiling C code that has to interoperate properly with exception handlers written in C++ ๐Ÿซถ. You might also want to disable it if you're compiling older C++ programs that don't use exception handling ๐Ÿ™ˆ

  • -fnon-call-exceptions โ€” makes trapping instructions able to throw exceptions ๐Ÿช„. Heads up: this needs platform-specific runtime support, which doesn't exist everywhere ๐Ÿ˜ญ. It also only lets trapping instructions throw exceptions, meaning memory references or floating-point instructions. It can't throw exceptions out of arbitrary signal handlers like "SIGALRM" ๐Ÿ’€
  • -fdelete-dead-exceptions โ€” instructions that may throw exceptions but don't otherwise contribute to the program's execution can be optimized away ๐Ÿ—‘๏ธ. This is enabled by default for the Ada front end, which the Ada language specification allows. Optimization passes that remove dead exceptions are enabled independently at different optimization levels ๐ŸŒˆ
  • -funwind-tables โ€” similar to -fexceptions, except it only generates any needed static data and leaves the generated code alone otherwise ๐Ÿฆ‹. You usually don't need to enable this yourself, because a language processor that needs this handling turns it on for you ๐Ÿซถ
  • -fasynchronous-unwind-tables โ€” generates an unwind table in DWARF format, if the target machine supports it ๐Ÿ“œ. The table is exact at each instruction boundary, so it can be used for stack unwinding from asynchronous events, like a debugger or garbage collector ๐Ÿ”
  • -fno-gnu-unique โ€” on systems with a recent GNU assembler and C library, the C++ compiler uses the "STB_GNU_UNIQUE" binding ๐Ÿงฉ. That keeps definitions of template static data members and static local variables in inline functions unique, even with "RTLD_LOCAL". It's needed to avoid problems with a library used by two different "RTLD_LOCAL" plugins that depend on a definition in one of them and disagree with the other about the binding of the symbol ๐Ÿคฏ

The catch is that this makes dlclose get ignored for affected DSOs ๐Ÿ™ˆ. So if your program relies on reinitializing a DSO via dlclose and dlopen, you can use -fno-gnu-unique ๐Ÿ’…

  • -fpcc-struct-return โ€” returns short struct and union values in memory like the longer ones, instead of in registers ๐Ÿ“ฆ. It's less efficient, but it lets GCC-compiled files play nicely with files compiled by other compilers, especially the Portable C Compiler (pcc) ๐Ÿค

The exact convention for returning structures in memory depends on the target configuration macros ๐ŸŽฏ. Short structures and unions are the ones whose size and alignment match some integer type ๐Ÿ“

Warning: code compiled with the -fpcc-struct-return switch is not binary compatible with code compiled with the -freg-struct-return switch ๐Ÿ˜ฌ. Only use it to conform to a non-default application binary interface.
  • -freg-struct-return โ€” returns struct and union values in registers when possible โšก. This is more efficient for small structures than -fpcc-struct-return ๐Ÿ’–

If you specify neither -fpcc-struct-return nor -freg-struct-return, GCC defaults to whichever convention is standard for the target ๐ŸŽ€. If there's no standard convention, GCC defaults to -fpcc-struct-return, except on targets where GCC is the principal compiler. In those cases we can choose the standard, and we chose the more efficient register return alternative ๐Ÿ‘‘

Warning: code compiled with the -freg-struct-return switch is not binary compatible with code compiled with the -fpcc-struct-return switch ๐Ÿ˜ฌ. Only use it to conform to a non-default application binary interface.
  • -fshort-enums โ€” allocates to an enum type only as many bytes as it needs for the 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 causes GCC to generate code that is not binary compatible with code generated without that switch ๐Ÿ˜ฌ. Only use it to conform to a non-default application binary interface.
  • -fshort-wchar โ€” overrides the underlying type for wchar_t to be short unsigned int instead of the target's default ๐Ÿ“. This one is useful for building programs that run under WINE ๐Ÿท
Warning: the -fshort-wchar switch causes GCC to generate code that is not binary compatible with code generated without that switch ๐Ÿ˜ฌ. Only use it to conform to a non-default application binary interface.
  • -fcommon โ€” in C code, this controls where global variables defined without an initializer get placed ๐Ÿ—‚๏ธ. The C standard calls these tentative definitions. They're different from declarations of a variable with 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 places uninitialized global variables in a common block instead ๐Ÿงบ. That lets the linker resolve all tentative definitions of the same variable in different compilation units to the same object, or to a non-tentative definition. It's inconsistent with C++, and on many targets it implies a speed and code size penalty on global variable references ๐Ÿข. It's mainly useful for letting legacy code link without errors ๐Ÿฅน

  • -fno-ident โ€” ignore the #ident directive ๐Ÿ™…โ€โ™€๏ธ
  • -finhibit-size-directive โ€” don't output a .size assembler directive, or anything else that would cause trouble if the function is split in the middle and the two halves end up placed far apart in memory โœ‚๏ธ. This is used when compiling crtstuff.c ๐Ÿงฉ. You shouldn't need it for anything else ๐Ÿ™…โ€โ™€๏ธ
  • -fverbose-asm โ€” puts extra commentary in the generated assembly code so it's easier to read ๐Ÿ“. This is mostly for people who actually need to read the generated assembly, like when debugging the compiler itself ๐Ÿ•ต๏ธโ€โ™€๏ธ

-fno-verbose-asm, the default, leaves the extra information out, which is handy when comparing two assembler files โš–๏ธ

The added comments include:

  • information on the compiler version and command-line options,
  • the source code lines associated with the assembly instructions, in the form FILENAME:LINENUMBER:CONTENT OF LINE,
  • hints on which high-level expressions correspond to the various assembly instruction operands.

For example, here's a 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 sending the result straight 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 โ€” records the command line used to invoke the compiler into the object file being created ๐Ÿ“ผ. This is only implemented on some targets, and the exact format of the recording depends on the target and binary file format. It usually takes the form of a section containing ASCII text ๐Ÿ”ค

This is related to -fverbose-asm, but that switch only records information 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 โ€” okay so this one spits out position-independent code (PIC) that's built for a shared library, if your target machine supports it ๐Ÿ’– All constant addresses go through a global offset table (GOT), and the dynamic loader fills in 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 max, the linker throws an error saying -fpic doesn't work, and then you recompile with -fPIC instead ๐Ÿ˜ญ (The maxes are 8k on the SPARC, 28k on AArch64, and 32k on the m68k and RS/6000. The x86 has no such limit ๐Ÿฆ‹)
    • 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 the target machine supports it, this emits position-independent code that's ready for dynamic linking, and it dodges 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 โ€” these are basically the same energy as -fpic and -fPIC, but the position-independent code can only be linked into executables ๐ŸŽ€ Usually you'll use these to compile code that's getting linked with the -pie GCC option.
    • Both -fpie and -fPIE define the macros __pie__ and __PIE__. The macros have the value 1 for -fpie and 2 for -fPIE ๐ŸŒธ
  • -fno-plt โ€” do not use the PLT for external function calls in position-independent code. Instead, load the callee address from the GOT at call sites and branch to it ๐Ÿงš This leads to more efficient code, 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.
    • Alternatively, the function attribute noplt can be used to avoid calls through the PLT for specific external functions ๐Ÿ’œ
    • In position-dependent code, a few targets also convert calls to functions that are marked to not use the PLT so they use the GOT instead ๐Ÿฆ‹
  • -fno-jump-tables โ€” no jump tables for switch statements, even in spots where they'd be more efficient than other code generation 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 need a GOT, so this option isn't needed there.
  • -ffixed-reg โ€” treat the register named reg as a fixed register, so generated code should never touch it (except maybe as a stack pointer, frame pointer, or in some other fixed role) ๐Ÿซถ
    • reg has to be the name of a register. The accepted register names are machine-specific and get defined in the REGISTER_NAMES macro in the machine description macro file.
    • This flag doesn't have a negative form, because it's a three-way choice โœจ
  • -fcall-used-reg โ€” treat the register named reg as an allocable register that gets clobbered by function calls. It can be allocated for temporaries or variables that don't live across a call. Functions compiled this way don't save and restore the register reg ๐Ÿ“
    • It's an error to use this flag with the frame pointer or stack pointer. Using it on other registers with fixed pervasive roles in the machine's execution model produces disastrous results ๐Ÿ’€
    • This flag doesn't have a negative form, because it specifies a three-way choice ๐ŸŒธ
  • -fcall-saved-reg โ€” treat the register named reg as an allocable register that's saved by functions. It can be allocated even for temporaries or variables that live across a call. Functions compiled this way save and restore the register reg if they use it ๐Ÿ’…
    • It's an error to use this flag with the frame pointer or stack pointer. Using it on other registers with fixed pervasive roles in the machine's execution model produces disastrous results ๐Ÿ’€
    • A different kind of disaster happens if you use this flag on a register where function values may be returned ๐Ÿ˜ญ
    • This flag doesn't have a negative form, because it specifies a three-way choice ๐ŸŽ€
  • -fpack-struct[=n] โ€” without a value, this packs all structure members together with no holes ๐Ÿงฉ When you give a value (which has to be a small power of two), it packs structure members according to that value as the maximum alignment. Objects with default alignment requirements larger than this get output potentially unaligned at the next fitting location.
Warning: the -fpack-struct switch makes GCC generate code that isn't binary compatible with code generated without that switch ๐Ÿ’€ It also makes the code suboptimal. Only use it to conform to a non-default application binary interface.
  • -fleading-underscore โ€” this one and its counterpart, -fno-leading-underscore, forcibly change the way C symbols are represented in the object file ๐Ÿ”ฎ One use is helping you link with legacy assembly code.
Warning: the -fleading-underscore switch makes GCC generate code that isn't binary compatible with code generated without that switch ๐Ÿ™ˆ Only use it to conform to a non-default application binary interface. Not all targets provide complete support for this switch.
  • -ftls-model=model โ€” alter the thread-local storage model that gets used ๐Ÿงš The model argument should be one of global-dynamic, local-dynamic, initial-exec or local-exec. Note that the choice is subject to optimization: the compiler may use a more efficient model for symbols that aren't visible outside of the translation unit, or if -fpic isn't given on the command line ๐ŸŒˆ
    • The default without -fpic is initial-exec. With -fpic, the default is global-dynamic โœจ
  • -ftrampolines โ€” for targets that normally need trampolines for nested functions, this always generates them instead of using descriptors ๐Ÿ’– Otherwise, targets that don't need them, like HP-PA or IA-64, do nothing.
    • A trampoline is a small piece of code that gets created at run time on the stack when the address of a nested function is taken, and it's used to call the nested function indirectly. Because of that, 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 skip generating them when it figures that's safe and swap them out for descriptors instead. Descriptors are made up of data only, but the generated code has to be prepared to deal with them. As of this writing, -fno-trampolines is enabled by default only for Ada ๐Ÿ‘‘
    • Code compiled with -ftrampolines and code compiled with -fno-trampolines are not binary compatible if nested functions are present. This option has to be used on a program-wide basis and handled with extreme care ๐Ÿซถ
  • -fvisibility=[default|internal|hidden|protected] โ€” sets the default ELF image symbol visibility to the option you pick, and all symbols get marked with it unless they're overridden in the code ๐Ÿฆ‹ Using this can substantially improve linking and load times of shared object libraries, produce more optimized code, give you near-perfect API export, and prevent symbol clashes. It's strongly recommended that you use this in any shared objects you distribute ๐Ÿ˜
    • Despite the name, default always means public, i.e., available to be linked against from outside the shared object ๐ŸŒธ protected and internal are pretty useless in real-world usage, so the only other commonly used option is hidden. If -fvisibility isn't specified, the default is default, meaning every symbol is public ๐Ÿ‘€
    • For a good explanation of the benefits of making sure ELF symbols have the correct visibility, check out "How To Write Shared Libraries" by Ulrich Drepper, found at https://www.akkadia.org/drepper/ ๐Ÿ“š A superior solution, made possible by this option, is to make the default hidden and mark things public instead of marking things hidden when the default is public. That's 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. This is a great boon to anyone working on cross-platform projects ๐Ÿ’œ
    • If you're adding visibility support to existing code, #pragma GCC visibility might be your bestie ๐Ÿ’… You enclose the declarations you want to set visibility for with, for example, #pragma GCC visibility push(hidden) and #pragma GCC visibility pop. Bear in mind that symbol visibility should be treated as 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 marked explicitly as hidden, to avoid PLT indirection overheads. Making this super clear also helps readability and self-documentation of the code ๐Ÿง  Note that because of ISO C++ specification requirements, operator new and operator delete must always be of default visibility.
    • Be aware that headers from outside your project, especially system headers and headers from any other library you use, may not be expecting to be compiled with visibility other than the default ๐Ÿ™ˆ You may need to explicitly say #pragma GCC visibility push(default) before including any of those headers.

extern declarations are totally unaffected by -fvisibility, so a ton of code can be recompiled with -fvisibility=hidden with zero changes ๐Ÿ’…โœจ. Lowkey though, calls to extern functions with no explicit visibility still go through the PLT ๐Ÿ™ˆ, so it's way more effective to use __attribute ((visibility)) and/or #pragma GCC visibility to tell the compiler which extern declarations should be treated as hidden ๐Ÿ”ฅ.

Ngl, -fvisibility does affect C++ vague linkage entities ๐Ÿงš. That means an exception class that gets thrown between DSOs has to be explicitly marked with default visibility, so the type_info nodes get unified between the DSOs ๐Ÿ’œ.

An overview of these techniques, their benefits, and how to use them lives at http://gcc.gnu.org/wiki/Visibility ๐Ÿฆ‹.

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

Use this one if you want accesses to volatile bit-fields (or other structure fields, even though the compiler usually respects those types anyway) to be a single access at the width of the field's type, aligned to a natural alignment when that's possible ๐ŸŽ€. For example, targets with memory-mapped peripheral registers might need every access to be 16 bits wide. With this flag you can declare all the peripheral bit-fields as unsigned short (assuming short is 16 bits on those targets) to force GCC to use 16-bit accesses, instead of a maybe-more-efficient 32-bit access ๐Ÿ“.

If this option is disabled, the compiler goes for the most efficient instruction. In the example above, that could be a 32-bit load instruction, even though it touches bytes that have 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 a single 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 would fault or truncate the result at run time ๐Ÿซถ.

Note: Due to restrictions of the C/C++11 memory model, write accesses are not allowed to touch non bit-field members. So it's recommended to define all bits of the field's type as bit-field members ๐Ÿ’€.

The default value of this option is determined by the application binary interface for the target processor ๐Ÿ‘‘.

โœจ -fsync-libcalls โœจ

This option controls whether any out-of-line instance of the __sync family of functions may be used to implement the C++11 __atomic family of functions ๐Ÿ”ฅ.

The default is enabled, so the only useful form of the option is -fno-sync-libcalls ๐Ÿ’…. This option is used in the implementation of the libatomic runtime library ๐ŸŒˆ.

โœจ GCC Developer Options โœจ

This section is all about command-line options that are mainly for GCC developers, like options that support compiler testing and investigating compiler bugs and compile-time performance problems ๐Ÿงš. That includes options that produce debug dumps at various points in the compilation, options that print statistics like memory use and execution time, and options that print info about GCC's configuration, like where it searches for libraries ๐Ÿ”. You should rarely need any of these for ordinary compiling and linking, bestie ๐Ÿซถ.

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, a default dump file name gets built by concatenating the base dump file name, a pass number, a phase letter, and the pass name ๐Ÿ’œ. The base dump file name is the name of the output file the compiler produces if you explicitly specified one and it's not an executable. Otherwise, it's the source file name ๐Ÿ“. The pass number comes from the order passes are registered with the compiler's pass manager. That's usually the same as the order of execution, BUT passes registered by plugins, target-specific passes, or passes that are otherwise registered late get numbered higher than the pass named final, even if they run earlier ๐Ÿ˜ญ. The phase letter is one of i (inter-procedural analysis), l (language-specific), r (RTL), or t (tree) โœจ. The files are created in the directory of the output file ๐Ÿ“.

โœจ -fcallgraph-info โœจ

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

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

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

This says to make debugging dumps during compilation at the times specified by the letters ๐Ÿ›. It's used for debugging the RTL-based passes of the compiler ๐Ÿ’–.

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

Debug dumps can be enabled with a -fdump-rtl switch or with some -d option letters. Here are the possible letters for use in pass and letters, and what they mean ๐Ÿ‘‘:

  • -fdump-rtl-alignments โ€” Dump after branch alignments have been computed. ๐Ÿ“
  • -fdump-rtl-asmcons โ€” Dump after fixing RTL statements that have unsatisfied in/out constraints. ๐Ÿ› ๏ธ
  • -fdump-rtl-auto_inc_dec โ€” Dump after auto-inc-dec discovery. This pass only runs on architectures that have auto inc or auto dec instructions. ๐ŸŽฏ
  • -fdump-rtl-barriers โ€” Dump after cleaning up the barrier instructions. ๐Ÿงน
  • -fdump-rtl-bbpart โ€” Dump after partitioning hot and cold basic blocks. ๐Ÿ”ฅโ„๏ธ
  • -fdump-rtl-bbro โ€” Dump after block reordering. ๐Ÿ”€
  • -fdump-rtl-btl1 and -fdump-rtl-btl2 โ€” these enable dumping after the two branch target load optimization passes. ๐ŸŽ€
  • -fdump-rtl-bypass โ€” Dump after jump bypassing and control flow optimizations. ๐Ÿฆ˜
  • -fdump-rtl-combine โ€” Dump after the RTL instruction combination pass. ๐Ÿงฉ
  • -fdump-rtl-compgotos โ€” Dump after duplicating the computed gotos. ๐Ÿญ
  • -fdump-rtl-ce1, -fdump-rtl-ce2, and -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 and -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 and -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 and -fdump-rtl-fwprop2 โ€” these enable dumping after the two forward propagation passes. โžก๏ธ
  • -fdump-rtl-gcse1 and -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 โ€” 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 and -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, and -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 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 and -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 โ€” okay bestie, this one dumps right after virtual registers get converted to hard registers ๐Ÿ’…
  • -fdump-rtl-web โ€” dumps after live range splitting โœจ
  • -fdump-rtl-regclass, -fdump-rtl-subregs_of_mode_init, -fdump-rtl-subregs_of_mode_finish, -fdump-rtl-dfinit, -fdump-rtl-dfinish โ€” these are defined but always produce empty files ๐Ÿ’€ so don't get your hopes up, bestie
  • -da, -fdump-rtl-all โ€” produces all the dumps listed above ๐ŸŒˆ
  • -dA โ€” annotates the assembler output with miscellaneous debugging info ๐ŸŽ€
  • -dD โ€” dumps all macro definitions at the end of preprocessing, in addition to the normal output ๐Ÿงš
  • -dH โ€” produces a core dump whenever an error occurs ๐Ÿ™ˆ
  • -dp โ€” annotates the assembler output with a comment saying which pattern and alternative got used ๐Ÿฆ‹ It also prints the length and cost of each instruction, which is lowkey iconic
  • -dP โ€” dumps the RTL in the assembler output as a comment before each instruction ๐Ÿ’œ It also turns on -dp annotation, so you get both
  • -dx โ€” just generates RTL for a function instead of fully compiling it ๐Ÿ“ This is 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 doing debugging dumps, this suppresses address output ๐Ÿ‘‘ That makes it way easier to diff dumps from 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 ๐Ÿ˜ญ bestie, the compiler is literally helping you report the bug
  • -fdump-unnumbered โ€” when doing debugging dumps, this suppresses instruction numbers and address output โœจ It makes diff way more feasible for compiler invocations with different options, especially with and without -g
  • -fdump-unnumbered-links โ€” when doing debugging dumps (see 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 โ€” okay so these control dumping at various stages of inter-procedural analysis language tree to a file ๐Ÿ’– The file name is made by appending a switch-specific suffix to the source file name, and it gets created in the same directory as the output file. Here are the dumps you can ask for:
    • 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 ๐Ÿงš

You can also add -optimized, -missed, -note, and -all, which mean the same thing as they do for -fopt-info. It defaults to -optimized.

For example, -fdump-ipa-inline-optimized-missed will show you the callsites that got inlined and the ones that didn't. Main character energy ๐Ÿ‘‘

By default, the dump has messages about successful optimizations (same as -optimized) along with the low-level details of the analysis ๐Ÿ’…

  • -fdump-lang-all, -fdump-lang-switch, -fdump-lang-switch-options, -fdump-lang-switch-options=filename โ€” these control dumping of language-specific info ๐ŸŽ€ The options and filename bits work the same way as in the -fdump-tree option. The switch values you can use are:
    • all โ€” enables all language-specific dumps ๐ŸŒธ
    • class โ€” dumps class hierarchy info ๐Ÿฆ‹ Virtual table info gets emitted unless you say 'slim'. This one is for C++ only
    • raw โ€” dumps the raw internal tree data ๐Ÿ“ This one is also C++ only
  • -fdump-passes โ€” prints the list of optimization passes that are turned on and off by your current command-line options to stderr ๐Ÿงš
  • -fdump-statistics-option โ€” enables and controls dumping of pass statistics into a separate file โœจ The file name is made by appending a suffix ending in .statistics to the source file name, and it lands 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, the default is to sum counters for each function compiled ๐Ÿ’œ

  • -fdump-tree-all, -fdump-tree-switch, -fdump-tree-switch-options, -fdump-tree-switch-options=filename โ€” this controls the dumping at various stages of processing the intermediate language tree to a file ๐Ÿซถ If you use the -options form, options is a list of - separated options that control the details of the dump. Not every option works with every dump, and the ones that don't make sense just get ignored. Here's what's available:
    • address โ€” prints the address of each node ๐Ÿ™ˆ Usually this isn't meaningful since it changes with the environment and source file. Its main use is tying a dump file to a debug environment
    • asmname โ€” if "DECL_ASSEMBLER_NAME" has been set for a decl, uses that in the dump instead of "DECL_NAME" ๐ŸŒˆ Its main use is working backward from mangled names in the assembly file
    • slim โ€” when dumping front-end intermediate representations, stops members of a scope or body of a function from being dumped just because that scope was reached. Only items directly reachable by some other path get dumped ๐Ÿ’… When dumping pretty-printed trees, this 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 are pretty-printed into a C-like representation
    • details โ€” enables more detailed dumps (not every dump option honors this) and includes info from the optimization passes ๐Ÿ”ฅ
    • stats โ€” enables dumping various statistics about the pass (again, not every dump option honors this) ๐Ÿ‘‘
    • 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 to file.passid.pass.dot ๐Ÿฆ‹ Each function gets pretty-printed as a subgraph, so GraphViz can render them all in one plot. This only works for RTL dumps, and the RTL is always dumped in slim form
    • vops โ€” enables showing virtual operands for every statement ๐Ÿ’œ
    • lineno โ€” enables showing line numbers for statements ๐ŸŒธ
    • uid โ€” enables showing the unique ID ("DECL_UID") for each variable โœจ
    • verbose โ€” enables showing the tree dump for each statement ๐ŸŽ€
    • eh โ€” enables showing the EH region number holding each statement ๐Ÿซถ
    • scev โ€” enables showing scalar evolution analysis details ๐ŸŒˆ
    • optimized โ€” enables showing optimization info (only in certain passes) ๐Ÿ’…
    • missed โ€” enables showing missed optimization info (only in certain passes) ๐Ÿ™ˆ
    • note โ€” enables other detailed optimization info (only 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 ๐Ÿ”ฅ

Okay, so if you want to figure out which tree dumps exist or 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 a code that matches 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 enable the dump file, append the pass code to the -fdump- option prefix and invoke GCC with it ๐Ÿ’– For example, to get the dump from the Early Value Range Propagation pass, invoke GCC with the -fdump-tree-evrp option. You can optionally name the dump file yourself. If you don't, GCC makes 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 (and the letter r for RTL passes), and finally the pass code ๐Ÿฆ‹ For example, the Early VRP pass dump might be in a file named myfile.c.038t.evrp in the current working directory
โš ๏ธ Heads up, bestie: the numeric codes are not stable and may change from one version of GCC to another ๐Ÿ’€

  • -fopt-info, -fopt-info-options, -fopt-info-options=filename โ€” controls optimization dumps from the various optimization passes ๐Ÿ’– If you use the -options form, options is a list of - separated option keywords that pick the dump details and optimizations

The options split into three groups, and it's giving organized ๐Ÿซถ

  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.

You can mix the options from each group freely since they don't overlap. If there's ever a conflict, the later options on the command line win ๐Ÿ‘‘

These 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 got successfully vectorized ๐Ÿ”ฅ
  • missed โ€” prints info about missed optimizations ๐Ÿ™ˆ Individual passes control what info goes in the output
  • note โ€” ๐Ÿ“ bestie, this one prints verbose info about optimizations, like certain transformations and more detailed messages about the decisions GCC makes. Main character info ๐Ÿ’…
  • all โ€” ๐Ÿ”ฅ prints the detailed optimization info, and that includes optimized, missed, and note all together. Everything, no cap โœจ

The following option controls the dump verbosity:

  • internals โ€” ๐Ÿค“ by default, only the "high-level" messages show up. This turns on the extra, more detailed messages, which are probably only interesting to GCC developers ๐Ÿ’œ

One or more of the following option keywords can be used to describe a group of optimizations:

  • ipa โ€” ๐Ÿงฉ enables dumps from all interprocedural optimizations.
  • loop โ€” ๐Ÿ” enables dumps from all loop optimizations.
  • inline โ€” ๐Ÿ“ฆ enables dumps from all inlining optimizations.
  • omp โ€” ๐Ÿš€ enables dumps from all OMP (Offloading and Multi Processing) optimizations.
  • vec โ€” ๐Ÿฆ‹ enables dumps from all vectorization optimizations.
  • optall โ€” ๐Ÿ‘‘ enables dumps from all optimizations. It's a superset of the optimization groups listed above, so it's giving everything.

If options is omitted, it defaults to optimized-optall. That means you get messages about successful optimizations from all the passes, and anything treated as "internals" gets left out ๐ŸŒธ

If the filename is provided, the dumps from all the applicable optimizations get concatenated into that file. Otherwise, the dump is output onto stderr ๐ŸŽ€ Though multiple -fopt-info options are accepted, only one of them can include a filename. If other filenames are provided, then all but the first such option are ignored ๐Ÿ™ˆ

Note that the output filename is overwritten in case of multiple translation units. If you want a combined output from multiple translation units, use stderr instead. ๐Ÿ’€

In the following example, the optimization info is output 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 information about missed optimization opportunities from 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 information about missed optimizations, as well as optimized locations, from all the inlining passes into inline.txt ๐Ÿ“ฆ

Finally, consider:

gcc -fopt-info-vec-missed=vec.miss -fopt-info-loop-optimized=loop.opt

Here the two output filenames vec.miss and loop.opt are in conflict, since only one output file is allowed. In this case, only the first option takes effect and the subsequent options are ignored. Thus only vec.miss is produced, which contains dumps from the vectorizer about missed opportunities ๐Ÿ˜ญ


-fsave-optimization-record

โœจ This writes a SRCFILE.opt-record.json.gz file detailing what optimizations were performed, for the ones that support -fopt-info.

This option is experimental, and the format of the data within the compressed JSON file is subject to change. โš ๏ธ

It's roughly a machine-readable version of -fopt-info-all, as a collection of messages with source file, line number and column number. Each message also comes with these extra bits:

  • the execution count of the code being optimized, plus metadata about whether that came from actual profile data or 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 those 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

Additionally, some messages are logically nested within other messages, reflecting implementation details of the optimization passes ๐ŸŒˆ


-fsched-verbose=n

On targets that use instruction scheduling, this option controls how much debugging output the scheduler prints to the dump files ๐Ÿ“

For n greater than zero, -fsched-verbose outputs the same information as -fdump-rtl-sched1 and -fdump-rtl-sched2. For n greater than one, it also outputs basic block probabilities, detailed ready list information and unit/insn info. For n greater than two, it includes RTL at abort point, control-flow and regions info. And for n over four, -fsched-verbose also includes dependence info ๐Ÿ’œ


-fenable-kind-pass, -fdisable-kind-pass=range-list

This is a set of options used to explicitly disable or enable optimization passes. They're intended for debugging GCC ๐Ÿ› ๏ธ Compiler users should use the regular options for enabling and disabling passes instead, bestie ๐Ÿ’…

  • -fdisable-ipa-pass โ€” disables IPA pass pass. pass is the pass name. If the same pass is statically invoked in the compiler multiple times, the pass name should be appended with a sequential number starting from 1.
  • -fdisable-rtl-pass, -fdisable-rtl-pass=range-list โ€” disables RTL pass pass. pass is the pass name. If the same pass is statically invoked in the compiler multiple times, the pass name should be appended with a sequential number starting from 1. range-list is a comma-separated list of function ranges or assembler names. Each range is a number pair separated by a colon, and the range is inclusive at both ends. If the range is trivial, the number pair can be simplified to a single number. If the function's call graph node's uid falls within one of the specified ranges, the pass is disabled for that function. The uid is shown in the function header of a dump file, and the pass names can be dumped by using option -fdump-passes ๐Ÿ”
  • -fdisable-tree-pass, -fdisable-tree-pass=range-list โ€” disables tree pass pass. See -fdisable-rtl for the description of option arguments.
  • -fenable-ipa-pass โ€” enables IPA pass pass. pass is the pass name. If the same pass is statically invoked in the compiler multiple times, the pass name should be appended with a sequential number starting from 1.
  • -fenable-rtl-pass, -fenable-rtl-pass=range-list โ€” enables RTL pass pass. See -fdisable-rtl for option argument description and examples.
  • -fenable-tree-pass, -fenable-tree-pass=range-list โ€” enables tree pass pass. See -fdisable-rtl for the description of option arguments.

Here are some examples showing uses of 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

โœ… This enables internal consistency checking. The default depends on the compiler configuration. -fchecking=2 enables further internal consistency checking that might affect code generation, so be careful with that one ๐Ÿ‘€


-frandom-seed=string

๐ŸŽฒ This option provides a seed that GCC uses in place of random numbers when generating certain symbol names that have to be different in every compiled file. It's also used to place unique stamps in coverage data files and the object files that produce them. You can use -frandom-seed to produce reproducibly identical object files, which is so satisfying ๐Ÿฅน

The string can either be a number (decimal, octal or hex) or an arbitrary string. If it's an arbitrary string, it gets converted to a number by computing CRC32 ๐Ÿ”ข

The string should be different for every file you compile ๐Ÿซถ


-save-temps, -save-temps=cwd

๐Ÿ’พ This stores the usual "temporary" intermediate files permanently. It places them in the current directory and names them based on the source file. So compiling foo.c with -c -save-temps produces files foo.i and foo.s, as well as foo.o. This creates a preprocessed foo.i output file, even though the compiler now normally uses an integrated preprocessor ๐Ÿง

When it's used in combination 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. The corresponding intermediate file can be obtained by renaming the source file before using -save-temps ๐Ÿง 

If you invoke GCC in parallel, compiling several different source files that share a common base name in different subdirectories, or the same source file compiled for multiple output destinations, the parallel compilers will probably interfere with each other and overwrite the temporary files. For instance: gcc -save-temps -o outdir1/foo.o indir1/foo.c& gcc -save-temps -o outdir2/foo.o indir2/foo.c& may result in foo.i and foo.o being written to simultaneously by both compilers. ๐Ÿ˜ฑ

-save-temps=obj

๐Ÿ’œ This stores the usual "temporary" intermediate files permanently. If the -o option is used, the temporary files are based on the object file. If the -o option is not used, the -save-temps=obj switch behaves like -save-temps ๐Ÿฆ‹

For example:

gcc -save-temps=obj -c foo.c
gcc -save-temps=obj -c bar.c -o dir/xbar.o
gcc -save-temps=obj foobar.c -o dir2/yfoobar

creates foo.i, foo.s, dir/xbar.i, dir/xbar.s, dir2/yfoobar.i, dir2/yfoobar.s, and dir2/yfoobar.o. ๐ŸŒธ

  • -time[=file] โ€” okay bestie, this one is a stopwatch for every little subprocess in the compile chain โฑ๏ธ ๐Ÿ’– For C source files, that's the compiler proper and the assembler (plus the linker too, if you're linking).

Without an output file, you get something like this:

# cc1 0.12 0.01
# as 0.00 0.01

The first number on each line is the "user time", which is how long the program was actually running its own code. The second number is the "system time", which is time spent in operating system routines on the program's behalf. Both are in seconds โœจ

With an output file, the info gets appended to that named file, and it looks like this:

0.12 0.01 cc1 <options>
0.00 0.01 as <options>

Now the "user time" and "system time" get moved in front of the program name, and the options passed to the program are shown too ๐Ÿงš So later you can totally tell what file was being compiled and with which options. Main character record-keeping, iykyk ๐Ÿ’…

  • -fdump-final-insns[=file] โ€” dumps the final internal representation (RTL) into file ๐Ÿฆ‹ If you leave off the optional argument (or the file is .), the dump file gets named by slapping .gkd onto the end of the compilation output file name.
  • -fcompare-debug[=opts] โ€” this one is giving double-check energy ๐Ÿ”ฅ If nothing errors during compilation, the compiler runs a second time with opts and -fcompare-debug-second added to the arguments for that second go. It dumps the final internal representation in both runs and prints an error if they don't match ๐Ÿ’€

If you skip the equal sign, the default -gtoggle gets used.

The environment variable GCC_COMPARE_DEBUG works as a sneaky switch: if it's defined, non-empty, and nonzero, it implicitly turns on -fcompare-debug ๐ŸŒˆ If GCC_COMPARE_DEBUG is set to a string starting with a dash, that string becomes opts. Otherwise the default -gtoggle is used.

-fcompare-debug=, with the equal sign but no opts, is the same as -fno-compare-debug. That one turns off the dumping of the final representation and the second compilation, and it even stops GCC_COMPARE_DEBUG from taking effect ๐Ÿ™ˆ

To check full coverage while testing -fcompare-debug, set GCC_COMPARE_DEBUG to say -fcompare-debug-not-overridden. GCC rejects that as an invalid option in any real compilation (as opposed to preprocessing, assembly, or linking). If you only want a warning instead, setting GCC_COMPARE_DEBUG to -w%n-fcompare-debug not overridden will do the trick ๐ŸŽ€


  • -fcompare-debug-second โ€” this one is passed to the compiler automatically for that second compilation kicked off by -fcompare-debug ๐Ÿซถ It comes along with options that silence warnings, and it leaves out any other options that would make the compiler write output to files or standard output as a side effect. Dump files and preserved temporary files get renamed to carry an extra .gk extension during the second compilation, so they don't overwrite the ones from the first run ๐ŸŒธ

When you hand this option to the compiler driver, it makes the first compilation get skipped entirely. So it's pretty much only useful for debugging the compiler itself ๐Ÿค“

  • -gtoggle โ€” flips debug info on or off ๐Ÿ”„ If leaving out this option would generate debug info, it turns generation off. Otherwise it turns it on at level 2. Where you put it in the command line doesn't matter. It takes effect after all the other options are processed, and it only does its thing once, no matter how many times you type it โœจ It's mainly meant to be used with -fcompare-debug.
  • -fvar-tracking-assignments-toggle โ€” toggles -fvar-tracking-assignments in the same way -gtoggle toggles -g ๐Ÿ’œ
  • -Q โ€” makes the compiler print out each function name as it gets compiled, and print some stats about each pass once it's done ๐Ÿฆ‹
  • -ftime-report โ€” the compiler prints some stats about the time each pass ate up when it finishes โฐ
  • -ftime-report-details โ€” records the time consumed by infrastructure parts separately for each pass ๐Ÿงฉ
  • -fira-verbose=n โ€” controls how chatty the dump file for the integrated register allocator is ๐Ÿ—ฃ๏ธ The default value is 5. If n is 10 or higher, the dump output gets sent to stderr, using the same format as n minus 10.
  • -flto-report โ€” prints a report with internal details on how the link-time optimizer is working ๐Ÿ” The contents of this report change from version to version. It's meant to be useful to GCC developers when they're processing object files in LTO mode (via -flto). It's disabled by default, so you have to ask for it ๐Ÿ’…
  • -flto-report-wpa โ€” same as -flto-report, but only prints for the WPA phase of link-time optimization ๐ŸŒˆ
  • -fmem-report โ€” the compiler prints some stats about permanent memory allocation when it finishes ๐Ÿง 
  • -fmem-report-wpa โ€” prints stats about permanent memory allocation for the WPA phase only ๐Ÿซง
  • -fpre-ipa-mem-report, -fpost-ipa-mem-report โ€” prints some stats about permanent memory allocation either before or after interprocedural optimization ๐Ÿ“
  • -fprofile-report โ€” prints some stats about how consistent the (estimated) profile is, and what effect each individual pass had ๐Ÿ“Š
  • -fstack-usage โ€” this one is giving stack receipts ๐Ÿงพ The compiler outputs stack usage info for the program, per function. The dump filename is made by tacking .su onto the auxname. The auxname comes from the output file name if you explicitly specified one and it's not an executable. Otherwise, it's the basename of the source file. Each entry has three fields:
    • The name of the function.
    • A number of bytes.
    • One or more qualifiers: "static", "dynamic", "bounded".

The "static" qualifier means the function handles the stack in a fixed way: a set number of bytes gets allocated for the frame on function entry and released on function exit. No other stack adjustments get made in the function. The second field is that fixed number of bytes ๐ŸŒฟ

The "dynamic" qualifier means the function also moves the stack around as it goes. On top of the static allocation, there are stack adjustments made in the body of the function, like pushing and popping arguments around function calls ๐Ÿ˜ญ If "bounded" is also there, the amount of those adjustments is bounded at compile time, and the second field is an upper bound on the total stack used by the function. 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 the compilation ๐Ÿ“ˆ This only works with the C++ front end, and the info is generally only useful to the G++ development team, so it's kind of a behind-the-scenes thing ๐Ÿ™ˆ
  • -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 ๐ŸŽฏ The 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 that would be used when linking, and that's it ๐Ÿ—บ๏ธ 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 in the command line ๐Ÿ“ That directory is supposed to exist in GCC_EXEC_PREFIX.
  • -print-multi-lib โ€” prints the mapping from multilib directory names to the compiler switches that enable them ๐Ÿ—‚๏ธ The directory name is separated from the switches by ;. Each switch starts with @ instead of -, with no spaces between multiple switches. This is supposed to make shell processing easier ๐Ÿš
  • -print-multi-os-directory โ€” prints the path to OS libraries for the selected multilib, relative to some lib subdirectory ๐Ÿ  If OS libraries are in the lib subdirectory and no multilibs are used, this is usually just .. If OS libraries are in libsuffix sibling directories, it prints something like ../lib64, ../lib, or ../lib32. If OS libraries are in lib/subdir subdirectories, it prints something like amd64, sparcv9, or ev6 ๐Ÿ’œ
  • -print-multiarch โ€” prints the path to OS libraries for the selected multiarch, relative to some lib subdirectory ๐Ÿน
  • -print-prog-name=program โ€” like -print-file-name, but it searches for a program such as cpp instead ๐Ÿ”Ž
  • -print-libgcc-file-name โ€” same as -print-file-name=libgcc.a ๐ŸŽ

This is handy 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, and doesn't do anything else ๐Ÿ•ต๏ธ

This is useful when gcc prints the error message installation problem, cannot exec cpp0: No such file or directory. ๐Ÿ˜ฑ To fix that, you either need to put cpp0 and the other compiler components where gcc expects to find them, or you can set the environment variable GCC_EXEC_PREFIX to the directory where you installed them. Don't forget the trailing /! ๐Ÿซถ

  • -print-sysroot โ€” prints the target sysroot directory used during compilation ๐ŸŒ This is the target sysroot specified 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, this option 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 such a suffix, it gives an error instead. Either way, it doesn't do anything else ๐ŸŽ€

-dumpmachineโ€” okay so this one prints the compiler's target machine, likei686-pc-linux-gnu` ๐Ÿ–ฅ๏ธ, and then it literally does nothing else ๐Ÿ’…

  • -dumpversion โ€” prints the compiler version (like 3.0, 6.3.0 or 7) and then stops right there ๐ŸŽ€. This is the version that shows up in filesystem paths and specs, so it's doing important behind-the-scenes work ๐Ÿซถ. Depending on how the compiler was configured, it might be one number (major version), two numbers separated by a dot (major and minor version), or three numbers separated by dots (major, minor and patchlevel version) โœจ.
  • -dumpfullversion โ€” prints the full compiler version and nothing else ๐Ÿฆ‹. The output is always three numbers separated by dots: major, minor and patchlevel version ๐Ÿ”ฅ.
  • -dumpspecs โ€” prints the compiler's built-in specs and then stops ๐ŸŒธ. (This one is used when GCC itself is being built, so it's giving insider build-system info ๐Ÿ™ˆ.)

๐ŸŒˆ Machine-Dependent Options ๐ŸŒˆ

Each target machine GCC supports can have its own options ๐Ÿ’œ. Like, you might want to compile for a particular processor variant or ABI, or control optimizations that are specific to that machine โœจ. By convention, the names of machine-specific options start with -m ๐Ÿงš.

Some configurations of the compiler also support extra target-specific options, usually so they stay compatible with other compilers on the same platform ๐Ÿซถ.

๐Ÿ’– AArch64 Options ๐Ÿ’–

These options are defined for AArch64 implementations ๐Ÿฆ‹:

  • -mabi=name โ€” generates code for the data model you pick ๐Ÿ‘‘. The valid values are ilp32, which is SysV-like with int, long int and pointers all at 32 bits, and lp64, which is SysV-like with int at 32 bits but long int and pointers at 64 bits ๐Ÿ’…. The default depends on the specific target configuration.
โš ๏ธ Heads up bestie: the LP64 and ILP32 ABIs are not link-compatible ๐Ÿ’€. You have to compile your entire program with the same ABI and link it with a compatible set of libraries, or things get messy fr fr.
  • -mbig-endian โ€” generates big-endian code ๐Ÿ’œ. This is the default when GCC is configured for an aarch64_be-*-* target.
  • -mgeneral-regs-only โ€” generates code that only uses the general-purpose registers ๐ŸŒธ. This stops the compiler from using floating-point and Advanced SIMD registers, but it doesn't put any restrictions on the assembler.
  • -mlittle-endian โ€” generates little-endian code ๐Ÿ“. This is the default when GCC is configured for an aarch64-*-* target but not an aarch64_be-*-* target.
  • -mcmodel=tiny โ€” generates code for the tiny code model ๐Ÿงš. The program and its statically defined symbols must be within 1MB of each other. Programs can be statically or dynamically linked.
  • -mcmodel=small โ€” generates code for the small code model โœจ. The program and its statically defined symbols must be within 4GB of each other. Programs can be statically or dynamically linked. This is the default code model, so you're already slaying with it ๐Ÿ‘‘.
  • -mcmodel=large โ€” generates code for the large code model ๐Ÿฆ‹. It makes no assumptions about addresses and sizes of sections. Programs can be statically linked only. This option is incompatible with -mabi=ilp32, -fpic and -fPIC ๐Ÿ™ˆ.
  • -mstrict-align, -mno-strict-align โ€” avoids or allows generating memory accesses that may not be aligned on a natural object boundary, as described in the architecture specification ๐Ÿ”ฅ.
  • -momit-leaf-frame-pointer, -mno-omit-leaf-frame-pointer โ€” omits or keeps the frame pointer in leaf functions ๐ŸŒˆ. The former behavior is the default.
  • -mstack-protector-guard=guard, -mstack-protector-guard-reg=reg, -mstack-protector-guard-offset=offset โ€” generates stack protection code using a canary at guard ๐Ÿ›ก๏ธ. The supported locations are global for a global canary or sysreg for a canary in an appropriate system register.

With the latter choice, the options -mstack-protector-guard-reg=reg and -mstack-protector-guard-offset=offset furthermore specify which system register to use as the base register for reading the canary, and from what offset from that base register ๐Ÿ’…. There is no default register or offset, because this is entirely for use within the Linux kernel ๐Ÿ’€.

  • -mstack-protector-guard=guard, -mstack-protector-guard-reg=reg, -mstack-protector-guard-offset=offset โ€” generates stack protection code using a canary at guard ๐Ÿ›ก๏ธ. The supported locations are global for a global canary or sysreg for a canary in an appropriate system register.

With the latter choice, the options -mstack-protector-guard-reg=reg and -mstack-protector-guard-offset=offset furthermore specify which system register to use as the base register for reading the canary, and from what offset from that base register ๐Ÿ’…. There is no default register or offset, because this is entirely for use within the Linux kernel ๐Ÿ’€.

  • -mtls-dialect=desc โ€” uses TLS descriptors as the thread-local storage mechanism for dynamic accesses of TLS variables ๐Ÿ’–. This is the default.
  • -mtls-dialect=traditional โ€” uses traditional TLS as the thread-local storage mechanism for dynamic accesses of TLS variables ๐ŸŒธ.
  • -mtls-size=size โ€” specifies the bit size of immediate TLS offsets โœจ. Valid values are 12, 24, 32 and 48. This option requires binutils 2.26 or newer, so check your toolchain first ๐Ÿซถ.
  • -mfix-cortex-a53-835769, -mno-fix-cortex-a53-835769 โ€” enables or disables the workaround for the ARM Cortex-A53 erratum number 835769 ๐Ÿ”ง. It works by inserting a NOP instruction between memory instructions and 64-bit integer multiply-accumulate instructions.
  • -mfix-cortex-a53-843419, -mno-fix-cortex-a53-843419 โ€” enables or disables the workaround for the ARM Cortex-A53 erratum number 843419 ๐Ÿ”ง. This erratum workaround is made at link time, so this option only passes the corresponding flag to the linker ๐Ÿ”—.
  • -mlow-precision-recip-sqrt, -mno-low-precision-recip-sqrt โ€” enables or disables the reciprocal square root approximation ๐Ÿงฎ. This option only has an effect if -ffast-math or -funsafe-math-optimizations is used as well. Enabling it reduces the precision of reciprocal square root results to about 16 bits for single precision and to 32 bits for double precision.
  • -mlow-precision-sqrt, -mno-low-precision-sqrt โ€” enables or disables the square root approximation ๐Ÿงฎ. This option only has an effect if -ffast-math or -funsafe-math-optimizations is used as well. Enabling it reduces the precision of square root results to about 16 bits for single precision and to 32 bits for double precision. If enabled, it implies -mlow-precision-recip-sqrt.
  • -mlow-precision-div, -mno-low-precision-div โ€” enables or disables the division approximation โž—. This option only has an effect if -ffast-math or -funsafe-math-optimizations is used as well. Enabling it reduces the precision of division results to about 16 bits for single precision and to 32 bits for double precision.
  • -mtrack-speculation, -mno-track-speculation โ€” enables or disables generation of additional code that tracks speculative execution through conditional branches ๐Ÿ‘€. The tracking state can then be used by the compiler when expanding calls to "__builtin_speculation_safe_copy", so it can generate a more efficient code sequence.
  • -moutline-atomics, -mno-outline-atomics โ€” enables or disables calls to out-of-line helpers that implement atomic operations โš›๏ธ. These helpers figure out at runtime whether the LSE instructions from ARMv8.1-A can be used. If they can't, they fall back to the load/store-exclusive instructions that are present in the base ARMv8.0 ISA.

This option is only applicable when compiling for the base ARMv8.0 instruction set ๐Ÿ™ˆ. If you're using a later revision, e.g. -march=armv8.1-a or -march=armv8-a+lse, the ARMv8.1-Atomics instructions will be used directly. The same applies when using -mcpu= when the selected CPU supports the lse feature. This option is on by default ๐Ÿ’œ.

  • -march=name โ€” specifies the name of the target architecture and, optionally, one or more feature modifiers ๐Ÿ›๏ธ. This option has the form -march=arch{+[no]feature}*.

Here's the vibe check on what each arch value gives you, and the features it 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
  • armv8.4-a (Armv8.4-A) โ€” includes by default armv8.3-a, +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

The value native is available on native AArch64 GNU/Linux ๐Ÿ–ฅ๏ธ and makes the compiler pick the architecture of the host system. This option has no effect if the compiler is unable to recognize the architecture of the host system,

The permissible values for feature are listed in the sub-section aarch64-feature-modifiers,,-march and -mcpu Feature Modifiers. Where conflicting feature modifiers are specified, the right-most feature is used ๐Ÿ‘‘.

GCC uses name to determine what kind of instructions it can emit when generating assembly code ๐Ÿง . If -march is specified without either -mtune or -mcpu also being specified, the code is tuned to perform well across a range of target processors implementing the target architecture โœจ.

  • -mtune=name โ€” specifies the name of the target processor that GCC should tune the performance of the code for ๐ŸŽฏ. The permissible values for this option 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, ares, exynos-m1, emag, falkor, neoverse-e1, neoverse-n1, neoverse-n2, neoverse-v1, neoverse-v2, neoverse-512tvb, 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, ampere1, ampere1a, 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 ๐Ÿฆ‹๐Ÿ’œ.

okay so the neoverse-512tvb value is giving very specific ๐Ÿฆ‹. It tells GCC to tune for Neoverse cores that (a) implement SVE and (b) have a total vector bandwidth of 512 bits per cycle. Basically, these cores can run 4 128-bit Advanced SIMD arithmetic instructions a cycle, and they can run an equal number of SVE arithmetic instructions per cycle too (2 for 256-bit SVE, 4 for 128-bit SVE) ๐Ÿ’…. It's more general than tuning for one specific core like Neoverse V1, but it's more specific than the default tuning we'll get to below ๐ŸŒธ.

Also, on native AArch64 GNU/Linux systems, native tunes performance to whatever host you're on โœจ. If the compiler can't recognize your host's processor, this option just does nothing ๐Ÿ™ˆ.

Where none of -mtune=, -mcpu= or -march= are specified, the code is tuned to perform well across a whole range of target processors ๐ŸŒˆ.

This option cannot be suffixed by feature modifiers ๐Ÿšซ.

๐Ÿ’– -mcpu=name

Name the target processor, and optionally slap one or more feature modifiers on the end ๐Ÿ’…. The form is -mcpu=cpu{+[no]feature}*. The values allowed for cpu are the same ones you get with -mtune, and you can check the feature modifiers in the sub-section on aarch64-feature-modifiers,,-march and -mcpu Feature Modifiers. If you give conflicting feature modifiers, the right-most one wins ๐Ÿ‘‘.

GCC uses name to figure out what kinds of instructions it's allowed to emit when it writes assembly (same as -march), and which processor to tune performance for (same as -mtune) โœจ. If you use this option alongside -march or -mtune, those two win for their part of the job ๐Ÿซถ.

-mcpu=neoverse-512tvb is special, because it doesn't point at one specific core. It means all Neoverse cores that (a) implement SVE and (b) have a total vector bandwidth of 512 bits a cycle ๐Ÿฆ‹. Unless you override it with -march, -mcpu=neoverse-512tvb generates code that can run on a Neoverse V1 core, since Neoverse V1 is the first Neoverse core with these properties ๐Ÿ”ฅ. Unless you override it with -mtune, it tunes code the same way -mtune=neoverse-512tvb does.

๐Ÿงš -moverride=string

This lets you override tuning decisions the back-end made in response to a -mtune= switch ๐Ÿ”ง. The syntax, semantics and accepted values for string are not guaranteed to stay the same across releases ๐Ÿ˜ญ.

This option is only intended to be useful when developing GCC. Don't go poking at it in your regular builds, bestie ๐Ÿ’€.

๐ŸŽ€ -mverbose-cost-dump

Turns on verbose cost model dumping in the debug dump files ๐Ÿ”. It's there for debugging the compiler itself, so it's a compiler-dev kind of flex ๐Ÿง .

๐ŸŒท -mpc-relative-literal-loads, -mno-pc-relative-literal-loads

Enable or disable PC-relative literal loads ๐Ÿฆ‹. With this on, literal pools get accessed using a single instruction and get emitted after each function. The catch is that this caps function size at 1MB ๐Ÿ“. It's enabled by default for -mcmodel=tiny.

๐Ÿ“ -msign-return-address=scope

Picks the function scope that return address signing gets applied to ๐Ÿ”. The permissible values are:

  • none โ€” turns return address signing off ๐Ÿ™…
  • non-leaf โ€” turns on pointer signing for functions that aren't leaf functions ๐ŸŒฟ
  • all โ€” turns on pointer signing for every single function ๐Ÿ’œ

The default value is none.

Heads up, babe: this option has been deprecated in favour of -mbranch-protection ๐Ÿฅ€.

๐ŸŒˆ -mbranch-protection=none|standard|pac-ret[+leaf+b-key]|bti

Picks which branch protection features to use โœจ. Here's the lineup:

  • none โ€” the default, turns off all types of branch protection ๐Ÿ™ˆ
  • standard โ€” turns on all types of branch protection features. If a feature has extra tuning options, standard sets it to its standard level ๐Ÿ‘‘
  • pac-ret[+leaf] โ€” turns return address signing on to its standard level, signing functions that save the return address to memory (non-leaf functions will practically always do this) using the A-key ๐Ÿ”‘. The optional argument leaf extends the signing to include leaf functions ๐ŸŒฟ.
  • b-key โ€” the optional argument that signs the functions 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 options:

  • retbr
  • blr

On top of that, -mharden-sls=all enables all SLS hardening, and -mharden-sls=none disables all of it ๐Ÿšซ.

๐ŸŒธ -msve-vector-bits=bits

Specifies how many bits are in an SVE vector register ๐Ÿฆ‹. This option only does anything when SVE is enabled, so don't expect magic without it ๐Ÿ™ƒ.

GCC supports two flavours of SVE code generation โœจ:

  • "vector-length agnostic" output, which works with any size of vector register ๐ŸŒŠ
  • "vector-length specific" output, which lets GCC make assumptions about the vector length when that helps with optimization ๐ŸŽฏ

The possible values of bits are scalable, 128, 256, 512, 1024 and 2048 ๐Ÿ’…. Specifying scalable selects vector-length agnostic output. Right now, -msve-vector-bits=128 also generates vector-length agnostic output for big-endian targets ๐Ÿ™ˆ. All other values generate vector-length specific code. These behaviours may change in future releases, so no value except scalable should be relied on for code that needs to be portable across different hardware SVE vector lengths ๐Ÿ˜ญ.

The default is -msve-vector-bits=scalable, which produces vector-length agnostic code ๐Ÿฅฐ.


๐Ÿฆ‹ -march and -mcpu Feature Modifiers ๐Ÿฆ‹

Feature modifiers used with -march and -mcpu can be any of the ones below, and each one also has an inverse you can write as nofeature ๐Ÿ”„.

  • crc โ€” enables the CRC extension. This is on by default for -march=armv8.1-a ๐Ÿ”ข.
  • crypto โ€” enables the Crypto extension. This also enables Advanced SIMD and floating-point instructions ๐Ÿ”.
  • fp โ€” enables floating-point instructions. This is on by default for all possible values for options -march and -mcpu ๐Ÿ”ฅ.
  • simd โ€” enables Advanced SIMD instructions. This also enables floating-point instructions. This is on by default for all possible values for options -march and -mcpu ๐Ÿ’–.
  • sve โ€” enables Scalable Vector Extension instructions. This also enables Advanced SIMD and floating-point instructions ๐ŸŒŠ.
  • lse โ€” enables Large System Extension instructions. This is on by default for -march=armv8.1-a ๐Ÿงฉ.
  • rdma โ€” enables Round Double Multiply Accumulate instructions. This is on by default for -march=armv8.1-a โœ–๏ธ.
  • fp16 โ€” enables the FP16 extension. This also enables floating-point instructions ๐ŸŒก๏ธ.
  • fp16fml โ€” enables the FP16 fmla extension. This also enables FP16 extensions and floating-point instructions. This is enabled by default for -march=armv8.4-a. Using this with architectures prior to Armv8.2-A is not supported ๐Ÿ™….
  • rcpc โ€” enables the RcPc extension. This does not change code generation from GCC, but it gets passed on to the assembler, so inline asm statements can use instructions from the RcPc extension ๐Ÿงต.
  • dotprod โ€” enables the Dot Product extension. This also enables Advanced SIMD instructions ๐ŸŽฒ.
  • aes โ€” enables the Armv8-a aes and pmull crypto extension. This also enables Advanced SIMD instructions ๐Ÿ—๏ธ.
  • sha2 โ€” enables the Armv8-a sha2 crypto extension. This also enables Advanced SIMD instructions ๐Ÿง.
  • sha3 โ€” enables the sha512 and sha3 crypto extension. This also enables Advanced SIMD instructions. Using this with architectures prior to Armv8.2-A is not supported ๐Ÿšซ.
  • sm4 โ€” enables the sm3 and sm4 crypto extension. This also enables Advanced SIMD instructions. Using this with architectures prior to Armv8.2-A is not supported ๐Ÿ™ˆ.
  • profile โ€” enables the Statistical Profiling extension. This is only to enable the extension at the assembler level and does not affect code generation ๐Ÿ“Š.
  • rng โ€” enables the Armv8.5-a Random Number instructions. This is only to enable the extension at the assembler level and does not affect code generation ๐ŸŽฐ.
  • memtag โ€” enables the Armv8.5-a Memory Tagging Extensions. Using this with architectures prior to Armv8.5-A is not supported ๐Ÿท๏ธ.
  • sb โ€” enables the Armv8-a Speculation Barrier instruction. This is only to enable the extension at the assembler level and does not affect code generation. This is enabled by default for -march=armv8.5-a ๐Ÿšง.
  • ssbs โ€” enables the Armv8-a Speculative Store Bypass Safe instruction. This is only to enable the extension at the assembler level and does not affect code generation. This is enabled by default for -march=armv8.5-a ๐Ÿ›ก๏ธ.
  • predres โ€” enables the Armv8-a Execution and Data Prediction Restriction instructions. This is only to enable the extension at the assembler level and does not affect code generation. This is enabled by default for -march=armv8.5-a ๐Ÿ”ฎ.
  • sve2 โ€” enables the Armv8-a Scalable Vector Extension 2. This also enables SVE instructions ๐ŸŒŠ.
  • sve2-bitperm โ€” enables SVE2 bitperm instructions. This also enables SVE2 instructions ๐Ÿช„.
  • sve2-sm4 โ€” enables SVE2 sm4 instructions. This also enables SVE2 instructions ๐ŸŒฟ.
  • sve2-aes โ€” enables SVE2 aes instructions. This also enables SVE2 instructions ๐Ÿ—๏ธ.
  • sve2-sha3 โ€” enables SVE2 sha3 instructions. This also enables SVE2 instructions ๐Ÿงช.
  • tme โ€” enables the Transactional Memory Extension ๐Ÿงพ.
  • i8mm โ€” enables 8-bit Integer Matrix Multiply instructions. This also enables Advanced SIMD and floating-point instructions. This is enabled by default for -march=armv8.6-a. Using this with architectures prior to Armv8.2-A is not supported ๐Ÿ”ข.
  • f32mm โ€” enables 32-bit Floating point Matrix Multiply instructions. This also enables SVE instructions. Using this with architectures prior to Armv8.2-A is not supported ๐Ÿงฎ.
  • f64mm โ€” enables 64-bit Floating point Matrix Multiply instructions. This also enables SVE instructions. Using this with architectures prior to Armv8.2-A is not supported ๐Ÿงฎ.
  • bf16 โ€” enables brain half-precision floating-point instructions. This also enables Advanced SIMD and floating-point instructions. This is enabled by default for -march=armv8.6-a. Using this with architectures prior to Armv8.2-A is not supported ๐Ÿง โœจ.

Okay so crypto is literally a bundle deal ๐Ÿ’… crypto brings along aes, sha2, and simd, and simd brings fp with it. Going the other way, nofp drags nosimd out with it, and nosimd takes nocrypto, noaes, and nosha2 ๐Ÿ˜ญ๐Ÿซถ


๐ŸŒธ Adapteva Epiphany Options ๐ŸŒธ

These -m options are defined for Adapteva Epiphany โœจ

  • -mhalf-reg-file โ€” Bestie, this one says don't allocate any register in the range "r32"..."r63" ๐Ÿ™ˆ That lets your code run on hardware variants that don't have those registers, so it's giving compatibility.
  • -mprefer-short-insn-regs โ€” Prefers registers that make short instructions possible. ngl this can bump the instruction count, so overall code size might go down or up ๐Ÿคทโ€โ™€๏ธ
  • -mbranch-cost=num โ€” Sets the cost of branches to roughly num "simple" instructions. It's only a heuristic, so don't expect the same results across releases ๐Ÿฆ‹
  • -mcmove โ€” Turns on the generation of conditional moves ๐ŸŒˆ
  • -mnops=num โ€” Emits num NOPs before every other instruction it generates ๐Ÿงš
  • -mno-soft-cmpsf โ€” For single-precision floating-point comparisons, this emits an "fsub" instruction and checks the flags. It's faster than a software comparison, BUT it can give wrong answers with NaNs, or when two different small numbers subtract to zero. The default is -msoft-cmpsf, which is slower but IEEE-compliant software comparison, so it's the safe pick ๐Ÿ’–
  • -mstack-offset=num โ€” Sets the gap between the top of the stack and the stack pointer. For example, a value of 8 means the eight bytes in sp+0...sp+7 can be used by leaf functions without stack allocation. Anything other than 8 or 16 is untested and probably won't work ๐Ÿ’€ This option also changes the ABI, so building with a different stack offset than your libraries generally breaks things. It's handy for checking whether a different offset gives better code, but if you want to actually build working programs, the move is configuring the toolchain with the right --with-stack-offset=num option.
  • -mno-round-nearest โ€” Makes the scheduler assume the rounding mode is set to truncating. The default is -mround-nearest ๐Ÿ“
  • -mlong-calls โ€” Unless an attribute says otherwise, this assumes any call might be out of range of the b / bl instructions. So it loads the function address into a register before making the (otherwise direct) call. This is the default, and it's giving cautious ๐Ÿ‘‘
  • -mshort-calls โ€” Unless an attribute says otherwise, this assumes all direct calls are in range of the b / bl instructions, so those 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 FP mode gets provided and expected at function call and return time. Matching it to the mode you mostly need at function start can make your programs smaller and faster by skipping unnecessary mode switches ๐Ÿ”ฅ

mode can be one of the following values:

  • caller โ€” Any mode is valid at function entry, and it gets kept or restored when the function returns and when it calls other functions. This is super useful for libraries or compilation units you want to drop into programs with different FPU modes. Being able to use a single object file is worth the extra mode switching overhead, compared to a more specific choice ๐Ÿฆ‹
  • truncate โ€” The mode used for floating-point calculations with truncating (round toward zero) rounding. That includes floating-point to integer conversion ๐Ÿ’œ
  • round-nearest โ€” The mode used for floating-point calculations with round-to-nearest-or-even rounding ๐ŸŒธ
  • int โ€” The mode used to do 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. These turn off, 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 can be 4 or 8, and the default is 8. Heads up, this is an ABI change! Many library function interfaces are still unaffected, as long as they don't use SIMD vector modes in places that change the size 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 the general case ๐Ÿ˜ญ
  • -m1reg-reg โ€” Picks a register to hold the constant -1, which makes loading small negative constants and certain bitmasks faster. The 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. The supported values for gpu are:
    • fiji โ€” Compiles for GCN3 Fiji devices (gfx803) ๐Ÿ”ฅ
    • gfx900 โ€” Compiles for GCN5 Vega 10 devices (gfx900) ๐Ÿ‘‘
    • gfx906 โ€” Compiles for GCN5 Vega 20 devices (gfx906) โœจ
  • -mstack-size=bytes โ€” Specifies how many bytes of stack space get requested for each GPU thread (wave-front).
Beware! There may be lots of threads and limited memory available, so be careful with this one ๐Ÿ’€

The size of the stack allocation may also affect run-time performance. The default is 32KB when using OpenACC or OpenMP, and 1MB otherwise ๐ŸŒธ


๐Ÿงš ARC Options ๐Ÿงš

The following options control the architecture variant that code is being compiled for ๐Ÿ’œ

  • -mbarrel-shifter โ€” Generates instructions supported by the barrel shifter. This is the default unless -mcpu=ARC601 or -mcpu=ARCEM is in effect ๐ŸŒˆ
  • -mjli-always โ€” Forces a function call to use the jli_s instruction. This option is only valid 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. The supported values for cpu are:
    • arc600 โ€” Compiles for ARC600. Aliases: -mA6, -mARC600 ๐Ÿฆ‹
    • arc601 โ€” Compiles for ARC601. Alias: -mARC601 ๐Ÿฆ‹
    • arc700 โ€” Compiles for ARC700. Aliases: -mA7, -mARC700. This is the default when configured with --with-cpu=arc700 ๐Ÿ‘‘
    • arcem โ€” Compiles for ARC EM ๐ŸŒธ
    • archs โ€” Compiles for ARC HS ๐ŸŒธ
    • em โ€” Compiles for ARC EM CPU with no hardware extensions ๐Ÿ“
    • em4 โ€” Compiles for ARC EM4 CPU ๐Ÿ“
    • em4_dmips โ€” Compiles for ARC EM4 DMIPS CPU ๐Ÿ“
    • em4_fpus โ€” Compiles for ARC EM4 DMIPS CPU with the single-precision floating-point extension ๐Ÿ”ฅ
    • em4_fpuda โ€” Compiles for ARC EM4 DMIPS CPU with single-precision floating-point and double assist instructions ๐Ÿ”ฅ
    • hs โ€” Compiles for ARC HS CPU with no hardware extensions except the atomic instructions ๐Ÿ’…
    • hs34 โ€” Compiles for ARC HS34 CPU ๐Ÿ’…
    • hs38 โ€” Compiles for ARC HS38 CPU ๐Ÿ’…
    • hs38_linux โ€” Compiles for ARC HS38 CPU with all hardware extensions turned on ๐Ÿ’…
    • arc600_norm โ€” Compiles for ARC 600 CPU with "norm" instructions enabled โœจ
    • arc600_mul32x16 โ€” Compiles for ARC 600 CPU with "norm" and 32x16-bit multiply instructions enabled โœจ
    • arc600_mul64 โ€” Compiles for ARC 600 CPU with "norm" and "mul64"-family instructions enabled โœจ
    • arc601_norm โ€” Compiles for ARC 601 CPU with "norm" instructions enabled โœจ
    • arc601_mul32x16 โ€” Compiles for ARC 601 CPU with "norm" and 32x16-bit multiply instructions enabled โœจ
    • arc601_mul64 โ€” Compiles for ARC 601 CPU with "norm" and "mul64"-family instructions enabled โœจ
    • nps400 โ€” Compiles for ARC 700 on the NPS400 chip ๐ŸŒˆ
    • em_mini โ€” Compiles for an ARC EM minimalist configuration featuring a reduced register set ๐Ÿฅบ
  • -mdpfp, -mdpfp-compact โ€” Generates double-precision FPX instructions, tuned for the compact implementation ๐Ÿ’–
  • -mdpfp-fast โ€” Generates double-precision FPX instructions, tuned for the fast implementation โญ
  • -mno-dpfp-lrsr โ€” Disables "lr" and "sr" instructions from using FPX extension aux registers ๐Ÿ™ˆ
  • -mea โ€” Generates extended arithmetic instructions. Right now only "divaw", "adds", "subs", and "sat16" are supported. This is only valid for -mcpu=ARC700 ๐Ÿ”ฅ
  • -mno-mpy โ€” Doesn't generate "mpy"-family instructions for ARC700. This option is deprecated, so maybe skip it ๐Ÿ’€
  • -mmul32x16 โ€” Generates 32x16-bit multiply and multiply-accumulate instructions ๐Ÿฆ‹
  • -mmul64 โ€” Generates "mul64" and "mulu64" instructions. This is 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 through target-specific builtins. This is only valid for -mcpu=ARC700 ๐Ÿ‘‘
  • -msoft-float โ€” This option is ignored! It's only here for compatibility. Software floating-point code is emitted by default, and that default can be overridden by the FPX options: -mspfp, -mspfp-compact, or -mspfp-fast for single precision, and -mdpfp, -mdpfp-compact, or -mdpfp-fast for double precision ๐Ÿ™ˆ
  • -mswap โ€” ๐Ÿ”„ Generates swap instructions, bestie, so the vibe is "swap it up."
  • -matomic โ€” ๐Ÿ’ช This turns on the locked load/store conditional extension so the atomic memory built-in functions can be implemented with it. Not available for ARC 6xx or ARC EM cores ๐Ÿ™….
  • -mdiv-rem โ€” โž— Enables the div and rem instructions for ARCv2 cores.
  • -mcode-density โ€” ๐Ÿงƒ Enables code density instructions for ARC EM. This one is on by default for ARC HS.
  • -mll64 โ€” ๐Ÿ” Enables double load/store operations for ARC HS cores.
  • -mtp-regno=regno โ€” ๐Ÿงต Specifies the thread pointer register number.
  • -mmpy-option=multo โ€” โœ–๏ธ Compiles ARCv2 code with a multiplier design option. You can give multo as either a string or a numeric value. wlh1 is the default ๐Ÿ‘‘. This is only available for ARCv2 cores. The recognized values are:
    • 0 or none โ€” No multiplier available.
    • 1 or w โ€” 16x16 multiplier, fully pipelined. Enables mpyw and mpyuw.
    • 2 or wlh1 โ€” 32x32 multiplier, fully pipelined (1 stage). Additionally enables mpy, mpyu, mpym, mpymu, and mpy_s.
    • 3 or wlh2 โ€” 32x32 multiplier, fully pipelined (2 stages). Additionally enables mpy, mpyu, mpym, mpymu, and mpy_s.
    • 4 or wlh3 โ€” Two 16x16 multipliers, blocking, sequential. Additionally enables mpy, mpyu, mpym, mpymu, and mpy_s.
    • 5 or wlh4 โ€” One 16x16 multiplier, blocking, sequential. Additionally enables mpy, mpyu, mpym, mpymu, and mpy_s.
    • 6 or wlh5 โ€” One 32x4 multiplier, blocking, sequential. Additionally enables mpy, mpyu, mpym, mpymu, and mpy_s.
    • 7 or plus_dmpy โ€” ARC HS SIMD support. ๐ŸŒˆ
    • 8 or plus_macd โ€” ARC HS SIMD support. ๐ŸŒˆ
    • 9 or plus_qmacw โ€” ARC HS SIMD support. ๐ŸŒˆ
  • -mfpu=fpu โ€” ๐Ÿงฎ Turns on support for specific floating-point hardware extensions for ARCv2 cores. The supported values for fpu are:
    • fpus โ€” Enables support for single-precision floating-point hardware extensions.
    • fpud โ€” Enables support for double-precision floating-point hardware extensions. The single-precision floating-point extension is also enabled. Not available for ARC EM.
    • fpuda โ€” Enables support for double-precision floating-point hardware extensions using double-precision assist instructions. The single-precision floating-point extension is also enabled. Only available for ARC EM.
    • fpuda_div โ€” Enables support for double-precision floating-point hardware extensions using double-precision assist instructions. The single-precision floating-point, square-root, and divide extensions are also enabled. Only available for ARC EM.
    • fpuda_fma โ€” Enables support for double-precision floating-point hardware extensions using double-precision assist instructions. The single-precision floating-point and fused multiply and add hardware extensions are also enabled. Only available for ARC EM.
    • fpuda_all โ€” Enables support for double-precision floating-point hardware extensions using double-precision assist instructions. All single-precision floating-point hardware extensions are also enabled. Only available for ARC EM.
    • fpus_div โ€” Enables support for single-precision floating-point, square-root and divide hardware extensions.
    • fpud_div โ€” Enables support for double-precision floating-point, square-root and divide hardware extensions. This option includes option fpus_div. Not available for ARC EM.
    • fpus_fma โ€” Enables support for single-precision floating-point and fused multiply and add hardware extensions.
    • fpud_fma โ€” Enables support for double-precision floating-point and fused multiply and add hardware extensions. This option includes option fpus_fma. Not available for ARC EM.
    • fpus_all โ€” Enables support for all single-precision floating-point hardware extensions.
    • fpud_all โ€” Enables support for all single- and double-precision floating-point hardware extensions. Not available for ARC EM.
  • -mirq-ctrl-saved=register-range, blink, lp_count โ€” ๐Ÿ›ก๏ธ Specifies the general-purpose registers that the processor automatically saves and restores on interrupt entry and exit. register-range is written as two registers separated by a dash. The range always starts with r0, and the upper limit is the fp register. blink and lp_count are optional. This option is only valid for ARC EM and ARC HS cores.
  • -mrgf-banked-regs=number โ€” ๐Ÿฆ Specifies how many registers get replicated in the second register bank on entry to a fast interrupt. Fast interrupts are the ones with the highest priority level, P0. They only save the PC and STATUS32 registers so they can skip memory transactions during entry and exit. Use this when you're using fast interrupts on an ARC V2 family processor. Permitted values are 4, 8, 16, and 32.
  • -mlpc-width=width โ€” ๐Ÿ”ข Specifies the width of the lp_count register. Valid values for width are 8, 16, 20, 24, 28, and 32 bits. The default width is fixed to 32 bits. If the width is less than 32, the compiler won't try to transform your loops into the zero-delay loop mechanism unless it's known that the lp_count register can hold the required loop-counter value. Depending on the width you pick, the compiler and run-time library might still use the loop mechanism for various needs. This option defines the macro __ARC_LPC_WIDTH__ with the value of width.
  • -mrf16 โ€” ๐ŸŽ€ Tells the compiler to generate code for a 16-entry register file. This option defines the __ARC_RF16__ preprocessor macro.
  • -mbranch-index โ€” ๐Ÿชœ Enables use of bi or bih instructions to implement jump tables.

The following options are passed through to the assembler, and they also define preprocessor macro symbols. ๐Ÿงš

  • -mdsp-packa โ€” Passed down to the assembler to enable the DSP Pack A extensions. Also sets the preprocessor symbol __Xdsp_packa. This option is deprecated ๐Ÿ’€.
  • -mdvbf โ€” Passed down to the assembler to enable the dual Viterbi butterfly extension. Also sets the preprocessor symbol __Xdvbf. This option is deprecated ๐Ÿ’€.
  • -mlock โ€” Passed down to the assembler to enable the locked load/store conditional extension. Also sets the preprocessor symbol __Xlock.
  • -mmac-d16 โ€” Passed down to the assembler. Also sets the preprocessor symbol __Xxmac_d16. This option is deprecated ๐Ÿ’€.
  • -mmac-24 โ€” Passed down to the assembler. Also sets the preprocessor symbol __Xxmac_24. This option is deprecated ๐Ÿ’€.
  • -mrtsc โ€” Passed down to the assembler to enable the 64-bit time-stamp counter extension instruction. Also sets the preprocessor symbol __Xrtsc. This option is deprecated ๐Ÿ’€.
  • -mswape โ€” Passed down to the assembler to enable the swap byte ordering extension instruction. Also sets the preprocessor symbol __Xswape.
  • -mtelephony โ€” Passed down to the assembler to enable dual- and single-operand instructions for telephony. Also sets the preprocessor symbol __Xtelephony. This option is deprecated ๐Ÿ’€.
  • -mxy โ€” Passed down to the assembler to enable the XY memory extension. Also sets the preprocessor symbol __Xxy.

The following options control how the assembly code gets annotated ๐Ÿ“:

  • -misize โ€” Annotates assembler instructions with estimated addresses.
  • -mannotate-align โ€” Explains what alignment considerations led to the decision to make an instruction short or long.

The following options are passed through to the linker ๐Ÿ”—:

  • -marclinux โ€” Passed through to the linker to specify use of the arclinux emulation. This is enabled by default in tool chains built for arc-linux-uclibc and arceb-linux-uclibc targets when profiling is not requested.
  • -marclinux_prof โ€” Passed through to the linker to specify use of the arclinux_prof emulation. This is enabled by default in tool chains built for arc-linux-uclibc and arceb-linux-uclibc targets when profiling is requested.

The following options control the semantics of the generated code ๐Ÿง :

  • -mlong-calls โ€” Generates calls as register indirect calls, which gives access to the full 32-bit address range.
  • -mmedium-calls โ€” Doesn't use less than a 25-bit addressing range for calls, which is the offset available for an unconditional branch-and-link instruction. Conditional execution of function calls is suppressed so the 25-bit range can be used, instead of the 21-bit range you'd get with conditional branch-and-link. This is the default for tool chains built for arc-linux-uclibc and arceb-linux-uclibc targets.
  • -G num โ€” Puts definitions of externally-visible data in a small data section if that data is no bigger than num bytes. The default value of num is 4 for any ARC configuration, or 8 when double load/store operations are available.
  • -mno-sdata โ€” Doesn't generate sdata references. This is the default for tool chains built for arc-linux-uclibc and arceb-linux-uclibc targets.
  • -mvolatile-cache โ€” Uses ordinarily cached memory accesses for volatile references. This is the default ๐Ÿ’œ.
  • -mno-volatile-cache โ€” Enables cache bypass for volatile references.

The following options fine-tune code generation โœจ:

  • -malign-call โ€” Does alignment optimizations for call instructions.
  • -mauto-modify-reg โ€” Enables the use of pre/post modify with register displacement.
  • -mbbit-peephole โ€” Enables bbit peephole2.
  • -mno-brcc โ€” This option disables a target-specific pass in arc_reorg that generates compare-and-branch (brcc) instructions. It has no effect on the generation of these instructions when they're driven by the combiner pass.

-mcase-vector-pcrel okay so this one turns on PC-relative switch case tables ๐Ÿฆ‹ so the switch case tables can get shortened โœจ this is the default for -Os ๐Ÿ’…

  • -mcase-vector-pcrel โ€” switch case tables go PC-relative, which lets the compiler shrink them ๐ŸŒธ
  • -mcompact-casesi โ€” turns on the compact casesi pattern ๐ŸŽ€ default for -Os, and it's only available for ARCv1 cores ๐Ÿ’€ this option is deprecated ๐Ÿ˜ญ
  • -mno-cond-exec โ€” switches off the ARCompact-only pass that generates conditional execution instructions ๐Ÿ™ˆ

okay this one is kinda a lot, bestie ๐Ÿซถ the target-independent conditional execution pass is often lacking on ARC because of delay slot scheduling and the interplay between operand numbers, literal sizes, instruction lengths, and conditional execution support ๐Ÿ’– so the ARC port keeps a special pass around that hunts for extra conditional execution chances after register allocation, branch shortening, and delay slot scheduling are done โœจ it generally (not always!) makes performance and code size better, but it costs extra compile time, which is why you can switch it off ๐Ÿ“

โš ๏ธ if call instructions blow past their allowed offset range because they got conditionalized, try -mmedium-calls instead ๐Ÿ˜ญ
  • -mearly-cbranchsi โ€” enables pre-reload use of the cbranchsi pattern ๐Ÿงš
  • -mexpand-adddi โ€” expands adddi3 and subdi3 at RTL generation time into add.f, adc etc. ๐Ÿ’… this option is deprecated ๐Ÿ’€
  • -mindexed-loads โ€” enables indexed loads ๐ŸŒˆ heads up, this can be problematic because some optimizers then assume indexed stores exist, and they don't ๐Ÿ™ˆ
  • -mlra โ€” enables Local Register Allocation ๐Ÿ”ฅ still experimental for ARC, so by default the compiler uses standard reload (that's -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 (-Os), prologues and epilogues that have to save or restore a ton of registers often get shortened by calling a special function in libgcc, and that's called 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 โ€” lets the compiler emit enter and leave instructions โœจ these are only valid for CPUs with the code-density feature ๐Ÿ’€
  • -mmixed-code โ€” tweaks register allocation to help 16-bit instruction generation ๐Ÿงš it usually makes the average instruction size smaller while the instruction count goes up ๐Ÿ“
  • -mq-class โ€” deprecated ๐Ÿ˜ญ enables q instruction alternatives, and it's 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 around instruction lengths and alignment ๐Ÿ”ฅ the values for level are:
    • 0 โ€” no size optimization. deprecated, and it's treated like 1 ๐Ÿ’€
    • 1 โ€” short instructions get used opportunistically โœจ
    • 2 โ€” on top of that, alignment of loops and of code after barriers gets dropped ๐Ÿฆ‹
    • 3 โ€” on top of that, optional data alignment gets dropped, and the option Os is enabled ๐Ÿ‘‘

it defaults to 3 when -Os is in effect ๐Ÿ’… otherwise, leaving it unset works the same as level 1 ๐ŸŒธ

  • -mtune=cpu โ€” sets instruction scheduling parameters for cpu, overriding anything implied by -mcpu= ๐ŸŽ€

supported values for cpu are:

  • ARC600 โ€” tunes for the ARC600 CPU ๐Ÿงš
  • ARC601 โ€” tunes for the ARC601 CPU ๐Ÿฆ‹
  • ARC700 โ€” tunes for the ARC700 CPU with the standard multiplier block ๐Ÿ’œ
  • ARC700-xmac โ€” tunes for the ARC700 CPU with the XMAC block ๐ŸŒˆ
  • ARC725D โ€” tunes for the ARC725D CPU โœจ
  • ARC750D โ€” tunes for the ARC750D CPU ๐Ÿ‘‘
  • -mmultcost=num โ€” the cost to assume for a multiply instruction, with 4 being equal to a normal instruction ๐Ÿ“
  • -munalign-prob-threshold=probability โ€” sets the probability threshold for unaligning branches ๐Ÿซถ when tuning for ARC700 and optimizing for speed, branches without a filled delay slot are preferably emitted unaligned and long, unless profiling says the probability of the branch being taken is below probability ๐Ÿ’– the default is (REG_BR_PROB_BASE/2), i.e. 5000 ๐Ÿ”ฅ

the following options are kept around for backward compatibility, but they're now deprecated and will be removed in a future release ๐Ÿ˜ญ๐Ÿฅ€

  • -margonaut โ€” obsolete FPX ๐Ÿ’€
  • -mbig-endian, -EB โ€” compile code for big-endian targets ๐ŸŒˆ using these is now deprecated ๐Ÿ˜ญ big-endian code is supported by configuring GCC to build the arceb-elf32 and arceb-linux-uclibc targets, where big endian is the default ๐Ÿฆ‹
  • -mlittle-endian, -EL โ€” compile code for little-endian targets ๐Ÿ’œ using these is now deprecated ๐Ÿ˜ญ little-endian code is supported by configuring GCC to build the arc-elf32 and arc-linux-uclibc targets, where little endian is the default ๐Ÿงš
  • -mbarrel_shifter โ€” replaced by -mbarrel-shifter ๐ŸŽ€
  • -mdpfp_compact โ€” replaced by -mdpfp-compact ๐ŸŒธ
  • -mdpfp_fast โ€” replaced by -mdpfp-fast โœจ
  • -mdsp_packa โ€” replaced by -mdsp-packa ๐Ÿซถ
  • -mEA โ€” replaced by -mea ๐Ÿ“
  • -mmac_24 โ€” replaced by -mmac-24 ๐Ÿ’…
  • -mmac_d16 โ€” replaced by -mmac-d16 ๐Ÿ”ฅ
  • -mspfp_compact โ€” replaced by -mspfp-compact ๐Ÿฆ‹
  • -mspfp_fast โ€” replaced by -mspfp-fast ๐Ÿ‘‘
  • -mtune=cpu โ€” the values arc600, arc601, arc700 and arc700-xmac for cpu are replaced by ARC600, ARC601, ARC700 and ARC700-xmac respectively ๐Ÿ’–
  • -multcost=num โ€” replaced by -mmultcost ๐ŸŒˆ

โœจ ARM Options โœจ

these -m options are defined for the ARM port ๐ŸŒธ

  • -mabi=name โ€” generates code for the specified ABI ๐ŸŽ€ permissible values are: apcs-gnu, atpcs, aapcs, aapcs-linux and iwmmxt ๐Ÿ’…
  • -mapcs-frame โ€” generates a stack frame that follows the ARM Procedure Call Standard for all functions, even if it isn't strictly needed for the code to run correctly ๐Ÿฆ‹ combining it with -fomit-frame-pointer means stack frames aren't generated for leaf functions ๐Ÿงš the default is -mno-apcs-frame ๐Ÿ’€ this option is deprecated ๐Ÿ˜ญ
  • -mapcs โ€” a synonym for -mapcs-frame, and it's deprecated ๐Ÿ™ˆ
  • -mthumb-interwork โ€” generates code that supports calling between the ARM and Thumb instruction sets ๐ŸŒˆ without this, on pre-v5 architectures, the two instruction sets can't be reliably used inside one program ๐Ÿ’œ the default is -mno-thumb-interwork, since the code gets slightly bigger when -mthumb-interwork is on ๐Ÿ“ in AAPCS configurations this option is meaningless ๐Ÿ’€
  • -mno-sched-prolog โ€” stops the reordering of instructions in the function prologue, and stops merging those instructions with the ones in the function's body ๐Ÿซถ that means every function starts with a recognizable set of instructions (or one of a small set of prologues), so you can use that to find where functions start in an executable chunk of code ๐Ÿ”ฅ the default is -msched-prolog โœจ
  • -mfloat-abi=name โ€” picks which floating-point ABI to use ๐ŸŽ€ permissible values are: soft, softfp and hard ๐Ÿ’…
    • soft โ€” GCC generates output with library calls for floating-point operations ๐ŸŒธ
    • softfp โ€” allows hardware floating-point instructions, but still uses the soft-float calling conventions ๐Ÿฆ‹
    • hard โ€” allows floating-point instructions and uses FPU-specific calling conventions ๐Ÿ‘‘

the default depends on the specific target configuration ๐Ÿงš the hard-float and soft-float ABIs are NOT link-compatible ๐Ÿ˜ญ you have to compile your whole program with the same ABI and link with a compatible set of libraries ๐Ÿ’€

  • -mgeneral-regs-only โ€” generates code that only uses the general-purpose registers ๐Ÿ’– this stops the compiler from using floating-point and Advanced SIMD registers, but it won't put any restrictions on the assembler ๐ŸŒˆ
  • -mlittle-endian โ€” generates code for a processor running in little-endian mode ๐Ÿ’œ this is the default for all standard configurations ๐Ÿ“
  • -mbig-endian โ€” generates code for a processor running in big-endian mode ๐Ÿซถ the default is to compile for a little-endian processor ๐Ÿ”ฅ
  • -mbe8, -mbe32 โ€” when linking a big-endian image, selects between the BE8 and BE32 formats ๐ŸŽ€ it has no effect on little-endian images and gets ignored there โœจ the default depends on the selected target architecture ๐Ÿฆ‹ for ARMv6 and later the default is BE8, and for older architectures the default is BE32 ๐Ÿ‘‘ BE32 format has been deprecated by ARM ๐Ÿ˜ญ
  • -march=name[+extension...] โ€” specifies the name of the target ARM architecture ๐ŸŒธ GCC uses this name to figure out what kinds of instructions it can emit when generating assembly code ๐Ÿงš this option can be used together with, or instead of, -mcpu= ๐Ÿ’…

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, armv7-r, armv8-r, armv6-m, armv6s-m, armv7-m, armv7e-m, armv8-m.base, armv8-m.main, armv8.1-m.main, iwmmxt and iwmmxt2 ๐Ÿซถ

also, these architectures don't support the Thumb execution state, so they're recognized but support is deprecated: armv4 ๐Ÿ’€

lots of the architectures support extensions ๐ŸŒˆ you can add them by appending +extension to the architecture name ๐Ÿ’œ extension options get processed in order and capabilities pile up ๐Ÿ“ an extension also turns on any base extensions it depends on, like how +crypto will always turn on +simd ๐Ÿ”ฅ the exception to the stacking rule is extensions prefixed with +no..., which switch off the specified option and any other extensions that depend on it ๐Ÿ‘‘ periodt ๐Ÿ’…โœจ

For example, -march=armv7-a+simd+nofp+vfpv4 is the same as -march=armv7-a+vfpv4 ๐Ÿ’… because the +nofp that comes after +simd wipes out +simd completely ๐Ÿ’€ lowkey a trap if you're not paying attention ๐Ÿ™ˆ

Most extension names are generic, but what they actually do depends on which architecture they're attached to ๐Ÿฆ‹ For example, +simd works on both armv7-a and armv8-a. On armv7-a it gives you the original ARMv7-A Advanced SIMD (Neon) extensions, and on armv8-a it gives you the ARMv8-A version โœจ

Here's the tea โ˜• The table below lists the supported extensions for each architecture. Any architecture that isn't mentioned doesn't support any extensions at all ๐Ÿฅฒ

armv5te, armv6, armv6j, armv6k, armv6kz, armv6t2, armv6z, armv6zk ๐ŸŒธ

  • +fp โ€” The VFPv2 floating-point instructions. You can also use +vfpv2 as an alias for this one ๐ŸŽ€
  • +nofp โ€” Turns off the floating-point instructions ๐Ÿšซ

armv7 ๐ŸŒˆ

The common subset of the ARMv7-A, ARMv7-R and ARMv7-M architectures, so it's the baseline everyone shares ๐Ÿซถ

  • +fp โ€” The VFPv3 floating-point instructions, with 16 double-precision registers. You can use +vfpv3-d16 as an alias for this one. Heads up: floating-point isn't supported by the base ARMv7-M architecture, but it is compatible with both ARMv7-A and ARMv7-R ๐Ÿ‘€
  • +nofp โ€” Turns off the floating-point instructions ๐Ÿšซ

armv7-a ๐Ÿ‘‘

  • +mp โ€” The multiprocessing extension ๐Ÿง 
  • +sec โ€” The security extension ๐Ÿ”’
  • +fp โ€” The VFPv3 floating-point instructions, with 16 double-precision registers. +vfpv3-d16 works as an alias here too โœจ
  • +simd โ€” The Advanced SIMD (Neon) v1 and the VFPv3 floating-point instructions. +neon and +neon-vfpv3 can both be used as aliases for this one ๐Ÿ”ฅ
  • +vfpv3 โ€” The VFPv3 floating-point instructions, with 32 double-precision registers ๐Ÿ’–
  • +vfpv3-d16-fp16 โ€” The VFPv3 floating-point instructions, with 16 double-precision registers plus the half-precision floating-point conversion operations ๐Ÿงš
  • +vfpv3-fp16 โ€” The VFPv3 floating-point instructions, with 32 double-precision registers plus the half-precision floating-point conversion operations ๐Ÿงš
  • +vfpv4-d16 โ€” The VFPv4 floating-point instructions, with 16 double-precision registers ๐Ÿฆ‹
  • +vfpv4 โ€” The VFPv4 floating-point instructions, with 32 double-precision registers ๐Ÿฆ‹
  • +neon-fp16 โ€” The Advanced SIMD (Neon) v1 and the VFPv3 floating-point instructions, plus the half-precision floating-point conversion operations ๐Ÿ“
  • +neon-vfpv4 โ€” The Advanced SIMD (Neon) v2 and the VFPv4 floating-point instructions ๐Ÿ’œ
  • +nosimd โ€” Turns off the Advanced SIMD instructions. Floating point stays on though, so it doesn't touch that part ๐Ÿ™…
  • +nofp โ€” Turns off the floating-point and Advanced SIMD instructions ๐Ÿšซ

armv7ve ๐Ÿ’…

The extended version of the ARMv7-A architecture, with support for virtualization ๐ŸŒธ

  • +fp โ€” The VFPv4 floating-point instructions, with 16 double-precision registers. +vfpv4-d16 works as an alias here โœจ
  • +simd โ€” The Advanced SIMD (Neon) v2 and 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 โ€” The VFPv3 floating-point instructions, with 16 double-precision registers plus the half-precision floating-point conversion operations ๐Ÿงš
  • +vfpv3-fp16 โ€” The VFPv3 floating-point instructions, with 32 double-precision registers plus the half-precision floating-point conversion operations ๐Ÿงš
  • +vfpv4-d16 โ€” The VFPv4 floating-point instructions, with 16 double-precision registers ๐Ÿฆ‹
  • +vfpv4 โ€” The VFPv4 floating-point instructions, with 32 double-precision registers ๐Ÿฆ‹
  • +neon โ€” The Advanced SIMD (Neon) v1 and the VFPv3 floating-point instructions. +neon-vfpv3 can be used as an alias for this one ๐ŸŽ€
  • +neon-fp16 โ€” The Advanced SIMD (Neon) v1 and the VFPv3 floating-point instructions, plus the half-precision floating-point conversion operations ๐Ÿ“
  • +nosimd โ€” Turns off the Advanced SIMD instructions. Floating point stays on ๐Ÿ™…
  • +nofp โ€” Turns off the floating-point and Advanced SIMD instructions ๐Ÿšซ

armv8-a ๐ŸŒŸ

  • +crc โ€” The Cyclic Redundancy Check (CRC) instructions ๐Ÿงฎ
  • +simd โ€” The ARMv8-A Advanced SIMD and floating-point instructions ๐Ÿ”ฅ
  • +crypto โ€” The cryptographic instructions ๐Ÿ”
  • +nocrypto โ€” Turns off the cryptographic instructions ๐Ÿšซ
  • +nofp โ€” Turns off the floating-point, Advanced SIMD and cryptographic instructions ๐Ÿšซ
  • +sb โ€” The Speculation Barrier instruction ๐Ÿ›ก๏ธ
  • +predres โ€” The Execution and Data Prediction Restriction instructions ๐Ÿ›ก๏ธ

armv8.1-a ๐Ÿฆ‹

  • +simd โ€” The ARMv8.1-A Advanced SIMD and floating-point instructions ๐Ÿ”ฅ
  • +crypto โ€” The cryptographic instructions. This also turns on the Advanced SIMD and floating-point instructions ๐Ÿ”
  • +nocrypto โ€” Turns off the cryptographic instructions ๐Ÿšซ
  • +nofp โ€” Turns off 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 ๐Ÿ’œ

  • +fp16 โ€” The half-precision floating-point data processing instructions. This also turns on the Advanced SIMD and floating-point instructions ๐Ÿ“
  • +fp16fml โ€” The half-precision floating-point fmla extension. This also turns on the half-precision floating-point extension, plus the Advanced SIMD and floating-point instructions ๐Ÿ“
  • +simd โ€” The ARMv8.1-A Advanced SIMD and floating-point instructions ๐Ÿ”ฅ
  • +crypto โ€” The cryptographic instructions. This also turns on the Advanced SIMD and floating-point instructions ๐Ÿ”
  • +dotprod โ€” Enables the Dot Product extension. This also turns on Advanced SIMD instructions โœจ
  • +nocrypto โ€” Turns off the cryptographic extension ๐Ÿšซ
  • +nofp โ€” Turns off 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 turns on Advanced SIMD and floating-point instructions ๐ŸŒˆ
  • +bf16 โ€” The Brain half-precision floating-point instructions. This also turns on Advanced SIMD and floating-point instructions ๐Ÿง 

armv8.4-a ๐ŸŒธ

  • +fp16 โ€” The half-precision floating-point data processing instructions. This also turns on 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 turns on the Advanced SIMD and floating-point instructions, plus the Dot Product extension ๐Ÿ”
  • +nocrypto โ€” Turns off the cryptographic extension ๐Ÿšซ
  • +nofp โ€” Turns off 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 turns on Advanced SIMD and floating-point instructions ๐ŸŒˆ
  • +bf16 โ€” The Brain half-precision floating-point instructions. This also turns on Advanced SIMD and floating-point instructions ๐Ÿง 

armv8.5-a ๐Ÿงš

  • +fp16 โ€” The half-precision floating-point data processing instructions. This also turns on 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 turns on the Advanced SIMD and floating-point instructions, plus the Dot Product extension ๐Ÿ”
  • +nocrypto โ€” Turns off the cryptographic extension ๐Ÿšซ
  • +nofp โ€” Turns off the floating-point, Advanced SIMD and cryptographic instructions ๐Ÿšซ
  • +i8mm โ€” The 8-bit Integer Matrix Multiply instructions. This also turns on Advanced SIMD and floating-point instructions ๐ŸŒˆ
  • +bf16 โ€” The Brain half-precision floating-point instructions. This also turns on Advanced SIMD and floating-point instructions ๐Ÿง 
  • armv8.6-a ๐Ÿ’œ
    • +fp16 โ€” the half-precision floating-point data processing instructions ๐Ÿซถ This also turns on the Advanced SIMD and floating-point instructions, plus the Dot Product extension and the half-precision fmla extension.
    • +simd โ€” the ARMv8.3-A Advanced SIMD and floating-point instructions, along with the Dot Product extension โœจ
    • +crypto โ€” the cryptographic instructions ๐Ÿ” This also enables the Advanced SIMD and floating-point instructions and the Dot Product extension.
    • +nocrypto โ€” turns off the cryptographic extension ๐Ÿ™…โ€โ™€๏ธ
    • +nofp โ€” turns off the floating-point, Advanced SIMD and cryptographic instructions all at once ๐Ÿ’€
    • +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.
  • armv7-r ๐ŸŒธ
    • +fp.sp โ€” the single-precision VFPv3 floating-point instructions ๐Ÿฆ‹ +vfpv3xd works as an alias for this one.
    • +fp โ€” the VFPv3 floating-point instructions with 16 double-precision registers ๐ŸŽ€ +vfpv3-d16 works as an alias for this one.
    • +vfpv3xd-d16-fp16 โ€” the single-precision VFPv3 floating-point instructions with 16 double-precision registers, plus the half-precision floating-point conversion operations โœจ
    • +vfpv3-d16-fp16 โ€” the VFPv3 floating-point instructions with 16 double-precision registers, plus the half-precision floating-point conversion operations ๐ŸŒˆ
    • +nofp โ€” 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 ๐Ÿ”ฅ
    • +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, based on the numbers you pass 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, based on the numbers you pass 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 ๐Ÿ’€

-march=native tells the compiler to auto-detect the architecture of the build computer ๐Ÿ•ต๏ธโ€โ™€๏ธ Heads up: right now this only works on GNU/Linux, and not every architecture gets recognized. If the auto-detect doesn't work out, the option has no effect ๐Ÿฅฒ


-mtune=name

This one tells GCC which target ARM processor to tune the performance of your code for ๐ŸŽฏ On some ARM implementations you can get better performance by using it. The permissible names are:

arm7tdmi, arm7tdmi-s, arm710t,
arm720t, arm740t, strongarm, strongarm110, strongarm1100,
0strongarm1110, arm8, arm810, arm9, arm9e, arm920, arm920t, arm922t,
arm946e-s, arm966e-s, arm968e-s, arm926ej-s, arm940t, arm9tdmi,
arm10tdmi, arm1020t, arm1026ej-s, arm10e, arm1020e, arm1022e,
arm1136j-s, arm1136jf-s, mpcore, mpcorenovfp, arm1156t2-s,
arm1156t2f-s, arm1176jz-s, arm1176jzf-s, generic-armv7-a, cortex-a5,
cortex-a7, cortex-a8, cortex-a9, cortex-a12, cortex-a15, cortex-a17,
cortex-a32, cortex-a35, cortex-a53, cortex-a55, cortex-a57,
cortex-a72, cortex-a73, cortex-a75, cortex-a76, cortex-a76ae,
cortex-a77, ares, cortex-r4, cortex-r4f, cortex-r5, cortex-r7,
cortex-r8, cortex-r52, cortex-m0, cortex-m0plus, cortex-m1,
cortex-m3, cortex-m4, cortex-m7, cortex-m23, cortex-m33,
cortex-m35p, cortex-m55, cortex-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.

Oh, and it can also tune for a big.LITTLE system ๐Ÿงฉ The names for those are:

cortex-a15.cortex-a7, cortex-a17.cortex-a7,
cortex-a57.cortex-a53, cortex-a72.cortex-a53, cortex-a72.cortex-a35,
cortex-a73.cortex-a53, cortex-a75.cortex-a55, cortex-a76.cortex-a55.

-mtune=generic-arch tells GCC to tune for a blend of processors within the architecture arch ๐ŸŒˆ The goal is code that runs well on the most popular processors right now, balancing optimizations that help some CPUs in the range while dodging the performance pitfalls of others. The effects of this option may change in future GCC versions as CPU models come and go ๐Ÿ”„

-mtune takes the same extension options as -mcpu, but the extension options don't affect how the generated code gets tuned ๐Ÿ™ƒ

-mtune=native tells the compiler to auto-detect the CPU of the build computer ๐Ÿ‘€ Same catch as before: it's only supported on GNU/Linux, not every architecture is recognized, and if the auto-detect fails the option has no effect ๐Ÿ’”


-mcpu=name[+extension...]

This specifies the name of the target ARM processor ๐Ÿ‘‘ GCC uses that name to figure out the target ARM architecture (like -march would) and the ARM processor type to tune performance for (like -mtune would). If you use this option alongside -march or -mtune, those win for their part of the job ๐Ÿ†

Lots of the supported CPUs have optional architectural extensions, and those are usually enabled by default โœ… If there are implementations that lack the extension, you can use the extension syntax to switch off the ones that are missing. For floating-point and Advanced SIMD (Neon) instructions, you also have to think about -mfloat-abi and -mfpu: floating-point and Advanced SIMD instructions only get used if -mfloat-abi isn't set to soft, and any -mfpu setting other than auto will override the available floating-point and SIMD extension instructions ๐Ÿง

For example, cortex-a9 shows up in three main configurations: integer only, with just a floating-point unit, or with floating-point and Advanced SIMD ๐Ÿง  All the instructions are enabled by default, but you can use +nosimd and +nofp to disable just the SIMD instructions, or both the SIMD and floating-point instructions, respectively ๐Ÿ™Œ

The permissible names for this option are the same as the ones for -mtune ๐Ÿ“

The following extension options are common to the listed CPUs ๐Ÿ’œ

  • +nodsp โ€” disables the DSP instructions on cortex-m33 and cortex-m35p ๐Ÿ™…โ€โ™€๏ธ
  • +nofp โ€” disables the floating-point instructions on arm9e, arm946e-s, arm966e-s, arm968e-s, arm10e, arm1020e, arm1022e, arm926ej-s, arm1026ej-s, cortex-r5, cortex-r7, cortex-r8, cortex-m4, cortex-m7, cortex-m33 and cortex-m35p ๐Ÿ’€ It also disables the floating-point and SIMD instructions on generic-armv7-a, cortex-a5, cortex-a7, cortex-a8, cortex-a9, cortex-a12, cortex-a15, cortex-a17, cortex-a15.cortex-a7, cortex-a17.cortex-a7, cortex-a32, cortex-a35, cortex-a53 and cortex-a55 ๐Ÿ˜ญ
  • +nofp.dp โ€” disables the double-precision part of the floating-point instructions on cortex-r5, cortex-r7, cortex-r8, cortex-r52 and cortex-m7 ๐Ÿฅบ
  • +nosimd โ€” disables the SIMD instructions (but not the floating-point ones) 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 ๐Ÿ”

On top of that, the generic-armv7-a pseudo target defaults to VFPv3 with 16 double-precision registers โœจ It supports these extension options: mp, sec, vfpv3-d16, vfpv3, vfpv3-d16-fp16, vfpv3-fp16, vfpv4-d16, vfpv4, neon, neon-vfpv3, neon-fp16 and neon-vfpv4. They mean the same thing as the extensions to -march=armv7-a ๐ŸŽ€

-mcpu=generic-arch is also allowed, and it's equivalent to -march=arch -mtune=generic-arch. Check out -mtune for more info ๐Ÿฆ‹

okay so -mcpu=native is giving auto-pilot ๐Ÿ’… It tells the compiler to auto-detect the CPU of the build computer ๐Ÿ–ฅ๏ธ ngl, this only works on GNU/Linux ๐Ÿง for now, and not every architecture gets recognized ๐Ÿฅฒ. If the auto-detect doesn't land, the option just has no effect. no drama ๐Ÿซถ

  • -mfpu=name โ€” bestie, this is where you tell GCC what floating-point hardware (or hardware emulation) the target actually has ๐Ÿงฎโœจ Your options 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. Note that neon is an alias for neon-vfpv3 and vfp is an alias for vfpv2 ๐Ÿ’–

auto is the default and it's so special ๐Ÿฆ‹ It makes the compiler pick the floating-point and Advanced SIMD instructions based on your -mcpu and -march settings.

If your floating-point hardware has the NEON extension (like -mfpu=neon), heads up: floating-point operations won't be generated by GCC's auto-vectorization pass 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 (in particular, denormal values get treated as zero), so using NEON instructions may lead to a loss of precision ๐Ÿ˜ญ

You can also set the fpu name at function level by using the target("fpu=") function attributes or pragmas ๐ŸŒธ

  • -mfp16-format=name โ€” this sets the format of the __fp16 half-precision floating-point type ๐Ÿ“ Your names are none, ieee, and alternative. The default is none, which means the __fp16 type isn't defined at all ๐Ÿ™ƒ
  • -mstructure-size-boundary=n โ€” all structures and unions get rounded up to a multiple of the number of bits you set here ๐Ÿ“ Permissible values are 8, 32 and 64. The default varies between toolchains; for the COFF targeted toolchain it's 8. A value of 64 is only allowed if the underlying ABI supports it. Going bigger can give you faster, more efficient code, but it can also increase the size of your program ๐Ÿ˜ Different values are potentially incompatible, too. Code compiled with one value can't necessarily be expected to work with code or libraries compiled with another if they exchange info using structures or unions ๐Ÿ’€
Deprecated โ€” this option is deprecated ๐Ÿฅ€
  • -mabort-on-noreturn โ€” generates a call to the function abort at the end of a noreturn function ๐Ÿงจ It gets executed if the function tries to return.
  • -mlong-calls, -mno-long-calls โ€” tells the compiler to perform function calls by first loading the address of the function into a register, and then performing a subroutine call on that register ๐Ÿ“ž You need this switch if the target function lies outside the 64-megabyte addressing range of the offset-based version of the subroutine call instruction. Even with this switch enabled, not all function calls become long calls ๐Ÿ™…โ€โ™€๏ธ The heuristic is that static functions, functions that have the short_call attribute, functions inside the scope of a #pragma no_long_calls directive, and functions whose definitions have already been compiled within the current compilation unit are not turned into long calls. The exceptions are weak function definitions, functions with the long_call attribute or the section attribute, and functions within the scope of a #pragma long_calls directive, which are always turned into long calls ๐Ÿ‘‘ This feature is not enabled by default. -mno-long-calls restores the default behavior, as does placing the function calls within the scope of a #pragma long_calls_off directive ๐Ÿงน Also, note these switches have no effect on how the compiler generates code to handle function calls via function pointers ๐Ÿซ 
  • -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 โ€” specifies the register to be used for PIC addressing ๐ŸŽฏ For the standard PIC base case, the default is any suitable register determined by the compiler. For the single PIC base case, the default is R9 if the target is EABI based or stack-checking is enabled, otherwise the default is R10.
  • -mpic-data-is-text-relative โ€” assumes the displacement between the text and data segments is fixed at static link time ๐Ÿงท This permits using PC-relative addressing operations to access data known to be in the data segment. For non-VxWorks RTP targets, this option is enabled by default. When it's disabled on such targets, it will enable -msingle-pic-base by default.
  • -mpoke-function-name โ€” writes the name of each function into the text section, directly preceding the function prologue โœ๏ธ The generated code is similar to 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 performing a stack backtrace, code can inspect 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, then we know that there is a function name embedded immediately preceding this location, and it has length ((pc[-3]) & 0xff000000) ๐Ÿ” iykyk ๐Ÿงš

  • -mthumb, -marm โ€” selects between generating code that executes in ARM and Thumb states ๐ŸŒˆ The default for most configurations is ARM state, but you can change it by configuring GCC with the --with-mode=state configure option. You can also override the ARM and Thumb mode for each function using the target("thumb") and target("arm") function attributes or pragmas โœจ
  • -mflip-thumb โ€” switches ARM/Thumb modes on alternating functions ๐Ÿ”€ This one is for regression testing of mixed Thumb/ARM code generation, and it is not intended for ordinary use when compiling code ๐Ÿšซ
  • -mtpcs-frame โ€” generates a stack frame that is compliant with the Thumb Procedure Call Standard for all non-leaf functions. (A leaf function is one that does not call any other functions ๐Ÿƒ) The default is -mno-tpcs-frame.
  • -mtpcs-leaf-frame โ€” generates a stack frame that is compliant with the Thumb Procedure Call Standard for all leaf functions. (A leaf function is one that does not call any other functions.) The default is -mno-apcs-leaf-frame.
  • -mcallee-super-interworking โ€” gives all externally visible functions in the file being compiled an ARM instruction set header, which switches to Thumb mode before executing the rest of the function ๐Ÿ” This allows these functions to be called from non-interworking code. This option is not valid in AAPCS configurations, because interworking is enabled by default.
  • -mcaller-super-interworking โ€” allows calls via function pointers (including virtual functions) to execute correctly, regardless of whether the target code has been compiled for interworking or not ๐Ÿค There is a small overhead in the cost of executing a function pointer if this option is enabled. This option is not valid in AAPCS configurations, because interworking is enabled by default.
  • -mtp=name โ€” specifies the access model for the thread local storage pointer ๐Ÿงต The valid models are soft, which generates calls to __aeabi_read_tp; cp15, which fetches the thread pointer from cp15 directly (supported in the arm6k architecture); and auto, which uses the best available method for the selected processor. The default setting is auto ๐Ÿ’œ
  • -mtls-dialect=dialect โ€” specifies the dialect to use 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 provides better performance for shared libraries ๐Ÿš€ The GNU descriptor scheme is compatible with the original scheme, but 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 these instructions. It is enabled by default when -mcpu=cortex-m3 is specified ๐Ÿ›ก๏ธ
  • -munaligned-access, -mno-unaligned-access โ€” enables (or disables) reading and writing of 16- and 32-bit values from addresses that are not 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 is not enabled, then words in packed data structures are accessed a byte at a time ๐Ÿข The ARM attribute Tag_CPU_unaligned_access is set in the generated object file to either true or false, depending upon the setting of this option. If unaligned access is enabled, then the preprocessor symbol __ARM_FEATURE_UNALIGNED is also defined ๐ŸŽ€
  • -mneon-for-64bits โ€” deprecated, and it has no effect ๐Ÿฅ€
  • -mslow-flash-data โ€” assumes loading data from flash is slower than fetching instructions ๐ŸŒ So literal loads are 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 okay so this one's about inline assembler syntax ๐Ÿ’… It tells GCC to assume 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 heads up, this may change in future releases of GCC. Divided syntax should be considered deprecated ๐Ÿ˜ญ

-mrestrict-it bestie, this one 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. It's on by default for ARMv8-A Thumb mode ๐ŸŽ€

-mprint-tune-info prints CPU tuning information as a comment in the assembler file ๐ŸŒธ This is only used for regression testing of the compiler and is not intended for ordinary use when compiling code ๐Ÿ™ˆ It's disabled by default.

-mverbose-cost-dump enables verbose cost model dumping in the debug dump files ๐Ÿงš This one is provided for debugging the compiler, so it's more of a behind-the-scenes thing ๐Ÿ’œ

-mpure-code do not allow constant data to be placed in code sections ๐Ÿ”ฅ Additionally, when compiling for ELF object format, it gives all text sections the ELF processor-specific section attribute SHF_ARM_PURECODE. This option is only available when generating non-PIC code for M-profile targets ๐Ÿ‘‘

-mcmse generates secure code as per the "ARMv8-M Security Extensions: Requirements on Development Tools Engineering Specification" ๐Ÿ“– You can find that spec at <https://developer.arm.com/documentation/ecm0359818/latest/> ๐Ÿฆ‹

-mfix-cmse-cve-2021-35465 mitigates a potential security issue with the "VLLDM" instruction on some M-profile devices when using CMSE (CVE-2021-365465) ๐Ÿ™ This option is enabled by default when -mcpu= is used with "cortex-m33", "cortex-m35p" or "cortex-m55" ๐Ÿ’– Use -mno-fix-cmse-cve-2021-35465 to disable the mitigation.

-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'll need to explicitly provide the PIC/PIE-related options as needed ๐Ÿซถ

ngl the static linking part is important: static linking is not supported because it would still involve the dynamic linker when the program self-relocates โš ๏ธ If that behavior is acceptable, use -static and -Wl,-dynamic-linker options ๐Ÿ™ˆ

The opposite -mno-fdpic option is useful (and required) for building 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 ๐Ÿงš

-mmcu=mcu specifies the Atmel AVR instruction set architecture (ISA) or MCU type ๐Ÿฆ‹

The default for this option is avr2 ๐Ÿ’–

GCC supports the following AVR devices and ISAs ๐Ÿ‘‘

  • "avr2" โ€” "Classic" devices with up to 8 KiB of program memory. MCU = "attiny22", "attiny26", "at90s2313", "at90s2323", "at90s2333", "at90s2343", "at90s4414", "at90s4433", "at90s4434", "at90c8534", "at90s8515", "at90s8535".
  • "avr25" โ€” "Classic" devices with up to 8 KiB of program memory and with the "MOVW" instruction. MCU = "attiny13", "attiny13a", "attiny24", "attiny24a", "attiny25", "attiny261", "attiny261a", "attiny2313", "attiny2313a", "attiny43u", "attiny44", "attiny44a", "attiny45", "attiny48", "attiny441", "attiny461", "attiny461a", "attiny4313", "attiny84", "attiny84a", "attiny85", "attiny87", "attiny88", "attiny828", "attiny841", "attiny861", "attiny861a", "ata5272", "ata6616c", "at86rf401".
  • "avr3" โ€” "Classic" devices with 16 KiB up to 64 KiB of program memory. MCU = "at76c711", "at43usb355".
  • "avr31" โ€” "Classic" devices with 128 KiB of program memory. MCU = "atmega103", "at43usb320".
  • "avr35" โ€” "Classic" devices with 16 KiB up to 64 KiB of program memory and with the "MOVW" instruction. MCU = "attiny167", "attiny1634", "atmega8u2", "atmega16u2", "atmega32u2", "ata5505", "ata6617c", "ata664251", "at90usb82", "at90usb162".
  • "avr4" โ€” "Enhanced" devices with up to 8 KiB of program memory. MCU = "atmega48", "atmega48a", "atmega48p", "atmega48pa", "atmega48pb", "atmega8", "atmega8a", "atmega8hva", "atmega88", "atmega88a", "atmega88p", "atmega88pa", "atmega88pb", "atmega8515", "atmega8535", "ata6285", "ata6286", "ata6289", "ata6612c", "at90pwm1", "at90pwm2", "at90pwm2b", "at90pwm3", "at90pwm3b", "at90pwm81".
  • "avr5" โ€” "Enhanced" devices with 16 KiB up to 64 KiB of program memory. MCU = "atmega16", "atmega16a", "atmega16hva", "atmega16hva2", "atmega16hvb", "atmega16hvbrevb", "atmega16m1", "atmega16u4", "atmega161", "atmega162", "atmega163", "atmega164a", "atmega164p", "atmega164pa", "atmega165", "atmega165a", "atmega165p", "atmega165pa", "atmega168", "atmega168a", "atmega168p", "atmega168pa", "atmega168pb", "atmega169", "atmega169a", "atmega169p", "atmega169pa", "atmega32", "atmega32a", "atmega32c1", "atmega32hvb", "atmega32hvbrevb", "atmega32m1", "atmega32u4", "atmega32u6", "atmega323", "atmega324a", "atmega324p", "atmega324pa", "atmega325", "atmega325a", "atmega325p", "atmega325pa", "atmega328", "atmega328p", "atmega328pb", "atmega329", "atmega329a", "atmega329p", "atmega329pa", "atmega3250", "atmega3250a", "atmega3250p", "atmega3250pa", "atmega3290", "atmega3290a", "atmega3290p", "atmega3290pa", "atmega406", "atmega64", "atmega64a", "atmega64c1", "atmega64hve", "atmega64hve2", "atmega64m1", "atmega64rfr2", "atmega640", "atmega644", "atmega644a", "atmega644p", "atmega644pa", "atmega644rfr2", "atmega645", "atmega645a", "atmega645p", "atmega649", "atmega649a", "atmega649p", "atmega6450", "atmega6450a", "atmega6450p", "atmega6490", "atmega6490a", "atmega6490p", "ata5795", "ata5790", "ata5790n", "ata5791", "ata6613c", "ata6614q", "ata5782", "ata5831", "ata8210", "ata8510", "ata5702m322", "at90pwm161", "at90pwm216", "at90pwm316", "at90can32", "at90can64", "at90scr100", "at90usb646", "at90usb647", "at94k", "m3000".
  • "avr51" โ€” "Enhanced" devices with 128 KiB of program memory. MCU = "atmega128", "atmega128a", "atmega128rfa1", "atmega128rfr2", "atmega1280", "atmega1281", "atmega1284", "atmega1284p", "atmega1284rfr2", "at90can128", "at90usb1286", "at90usb1287".
  • "avr6" โ€” "Enhanced" devices with 3-byte PC, i.e. with more than 128 KiB of program memory. MCU = "atmega256rfr2", "atmega2560", "atmega2561", "atmega2564rfr2".
  • "avrxmega2" โ€” "XMEGA" devices with more than 8 KiB and up to 64 KiB of program memory. MCU = "atxmega8e5", "atxmega16a4", "atxmega16a4u", "atxmega16c4", "atxmega16d4", "atxmega16e5", "atxmega32a4", "atxmega32a4u", "atxmega32c3", "atxmega32c4", "atxmega32d3", "atxmega32d4", "atxmega32e5".
  • "avrxmega3" โ€” "XMEGA" devices with up to 64 KiB of combined program memory and RAM, and with program memory visible in the RAM address space. MCU = "attiny202", "attiny204", "attiny212", "attiny214", "attiny402", "attiny404", "attiny406", "attiny412", "attiny414", "attiny416", "attiny417", "attiny804", "attiny806", "attiny807", "attiny814", "attiny816", "attiny817", "attiny1604", "attiny1606", "attiny1607", "attiny1614", "attiny1616", "attiny1617", "attiny3214", "attiny3216", "attiny3217", "atmega808", "atmega809", "atmega1608", "atmega1609", "atmega3208", "atmega3209", "atmega4808", "atmega4809".
  • "avrxmega4" โ€” "XMEGA" devices with more than 64 KiB and up to 128 KiB of program memory. MCU = "atxmega64a3", "atxmega64a3u", "atxmega64a4u", "atxmega64b1", "atxmega64b3", "atxmega64c3", "atxmega64d3", "atxmega64d4".
  • "avrxmega5" โ€” "XMEGA" devices with more than 64 KiB and up to 128 KiB of program memory and more than 64 KiB of RAM. MCU = "atxmega64a1", "atxmega64a1u".
  • "avrxmega6" โ€” "XMEGA" devices with more than 128 KiB of program memory. MCU = "atxmega128a3", "atxmega128a3u", "atxmega128b1", "atxmega128b3", "atxmega128c3", "atxmega128d3", "atxmega128d4", "atxmega192a3", "atxmega192a3u", "atxmega192c3", "atxmega192d3", "atxmega256a3", "atxmega256a3b", "atxmega256a3bu", "atxmega256a3u", "atxmega256c3", "atxmega256d3", "atxmega384c3", "atxmega384d3".
  • "avrxmega7" โ€” "XMEGA" devices with more than 128 KiB of program memory and more than 64 KiB of RAM. MCU = "atxmega128a1", "atxmega128a1u", "atxmega128a4u".
  • "avrtiny" โ€” "TINY" Tiny core devices with 512 B up to 4 KiB of program memory. MCU = "attiny4", "attiny5", "attiny9", "attiny10", "attiny20", "attiny40".
  • "avr1" โ€” This ISA is implemented by the minimal AVR core and 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 outgoing function arguments 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 need not be removed from the stack after such a function call ๐Ÿงš

This option can lead to reduced code size for functions that perform 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 โ€” okay so this one tells GCC to expand function prologues and epilogues into calls to the right subroutines ๐Ÿงš Your code size gets smaller, which is giving efficiency โœจ
  • -mdouble=bits, -mlong-double=bits โ€” these set how many bits the double or long double type gets, respectively ๐Ÿ’œ The allowed values are 32 and 64. Whether a particular value is allowed depends on the --with-double= and --with-long-double= configure options (https://gcc.gnu.org/install/configure.html#avr), and the same rule applies to the default values of these options ๐Ÿค“
  • -mgas-isr-prologues โ€” ISRs are allowed to use the __gcc_isr pseudo instruction, which is supported by GNU Binutils ๐Ÿฆ‹ If this option is on, you can still turn the feature off for individual ISRs with the no_gccisr function attribute (see AVR Function Attributes). It's switched on by default when optimization is on (but not with -Og, @pxref{Optimize Options}), and only if GNU Binutils supports PR21683 (https://sourceware.org/PR21683) ๐ŸŒธ
  • -mint8 โ€” this makes int an 8-bit integer ๐Ÿ“ All the sizes shift with it: 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 is the payoff.
๐Ÿšจ Heads up bestie: this option does NOT conform to the C standards, even though it gives you smaller code size.
  • -mmain-is-OS_task โ€” do not save registers in main ๐Ÿ‘‘ It has the same effect as attaching the OS_task attribute to main (see AVR Function Attributes). It's turned on by default when optimization is on.
  • -mn-flash=num โ€” assume the flash memory is num times 64 KiB big ๐Ÿงš
  • -mno-interrupts โ€” the generated code is not compatible with hardware interrupts, but the code size is smaller ๐Ÿ’€
๐Ÿšจ Do not use this one if your code needs interrupts. The generated code is not compatible with them.
  • -mrelax โ€” this tries to swap CALL (or JMP) for the shorter RCALL (or RJMP) instruction whenever that's possible โœจ Setting -mrelax just adds the --mlink-relax option to the assembler's command line and the --relax option to the linker's command line.

Jump relaxing is done by the linker, because jump offsets aren't known until the code gets located ๐Ÿฆ‹ So the assembler code the compiler generates stays the same, but the instructions in the executable may differ from the ones in the assembler code.

Relaxing must be turned on if linker stubs are needed. See 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 RJMP and RCALL can target the whole program memory ๐ŸŒˆ

This option is used internally for multilib selection. It's not an optimization option, and you don't need to set it by hand ๐Ÿ™ˆ

  • -msp8 โ€” treat the stack pointer register as an 8-bit register, aka assume the high byte of the stack pointer is zero ๐Ÿ’… In general, you don't need to set this one by hand.

This option is used internally by the compiler to select and build multilibs for the avr2 and avr25 architectures. These architectures mix devices with and without SPH. For any setting other than -mmcu=avr2 or -mmcu=avr25, the compiler driver adds or removes this option from the compiler proper's command line, because the compiler then knows whether the device or architecture has an 8-bit stack pointer (and 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 a small non-negative number less than 64, into a register Rn is done like this:

adiw r26, const   ; X += const
ld   <Rn>, X        ; <Rn> = *X
sbiw r26, const   ; X -= const
  • -mtiny-stack โ€” only change the lower 8 bits of the stack pointer ๐Ÿงš
  • -mfract-convert-truncate โ€” allows 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 โ€” this stops the driver from adding -specs=device-specs/specs-mcu to its command line ๐Ÿ’… Now YOU are in charge of giving the subprocesses (compiler proper, assembler and linker) the right command line options. That means you have to supply your own private device specs file with -specs=path-to-specs-file. There's no more need for -mmcu=mcu.

This option can also replace the older way of specifying custom device-specs files. That old way needed -B some-path to point to a directory containing a folder named "device-specs", and that folder had to contain a specs file named "specs-mcu", where mcu was whatever you set with -mmcu=mcu ๐ŸŒธ

  • -Waddr-space-convert โ€” warns about conversions between address spaces where the resulting address space isn't contained in the incoming address space โญ
  • -Wmisspelled-isr โ€” warns if an ISR is misspelled, i.e. without the __vector prefix. It's 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 gets 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 the EICALL or EIJMP instructions are used ๐Ÿ”ฅ

Indirect jumps and calls on these devices are handled as follows 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 in order to emulate an indirect call/jump by means of a RET instruction.
  • The compiler assumes that EIND never changes during the startup code or during the application. In particular, EIND is not saved/restored in function or interrupt service routine prologue/epilogue.
  • For indirect calls to functions and computed goto, the linker generates stubs. Stubs are jump pads, sometimes also called trampolines. So the indirect call/jump lands on such a stub, and the stub contains a direct jump to the desired address ๐Ÿฆ‹
  • Linker relaxation must be turned on so that 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. Yikes.
  • The default linker script is arranged for code with EIND = 0. If your code is supposed to work for a setup with EIND != 0, you'll need a custom linker script to place the sections whose name starts with .trampolines into the segment where EIND points to ๐Ÿงš
  • The startup code from libgcc never sets EIND. Notice that the startup code is a blend of code from libgcc and AVR-LibC. For the impact of AVR-LibC on EIND, see the AVR-LibC user manual (http://nongnu.org/avr-libc/user-manual/) ๐Ÿ“–
  • It's legit for user-specific startup code to set up EIND early, for example with initialization code located in section .init3. That code runs before the general startup code that initializes RAM and calls constructors, but after the bit of AVR-LibC startup code that sets EIND to the segment where the vector table is located ๐Ÿซถ
#include <avr/io.h>

static void
__attribute__((section(".init3"),naked,used,no_instrument_function))
init3_set_eind (void)
{
  __asm volatile ("ldi r24,pm_hh8(__trampolines_start)\n\t"
                  "out %i0,r24" :: "n" (&EIND) : "r24","memory");
}

The __trampolines_start symbol is defined in the linker script โœจ

  • Stubs are generated automatically by the linker if the following two conditions are met:
    • The address of a label is taken by means of the gs modifier (short for generate stubs), like so:
LDI r24, lo8(gs(<func>))
LDI r25, hi8(gs(<func>))
  • The final location of that label is in a code segment outside the segment where the stubs are located.
  • The compiler emits such gs modifiers for code labels in the following situations:
    • Taking the address of a function or code label.
    • Computed goto.
    • If the prologue-save function is used, see the -mcall-prologues command-line option.
    • Switch/case dispatch tables. If you do not want such dispatch tables, you can specify the -fno-jump-tables command-line option.
    • C and C++ constructors/destructors called during startup/shutdown.
    • If the tools hit a gs() modifier explained above.
  • Jumping to non-symbolic addresses like so is not supported ๐Ÿ’€
int main (void)
{
    /* Call function at word address 0x2 */
    return ((int(*)(void)) 0x2)();
}

Instead, a stub has to be set up, i.e. the function has to be called through a symbol (func_4 in the example):

int main (void)
{
    extern int func_4 (void);

    /* Call function at byte address 0x4 */
    return func_4();
}

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 ๐Ÿซถ
  • ๐ŸŒธ Okay so if you use an AVR named address space other than generic or __flash, GCC sets RAMPZ as needed before the operation. Prep work, but make it cute โœจ
  • ๐Ÿ’… If the device supports RAM bigger than 64 KiB and the compiler needs to change RAMPZ to pull off an operation, RAMPZ gets reset to zero afterwards. Clean up after yourself, bestie ๐Ÿงน
  • ๐Ÿฆ‹ If the device comes with a specific RAMP register, the ISR prologue/epilogue saves and restores that SFR, and initializes it with zero in case the ISR code might (implicitly) use it. Protecting the vibe ๐Ÿซถ
๐Ÿšจ 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, it's giving disaster ๐Ÿ’€

๐ŸŒˆ AVR Built-in Macros ๐ŸŒˆ

GCC defines several built-in macros so your code can check whether features are present or absent, which is literally so iconic ๐Ÿ”ฅ Almost all of the following are deduced from device capabilities, so they get triggered by the -mmcu= command-line option.

For even more AVR-specific built-in macros, check out AVR Named Address Spaces and AVR Built-in Functions ๐Ÿงš

  • __AVR_ARCH__ โ€” A built-in macro that resolves to a decimal number identifying the architecture. It depends on the -mmcu=mcu option. The possible values are below โœจ
2, 25, 3, 31, 35, 4, 5, 51, 6
    for mcu="avr2", "avr25", "avr3", "avr31", "avr35", "avr4", "avr5", "avr51", "avr6",
    respectively

100, 102, 103, 104, 105, 106, 107
    for mcu="avrtiny", "avrxmega2", "avrxmega3", "avrxmega4", "avrxmega5",
    "avrxmega6", "avrxmega7", respectively

If mcu specifies a device, this built-in macro gets 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 names follow the scheme __AVR_Device__, where Device is the device name from 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 an actual device but just 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 an actual device but just 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 for 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__, __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__, __AVR_HAVE_16BIT_SP__ โ€” The stack pointer (SP) register is treated by the compiler as an 8-bit or 16-bit register, respectively. Defining these macros is affected by -mtiny-stack ๐Ÿ“
  • __AVR_HAVE_SPH__, __AVR_SP8__ โ€” The device has the SPH (high part of stack pointer) special function register, or has an 8-bit stack pointer, respectively. Defining these macros is affected by -mmcu=, and in the cases of -mmcu=avr2 and -mmcu=avr25 also by -msp8 ๐Ÿ™ˆ
  • __AVR_HAVE_RAMPD__, __AVR_HAVE_RAMPX__, __AVR_HAVE_RAMPY__, __AVR_HAVE_RAMPZ__ โ€” The device has the RAMPD, RAMPX, RAMPY, or RAMPZ special function register, respectively ๐Ÿฆ‹
  • __NO_INTERRUPTS__ โ€” This macro reflects the -mno-interrupts command-line option ๐Ÿซถ
  • __AVR_ERRATA_SKIP__, __AVR_ERRATA_SKIP_JMP_CALL__ โ€” Some AVR devices (AT90S8515, ATmega103) must not skip 32-bit instructions because of a hardware erratum. The skip instructions are SBRS, SBRC, SBIS, SBIC, and CPSE. The second macro is only defined if __AVR_HAVE_JMP_CALL__ is also set ๐Ÿ™ˆ
  • __AVR_ISA_RMW__ โ€” The device has Read-Modify-Write instructions (XCH, LAC, LAS, and LAT) ๐Ÿ”ฅ
  • __AVR_SFR_OFFSET__=offset โ€” Instructions that can address I/O special function registers directly, like IN, OUT, SBI, etc., may use a different address than an instruction accessing RAM, like LD or STS. This offset depends on the device architecture and has to be subtracted from the RAM address to get the respective I/O address ๐Ÿง 
  • __AVR_SHORT_CALLS__ โ€” The -mshort-calls command-line option is set ๐ŸŒธ
  • __AVR_PM_BASE_ADDRESS__=addr โ€” Some devices support reading from flash memory using LD* instructions. The flash memory shows up 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 attribute progmem and pgm_read_* ๐Ÿ‘‘
  • __WITH_AVRLIBC__ โ€” The compiler is configured to be used together with AVR-Libc. See the --with-avrlibc configure option ๐ŸŽ€
  • __HAVE_DOUBLE_MULTILIB__ โ€” Defined if -mdouble= acts as a multilib option ๐ŸŒˆ
  • __HAVE_DOUBLE32__, __HAVE_DOUBLE64__ โ€” Defined if the compiler supports 32-bit double or 64-bit double, respectively. The actual layout is specified by option -mdouble= โœจ
  • __DEFAULT_DOUBLE__ โ€” The size in bits of double if -mdouble= is not set. To test the layout of double in a program, use the built-in macro __SIZEOF_DOUBLE__ ๐Ÿ“
  • __HAVE_LONG_DOUBLE32__, __HAVE_LONG_DOUBLE64__, __HAVE_LONG_DOUBLE_MULTILIB__, __DEFAULT_LONG_DOUBLE__ โ€” Same as above, but for long double instead of double ๐Ÿ’–
  • __WITH_DOUBLE_COMPARISON__ โ€” Reflects the --with-double-comparison={tristate|bool|libf7} configure option (https://gcc.gnu.org/install/configure.html#avr), and is defined to 2 or 3 ๐Ÿฆ‹
  • __WITH_LIBF7_LIBGCC__, __WITH_LIBF7_MATH__, __WITH_LIBF7_MATH_SYMBOLS__ โ€” Reflects the --with-libf7={libgcc|math|math-symbols} configure option (https://gcc.gnu.org/install/configure.html#avr) ๐Ÿซถ

๐Ÿฆ‹ Blackfin Options ๐Ÿฆ‹

  • -mcpu=cpu[-sirevision] โ€” Specifies the name of the target Blackfin processor. 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 specifies the silicon revision of the target Blackfin processor. Any workarounds available for that silicon revision get enabled. If sirevision is none, no workarounds are enabled. If sirevision is any, all workarounds for the targeted processor are enabled.
    • The __SILICON_REVISION__ macro is defined to two hexadecimal digits representing the major and minor numbers in the silicon revision. If sirevision is none, __SILICON_REVISION__ is not defined. If sirevision is any, __SILICON_REVISION__ is defined to be 0xffff. If this optional sirevision is not used, GCC assumes the latest known silicon revision of the targeted Blackfin processor.
    • GCC defines a preprocessor macro for the specified cpu. For the bfin-elf toolchain, this option causes the hardware BSP provided by libgloss to be linked in if -msim is not given.
    • Without this option, bf532 is used as the processor by default.
    • Heads up: 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 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 occurring ๐Ÿ’€
  • -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 occurring too soon after a conditional branch ๐Ÿ’œ
  • -mlow64k โ€” When enabled, the compiler is free to take advantage of the knowledge that the entire program fits into the low 64k of memory ๐Ÿ“
  • -mno-low64k โ€” Assume that the program is arbitrarily large. This is the default ๐ŸŒธ
  • -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 โ€” okay so this one is the default ๐Ÿ’… It tells the compiler NOT to assume ID-based shared libraries are in use. Main character behavior ๐Ÿ‘‘
  • -mleaf-id-shared-library โ€” this one supports shared libraries through the library ID method, but it assumes the library or executable won't link against any other ID shared libraries ๐Ÿฆ‹ Bestie, that assumption lets the compiler use faster code for jumps and calls โœจ
  • -mno-leaf-id-shared-library โ€” the opposite vibe ๐Ÿ™ˆ It doesn't assume the code avoids linking with ID shared libraries, so the jump and call instructions come out slower ๐Ÿข
  • -mshared-library-id=n โ€” sets the identification number of the ID-based shared library being compiled ๐Ÿ”ข Using 0 gives you more compact code ๐ŸŽ€ Any other value forces that number onto the current library, but it's no more space- or time-efficient than just leaving this option out ๐Ÿคทโ€โ™€๏ธ
  • -msep-data โ€” lets the data segment live in a different area of memory from the text segment ๐Ÿงš This makes execute in place possible in an environment without virtual memory management, because it gets rid of relocations against the text section ๐Ÿ’œ
  • -mno-sep-data โ€” assumes the data segment sits right after the text segment ๐ŸŒธ This is the default.
  • -mlong-calls, -mno-long-calls โ€” with -mlong-calls, the compiler loads the function's address into a register first, then makes a subroutine call through that register ๐Ÿ“ž You need this if the target function is outside the 24-bit addressing range of the offset-based subroutine call instruction ๐ŸŒˆ It's not enabled by default, and -mno-long-calls puts you back to the default behavior. Heads up: these switches have no effect on how function calls through function pointers are generated ๐Ÿ’€
  • -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 in the name 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 ๐ŸŒˆ This makes the compiler use proper start files and link scripts that support multicore, and it defines the macro "__BFIN_MULTICORE" ๐ŸŽ€ It can only be used with -mcpu=bf561[-sirevision] ๐Ÿ’…

You can pair it with -mcorea or -mcoreb for the one-application-per-core programming model ๐Ÿ‘ฏโ€โ™€๏ธ Without either of those, you get the single-application/dual-core model. In that model, the main function of Core B should be named "coreb_main" ๐Ÿ’œ If you skip -mmulticore entirely, you get the single-core application programming model ๐Ÿซถ

  • -mcorea โ€” builds a standalone application for Core A of BF561 in the one-application-per-core model ๐Ÿ‘‘ Start files and link scripts support Core A, and the macro "__BFIN_COREA" gets defined. This option can only be used together with -mmulticore ๐Ÿ”ฅ
  • -mcoreb โ€” same energy, but for Core B of BF561 ๐Ÿฆ‹ It defines "__BFIN_COREB", and when you use it, "coreb_main" should be used instead of "main" ๐Ÿ“ This one also can only be used together with -mmulticore โœจ
  • -msdram โ€” builds a standalone application for SDRAM ๐Ÿง  Start files and link scripts put the app into SDRAM, and the macro "__BFIN_SDRAM" is defined. 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, but for standalone applications the default is off ๐ŸŒธ

๐Ÿฆ‹ C6X Options ๐Ÿฆ‹

  • -march=name โ€” specifies the name of the target architecture ๐ŸŽฏ GCC uses this to figure out what kinds of instructions it's allowed to emit when generating assembly code. The permissible names are c62x, c64x, c64x+, c67x, c67x+, and c674x ๐Ÿ’–
  • -mbig-endian โ€” generates code for a big-endian target ๐ŸŒŠ
  • -mlittle-endian โ€” generates code for a little-endian target ๐Ÿ’œ This is the default โœจ
  • -msim โ€” picks startup files and a linker script that work with the simulator ๐Ÿงช
  • -msdata=default โ€” puts small global and static data in the ".neardata" section, which is pointed to by register B14 ๐ŸŽ€ Small uninitialized global and static data goes in the ".bss" section, which sits right next to ".neardata" ๐Ÿงš Small read-only data goes in the ".rodata" section ๐ŸŒˆ Large pieces of data use the matching sections ".fardata", ".far", and ".const" ๐Ÿ’…
  • -msdata=all โ€” puts all data, not just the small objects, into the sections reserved for small data ๐Ÿ“ It uses addressing relative to the B14 register to get at them ๐Ÿซถ
  • -msdata=none โ€” makes no use of the small-data sections at all, and uses absolute addresses for all data ๐Ÿ’€ All initialized global and static data goes in ".fardata", all uninitialized data goes in ".far", and all constant data goes in ".const" ๐ŸŒธ

๐ŸŒˆ CRIS Options ๐ŸŒˆ

These options are defined specifically for the CRIS ports ๐Ÿงš

  • -march=architecture-type, -mcpu=architecture-type โ€” generates code for the specified architecture ๐ŸŽ€ The choices are v3, v8, and v10, which map to 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 applicable about the generated code to the given architecture-type โœจ The one exception is the ABI and the set of available instructions, which stay the same ๐Ÿฆ‹ The choices are the same as for -march=architecture-type ๐Ÿซถ
  • -mmax-stack-frame=n โ€” warns when the stack frame of a function 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 option is active by default โœ…
  • -mpdebug โ€” enables CRIS-specific verbose debug-related information 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 โ€” don't use condition-code results from previous instructions ๐Ÿ™…โ€โ™€๏ธ Always emit compare and test instructions before using condition codes ๐Ÿ’…
  • -mno-side-effects โ€” don't emit instructions with side effects in addressing modes other than post-increment ๐Ÿง 
  • -mstack-align, -mno-stack-align, -mdata-align, -mno-data-align, -mconst-align, -mno-const-align โ€” these arrange (or, with the no- versions, eliminate the arrangement of) alignment for the stack frame, individual data, and constants ๐Ÿ“ The alignment matches the maximum single data access size for the chosen CPU model ๐ŸŽฏ The default is 32-bit alignment, and ABI details like structure layout aren't affected by these options ๐Ÿ’–
  • -m32-bit, -m16-bit, -m8-bit โ€” similar to the stack, data, and const align options above ๐ŸŒˆ These make the stack frame, writable data, and constants all 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 ๐Ÿ˜ญ
โš ๏ธ Only use this option together with visual inspection of the compiled code. No warnings or errors are generated when call-saved registers need saving, or when storage for local variables needs allocating. This one is dangerous if you're not checking the output yourself ๐Ÿ’€
  • -mno-gotplt, -mgotplt โ€” with -fpic and -fPIC, -mno-gotplt means don't generate instruction sequences that load function addresses from the PLT part of the GOT, and -mgotplt means do generate them. Those sequences are used instead of the traditional calls to the PLT on other architectures ๐Ÿฆ‹ The default is -mgotplt ๐Ÿซถ
  • -melf โ€” a legacy no-op option ๐Ÿ•ฐ๏ธ It's only recognized with the cris-axis-elf and cris-axis-linux-gnu targets.
  • -mlinux โ€” another legacy no-op option ๐Ÿ•ฐ๏ธ It's only recognized with the cris-axis-linux-gnu target.
  • -sim โ€” recognized for the cris-axis-elf target ๐Ÿงช 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 locate 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 ๐ŸŽ€ The CR16C+ architecture is the default ๐Ÿ‘‘
  • -msim โ€” links the library libsim.a, which is compatible with the simulator ๐Ÿงช This only applies to the ELF compiler ๐Ÿงš
  • -mint32 โ€” chooses the integer type to be 32-bit wide ๐Ÿ”ข
  • -mbit-ops โ€” generates "sbit" and "cbit" instructions for bit manipulations ๐Ÿ”ง
  • -mdata-model=model โ€” chooses a data model ๐Ÿ“ฆ The choices for model are near, far, or medium, and medium is the default ๐ŸŒˆ Heads up though: far is not valid with -mcr16c, because the CR16C architecture doesn't support the far data model ๐Ÿ™ˆ

๐Ÿ“ C-SKY Options ๐Ÿ“

GCC supports these options when compiling for C-SKY V2 processors ๐Ÿซถ

  • -march=arch โ€” specifies the C-SKY target architecture ๐ŸŽฏ Valid values for arch are ck801, ck802, ck803, ck807, and ck810. The default is ck810 ๐Ÿ‘‘
  • -mcpu=cpu โ€” okay so this is where you pick your C-SKY target processor ๐ŸŽ€ The valid cpu values 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 ๐Ÿ’…
  • -mbig-endian, -EB, -mlittle-endian, -EL โ€” pick your byte order, big-endian or little-endian ๐ŸŒธ Little-endian is the default, so you get that if you don't say anything โœจ
  • -mhard-float, -msoft-float โ€” hardware or software floating-point, your call ๐Ÿฆ‹ Soft float is the default, so hardware only kicks in when you ask for it ๐Ÿ’œ
  • -mdouble-float, -mno-double-float โ€” when -mhard-float is in effect, this turns on double-precision float instructions ๐Ÿ”ฅ It's on by default except when you're compiling for CK803.
  • -mfdivdu, -mno-fdivdu โ€” with -mhard-float in effect, this turns on generation of "frecipd", "fsqrtd", and "fdivd" instructions ๐Ÿงš It's on by default except when compiling for CK803.
  • -mfpu=fpu โ€” picks your floating-point processor ๐Ÿ‘‘ This one only works with -mhard-float. The values are fpv2_sf (same as -mno-double-float -mno-fdivdu), fpv2 (-mdouble-float -mno-divdu), and fpv2_divd (-mdouble-float -mdivdu).
  • -melrw, -mno-elrw โ€” enables the extended lrw instruction ๐ŸŒˆ It defaults to on for CK801 and off for everything else.
  • -mistack, -mno-istack โ€” enables interrupt stack instructions. The default is off ๐Ÿซถ
Heads up bestie: -mistack is required if you want to handle the interrupt and isr function attributes ๐Ÿšจ
  • -mmp โ€” enables multiprocessor instructions, default off ๐Ÿ’–
  • -mcp โ€” enables coprocessor instructions, default off ๐ŸŒธ
  • -mcache โ€” the manual says this one enables coprocessor instructions too, and the default is off ๐Ÿ™ˆ
  • -msecurity โ€” enables C-SKY security instructions, default off ๐Ÿ”’
  • -mtrust โ€” enables C-SKY trust instructions, default off ๐Ÿฆ‹
  • -mdsp, -medsp, -mvdsp โ€” these enable C-SKY DSP, Enhanced DSP, or Vector DSP instructions, respectively ๐ŸŽ€ They all default to off.
  • -mdiv, -mno-div โ€” generates divide instructions. Default is off โœจ
  • -msmart, -mno-smart โ€” generates code for Smart Mode, which only uses registers numbered 0-7 so you can use 16-bit instructions ๐Ÿ’… This is ignored for CK801, where it's required behavior, and it defaults to on for CK802. For other targets, the default is off.
  • -mhigh-registers, -mno-high-registers โ€” generates code using the high registers numbered 16-31 ๐Ÿ‘‘ This isn't supported on CK801, CK802, or CK803, but it's enabled by default for other processors.
  • -manchor, -mno-anchor โ€” generates code using global anchor symbol addresses ๐Ÿงš
  • -mpushpop, -mno-pushpop โ€” generates code using "push" and "pop" instructions ๐Ÿ“ This one defaults to on.
  • -mmultiple-stld, -mstm, -mno-multiple-stld, -mno-stm โ€” generates code using "stm" and "ldm" instructions ๐Ÿ’œ This isn't supported on CK801, but it's enabled by default on other processors.
  • -mconstpool, -mno-constpool โ€” creates constant pools in the compiler instead of handing that job off to the assembler ๐ŸŒˆ This is the default and is required for correct code generation on CK801 and CK802. It's optional on other processors.
  • -mstack-size, -mno-stack-size โ€” emits .stack_size directives for each function in the assembly output โญ This defaults to off.
  • -mccrt, -mno-ccrt โ€” generates code for the C-SKY compiler runtime instead of libgcc ๐Ÿซถ This defaults to off.
  • -mbranch-cost=n โ€” sets the branch costs to roughly n instructions ๐Ÿฆ‹ The default is 1.
  • -msched-prolog, -mno-sched-prolog โ€” permits scheduling of function prologue and epilogue sequences ๐Ÿ™ˆ Heads up, this can give you code that isn't compliant with the C-SKY V2 ABI prologue requirements, and that code can't be debugged or backtraced.
Using -msched-prolog can produce code that cannot be debugged or backtraced, so only flip it on if you know what you're doing ๐Ÿ’€ It's disabled by default.

โœจ Darwin Options โœจ

These options are defined for all architectures running the Darwin operating system ๐ŸŽ

FSF GCC on Darwin doesn't make "fat" object files. It makes an object file for the single architecture that GCC was built to target ๐Ÿ’… Apple's GCC on Darwin does make "fat" files if you use multiple -arch options. It does that by running the compiler or linker multiple times and joining the results together with lipo ๐Ÿ”ฅ

The subtype of the file it creates (like ppc7400, ppc970, or i686) is determined by the flags that specify the ISA GCC is targeting, like -mcpu or -march ๐ŸŽ€ The -force_cpusubtype_ALL option can be used to override this.

The Darwin tools act differently when they hit 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 can't put 64-bit instructions in a ppc750 object file, period ๐Ÿ™… The linker for shared libraries, /usr/bin/libtool, fails and prints an error if you ask it to create a shared library with a less restrictive subtype than its input files. For example, trying to put a ppc970 object file in a ppc7400 library is a no-go ๐Ÿ’€ The linker for executables, ld, quietly gives the executable the most restrictive subtype of any of its input files ๐Ÿคซ

  • -Fdir โ€” adds the framework directory dir to the head of the list of directories searched for header files ๐ŸŒธ These directories are interleaved with the ones from -I options and get scanned left-to-right.
    • A framework directory is a directory with frameworks in it. ๐Ÿงš
    • A framework is a directory with a Headers and/or PrivateHeaders directory directly inside it, and its name ends in .framework. Its name is that directory's name without 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 in 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're in the same framework โœจ
    • A subframework shouldn't 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. The mechanism might be extended to support that later.
    • The standard frameworks live in /System/Library/Frameworks and /Library/Frameworks ๐Ÿฆ‹
    • An example include looks like "#include <Framework/header.h>", where Framework is the framework's name and header.h is found in its PrivateHeaders or Headers directory ๐ŸŽ€
  • -iframeworkdir โ€” like -F, except the directory is treated as a system directory ๐Ÿซถ The big difference is that with -iframework, the compiler doesn't warn about constructs in header files found via dir. This option is only valid for the C family of languages.
  • -gused โ€” emits debugging information for symbols that are used ๐Ÿ” For the stabs debugging format, this enables -feliminate-unused-debug-symbols. It's on by default, so ON it stays โœจ
  • -gfull โ€” emits debugging information for all symbols and types ๐ŸŒˆ
  • -mmacosx-version-min=version โ€” the earliest MacOS X version this executable will run on is version ๐Ÿ“ Typical values are 10.1, 10.2, and 10.3.9.

If the compiler was built to use the system's headers by default, the default for this option is the system version the compiler is running on. Otherwise, the default is to make choices that are compatible with as many systems and code bases as possible ๐Ÿงš

  • -mkernel โ€” enables kernel development mode ๐Ÿ’œ The -mkernel option sets -static, -fno-common, -fno-use-cxa-atexit, -fno-exceptions, -fno-non-call-exceptions, -fapple-kext, -fno-weak, and -fno-rtti, where applicable. For PowerPC targets, this mode also sets -mno-altivec, -msoft-float, -fno-builtin, and -mlong-branch ๐Ÿ‘‘
  • -mone-byte-bool โ€” overrides the defaults for "bool" so that sizeof(bool)==1 ๐ŸŽ€ By default, sizeof(bool) is 4 when compiling for Darwin/PowerPC and 1 when compiling for Darwin/x86. That means this option does nothing on x86 ๐Ÿ™ˆ
Warning: -mone-byte-bool makes GCC generate code that isn't binary compatible with code generated without that switch ๐Ÿšจ You may need to recompile all the other modules in a program, including system libraries. Only use this switch to conform to a non-default data model.
  • -mfix-and-continue, -ffix-and-continue, -findirect-data โ€” generates code for fast turnaround development ๐Ÿ”ฅ That's the kind of thing that lets GDB dynamically load .o files into programs that are already running โœจ -findirect-data and -ffix-and-continue are only here for backwards compatibility.
  • -all_load โ€” loads all members of static archive libraries ๐Ÿ“š See man ld(1) for more information.
  • -arch_errors_fatal โ€” makes errors about files with the wrong architecture fatal ๐Ÿ’€
  • -bind_at_load โ€” marks the output file so the dynamic linker binds all undefined references when the file is loaded or launched ๐ŸŒธ
  • -bundle โ€” produces a Mach-o bundle format file ๐Ÿงš See man ld(1) for more information.
  • -bundle_loader executable โ€” specifies the executable that will load the build output file being linked ๐Ÿฆ‹ See man ld(1) for more information.
  • -dynamiclib โ€” when you pass this, GCC produces a dynamic library instead of an executable when linking, using the Darwin libtool command ๐Ÿ’–
  • -force_cpusubtype_ALL โ€” gives GCC's output file the ALL subtype, instead of one controlled by the -mcpu or -march option ๐Ÿ‘‘

Okay so these are the Darwin linker options, and they're giving "pass it along and don't ask questions" energy ๐Ÿ’… Here's the whole guest list, bestie. A few of them show up twice, and I kept every single one ๐Ÿซถ

  • -allowable_client client_name
  • -client_name
  • -compatibility_version
  • -current_version
  • -dead_strip
  • -dependency-file
  • -dylib_file
  • -dylinker_install_name
  • -dynamic
  • -exported_symbols_list
  • -filelist
  • -flat_namespace
  • -force_flat_namespace
  • -headerpad_max_install_names
  • -image_base
  • -init
  • -install_name
  • -keep_private_externs
  • -multi_module
  • -multiply_defined
  • -multiply_defined_unused
  • -noall_load
  • -no_dead_strip_inits_and_terms
  • -nofixprebinding
  • -nomultidefs
  • -noprebind
  • -noseglinkedit
  • -pagezero_size
  • -prebind
  • -prebind_all_twolevel_modules
  • -private_bundle
  • -read_only_relocs
  • -sectalign
  • -sectobjectsymbols
  • -whyload
  • -seg1addr
  • -sectcreate
  • -sectobjectsymbols
  • -sectorder
  • -segaddr
  • -segs_read_only_addr
  • -segs_read_write_addr
  • -seg_addr_table
  • -seg_addr_table_filename
  • -seglinkedit
  • -segprot
  • -segs_read_only_addr
  • -segs_read_write_addr
  • -single_module
  • -static
  • -sub_library
  • -sub_umbrella
  • -twolevel_namespace
  • -umbrella
  • -undefined
  • -unexported_symbols_list
  • -weak_reference_mismatches
  • -whatsloaded

These options get passed straight to the Darwin linker ๐Ÿ”— The Darwin linker man page has all the juicy details on each one, so go check there if you want the full tea ๐Ÿต

๐ŸŒธ DEC Alpha Options ๐ŸŒธ

These -m options are made for DEC Alpha implementations, so they only show up for those chips โœจ

  • -mno-soft-float, -msoft-float โ€” This pair is the hardware floating-point toggle ๐Ÿ”ฅ -mno-soft-float means use the hardware floating-point instructions, and -msoft-float means don't. When -msoft-float is on, the functions in libgcc.a do the floating-point work. Unless they've been swapped out for routines that emulate those operations, or compiled to call those emulation routines, these routines still issue floating-point operations. If you're compiling for an Alpha with no floating-point operations, you have to make sure the library is built so it doesn't call them. Also, Alpha implementations without floating-point operations are required to have floating-point registers, so that part's non-negotiable ๐Ÿ’€
  • -mfp-reg, -mno-fp-regs โ€” -mfp-reg generates code that uses the floating-point register set, and -mno-fp-regs generates code that doesn't. -mno-fp-regs implies -msoft-float. If the floating-point register set isn't used, floating-point operands get passed in integer registers as if they were integers, and floating-point results come back 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 has to be compiled with that option too. A typical use is building a kernel that doesn't use any floating-point registers, so it doesn't need to save and restore them ๐Ÿงš
  • -mieee โ€” The Alpha architecture has floating-point hardware that's tuned for maximum performance. It's mostly IEEE compliant, but full compliance needs some 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 runs a bit slower, but it can properly handle denormalized numbers and exceptional IEEE values like not-a-number and plus/minus infinity. Other Alpha compilers call this option -ieee_with_no_inexact.
DEBIAN SPECIFIC: This option is on by default for alpha-linux-gnu, unless -ffinite-math-only (which is part of the -ffast-math set) is specified. The reason is that the software functions in the GNU libc math libraries generate denormalized numbers, NaNs, and infs. All of those will cause a program to SIGFPE when it tries to use the results without -mieee. ๐Ÿ˜ญ
  • -mieee-with-inexact โ€” This is like -mieee, except the generated code also maintains the IEEE inexact-flag, so it becomes fully-compliant IEEE math ๐Ÿ”ฅ On top of _IEEE_FP, the preprocessor macro _IEEE_FP_EXACT gets defined too. On some Alpha implementations this can run significantly slower than the default code. Very little code actually depends on the inexact-flag, so you should normally not specify this option. Other Alpha compilers call this option -ieee_with_inexact.
  • -mfp-trap-mode=trap-mode โ€” This option controls which floating-point related traps are enabled. Other Alpha compilers call it -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, like the division by zero trap.
    • u โ€” On top of everything n enables, underflow traps are enabled too.
    • su โ€” Like u, but the instructions get marked as safe for software completion (see the Alpha architecture manual for details).
    • sui โ€” Like su, but inexact traps are enabled as well.
  • -mfp-rounding-mode=rounding-mode โ€” Selects the IEEE rounding mode ๐ŸŒˆ Other Alpha compilers call it -fprm rounding-mode. The rounding-mode can be one of:
    • n โ€” Normal IEEE rounding mode. Floating-point numbers get rounded towards the nearest machine number, or towards the even machine number in case of a tie.
    • m โ€” Round towards minus infinity.
    • c โ€” Chopped rounding mode. Floating-point numbers get rounded towards zero.
    • d โ€” Dynamic rounding mode. A field in the floating-point control register (fpcr, see the Alpha architecture reference manual) controls which rounding mode is in effect. The C library initializes this register for rounding towards plus infinity, so unless your program changes the fpcr, d works out to round towards plus infinity.
  • -mtrap-precision=trap-precision โ€” Alpha floating-point traps are imprecise, which is a big deal ๐Ÿ˜ฌ Without software help, you can't recover from a floating trap, and program execution normally has to be terminated. GCC can generate code that helps operating system trap handlers figure out the exact spot that caused a floating-point trap. Depending on what your application needs, you can pick one of these precision levels:
    • p โ€” Program precision. This is the default, and it means a trap handler can only tell which program caused a floating-point exception.
    • f โ€” Function precision. The trap handler can figure out which function caused a floating-point exception.
    • i โ€” Instruction precision. The trap handler can figure out the exact instruction that caused a floating-point exception.

Other Alpha compilers offer the equivalent options -scope_safe and -resumption_safe.

  • -mieee-conformant โ€” This option marks the generated code as IEEE conformant ๐ŸŽ€
You must not use this option unless you also specify -mtrap-precision=i and either -mfp-trap-mode=su or -mfp-trap-mode=sui. Its only effect is to emit the line .eflag 48 in the function prologue of the generated assembly file.
  • -mbuild-constants โ€” Normally GCC looks at a 32- or 64-bit integer constant to see if it can build it from smaller constants in two or three instructions. If it can't, it outputs the constant as a literal and generates code to load it from the data segment at run time ๐Ÿง 

Use this option to make GCC build all integer constants using code, even if that takes more instructions (the maximum is six). You typically use this option to build a shared library dynamic loader. Since the loader is itself a shared library, it has to relocate itself in memory before it can find the variables and constants in its own data segment.

  • -mbwx, -mno-bwx, -mcix, -mno-cix, -mfix, -mno-fix, -mmax, -mno-max โ€” These tell GCC whether it should generate code that uses the optional BWX, CIX, FIX and MAX instruction sets ๐Ÿ’œ The default is to use the instruction sets supported by the CPU type you specify via the -mcpu= option, or the CPU that GCC was built on if you don't specify one.
  • -mfloat-vax, -mfloat-ieee โ€” Generate code that uses (or doesn't use) VAX F and G floating-point arithmetic instead of IEEE single and double precision ๐Ÿฆ‹
  • -mexplicit-relocs, -mno-explicit-relocs โ€” Older Alpha assemblers had no way to generate symbol relocations except through assembler macros, and those macros don't allow optimal instruction scheduling. GNU binutils as of version 2.12 supports a new syntax that lets the compiler explicitly mark which relocations apply to which instructions. This option is mostly useful for debugging, since GCC detects the assembler's capabilities when it's built and sets the default 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 accessed via 16-bit relocations off of the $gp register. This limits the small data area to 64KB, but lets the variables be accessed directly with a single instruction โœจ

The default is -mlarge-data. With this option, the data area is limited to just below 2GB. Programs that need more than 2GB of data must use "malloc" or "mmap" to allocate that 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 โ€” With -msmall-text, the compiler assumes the code of the entire program (or shared library) fits in 4MB, so it's reachable with a branch instruction ๐Ÿ“ When -msmall-data is used, the compiler can assume all local symbols share the same $gp value, which cuts the number of instructions needed for a function call from 4 to 1.

The default is -mlarge-text.

  • -mcpu=cpu_type โ€” okay so this sets the instruction set and the scheduling vibes for machine type cpu_type ๐Ÿ’–. You can name it with the EV style name or the chip number. GCC has scheduling params for the EV4, EV5, and EV6 family, and it picks the instruction set defaults based on the processor you choose. If you don't pick a processor type, GCC just goes with whatever 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 selects the best architecture option for the host processor. -mcpu=native has no effect if GCC does not recognize the processor ๐Ÿฆ‹.

  • -mtune=cpu_type โ€” this one is lowkey simpler. It only sets the instruction scheduling parameters for machine type cpu_type, and the instruction set stays exactly as it is ๐ŸŽ€.

Native toolchains also support the value native, which selects the best architecture option for the host processor. -mtune=native has no effect if GCC does not recognize the processor ๐Ÿซถ.

  • -mmemory-latency=time โ€” sets the latency the scheduler should assume for typical memory references as the application sees them. ngl this number depends a LOT on the application's memory access patterns 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 at the Level 1, 2, and 3 caches (also called Dcache, Scache, and Bcache), plus main memory. Note that L3 is only valid for EV5 ๐Ÿ’œ.

โœจ eBPF Options โœจ

  • -mframe-limit=bytes โ€” this is 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 sets 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. ๐Ÿง  Right now version can be one of 4.0, 4.1, 4.2, 4.3, 4.4, 4.5, 4.6, 4.7, 4.8, 4.9, 4.10, 4.11, 4.12, 4.13, 4.14, 4.15, 4.16, 4.17, 4.18, 4.19, 4.20, 5.0, 5.1, 5.2, latest, or native ๐Ÿ’….
  • -mbig-endian โ€” generate code for a big-endian target ๐ŸŒธ.
  • -mlittle-endian โ€” generate code for a little-endian target. This is the default ๐Ÿ’–.
  • -mxbpf โ€” generates code for an expanded version of BPF that relaxes some of the restrictions the BPF architecture normally imposes ๐Ÿฆ‹:
    • -<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 โ€” tells GCC the program will run on the simulator. This links in an alternate runtime startup and library ๐Ÿงš.
๐Ÿšจ bestie, 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 instead ๐Ÿ’€.
  • -mlra โ€” enables Local Register Allocation. It's still experimental for FT32, so by default the compiler uses standard reload ๐Ÿ™ˆ.
  • -mnodiv โ€” doesn't use div and mod instructions ๐ŸŒˆ.
  • -mft32b โ€” enables use of the extended instructions of the FT32B processor โœจ.
  • -mcompress โ€” compresses all code using the Ft32B code compression scheme ๐Ÿฆ‹.
  • -mnopm โ€” doesn't generate code that reads program memory ๐Ÿ”ฅ.

โœจ FRV Options โœจ

  • -mgpr-32 โ€” only uses the first 32 general-purpose registers ๐Ÿ’….
  • -mgpr-64 โ€” uses all 64 general-purpose registers ๐Ÿ‘‘.
  • -mfpr-32 โ€” uses only the first 32 floating-point registers ๐ŸŒธ.
  • -mfpr-64 โ€” uses all 64 floating-point registers โœจ.
  • -mhard-float โ€” uses hardware instructions for floating-point operations ๐Ÿ”ฅ.
  • -msoft-float โ€” uses library routines for floating-point operations instead ๐Ÿซถ.
  • -malloc-cc โ€” dynamically allocates condition code registers ๐Ÿงš.
  • -mfixed-cc โ€” doesn't try to dynamically allocate condition code registers. It only uses icc0 and fcc0 ๐Ÿ’–.
  • -mdword โ€” changes the ABI to use double word insns ๐ŸŽ€.
  • -mno-dword โ€” doesn't use double word instructions ๐Ÿ™ˆ.
  • -mdouble โ€” uses floating-point double instructions ๐Ÿ’œ.
  • -mno-double โ€” doesn't use floating-point double instructions ๐Ÿ“.
  • -mmedia โ€” uses media instructions ๐Ÿฆ‹.
  • -mno-media โ€” doesn't use media instructions ๐Ÿ’….
  • -mmuladd โ€” uses multiply and add/subtract instructions ๐ŸŒˆ.
  • -mno-muladd โ€” doesn't use multiply and add/subtract instructions ๐Ÿ’€.
  • -mfdpic โ€” selects the FDPIC ABI, which uses function descriptors to represent pointers to functions ๐Ÿง . Without any PIC/PIE-related options, it implies -fPIE. With -fpic or -fpie, it assumes GOT entries and small data are within a 12-bit range from the GOT base address. With -fPIC or -fPIE, GOT offsets are computed with 32 bits. With a bfin-elf target, this option implies -msim ๐Ÿ‘‘.
  • -minline-plt โ€” enables inlining of PLT entries in function calls to functions that aren't known to bind locally ๐Ÿ”ฅ. It has no effect without -mfdpic. It's enabled by default 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 โ€” does not assume a large TLS segment when generating thread-local code ๐Ÿงš.
  • -mgprel-ro โ€” enables the use of "GPREL" relocations in the FDPIC ABI for data that is known to be in read-only sections ๐ŸŽ€. It's enabled by default, except for -fpic or -fpie. Even though it may help make the global offset table smaller, it trades 1 instruction for 4 there. With -fPIC or -fPIE, it trades 3 instructions for 4, one of which may be shared by multiple symbols, and it avoids 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 โ€” uses only the first four media accumulator registers ๐ŸŒธ.
  • -macc-8 โ€” uses all eight media accumulator registers โœจ.
  • -mpack โ€” packs VLIW instructions ๐Ÿ”ฅ.
  • -mno-pack โ€” does not pack VLIW instructions ๐Ÿ’€.
  • -mno-eflags โ€” does not mark ABI switches in e_flags ๐ŸŽ€.
  • -mcond-move โ€” enables the use of conditional-move instructions. This is the default ๐Ÿ’–.
โš ๏ธ This switch is mostly for debugging the compiler and will probably get removed in a future version, so don't build your whole life around it ๐Ÿ™ˆ.
  • -mno-cond-move โ€” disables the use of conditional-move instructions ๐Ÿงš.
โš ๏ธ Mostly for debugging the compiler, and it'll likely be removed in a future version ๐Ÿ’€.
  • -mscc โ€” enables the use of conditional set instructions. This is the default ๐ŸŒˆ.
โš ๏ธ Mostly for debugging the compiler, and it'll likely be removed in a future version ๐Ÿ’….
  • -mno-scc โ€” disables the use of conditional set instructions ๐Ÿ‘‘.
โš ๏ธ Mostly for debugging the compiler, and it'll likely be removed in a future version ๐Ÿฆ‹.
  • -mcond-exec โ€” enables the use of conditional execution. This is the default ๐Ÿ”ฅ.
โš ๏ธ Mostly for debugging the compiler, and it'll likely be removed in a future version ๐Ÿซถ.
  • -mno-cond-exec โ€” disables the use of conditional execution ๐ŸŒธ.
โš ๏ธ Mostly for debugging the compiler, and it'll likely be removed in a future version ๐Ÿง .
  • -mvliw-branch โ€” runs a pass to pack branches into VLIW instructions. This is the default โœจ.
โš ๏ธ Mostly for debugging the compiler, and it'll likely be removed in a future version ๐Ÿ’–.
  • -mno-vliw-branch โ€” does not run a pass to pack branches into VLIW instructions ๐Ÿ“.
โš ๏ธ Mostly for debugging the compiler, and it'll likely be removed in a future version ๐Ÿ’œ.
  • -mmulti-cond-exec โ€” enables optimization of && and || in conditional execution. This is the default ๐ŸŽ€.
โš ๏ธ Mostly for debugging the compiler, and it'll likely be removed in a future version ๐Ÿ™ˆ.
  • -mno-multi-cond-exec โ€” disables optimization of && and || in conditional execution ๐ŸŒˆ.
โš ๏ธ Mostly for debugging the compiler, and it'll likely be removed in a future version ๐Ÿ’….
  • -mnested-cond-exec โ€” enables nested conditional execution optimizations. This is the default ๐Ÿ‘‘.
โš ๏ธ Mostly for debugging the compiler, and it'll likely be removed in a future version ๐Ÿฆ‹.
  • -mno-nested-cond-exec โ€” disables nested conditional execution optimizations ๐Ÿ”ฅ.
โš ๏ธ Mostly for debugging the compiler, and it'll likely be removed in a future version ๐Ÿ’€.

Okay so this one's mainly for debugging the compiler, and it'll likely get yeeted in a future version ๐Ÿ’€ don't get too attached bestie.


  • -moptimize-membar โ€” This one's giving clean-up energy ๐Ÿงน It removes redundant membar instructions from the compiler-generated code. It's on by default, so you get the glow-up for free โœจ
  • -mno-optimize-membar โ€” Not feeling the auto clean-up? This turns off the automatic removal of redundant membar instructions from the generated code ๐Ÿ™…โ€โ™€๏ธ
  • -mtomcat-stats โ€” Tells gas to print out tomcat statistics ๐Ÿ“Š
  • -mcpu=cpu โ€” Pick the processor type you want code generated for ๐Ÿ’ป The possible values are frv, fr550, tomcat, fr500, fr450, fr405, fr400, fr300 and simple. Choose your fighter ๐Ÿซถ

๐ŸŽ€ GNU/Linux Options ๐ŸŽ€

These -m options are defined for GNU/Linux targets, so if you're on Linux, these are your people ๐Ÿง

  • -mglibc โ€” Use the GNU C library ๐Ÿ“š This is the default except on *-*-linux-*uclibc*, *-*-linux-*musl* and *-*-linux-*android* targets, so don't stress if you're on one of those ๐Ÿ’…
  • -muclibc โ€” Use the uClibc C library. This is the default on *-*-linux-*uclibc* targets ๐Ÿฆ‹
  • -mmusl โ€” Use the musl C library. This is the default on *-*-linux-*musl* targets ๐ŸŒธ
  • -mbionic โ€” Use the Bionic C library. This is the default on *-*-linux-*android* targets ๐Ÿค–
  • -mandroid โ€” Compile code that's compatible with the Android platform ๐Ÿ“ฑ This is the default on *-*-linux-*android* targets, and it's very main character energy.
When compiling, -mandroid 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. Bestie, that's a lot of work for one flag ๐Ÿ˜ญ
  • -tno-android-cc โ€” Disables the compilation effects of -mandroid, so -mbionic, -fPIC, -fno-exceptions and -fno-rtti are not turned on by default ๐Ÿ™…โ€โ™€๏ธ
  • -tno-android-ld โ€” Disables the linking effects of -mandroid, so the linker just gets standard Linux linking options instead ๐Ÿง

๐ŸŒˆ H8/300 Options ๐ŸŒˆ

These -m options are defined for the H8/300 implementations ๐Ÿ”ง

  • -mrelax โ€” Shortens some address references at link time, when possible ๐Ÿช„ It does this by using the linker option -relax.
  • -mh โ€” Generate code for the H8/300H ๐Ÿ’œ
  • -ms โ€” Generate code for the H8S ๐Ÿ’œ
  • -mn โ€” Generate code for the H8S and H8/300H in the normal mode. This one has to be used with either -mh or -ms ๐Ÿซถ
  • -ms2600 โ€” Generate code for the H8S/2600. This switch must be used with -ms ๐Ÿ’…
  • -mexr โ€” Extended registers get stored on the stack before a function with the monitor attribute runs. This is the default option, and it's only valid for H8S targets ๐Ÿงš
  • -mno-exr โ€” Extended registers do not get stored on the stack before a function with the monitor attribute runs. This is the default option for this one, and it's only valid for H8S targets ๐Ÿ™ˆ
  • -mint32 โ€” Makes int data 32 bits by default ๐Ÿ”ฅ
  • -malign-300 โ€” On the H8/300H and H8S, this uses the same alignment rules as the H8/300 โœจ The default for the H8/300H and H8S is to align longs and floats on 4-byte boundaries, but -malign-300 moves them to 2-byte boundaries instead. This option has no effect on the H8/300 ๐Ÿ™ƒ

๐Ÿฆ‹ HPPA Options ๐Ÿฆ‹

These -m options are defined for the HPPA family of computers, which is a whole vibe ๐Ÿ–ฅ๏ธ

  • -march=architecture-type โ€” Generate code for the specified architecture ๐Ÿ›๏ธ The choices are 1.0 for PA 1.0, 1.1 for PA 1.1, and 2.0 for PA 2.0 processors. To figure out the right architecture option for your machine on an HP-UX system, check out /usr/lib/sched.models ๐Ÿ‘€ Code compiled for lower numbered architectures runs on higher numbered architectures, but not the other way around, so keep that in mind ๐Ÿ’€
  • -mpa-risc-1-0, -mpa-risc-1-1, -mpa-risc-2-0 โ€” These are synonyms for -march=1.0, -march=1.1, and -march=2.0 respectively ๐Ÿซถ
  • -mcaller-copies โ€” The caller copies function arguments that get passed by hidden reference ๐Ÿซฃ This one should be used with care, because it's not compatible with the default 32-bit runtime. The good news is that only aggregates larger than eight bytes are passed by hidden reference, and this option gives you better compatibility with OpenMP ๐ŸŒธ
  • -mjump-in-delay โ€” This option is ignored and only provided for compatibility purposes ๐Ÿคทโ€โ™€๏ธ
  • -mdisable-fpregs โ€” Prevents floating-point registers from being used in any manner ๐Ÿšซ This is necessary for compiling kernels that do lazy context switching of floating-point registers. Heads up though: 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 generate faster indirect calls and use unscaled index address modes. Such code is suitable for level 0 PA systems and kernels ๐Ÿ“
  • -mfast-indirect-calls โ€” Generates code that assumes calls never cross space boundaries, so GCC can emit code that does faster indirect calls ๐ŸŽ๏ธ
This option does not work in the presence of shared libraries or nested functions. Be careful, bestie ๐Ÿ™ˆ
  • -mfixed-range=register-range โ€” Generates code that treats the given register range as fixed registers, meaning the register allocator can't use them ๐Ÿ”’ This is super useful when compiling kernel code. You specify a register range as two registers separated by a dash, and you can specify multiple ranges separated by a comma ๐Ÿงฉ
  • -mlong-load-store โ€” Generates 3-instruction load and store sequences, which are sometimes required by the HP-UX 10 linker ๐Ÿ”— This is equivalent to the +k option to the HP compilers ๐Ÿ’…
  • -mportable-runtime โ€” Uses the portable calling conventions HP proposed for ELF systems ๐ŸŒˆ
  • -mgas โ€” Enables the use of assembler directives that only GAS understands ๐Ÿฃ
  • -mschedule=cpu-type โ€” Schedules code according to the constraints for the machine type cpu-type ๐Ÿ—“๏ธ The choices are 700 7100, 7100LC, 7200, 7300 and 8000. Same deal as before: check /usr/lib/sched.models on an HP-UX system to find the proper scheduling option for your machine. The default scheduling is 8000 โœจ
  • -mlinker-opt โ€” Enables the optimization pass in the HP-UX linker ๐Ÿ” Heads up: this makes symbolic debugging impossible ๐Ÿ˜ญ It also triggers a bug in the HP-UX 8 and HP-UX 9 linkers, where they give bogus error messages when linking some programs ๐Ÿซ 
  • -msoft-float โ€” Generates output containing 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 need 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. In particular, you need to compile libgcc.a, the library that comes with GCC, with -msoft-float for this to work ๐Ÿงต

  • -msio โ€” Generates the predefine _SIO for server IO ๐Ÿ–ฅ๏ธ The default is -mwsio. -mwsio generates the predefines __hp9000s700, __hp9000s700__ and _WSIO for workstation IO. Both 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 gets called is determined 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, it doesn't affect which ld gets called, only the parameters. That's still determined by the --with-ld configure option, GCC's program search path, and finally the user's PATH. You can print the linker used by GCC 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. Those limits for normal calls are 7,600,000 and 240,000 bytes, respectively for the PA 2.0 and PA 1.X architectures. Sibcalls are always limited at 240,000 bytes ๐Ÿ“

Distances are measured from the beginning of functions when using -ffunction-sections, or when using -mgas and -mno-portable-runtime together under HP-UX with the SOM linker ๐Ÿงญ

It's normally not desirable to use this option because it degrades performance ๐Ÿ˜ญ However, it may be useful in large applications, particularly when partial linking is used to build the application.

The types of long calls used depend on the capabilities of the assembler and linker, and the type of code being generated. The impact on systems that support long absolute calls, and long pic symbol-difference or pc-relative calls, should be relatively small. However, an indirect call is used on 32-bit ELF systems in pic code, and it is quite long ๐Ÿข

  • -munix=unix-std โ€” Generates compiler predefines and selects a startfile for the specified UNIX standard ๐Ÿ“œ The choices for unix-std are 93, 95 and 98. 93 is supported on all HP-UX versions. 95 is available on HP-UX 10.10 and later. 98 is available on HP-UX 11.11 and later. The default values are 93 for HP-UX 10.00, 95 for HP-UX 10.10 through 11.00, and 98 for HP-UX 11.11 and later ๐Ÿ—“๏ธ
  • -munix=93 โ€” okay so this one gives you the exact same predefines as GCC 3.3 and 3.4 ๐Ÿ’…
  • -munix=95 โ€” this one adds extra predefines for XOPEN_UNIX and _XOPEN_SOURCE_EXTENDED, plus the startfile unix95.o ๐Ÿฆ‹
  • -munix=98 โ€” this one adds even more predefines: _XOPEN_UNIX, _XOPEN_SOURCE_EXTENDED, _INCLUDE__STDC_A1_SOURCE, and _INCLUDE_XOPEN_SOURCE_500, plus the startfile unix98.o ๐ŸŒˆ
โš ๏ธ bestie, this option changes the interfaces for a bunch of library routines, and it also messes with how the C library behaves. Use it with extreme care ๐Ÿ˜ญ

Library code that's supposed 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 everywhere ๐Ÿ™ˆ

  • -nolibdld โ€” stops the generation of link options that search libdld.sl when -static is used on HP-UX 10 and later ๐Ÿ”—
  • -static โ€” the HP-UX version of setlocale in libc depends on libdld.sl, and there's no archive version of it โœจ So when you pass -static, you need special link options to sort that dependency out.

On HP-UX 10 and later, the GCC driver adds those necessary options for you when 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 with the dce thread library under HP-UX ๐Ÿงต It sets flags for both the preprocessor and the linker.

โœจ IA-64 Options โœจ

These are the -m options defined for the Intel IA-64 architecture ๐Ÿ’œ

  • -mbig-endian โ€” generates code for a big-endian target. This is the default for HP-UX ๐Ÿ“
  • -mlittle-endian โ€” generates code for a little-endian target. This is the default for AIX5 and GNU/Linux ๐ŸŒˆ
  • -mgnu-as, -mno-gnu-as โ€” generates (or doesn't generate) code for the GNU assembler. This is the default โœจ
  • -mgnu-ld, -mno-gnu-ld โ€” generates (or doesn't generate) code for the GNU linker. This is the default ๐Ÿ”—
  • -mno-pic โ€” generates code that doesn't use a global pointer register ๐Ÿ™…โ€โ™€๏ธ The result isn't position independent code, and it violates the IA-64 ABI, so be careful ๐Ÿ˜ฌ
  • -mvolatile-asm-stop, -mno-volatile-asm-stop โ€” generates (or doesn't generate) a stop bit right before and after volatile asm statements ๐Ÿ’…
  • -mregister-names, -mno-register-names โ€” generates (or doesn't generate) in, loc, and out register names for the stacked registers. This 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 a single constant global pointer value. This is useful when compiling kernel code ๐Ÿงš
  • -mauto-pic โ€” generates code that's self-relocatable. This implies -mconstant-gp. It's useful when compiling firmware code ๐Ÿซถ
  • -minline-float-divide-min-latency โ€” generates code for inline divides of floating-point values using the minimum latency algorithm ๐Ÿ”ฅ
  • -minline-float-divide-max-throughput โ€” generates code for inline divides of floating-point values using the maximum throughput algorithm ๐Ÿ”ฅ
  • -mno-inline-float-divide โ€” doesn't generate inline code for divides of floating-point values ๐Ÿ™ˆ
  • -minline-int-divide-min-latency โ€” generates code for inline divides of integer values using the minimum latency algorithm โญ
  • -minline-int-divide-max-throughput โ€” generates code for inline divides of integer values using the maximum throughput algorithm โญ
  • -mno-inline-int-divide โ€” doesn't generate inline code for divides of integer values ๐Ÿ™ˆ
  • -minline-sqrt-min-latency โ€” generates code for inline square roots using the minimum latency algorithm ๐ŸŒธ
  • -minline-sqrt-max-throughput โ€” generates code for inline square roots using the maximum throughput algorithm ๐ŸŒธ
  • -mno-inline-sqrt โ€” doesn't generate inline code for sqrt ๐Ÿ™ˆ
  • -mfused-madd, -mno-fused-madd โ€” does (or doesn't) generate code that uses the fused multiply/add or multiply/subtract instructions. The default is to use these instructions ๐Ÿ’–
  • -mno-dwarf2-asm, -mdwarf2-asm โ€” doesn't (or does) generate assembler code for the DWARF line number debugging info. This might be useful when you're not using the GNU assembler ๐Ÿฆ‹
  • -mearly-stop-bits, -mno-early-stop-bits โ€” allows stop bits to be placed earlier than immediately before the instruction that triggered the stop bit. This can improve instruction scheduling, but it doesn't always ๐Ÿคทโ€โ™€๏ธ
  • -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 ๐Ÿงš A register range is written as two registers separated by a dash, and you can give multiple ranges separated by a comma.
  • -mtls-size=tls-size โ€” specifies the bit size of immediate TLS offsets. The valid values are 14, 22, and 64 ๐ŸŽ€
  • -mtune=cpu-type โ€” tunes the 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 โ€” (dis/en)ables data speculative scheduling before reload. This results in generation of ld.a instructions and the matching check instructions (ld.c / chk.a). The default setting is disabled ๐ŸŒ€
  • -msched-ar-data-spec, -mno-sched-ar-data-spec โ€” (en/dis)ables data speculative scheduling after reload. This results in generation of ld.a instructions and the matching check instructions (ld.c / chk.a). The default setting is enabled ๐ŸŒ€
  • -mno-sched-control-spec, -msched-control-spec โ€” (dis/en)ables control speculative scheduling. This feature is only available during region scheduling (that is, before reload). It results in generation of the ld.s instructions and the matching check instructions chk.s. The default setting is disabled ๐ŸŒ€
  • -msched-br-in-data-spec, -mno-sched-br-in-data-spec โ€” (en/dis)ables speculative scheduling of instructions that depend on the data speculative loads before reload. This only works if -msched-br-data-spec is enabled. The default setting is enabled ๐ŸŒ€
  • -msched-ar-in-data-spec, -mno-sched-ar-in-data-spec โ€” (en/dis)ables speculative scheduling of instructions that depend on the data speculative loads after reload. This only works if -msched-ar-data-spec is enabled. The default setting is enabled ๐ŸŒ€
  • -msched-in-control-spec, -mno-sched-in-control-spec โ€” (en/dis)ables speculative scheduling of instructions that depend on the control speculative loads. This only works if -msched-control-spec is enabled. The default setting is enabled ๐ŸŒ€
  • -mno-sched-prefer-non-data-spec-insns, -msched-prefer-non-data-spec-insns โ€” if enabled, data-speculative instructions only get picked for scheduling when there are no other choices at the moment. This makes data speculation much more conservative. The default setting is disabled ๐Ÿซง
  • -mno-sched-prefer-non-control-spec-insns, -msched-prefer-non-control-spec-insns โ€” if enabled, control-speculative instructions only get picked for scheduling when there are no other choices at the moment. This makes control speculation much more conservative. The default setting is disabled ๐Ÿซง
  • -mno-sched-count-spec-in-critical-path, -msched-count-spec-in-critical-path โ€” if enabled, speculative dependencies get considered when computing instruction priorities. This makes speculation a bit more conservative. The default setting is disabled ๐Ÿซง
  • -msched-spec-ldc โ€” uses a simple data speculation check. This option is on by default โœ…
  • -msched-control-spec-ldc โ€” uses a simple check for control speculation. This option is on by default โœ…
  • -msched-stop-bits-after-every-cycle โ€” places a stop bit after every cycle when scheduling. This option is on by default โœ…
  • -msched-fp-mem-deps-zero-cost โ€” assumes that floating-point stores and loads 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 โ€” sets a limit on 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 preventing cache bank conflicts. The default value is 1 ๐Ÿง 
  • -msched-max-memory-insns-hard-limit โ€” makes the limit set by msched-max-memory-insns a hard limit, so no more than that number of memory insns can go in an instruction group. Otherwise the limit is "soft," which means non-memory operations get 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 โ€” enables divide and modulus instructions ๐Ÿ’ซ
  • -mmultiply-enabled โ€” enables multiply instructions ๐Ÿ’ซ
  • -msign-extend-enabled โ€” enables sign extend instructions ๐Ÿ’ซ
  • -muser-enabled โ€” enables user-defined instructions ๐Ÿ’ซ

๐Ÿฆ‹ M32C Options ๐Ÿฆ‹

  • -mcpu=name โ€” selects the CPU that code gets generated for. name can be r8c for the R8C/Tiny series, m16c for the M16C (up to /60) series, m32cm for the M16C/80 series, or m32c for the M32C/80 series ๐ŸŒˆ
  • -msim โ€” says the program will run on the simulator. This links in an alternate runtime library that supports things like file I/O ๐Ÿงช
๐Ÿšจ never use this option when you're generating programs that will run on real hardware! You have to provide your own runtime library for whatever I/O functions you need.
  • -memregs=number: okay so this one sets how many memory-based pseudo-registers GCC uses during code generation ๐Ÿ’พ. They get treated like real registers, which makes it a tradeoff: GCC can squeeze your code into the registers it has, but leaning on memory instead of actual registers costs performance ๐Ÿ˜ญ. Every module in a program has to be compiled with the same number, so 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: generate code for the M32R/2 ๐Ÿฆ‹
  • -m32rx: generate code for the M32R/X โœจ
  • -m32r: generate code for the M32R. This is the default ๐Ÿ‘‘
  • -mmodel=small: GCC assumes all objects live in the lower 16MB of memory, so their addresses can be loaded with the ld24 instruction, and that all subroutines are reachable with the bl instruction. This is the default ๐ŸŽ€

The addressability of a particular object can be set with the model attribute ๐Ÿ’….

  • -mmodel=medium: GCC assumes objects can be anywhere in the 32-bit address space, so it generates seth/add3 instructions to load their addresses, and assumes all subroutines are reachable with the bl instruction ๐ŸŒˆ.
  • -mmodel=large: GCC assumes objects can be anywhere in the 32-bit address space (generating seth/add3 instructions to load their addresses), and assumes subroutines might not be reachable with the bl instruction. This means it generates the much slower seth/add3/jl instruction sequence ๐Ÿข.
  • -msdata=none: disables the small data area. Variables go into one of .data, .bss, or .rodata (unless the section attribute has been specified). This is the default ๐Ÿ’œ.

The small data area consists of the sections .sdata and .sbss. Objects can be explicitly put in the small data area with the section attribute using one of these sections ๐Ÿงš.

  • -msdata=sdata: puts small global and static data in the small data area, but does not generate special code to reference them ๐Ÿ“.
  • -msdata=use: puts small global and static data in the small data area, and generates special instructions to reference them ๐Ÿ”ฅ.
  • -G num: puts global and static objects less than or equal to num bytes into the small data or BSS sections instead of the normal data or BSS sections. The default value of num is 8. The -msdata option must be set to one of sdata or use for this to have any effect ๐Ÿซถ.

All modules should be compiled with the same -G num value. Compiling with different values of num may or may not work. If it doesn't, the linker gives an error message. Incorrect code is not generated, though ๐Ÿ™ˆ.

  • -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 a 32-byte alignment for loops. This is the default ๐Ÿ’….
  • -missue-rate=number: issues number instructions per cycle. number can only be 1 or 2 โšก.
  • -mbranch-cost=number: number can only be 1 or 2. If it's 1, branches are preferred over conditional code. If it's 2, the opposite applies ๐Ÿฆ‹.
  • -mflush-trap=number: specifies the trap number to use to flush the cache. The default is 12, and valid numbers are between 0 and 15 inclusive ๐ŸŒธ.
  • -mno-flush-trap: specifies that the cache cannot be flushed by using a trap ๐Ÿšซ.
  • -mflush-func=name: specifies the name of the operating system function to call to flush the cache. The default is _flush_cache, but a function call is only used if a trap is not available ๐Ÿ› ๏ธ.
  • -mno-flush-func: indicates that there is no OS function for flushing the cache ๐Ÿ™…โ€โ™€๏ธ.

๐ŸŒˆ M680x0 Options ๐ŸŒˆ

These are the -m options defined for M680x0 and ColdFire processors. The default settings depend on which architecture was selected when the compiler was configured, so the defaults for the most common choices are given below ๐Ÿ’–.

  • -march=arch: generates code for a specific M680x0 or ColdFire instruction set architecture. Permissible values of arch for M680x0 architectures are 68000, 68010, 68020, 68030, 68040, 68060 and cpu32. ColdFire architectures are selected according to Freescale's ISA classification, and the permissible values are isaa, isaaplus, isab and isac ๐Ÿง .

GCC defines the macro __mcfarch__ whenever it's generating code for a ColdFire target. The arch in this macro is one of the -march arguments given above ๐ŸŽ€.

When used together, -march and -mtune select code that runs on a family of similar processors but is optimized for a particular microarchitecture โœจ.

  • -mcpu=cpu: generates code for a specific M680x0 or ColdFire processor. The M680x0 cpus are 68000, 68010, 68020, 68030, 68040, 68060, 68302, 68332 and cpu32. Here's the ColdFire table, which also sorts the CPUs into families ๐Ÿงš:
Family : -mcpu arguments
51 : 51 51ac 51ag 51cn 51em 51je 51jf 51jg 51jm 51mm 51qe 51qm
5206 : 5202 5204 5206
5206e : 5206e
5208 : 5207 5208
5211a : 5210a 5211a
5213 : 5211 5212 5213
5216 : 5214 5216
52235 : 52230 52231 52232 52233 52234 52235
5225 : 5224 5225
52259 : 52252 52254 52255 52256 52258 52259
5235 : 5232 5233 5234 5235 523x
5249 : 5249
5250 : 5250
5271 : 5270 5271
5272 : 5272
5275 : 5274 5275
5282 : 5280 5281 5282 528x
53017 : 53011 53012 53013 53014 53015 53016 53017
5307 : 5307
5329 : 5327 5328 5329 532x
5373 : 5372 5373 537x
5407 : 5407
5475 : 5470 5471 5472 5473 5474 5475 547x 5480 5481 5482 5483 5484
5485

-mcpu=cpu overrides -march=arch if arch is compatible with cpu. Other combinations of -mcpu and -march are rejected ๐Ÿšซ.

GCC defines the macro __mcf_cpu_cpu when a ColdFire target cpu is selected. It also defines __mcf_family_family, where the value of family is given by the table above ๐Ÿ’œ.

  • -mtune=tune: tunes the code for a particular microarchitecture within the constraints set by -march and -mcpu. The M680x0 microarchitectures are 68000, 68010, 68020, 68030, 68040, 68060 and cpu32. The ColdFire microarchitectures are cfv1, cfv2, cfv3, cfv4 and cfv4e ๐Ÿฆ‹.

You can also use -mtune=68020-40 for code that needs to run relatively well on 68020, 68030 and 68040 targets. -mtune=68020-60 is similar but includes 68060 targets as well. These two options select the same tuning decisions as -m68020-40 and -m68020-60 respectively ๐ŸŒธ.

GCC defines the macros __mcarch and __mcarch__ when tuning for 680x0 architecture arch. It also defines mcarch unless either -ansi or a non-GNU -std option is used. If GCC is tuning for a range of architectures, as selected by -mtune=68020-40 or -mtune=68020-60, it defines the macros for every architecture in the range ๐Ÿงš.

GCC also defines the macro __muarch__ when tuning for ColdFire microarchitecture uarch, where uarch is one of the arguments given above โœจ.

  • -m68000, -mc68000: generates output for a 68000. This is the default when the compiler is configured for 68000-based systems, and it's equivalent to -march=68000 ๐Ÿ’….

Use this option 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, and 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, and 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, and it's equivalent to -march=68030 ๐Ÿ’–.
  • -m68040: generates output for a 68040. This is the default when the compiler is configured for 68040-based systems, and it's equivalent to -march=68040 ๐Ÿ‘‘.

This option inhibits the use of 68881/68882 instructions that have to be emulated by 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, and it's equivalent to -march=68060 ๐Ÿ”ฅ.

This option inhibits the use of 68020 and 68881/68882 instructions that have to be emulated by software on the 68060. Use 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, and it's equivalent to -march=cpu32 ๐Ÿง .

Use this option for microcontrollers with a CPU32 or CPU32+ core, including the 68330, 68331, 68332, 68333, 68334, 68336, 68340, 68341, 68349 and 68360 ๐Ÿ’œ.

  • -m5200: generates output for a 520X ColdFire CPU. This is the default when the compiler is configured for 520X-based systems. It's equivalent to -mcpu=5206, and is deprecated in favor of that option ๐Ÿšง.

Use this option for microcontroller with a 5200 core, including the MCF5202, MCF5203, MCF5204 and MCF5206 โœจ.

  • -m5206e: generates output for a 5206e ColdFire CPU. The option is deprecated in favor of the equivalent -mcpu=5206e ๐Ÿšง.
  • -m528x: generates output for a member of the ColdFire 528X family. The option is deprecated in favor of the equivalent -mcpu=528x ๐Ÿšง.
  • -m5307: generates output for a ColdFire 5307 CPU. The option is deprecated in favor of the equivalent -mcpu=5307 ๐Ÿšง.
  • -m5407: generates output for a ColdFire 5407 CPU. The option is deprecated in favor of the equivalent -mcpu=5407 ๐Ÿšง.
  • -mcfv4e: generates output for a ColdFire V4e family CPU (e.g. 547x/548x). This includes the use of hardware floating-point instructions. It's equivalent to -mcpu=547x, and is deprecated in favor of that option ๐ŸŒŠ.
  • -m68020-40: generates output for a 68040, without using any of the new instructions. This results in code that can run relatively efficiently on a 68020/68881, a 68030, or a 68040. The generated code does use the 68881 instructions that are emulated on the 68040 ๐Ÿฆ‹.

Bestie, this one's basically the same as -march=68020 -mtune=68020-40 ๐Ÿ’–

  • -m68020-60 โ€” Okay, this one generates code for a 68060 but skips all the shiny new instructions ๐Ÿ’…. The result runs pretty efficiently on a 68020/68881, a 68030, or a 68040. The generated code does use the 68881 instructions, which the 68060 emulates ๐Ÿฆ‹
    • The option is equivalent to -march=68020 -mtune=68020-60.
  • -mhard-float, -m68881 โ€” Turns on floating-point instructions โœจ This is the default for 68020 and up, and for ColdFire devices that have an FPU. It defines the macro __HAVE_68881__ on M680x0 targets and __mcffpu__ on ColdFire targets.
  • -msoft-float โ€” No floating-point instructions here, just library calls instead ๐Ÿซถ This is the default for 68000, 68010, and 68832 targets, and also for ColdFire devices with no FPU.
  • -mdiv, -mno-div โ€” Generate (or don't generate) ColdFire hardware divide and remainder instructions ๐Ÿงฎ If -march is used without -mcpu, the default is "on" for ColdFire architectures and "off" for M680x0 architectures. Otherwise, the default comes from the target CPU (either the default CPU, or the one specified by -mcpu). For example, the default is "off" for -mcpu=5206 and "on" for -mcpu=5206e.
    • GCC defines the macro __mcfhwdiv__ when this option is enabled.
  • -mshort โ€” Treats 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 whose API mandates promotion to 32-bit.
  • -mno-short โ€” Don't treat int as 16 bits wide. This is the default ๐Ÿ’œ
  • -mnobitfield, -mno-bitfield โ€” Skip the bit-field instructions. -m68000, -mcpu32 and -m5200 imply -mnobitfield.
  • -mbitfield โ€” Use the bit-field instructions. -m68020 implies -mbitfield, and this is the default if you're using a configuration designed for a 68020 ๐ŸŒˆ
  • -mrtd โ€” Okay, this one swaps in a totally different function-calling convention ๐Ÿ“ Functions that take a fixed number of arguments return with the rtd instruction, which pops their arguments while returning. That saves one instruction in the caller, since there's no need to pop the arguments there.
    • This calling convention is incompatible with the one normally used on Unix, so you can't use it if you need to call libraries compiled with the Unix compiler ๐Ÿ™…
    • You must provide function prototypes for all functions that take variable numbers of arguments (including printf). Otherwise, incorrect code gets generated for calls to those functions.
    • Seriously incorrect code results if you call a function with too many arguments ๐Ÿ’€ (Normally, extra arguments are harmlessly ignored.)
    • The rtd instruction is supported by the 68010, 68020, 68030, 68040, 68060 and CPU32 processors, but not by the 68000 or 5200.
    • The default is -mno-rtd.
  • -malign-int, -mno-align-int โ€” Controls whether GCC aligns int, long, long long, float, double, and long double variables on a 32-bit boundary (-malign-int) or a 16-bit boundary (-mno-align-int) ๐Ÿ“ Aligning on 32-bit boundaries makes code run somewhat faster on processors with 32-bit busses, but it costs more memory.
โš ๏ธ Warning: if you use the -malign-int switch, GCC aligns structures containing the above types differently than most published application binary interface specifications for the m68k. Heads up, bestie ๐Ÿซถ

Use the pc-relative addressing mode of the 68000 directly, instead of using a global offset table ๐Ÿงญ At present, this option implies -fpic, allowing at most a 16-bit offset for pc-relative addressing. -fPIC is not presently supported with -mpcrel, though this could be supported for 68020 and higher processors.

  • -mno-strict-align, -mstrict-align โ€” -mno-strict-align means do not assume unaligned memory references are handled by the system, and -mstrict-align means do assume it ๐Ÿ™ƒ
  • -msep-data โ€” Generate code that lets the data segment live in a different area of memory from the text segment ๐Ÿงš This allows execute-in-place in an environment without virtual memory management. This option implies -fPIC.
  • -mno-sep-data โ€” Generate code that assumes the data segment follows the text segment. This is the default.
  • -mid-shared-library โ€” Generate code that supports shared libraries via the library ID method ๐Ÿฆ‹ This allows execute-in-place and shared libraries in an environment without virtual memory management. This option implies -fPIC.
  • -mno-id-shared-library โ€” Generate code that doesn't assume ID-based shared libraries are being used. This is the default.
  • -mshared-library-id=n โ€” Specifies the identification number of the ID-based shared library being compiled ๐Ÿ”ข Specifying a value of 0 generates more compact code. Other values force the allocation of that number to the current library, but that's no more space- or time-efficient than omitting this option.
  • -mxgot, -mno-xgot โ€” When generating position-independent code for ColdFire, this generates code that works if the GOT has more than 8192 entries ๐Ÿข It's larger and slower than code generated without this option. On M680x0 processors you don't need this option, since -fPIC is enough.
    • GCC normally uses a single instruction to load values from the GOT. 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_68K_GOT16O foobar
  • If this happens, recompile your code with -mxgot. It should then work with very large GOTs. However, 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 linkers, 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 โ€” Inline constants into the code stream if it can be done in two instructions or less โœจ
  • -mdiv, -mno-div โ€” Use the divide instruction. (Enabled by default.) ๐Ÿ”ฅ
  • -mrelax-immediate, -mno-relax-immediate โ€” Allow arbitrary-sized immediates in bit operations.
  • -mwide-bitfields, -mno-wide-bitfields โ€” Always treat bit-fields as int-sized.
  • -m4byte-functions, -mno-4byte-functions โ€” Force all functions to be aligned to a 4-byte boundary.
  • -mcallgraph-data, -mno-callgraph-data โ€” Emit callgraph information ๐Ÿ“Š
  • -mslow-bytes, -mno-slow-bytes โ€” Prefer word access when reading byte quantities.
  • -mlittle-endian, -mbig-endian โ€” Generate code for a little-endian target.
  • -m210, -m340 โ€” Generate code for the 210 processor.
  • -mno-lsim โ€” Assume runtime support has already been provided, so leave 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 the absolute difference between two registers ๐ŸŒˆ
  • -mall-opts โ€” Turns on every optional instruction: average, multiply, divide, bit operations, leading zero, absolute difference, min/max, clip, and saturation ๐Ÿ‘‘
  • -maverage โ€” Enables the ave instruction, which computes the average of two registers.
  • -mbased=n โ€” Variables of size n bytes or smaller get placed in the .based section by default ๐Ÿ’œ Based variables use the $tp register as a base register, and there's a 128-byte limit to the .based section.
  • -mbitops โ€” Enables the bit operation instructions: bit test (btstm), set (bsetm), clear (bclrm), invert (bnotm), and test-and-set (tas) ๐Ÿฆ‹
  • -mc=name โ€” Picks which section constant data gets placed in. name may be tiny, near, or far.
  • -mclip โ€” Enables the clip instruction. Note that -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 and 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. Note that the coprocessor is normally enabled via the -mconfig= option.
  • -mcop32 โ€” Enables the 32-bit coprocessor's instructions.
  • -mcop64 โ€” Enables the 64-bit coprocessor's instructions.
  • -mivc2 โ€” Enables IVC2 scheduling. IVC2 is a 64-bit VLIW coprocessor ๐Ÿ”ฅ
  • -mdc โ€” Causes constant variables to be placed in the .near section.
  • -mdiv โ€” Enables the div and divu instructions.
  • -meb โ€” Generate big-endian code.
  • -mel โ€” Generate little-endian code.
  • -mio-volatile โ€” Tells the compiler that any variable marked with the io attribute is to be considered volatile ๐Ÿ‘€
  • -ml โ€” Causes variables to be assigned to the .far section by default.
  • -mleadz โ€” Enables the leadz (leading zero) instruction.
  • -mm โ€” Causes variables to be assigned to the .near section by default.
  • -mminmax โ€” Enables the min and max instructions.
  • -mmult โ€” Enables the multiplication and multiply-accumulate instructions.
  • -mno-opts โ€” Disables all the optional instructions enabled by -mall-opts ๐Ÿ™…
  • -mrepeat โ€” Enables the repeat and erepeat instructions, which are used for low-overhead looping ๐Ÿ”
  • -ms โ€” okay so this one makes every variable default to the .tiny section ๐Ÿงš Heads up, that section has a 65536-byte limit ๐Ÿ™ˆ and accesses to these variables use the %gp base register ๐Ÿ’…
  • -msatur โ€” turns on the saturation instructions โœจ ngl the compiler doesn't actually generate these itself yet, but the flag is here for compatibility with other tools, like as ๐Ÿซถ
  • -msdram โ€” links the SDRAM-based runtime instead of the default ROM-based runtime ๐Ÿงธ
  • -msim โ€” links the simulator run-time libraries ๐Ÿ–ฅ๏ธ
  • -msimnovec โ€” links the simulator runtime libraries, but leaves out the built-in support for reset and exception vectors and tables ๐Ÿ™ƒ
  • -mtf โ€” makes all functions default to the .far section ๐Ÿฆ‹ Without this one, functions default to .near
  • -mtiny=n โ€” variables that are n bytes or smaller get put in the .tiny section, and they use the $gp base register ๐Ÿ’œ The default is 4, but remember the .tiny section has that 65536-byte limit too ๐Ÿ˜ญ

๐ŸŒธ MicroBlaze Options ๐ŸŒธ

  • -msoft-float โ€” software emulation for floating point, and this is the default ๐Ÿ’…
  • -mhard-float โ€” uses hardware floating-point instructions ๐Ÿ”ฅ
  • -mmemcpy โ€” don't optimize block moves, just use memcpy ๐Ÿ“
  • -mno-clearbss โ€” deprecated ๐Ÿ’€ use -fno-zero-initialized-in-bss instead
  • -mcpu=cpu-type โ€” uses the features of, and schedules code for, the CPU you pick ๐Ÿ‘‘ Supported values follow 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, and v6.00.a โœจ
  • -mxl-soft-mul โ€” software multiply emulation, the default ๐Ÿง
  • -mxl-soft-div โ€” software emulation for divides, also the default
  • -mxl-barrel-shift โ€” uses the hardware barrel shifter ๐ŸŽ๏ธ
  • -mxl-pattern-compare โ€” uses pattern compare instructions ๐ŸŽ€
  • -msmall-divides โ€” uses table lookup optimization for small signed integer divisions ๐Ÿงฎ
  • -mxl-stack-check โ€” deprecated, bestie ๐Ÿ’€ use -fstack-check instead
  • -mxl-gp-opt โ€” uses GP-relative ".sdata"/".sbss" sections ๐ŸŒˆ
  • -mxl-multiply-high โ€” uses multiply high instructions for the high part of a 32x32 multiply ๐Ÿ’ช
  • -mxl-float-convert โ€” uses hardware floating-point conversion instructions ๐Ÿ”„
  • -mxl-float-sqrt โ€” uses the hardware floating-point square root instruction โญ
  • -mbig-endian โ€” generates code for a big-endian target ๐Ÿ˜
  • -mlittle-endian โ€” generates code for a little-endian target ๐Ÿœ
  • -mxl-reorder โ€” uses reorder instructions (swap and byte reversed load/store) ๐Ÿ”€
  • -mxl-mode-app-model โ€” selects the application model app-model ๐Ÿซง The valid models are:
    • executable โ€” normal executable (default), uses the startup code crt0.o
    • -mpic-data-is-text-relative โ€” assumes the displacement between the text and data segments is fixed at static link time ๐Ÿงท This lets data get referenced by offset from the start of the text address instead of the GOT, since PC-relative addressing isn't supported
    • xmdstub โ€” for use with the Xilinx Microprocessor Debugger (XMD) based software intrusive debug agent called xmdstub ๐Ÿ” This one uses the startup file crt1.o and sets the start address of the program to 0x800
    • bootstrap โ€” for applications that get loaded by a bootloader ๐Ÿฅพ This model uses the startup file crt2.o, which doesn't contain a processor reset vector handler, so it's perfect for handing control back to the bootloader on a processor reset instead of the application
    • novectors โ€” for applications that don't need any of the MicroBlaze vectors ๐Ÿ™…โ€โ™€๏ธ This can be handy inside a monitoring application, and it uses crt3.o as its startup file

Option -xl-mode-app-model is a deprecated alias for -mxl-mode-app-model.


๐Ÿฆ‹ MIPS Options ๐Ÿฆ‹

  • -EB โ€” generates big-endian code ๐Ÿ’™
  • -EL โ€” generates little-endian code ๐Ÿ’œ This is the default for mips*el-*-* configurations
  • -march=arch โ€” generates code that runs on arch, which can be the name of a generic MIPS ISA or the name of a particular processor โœจ The ISA names are mips1, mips2, mips3, mips4, mips32, mips32r2, mips32r3, mips32r5, mips32r6, mips64, mips64r2, mips64r3, mips64r5 and mips64r6. The processor names are 4kc, 4km, 4kp, 4ksc, 4kec, 4kem, 4kep, 4ksd, 5kc, 5kf, 20kc, 24kc, 24kf2_1, 24kf1_1, 24kec, 24kef2_1, 24kef1_1, 34kc, 34kf2_1, 34kf1_1, 34kn, 74kc, 74kf2_1, 74kf1_1, 74kf3_2, 1004kc, 1004kf2_1, 1004kf1_1, i6400, i6500, interaptiv, loongson2e, loongson2f, loongson3a, gs464, gs464e, gs264e, m4k, m14k, m14kc, m14ke, m14kec, m5100, m5101, octeon, octeon+, octeon2, octeon3, orion, p5600, p6600, r2000, r3000, r3900, r4000, r4400, r4600, r4650, r4700, r5900, r6000, r8000, rm7000, rm9000, r10000, r12000, r14000, r16000, sb1, sr71000, vr4100, vr4111, vr4120, vr4130, vr4300, vr5000, vr5400, vr5500, xlr and xlp.
    • The special value from-abi picks the most compatible architecture for the selected ABI, which 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 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"
    • The "_MIPS_ARCH" macro uses the processor names listed above, so it has the full prefix and doesn't abbreviate 000 as k ๐Ÿ“ For from-abi, the macro names the resolved architecture (either "mips1" or "mips3"). It names the default architecture when no -march option is given
  • -mtune=arch โ€” optimizes for arch ๐ŸŽฏ Among other things, this one controls the way instructions get scheduled and the perceived cost of arithmetic operations. The list of arch values is the same as for -march
    • When this option isn't used, GCC optimizes for the processor specified by -march ๐Ÿ’ก By using -march and -mtune together, you can generate code that runs on a whole 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 ๐Ÿ”
  • -mips2 โ€” equivalent to -march=mips2 ๐Ÿ”
  • -mips3 โ€” equivalent to -march=mips3 ๐Ÿ”
  • -mips4 โ€” equivalent to -march=mips4 ๐Ÿ”
  • -mips32 โ€” equivalent to -march=mips32 ๐Ÿ”
  • -mips32r3 โ€” equivalent to -march=mips32r3 ๐Ÿ”
  • -mips32r5 โ€” equivalent to -march=mips32r5 ๐Ÿ”
  • -mips32r6 โ€” equivalent to -march=mips32r6 ๐Ÿ”
  • -mips64 โ€” equivalent to -march=mips64 ๐Ÿ”
  • -mips64r2 โ€” equivalent to -march=mips64r2 ๐Ÿ”
  • -mips64r3 โ€” equivalent to -march=mips64r3 ๐Ÿ”
  • -mips64r5 โ€” equivalent to -march=mips64r5 ๐Ÿ”
  • -mips64r6 โ€” equivalent to -march=mips64r6 ๐Ÿ”
  • -mips16, -mno-mips16 โ€” generates (or doesn't generate) MIPS16 code ๐Ÿงƒ If GCC is targeting a MIPS32 or MIPS64 architecture, it uses the MIPS16e ASE. You can also control MIPS16 code generation on a per-function basis with the mips16 and nomips16 attributes
  • -mflip-mips16 โ€” generates MIPS16 code on alternating functions ๐ŸŽข This one exists for regression testing of mixed MIPS16/non-MIPS16 code generation, so it's not meant for ordinary use when compiling your own code ๐Ÿšซ
  • -minterlink-compressed, -mno-interlink-compressed โ€” requires (or doesn'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, so it has to use a call or an indirect jump. -minterlink-compressed therefore disables direct jumps unless GCC knows the target of the jump isn't compressed
  • -minterlink-mips16, -mno-interlink-mips16 โ€” aliases of -minterlink-compressed and -mno-interlink-compressed ๐Ÿ•ฐ๏ธ These predate the microMIPS ASE and are kept around for backwards compatibility
  • -mabi=32, -mabi=o64, -mabi=n32, -mabi=64, -mabi=eabi โ€” generates code for the given ABI ๐ŸŽ€
    • The EABI has a 32-bit and a 64-bit variant ๐Ÿงฉ GCC normally generates 64-bit code when you pick a 64-bit architecture, but you can use -mgp32 to get 32-bit code instead
    • For info about the O64 ABI, check out <http://gcc.gnu.org/projects/mipso64-abi.html> ๐Ÿ“š
    • GCC supports a variant of the o32 ABI where the floating-point registers are 64 bits wide instead of 32 โœจ You can select this combo with -mabi=32 -mfp64. It relies on the mthc1 and mfhc1 instructions, so it's only supported for MIPS32R2, MIPS32R3, and MIPS32R5 processors ๐Ÿซถ
    • The register assignments for arguments and return values stay the same, but each scalar value gets passed in a single 64-bit register rather than a pair of 32-bit registers ๐Ÿ’… For example, scalar floating-point values are returned in $f0 only, not a $f0/$f1 pair. The set of call-saved registers also stays the same, in that the even-numbered double-precision registers are saved ๐Ÿฅฐ

Okay so bestie, there are two extra o32 ABI variants that help you transition from 32-bit to 64-bit registers ๐Ÿฆ‹. They're -mfpxx and -mfp64 -mno-odd-spreg (aka FP64A) ๐Ÿ’…. FPXX is the flexible one: all code has to run correctly with 32-bit or 64-bit registers ๐Ÿซถ. You can interlink it with FP32 or FP64, but not both at once ๐Ÿ˜ญ. FP64A is basically FP64 but it bans odd-numbered single-precision registers ๐Ÿ™ˆ. Pair it with the "FRE" mode of FPUs in MIPS32R5 processors and FP32 and FP64A code can link together and run in the same process without switching FPU modes โœจ iconic.

  • -mabicalls, -mno-abicalls โ€” Generate (or don't generate) code that fits SVR4-style dynamic objects ๐ŸŒธ. -mabicalls is the default on SVR4-based systems ๐Ÿ’–.
  • -mshared, -mno-shared โ€” Generate (or don't generate) fully position-independent code that can slot into shared libraries ๐Ÿงš. This only affects -mabicalls โœจ.

All -mabicalls code has traditionally been position-independent, no matter what -fPIC and -fpic say ๐Ÿ™„. But as an extension, the GNU toolchain lets executables use absolute accesses for locally-binding symbols, use shorter GP initialization sequences, and generate direct calls to locally-defined functions. That's the mode -mno-shared selects ๐Ÿ’….

-mno-shared needs binutils 2.16 or higher and makes objects that only the GNU linker can link ๐Ÿ”ฅ. The option doesn't change the ABI of the final executable, only the ABI of relocatable objects. Using -mno-shared usually makes executables both smaller and quicker ๐Ÿƒโ€โ™€๏ธ๐Ÿ’จ. -mshared is the default.

  • -mplt, -mno-plt โ€” Assume (or don't assume) that the static and dynamic linkers support PLTs and copy relocations ๐ŸŽ€. This only affects -mno-shared -mabicalls. For the n64 ABI, it does nothing without -msym32 ๐Ÿ™ˆ.

You can make -mplt the default by configuring GCC with --with-mips-plt. Otherwise the default is -mno-plt ๐Ÿ’œ.

  • -mxgot, -mno-xgot โ€” Lift (or don't lift) the usual limits on how big the global offset table can be ๐Ÿ“.

GCC normally uses one instruction to load values from the GOT. That's pretty efficient, but it only works if the GOT is smaller than about 64k ๐Ÿ˜ฌ. Anything bigger and the linker will throw something like this at you:

relocation truncated to fit: R_MIPS_GOT16 foobar

If that happens, recompile with -mxgot ๐Ÿซถ. It works with very large GOTs, but the code is also less efficient, because it takes three instructions to fetch the value of a global symbol ๐Ÿ’€.

Some linkers can create multiple GOTs. If you've got one of those, you should only need -mxgot when a single object file accesses more than 64k's worth of GOT entries. Very few linkers do ๐ŸŒˆ.

These options do nothing 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 any particular width for floating-point registers ๐Ÿฆ‹.
  • -mhard-float โ€” Use floating-point coprocessor instructions ๐Ÿ’….
  • -msoft-float โ€” Don't use floating-point coprocessor instructions. Do the floating-point math with library calls instead ๐Ÿซถ.
  • -mno-float โ€” Same as -msoft-float, but it also insists that the program never does any floating-point operations ๐Ÿ˜ญ. This is only supported by some bare-metal MIPS configurations, which may pick a special set of libraries that lack all floating-point support (including, for example, the floating-point "printf" formats) ๐Ÿ’€. If code compiled with -mno-float accidentally contains floating-point operations, it'll probably fail at link time or run time ๐Ÿ™ˆ.
  • -msingle-float โ€” Assume the floating-point coprocessor only does single-precision operations ๐ŸŒธ.
  • -mdouble-float โ€” Assume the floating-point coprocessor does double-precision operations. This is the default ๐Ÿ’œ.
  • -modd-spreg, -mno-odd-spreg โ€” Enable (or don't enable) odd-numbered single-precision floating-point registers for the o32 ABI ๐Ÿ“. This is the default for processors known to support them. With the o32 FPXX ABI, -mno-odd-spreg is set by default ๐Ÿ™ˆ.
  • -mabs=2008, -mabs=legacy โ€” These control how special not-a-number (NaN) IEEE 754 floating-point data gets handled by the "abs.fmt" and "neg.fmt" machine instructions ๐Ÿ‘‘.

By default, or when -mabs=legacy is used, the legacy treatment is selected ๐Ÿงš. Here, these instructions count as arithmetic and get avoided wherever correct operation matters and the input might be a NaN. Instead, a longer sequence that manipulates the sign bit by hand is used, unless -ffinite-math-only has also been specified ๐Ÿ˜ญ.

-mabs=2008 selects the IEEE 754-2008 treatment โœจ. These instructions count as non-arithmetic, so they operate correctly in all cases, including when the input operand is a NaN. They're always used for the respective operations ๐Ÿ’….

  • -mnan=2008, -mnan=legacy โ€” These control the encoding of special not-a-number (NaN) IEEE 754 floating-point data ๐Ÿฆ‹.

-mnan=legacy selects the legacy encoding ๐ŸŒธ. Here, quiet NaNs (qNaNs) are marked by the first bit of their trailing significand field being 0, and signaling NaNs (sNaNs) are marked by that first bit being 1 ๐Ÿ’–.

-mnan=2008 selects the IEEE 754-2008 encoding ๐Ÿ”ฅ. Here, qNaNs have that first bit set to 1, and sNaNs have it set to 0 โœจ.

The default is -mnan=legacy, unless GCC was configured with --with-nan=2008 ๐Ÿ‘‘.

  • -mllsc, -mno-llsc โ€” Use (or don't use) the ll, sc, and sync instructions to implement atomic memory built-in functions ๐ŸŽ€. If you specify neither, GCC uses those instructions as long as the target architecture supports them ๐Ÿซถ.

-mllsc is handy if the runtime environment can emulate the instructions, and -mno-llsc can be useful when compiling for nonstandard ISAs ๐Ÿงš. You can make either one the default by configuring GCC with --with-llsc or --without-llsc respectively. --with-llsc is the default for some configurations; check the installation documentation for details ๐ŸŒˆ.

  • -mdsp, -mno-dsp โ€” Use (or don't use) revision 1 of the MIPS DSP ASE ๐Ÿ’…. This 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 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 needs hardware floating-point support to be enabled ๐Ÿ™ˆ.
  • -mdmx, -mno-mdmx โ€” Use (or don't use) MIPS Digital Media Extension instructions ๐Ÿ”ฅ. This 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 with the "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 ๐Ÿงš. Check out -mlong32 for the lowdown on the default and how the pointer size gets determined ๐Ÿ™ˆ.
  • -mlong32 โ€” Force "long", "int", and pointer types to be 32 bits wide ๐ŸŒธ.

The default sizes of "int"s, "long"s, and pointers depend on the ABI ๐Ÿซถ. All the supported ABIs use 32-bit "int"s. The n64 ABI uses 64-bit "long"s, and so does the 64-bit EABI, but the others use 32-bit "long"s ๐Ÿ’…. Pointers are the same size as "long"s, or the same size as integer registers, whichever is smaller โœจ.

  • -msym32, -mno-sym32 โ€” Assume (or don't assume) that all symbols have 32-bit values, no matter which ABI you picked ๐Ÿฆ‹. This is useful together with -mabi=64 and -mno-abicalls, because it lets GCC generate shorter and faster references to symbolic addresses ๐Ÿ’–.
  • -G num โ€” Put definitions of externally-visible data in a small data section if that data is no bigger than num bytes ๐ŸŒˆ. GCC can then generate more efficient accesses to the data; see -mgpopt for details ๐Ÿ”ฅ.

The default -G option depends on the configuration ๐ŸŽ€.

  • -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 whining that an application is using too much small data, bestie, try rebuilding the less performance-critical parts with -mno-local-sdata ๐Ÿฅบ. You might also want to build large libraries with -mno-local-sdata too, so they leave more room for the main program ๐Ÿงš


  • -mextern-sdata, -mno-extern-sdata โ€” This one is about data defined somewhere else ๐Ÿงณ. GCC will assume it lives in a small data section (or not assume, with -mno-extern-sdata) as long as it fits under the -G limit. -mextern-sdata is the default for every configuration, periodt ๐Ÿ’…

Okay, but this part is a big deal ๐Ÿ˜ญ 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 another module defines Var, you must either compile that module with a high-enough -G setting or attach a "section" attribute to Var's definition. If Var is common, you must link the application with a high-enough -G setting.

The easiest way to keep this from going sideways is to compile and link every module with the same -G option ๐Ÿซถ. But if you want to build 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 the code is part of a library that might be used in a boot monitor, programs that call boot monitor routines pass an unknown value in $gp. (In those situations, the boot monitor itself is usually compiled with -G0.)

-mno-gpopt implies -mno-local-sdata and -mno-extern-sdata. Keep that in mind, it's giving domino effect ๐Ÿ‘€

  • -membedded-data, -mno-embedded-data โ€” Variables go to the read-only data section first if possible, then the small data section if possible, and otherwise into data. The code comes out slightly slower than the default, but it uses less RAM while running, so some embedded systems might prefer it โœจ
  • -muninit-const-in-rodata, -mno-uninit-const-in-rodata โ€” Puts uninitialized "const" variables in the read-only data section. This only means something when you're also using -membedded-data ๐ŸŽ€
  • -mcode-readable=setting โ€” Tells GCC whether it's allowed to generate code that reads from executable sections. There are three settings to choose from ๐ŸŒˆ
    • -mcode-readable=yes โ€” Instructions can freely access executable sections. This is the default, so you're probably already here ๐Ÿ’–
    • -mcode-readable=pcrel โ€” MIPS16 PC-relative load instructions can access executable sections, but other instructions must not. This is useful on 4KSc and 4KSd processors when the code TLBs have the Read Inhibit bit set. It's also handy on processors that can be configured with 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 โ€” Turns the %hi() and %lo() assembler relocation operators on (or off). This has been superseded by -mexplicit-relocs, but it's kept around for backwards compatibility ๐Ÿ“
  • -mexplicit-relocs, -mno-explicit-relocs โ€” Uses (or doesn't use) assembler relocation operators when dealing with symbolic addresses. The alternative, picked 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 โ€” Traps (or doesn'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"). So -mdivide-traps lets conditional traps happen on architectures that support them, and -mdivide-breaks forces 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 with -mno-check-zero-division.

  • -mload-store-pairs, -mno-load-store-pairs โ€” Turns an optimization on (or off) that pairs consecutive load or store instructions so they can do load/store bonding ๐Ÿฆ‹ It's on by default, but it only takes effect when the selected architecture is known to support bonding.
  • -mmemcpy, -mno-memcpy โ€” Forces (or doesn'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 โ€” Disables (or doesn'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 โ€” Enables (or disables) use of the "mad", "madu" and "mul" instructions, as provided by the R4650 ISA ๐ŸŒธ
  • -mimadd, -mno-imadd โ€” Enables (or disables) 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 โ€” Enables (or disables) use of the floating-point multiply-accumulate instructions, when they're available. The default is -mfused-madd ๐Ÿงš

Heads up on the R8000 CPU: when multiply-accumulate instructions are used, the intermediate product is calculated to infinite precision and is not subject to the FCSR Flush to Zero bit. That may be undesirable in some circumstances ๐Ÿ˜ฌ On other processors the result is numerically identical to the equivalent computation using separate multiply, add, subtract and negate instructions.

  • -nocpp โ€” Tells the MIPS assembler to not run its preprocessor over user assembler files (with a .s suffix) when assembling them ๐Ÿ™…โ€โ™€๏ธ
  • -mfix-24k, -mno-fix-24k โ€” Works around the 24K E48 (lost data on stores during refill) errata ๐Ÿฉน The workarounds are implemented by the assembler rather than by GCC.
  • -mfix-r4000, -mno-fix-r4000 โ€” Works around certain R4000 CPU errata:
    • A double-word or a variable shift may give an incorrect result if executed immediately after starting an integer division.
    • A double-word or a variable shift may give an incorrect result if executed while an integer multiplication is in progress.
    • An integer division may give an incorrect result if started in a delay slot of a taken branch or a jump.
  • -mfix-r4400, -mno-fix-r4400 โ€” Works around certain R4400 CPU errata:
    • A double-word or a variable shift may give an incorrect result if executed immediately after starting an integer division.
  • -mfix-r10000, -mno-fix-r10000 โ€” Works around certain R10000 errata ๐Ÿ”ง
    • "ll"/"sc" sequences may not behave atomically on revisions prior to 3.0. They may deadlock on revisions 2.6 and earlier.

This option can only be used if the target architecture supports branch-likely instructions. -mfix-r10000 is the default when -march=r10000 is used; -mno-fix-r10000 is the default otherwise.

  • -mfix-r5900, -mno-fix-r5900 โ€” Don't try 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, cause loops to execute only once or twice, due to a hardware bug in the R5900 chip. The workaround is implemented by the assembler rather than by GCC.
  • -mfix-rm7000, -mno-fix-rm7000 โ€” Works around the RM7000 "dmult"/"dmultu" errata. The workarounds are implemented by the assembler rather than by GCC ๐Ÿ“
  • -mfix-vr4120, -mno-fix-vr4120 โ€” Works around certain VR4120 errata:
    • "dmultu" does not always produce the correct result.
    • "div" and "ddiv" do not always produce the correct result if one of the operands is negative.

The workarounds for the division errata rely on special functions in libgcc.a. At the moment, these functions are only provided by the "mips64vr*-elf" configurations ๐Ÿ˜ค

Other VR4120 errata require a NOP to be inserted between certain pairs of instructions. Those are handled by the assembler, not by GCC itself.

  • -mfix-vr4130 โ€” Works around the VR4130 "mflo"/"mfhi" errata. The workarounds are implemented by the assembler rather than by GCC, although GCC avoids using "mflo" and "mfhi" if the VR4130 "macc", "macchi", "dmacc" and "dmacchi" instructions are available instead โœจ
  • -mfix-sb1, -mno-fix-sb1 โ€” Works around certain SB-1 CPU core errata. (This flag currently works around the SB-1 revision 2 "F1" and "F2" floating-point errata.) ๐ŸŒˆ
  • -mr10k-cache-barrier=setting โ€” Specifies whether GCC should insert cache barriers to avoid the side effects of speculation on R10K processors ๐Ÿง 

Like a lot of processors, the R10K tries to predict the outcome of a conditional branch and speculatively executes instructions from the "taken" branch. It later aborts those instructions if the predicted outcome was wrong. But on the R10K, even aborted instructions can have side effects ๐Ÿ’€

okay so this problem only hits kernel stores and, depending on the system, kernel loads ๐Ÿ˜ญ a speculatively-executed store can pull the target memory into cache and mark that cache line as dirty, even if the store itself gets aborted later ๐Ÿ™ˆ then if a DMA operation writes to that same memory before the "dirty" line is flushed, the cached data overwrites the DMA-ed data ๐Ÿ’€ see the R10K processor manual for the full tea, including other potential problems ๐Ÿ“–

one workaround is to slot cache barrier instructions in front of every memory access that might get speculatively executed and that might have side effects even if it's aborted ๐Ÿงฑ -mr10k-cache-barrier=setting is the knob that controls GCC's version of this fix ๐ŸŽ›๏ธ it assumes that aborted accesses to any byte in these regions don't have side effects:

  1. the memory occupied by the current function's stack frame;
  2. the memory occupied by an incoming stack argument;
  3. the memory occupied by an object with a link-time-constant address.

making sure speculative accesses to these regions are actually safe is the kernel's job, not GCC's ๐Ÿ‘‘

if the 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 respects this rule for functions it compiles itself ๐Ÿ’… it expects non-GCC functions (think hand-written assembly code) to play by the same rules ๐Ÿ“

this option comes in three flavors ๐ŸŒธ

  • -mr10k-cache-barrier=load-store โ€” drops a cache barrier in front of any load or store that might get speculatively executed and that might have side effects even if aborted ๐Ÿ”ฅ
  • -mr10k-cache-barrier=store โ€” same vibe, but only stores get a barrier ๐Ÿฉท
  • -mr10k-cache-barrier=none โ€” turns off cache barrier insertion entirely. This is the default setting ๐Ÿซถ
  • -mflush-func=func, -mno-flush-func โ€” picks which function gets called to flush the I and D caches, or tells GCC to skip calling 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 (which flushes both caches) โœจ the default depends on what target GCC was configured for, but it's usually _flush_func or __cpu_flush ๐ŸŒธ
  • 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 ๐Ÿคทโ€โ™€๏ธ a zero cost redundantly 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 selected architecture defaults to ๐ŸŽ€ by default, Branch Likely instructions may be generated if the selected architecture supports them. The exception is the MIPS32 and MIPS64 architectures (and processors that implement them): for those, Branch Likely instructions aren't 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 gets generated if one is available. If it isn't, a delay slot form of the branch is 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 if one is available ๐Ÿง 
  • -mfp-exceptions, -mno-fp-exceptions โ€” specifies whether FP exceptions are enabled. This affects how FP instructions are scheduled for some processors ๐ŸŽถ the default is that FP exceptions are enabled ๐Ÿ’–

for instance, on the SB-1, if FP exceptions are disabled and we're emitting 64-bit code, then we can use both FP pipes. Otherwise, we can only use one FP pipe ๐Ÿงš

  • -mvr4130-align, -mno-vr4130-align โ€” the VR4130 pipeline is two-way superscalar, but it can only issue two instructions together if the first one is 8-byte aligned ๐Ÿ˜ค when this option is enabled, GCC aligns pairs of instructions that it thinks should execute in parallel ๐ŸŒˆ

this option only has an effect when optimizing for the VR4130. It normally makes code faster, but at the expense of making it bigger ๐Ÿ“ฆ it's enabled by default at optimization level -O3 โญ

  • -msynci, -mno-synci โ€” enables (or disables) generation of "synci" instructions on architectures that support it ๐Ÿ› ๏ธ the "synci" instructions (if enabled) are generated when "__builtin___clear_cache" is compiled ๐Ÿ’…

this option defaults to -mno-synci, but you can override that default by configuring GCC with --with-synci ๐Ÿ”ง when compiling code for single processor systems, it's generally safe to use "synci" ๐Ÿ‘

โš ๏ธ heads up, bestie: on many multi-core (SMP) systems, "synci" doesn't invalidate the instruction caches on all cores and may lead to undefined behavior ๐Ÿ’€
  • -mrelax-pic-calls, -mno-relax-pic-calls โ€” tries to turn PIC calls that are normally dispatched via register $25 into direct calls ๐Ÿฆ‹ this is only possible if the linker can resolve the destination at link time and if the destination is within range for a direct call ๐Ÿ“

-mrelax-pic-calls is the default if GCC was configured to use an assembler and a linker that support the ".reloc" assembly directive and -mexplicit-relocs is in effect. With -mno-explicit-relocs, this optimization can be done by the assembler and the linker alone, without help from the compiler ๐Ÿซถ

  • -mmcount-ra-address, -mno-mcount-ra-address โ€” emits (or doesn't emit) code that lets "_mcount" modify the calling function's return address ๐Ÿ”ฎ when enabled, this option extends the usual "_mcount" interface with a new ra-address parameter. It has type "intptr_t *" and is passed in register $12 ๐ŸŽฏ "_mcount" can then modify the return address by doing both of the following:
    • returning the new address in register $31
    • storing the new address in "*ra-address", if ra-address is nonnull

the default is -mno-mcount-ra-address ๐Ÿ™ˆ

  • -mframe-header-opt, -mno-frame-header-opt โ€” enables (or disables) frame header optimization in the o32 ABI ๐Ÿงบ when using the o32 ABI, calling functions allocate 16 bytes on the stack for the called function to write out register arguments. When enabled, this optimization suppresses that frame header allocation 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 "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, passing all values in registers, no matter the size ๐Ÿงฉ
  • -mepsilon, -mno-epsilon โ€” generates floating-point comparison instructions that compare with respect to the "rE" epsilon register ๐ŸŽฏ
  • -mabi=mmixware, -mabi=gnu โ€” generates code that passes function parameters and return values that (in the called function) are seen as registers $0 and up ๐ŸŒธ the GNU ABI does it differently, using global registers $231 and up ๐Ÿ”
  • -mzero-extend, -mno-zero-extend โ€” when reading data from memory in sizes shorter than 64 bits, uses (or doesn't use) zero-extending load instructions by default, instead of sign-extending ones ๐Ÿ“
  • -mknuthdiv, -mno-knuthdiv โ€” 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 โ€” generates (or doesn't generate) code that uses base addresses. Using a base address automatically generates a request (handled by the assembler and the linker) for a constant to be set up in a global register. That register is used for one or more base address requests within the range 0 to 255 from the value held in the register. This generally leads to short and fast code, but the number of different data items that can be addressed is limited ๐Ÿ“‰ so a program that uses lots of static data may need -mno-base-addresses ๐Ÿ’€
  • -msingle-exit, -mno-single-exit โ€” forces (or doesn't force) generated code to have a single exit point in each function ๐Ÿšช

๐ŸŽ€ MN10300 Options ๐ŸŽ€

these -m options are defined for Matsushita MN10300 architectures:

  • -mmult-bug โ€” generates code to avoid bugs in the multiply instructions for the MN10300 processors. This is the default ๐Ÿ›ก๏ธ
  • -mno-mult-bug โ€” does not generate code to avoid bugs in the multiply instructions for the MN10300 processors ๐Ÿ™ƒ
  • -mam33 โ€” generates code using features specific to the AM33 processor ๐Ÿ’…
  • -mno-am33 โ€” does not generate code using features specific to the AM33 processor. This is the default ๐ŸŒท
  • -mam33-2 โ€” generates code using features specific to the AM33/2.0 processor ๐Ÿ‘‘
  • -mam34 โ€” okay bestie, this one unlocks features made specifically for the AM34 processor ๐Ÿ’…โœจ
  • -mtune=cpu-type โ€” tells the scheduler which CPU's timing to vibe with when it lines up instructions ๐ŸŽ€ It does not change the processor you're targeting, so no glow-up there. The CPU type has to be one of mn10300, am33, am33-2 or am34 ๐Ÿฆ‹
  • -mreturn-pointer-on-d0 โ€” when a function returns a pointer, this puts that pointer in both a0 and d0 ๐Ÿซถ Without it, the pointer only goes in a0, and calling those functions without a prototype throws errors ๐Ÿ˜ญ Heads up: this one is on by default. If you want it off, use -mno-return-pointer-on-d0 ๐Ÿ™ˆ
  • -mno-crt0 โ€” skips linking the C run-time initialization object file ๐ŸŒธ
  • -mrelax โ€” tells the linker to run a relaxation pass that shortens branches, calls and absolute memory addresses ๐Ÿ”ฅ This only does anything when you pass it on the command line for the final link step ๐Ÿ’œ
โš ๏ธ bestie, this one makes symbolic debugging impossible. Think before you flip it on ๐Ÿ’€
  • -mliw โ€” lets the compiler generate Long Instruction Word instructions when the target is AM33 or later ๐ŸŒˆ This is the default, and it defines the preprocessor macro __LIW__ โœจ
  • -mno-liw โ€” no LIW instructions for you ๐Ÿ™…โ€โ™€๏ธ This one defines the preprocessor macro __NO_LIW__ ๐Ÿซฅ
  • -msetlb โ€” allows the compiler to generate SETLB and Lcc instructions when the target is AM33 or later ๐Ÿงš This is the default, and it defines the preprocessor macro __SETLB__ ๐Ÿ’–
  • -mno-setlb โ€” blocks SETLB and Lcc instructions entirely ๐Ÿฅ€ It defines the preprocessor macro __NO_SETLB__ ๐ŸŽ€

๐Ÿฆ‹ Moxie Options ๐Ÿฆ‹

okay so these are the options defined for Moxie, and they're giving very specific vibes ๐ŸŒธ

  • -meb โ€” generates big-endian code ๐Ÿ‘‘ This is the default for moxie-*-* configurations ๐Ÿ’…
  • -mel โ€” generates little-endian code ๐Ÿ“
  • -mmul.x โ€” generates mul.x and umul.x instructions โœจ This is the default for moxiebox-*-* configurations ๐Ÿงš
  • -mno-crt0 โ€” skips linking the C run-time initialization object file, same as before, periodt ๐Ÿ’œ

๐ŸŒˆ MSP430 Options ๐ŸŒˆ

these options are defined for the MSP430, so if that's your chip, pay attention bestie ๐Ÿ‘€

  • -masm-hex โ€” forces assembly output to always use hex constants ๐Ÿ“ Normally these show up as signed decimals, but this option is there for testsuite and/or aesthetic purposes ๐ŸŽ€
  • -mmcu= โ€” selects the MCU you're targeting ๐Ÿฆ‹ The name gets converted to upper case, wrapped with __ before and after, and turned into a C preprocessor symbol ๐Ÿ’– The msp430.h header then uses that symbol to pick an MCU-specific supplementary header file ๐Ÿซถ

The option also sets the ISA to use ๐Ÿ”ฅ If the MCU name is known to only support the 430 ISA, that's what gets selected. Otherwise the 430X ISA is selected ๐Ÿ’… A generic MCU name of msp430 selects the 430 ISA, and the generic msp430x MCU name selects the 430X ISA โœจ

On top of that, an MCU-specific linker script gets added to the linker command line ๐ŸŒธ The script's name is the MCU name with .ld appended. So -mmcu=xxx on the gcc command line defines the C preprocessor symbol __XXX__ and makes the linker search for a script called xxx.ld ๐Ÿงš

The ISA and hardware multiply support for each MCU is hard-coded into GCC ๐Ÿ’œ But if you need more devices than that list covers, an external devices.csv file can extend device support ๐ŸŒˆ

GCC looks for devices.csv using the methods below, in 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 containing devices.csv, and GCC searches that directory for it ๐Ÿฆ‹ If the file is found, that directory also gets registered as an include path and a linker library path ๐Ÿ’– Header files and linker scripts in there can be used without manually specifying -I and -L on the command line ๐Ÿซถ
  3. The msp430-elf{,bare}/include/devices directory โ€” last stop: GCC checks msp430-elf{,bare}/include/devices from the toolchain root directory ๐Ÿ”ฅ This directory doesn't exist in a default installation, but if you've made it and copied devices.csv in there, the MCU data gets read ๐Ÿ’… Just like above, this directory also gets registered as an include path and linker library path โœจ

If none of those search methods find devices.csv, the hard-coded MCU data is used ๐ŸŒธ

  • -mwarn-mcu, -mno-warn-mcu โ€” this option enables or disables warnings about 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 ๐Ÿงš It's on by default ๐Ÿ’œ
  • -mcpu= โ€” specifies the ISA to use ๐Ÿฅ€ Accepted values are msp430, msp430x and msp430xv2 ๐ŸŽ€ This option is deprecated, so use -mmcu= to select the ISA instead ๐Ÿ’€
  • -msim โ€” links to the simulator runtime libraries and linker script ๐Ÿฆ‹ This overrides any scripts that would've been selected by -mmcu= ๐Ÿ‘‘
  • -mlarge โ€” uses large-model addressing, with 20-bit pointers and a 32-bit size_t ๐Ÿ”ฅ
  • -msmall โ€” uses small-model addressing, with 16-bit pointers and a 16-bit size_t ๐Ÿซถ
  • -mrelax โ€” this one gets passed to the assembler and linker ๐ŸŒˆ It lets the linker do certain optimizations that can't happen until the final link โœจ
  • -mhwmult= โ€” describes the type of hardware multiply the target supports ๐Ÿ’– Accepted values are none for no hardware multiply, 16bit for the original 16-bit-only multiply from early MCUs, 32bit for the 16/32-bit multiply in later MCUs, and f5series for the 16/32-bit multiply in F5-series MCUs ๐Ÿงš You can also give auto, which tells GCC to figure out the hardware multiply support from the MCU name you passed with -mmcu ๐Ÿ’… If there's no -mmcu option, or the MCU name isn't recognized, no hardware multiply support is assumed ๐Ÿ˜ญ auto is the default setting ๐ŸŒธ

Hardware multiplies are normally done by calling a library routine, which saves space in the generated code ๐Ÿ“ When you compile at -O3 or higher, though, the hardware multiplier gets invoked inline ๐Ÿ”ฅ That makes the code bigger, but faster ๐Ÿ’œ

The hardware multiply routines disable interrupts while they run and restore the previous interrupt state when they finish ๐Ÿซถ So they're safe to use inside interrupt handlers as well as in normal code ๐Ÿ‘‘

  • -minrt โ€” enables a minimum runtime environment with no static initializers or constructors ๐Ÿฅ€ It's meant for memory-constrained devices ๐ŸŽ€ The compiler puts 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 ๐Ÿ’– These tiny versions are not reentrant, so be careful with them in multi-threaded apps ๐Ÿ˜ฌ

Stream support has been removed, and the string to print always goes to stdout via the write syscall ๐Ÿงš The string isn't buffered before it's sent to write ๐ŸŒˆ

This option requires Newlib Nano IO, so GCC must be configured with --enable-newlib-nano-formatted-io โœจ

  • -mcode-region=, -mdata-region= โ€” these tell the compiler where to place functions and data that don't have one of the lower, upper, either or section attributes ๐Ÿซถ The possible values are lower, upper, either or any, and the first three behave like the matching attribute ๐Ÿ’… The fourth value, any, is the default ๐Ÿ”ฅ It leaves placement entirely up to the linker script and how it assigns the standard sections (.text, .data, etc) to the memory regions ๐ŸŒธ
  • -msilicon-errata= โ€” passes a request to the assembler to enable the fixes for the named silicon errata ๐Ÿฆ‹
  • -msilicon-errata-warn= โ€” passes a request to the assembler to enable warning messages for when a silicon errata might need to be applied ๐Ÿ™ˆ
  • -mwarn-devices-csv, -mno-warn-devices-csv โ€” warns if devices.csv isn't found or there are problems parsing it ๐Ÿงš Default is on ๐Ÿ’œ

๐Ÿ’œ NDS32 Options ๐Ÿ’œ

these options are defined for NDS32 implementations, so let's get into it ๐ŸŒˆ

  • -mbig-endian โ€” generates code in big-endian mode ๐Ÿ‘‘
  • -mlittle-endian โ€” generates code in little-endian mode ๐Ÿ“
  • -mreduced-regs โ€” uses reduced-set registers for register allocation ๐Ÿฅ€
  • -mfull-regs โ€” uses full-set registers for register allocation ๐Ÿ’–
  • -mcmov โ€” generates conditional move instructions โœจ
  • -mno-cmov โ€” does not generate conditional move instructions ๐Ÿ™…โ€โ™€๏ธ
  • -mext-perf โ€” generates performance extension instructions ๐Ÿ”ฅ
  • -mno-ext-perf โ€” does not generate performance extension instructions ๐ŸŒธ
  • -mext-perf2 โ€” generates performance extension 2 instructions ๐Ÿฆ‹
  • -mno-ext-perf2 โ€” does not generate performance extension 2 instructions ๐Ÿซถ
  • -mext-string โ€” generates string extension instructions ๐Ÿงš
  • -mno-ext-string โ€” does not generate string extension instructions ๐Ÿ’…
  • -mv3push โ€” generates v3 push25/pop25 instructions ๐ŸŽ€
  • -mno-v3push โ€” does not generate v3 push25/pop25 instructions ๐Ÿฅ€
  • -m16-bit โ€” generates 16-bit instructions ๐ŸŒˆ
  • -mno-16-bit โ€” does not generate 16-bit instructions ๐Ÿ™ˆ
  • -misr-vector-size=num โ€” specifies the size of each interrupt vector, which must be 4 or 16 ๐Ÿ‘‘
  • -mcache-block-size=num โ€” specifies the size of each cache block, which must be a power of 2 between 4 and 512 ๐Ÿ’–
  • -march=arch โ€” specifies the name of the target architecture ๐Ÿงš
  • -mcmodel=code-model โ€” sets the code model to one of the values below ๐Ÿ’…
    • 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: Okay bestie, the data segment has to squeeze into 512KB, but the read-only data can roam anywhere in a 4GB addressing space. ๐Ÿ’– The text segment should still stay within 16MB addressing space. ๐Ÿซถ
  • large: All the text and data segments can live within a 4GB addressing space. โœจ
  • -mctor-dtor: Turns on the constructor/destructor feature. ๐ŸŽ€
  • -mrelax: Tells the linker to relax instructions. ๐Ÿฆ‹

๐ŸŒธ Nios II Options ๐ŸŒธ

These are the options defined for the Altera Nios II processor. ๐Ÿ’…

  • -G num: Puts global and static objects that are less than or equal to num bytes into the small data or BSS sections instead of the normal data or BSS sections. The default value of num is 8. ๐Ÿ“
  • -mgpopt=option, -mgpopt, -mno-gpopt: Okay so these control whether GP-relative accesses get generated (or not!). The following 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. Also use GP-relative addressing for objects that have been explicitly placed in a small data section via a "section" attribute. โœจ
    • global: As for local, but also generate GP-relative accesses for small data objects that are external, weak, or common. If you use this option, you must ensure 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.

Heads up: the Nios II ABI does not permit GP-relative accesses from shared libraries. ๐Ÿšซ

You may need to specify -mno-gpopt explicitly when building programs that include large amounts of small data, including large GOT data sections. In this case, the 16-bit offset for GP-relative addressing may not be large enough to allow access to the entire small data section. ๐ŸŒˆ

  • -mgprel-sec=regexp: This option specifies additional section names that can be accessed via GP-relative addressing. It is most useful in conjunction with "section" attributes on variable declarations and a custom linker script. The regexp is a POSIX Extended Regular Expression. This option does not affect the behavior of the -G option, and 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 specifies names of sections that can be accessed via a 16-bit offset from "r0"; that is, in the low 32K or high 32K of the 32-bit address space. It is most useful in conjunction with "section" attributes on variable declarations and a custom linker script. The regexp is a POSIX Extended Regular Expression. In contrast to the use of GP-relative addressing for small data, zero-based addressing is never generated by default and there are no conventional section names used in standard linker scripts for sections in the low or high areas of memory. ๐Ÿฆ–
  • -mel, -meb: Generate little-endian (default) or big-endian (experimental) code, respectively. ๐ŸŒŠ
  • -march=arch: This specifies the name of the target Nios II architecture. GCC uses this name to determine what kind of instructions it can emit when generating assembly code. Permissible names are: r1, r2. The preprocessor macro "__nios2_arch__" is available to programs, 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 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 emitting the mul, mulx, and div family of instructions by the compiler. The default is to emit mul and not emit div and 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 these instructions are optional extensions to the R2 architecture, the default is not to emit them. ๐Ÿง 
  • -mcustom-insn=N, -mno-custom-insn: Each -mcustom-insn=N option enables use of a custom instruction with encoding N when generating code that uses insn. For example, -mcustom-fadds=253 generates custom instruction 253 for single-precision floating-point add operations instead of the default behavior of using a library call. ๐Ÿ”ง

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 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 the following transfer instructions for internal registers X and Y must be provided to use any of the double-precision floating-point instructions. Custom instructions taking two double-precision source operands expect the first operand in the 64-bit register X. The other operand (or only operand of a unary operation) is given to the custom arithmetic instruction with the least significant half in source register src1 and the most significant half in src2. A custom instruction that returns a double-precision result returns the most significant 32 bits in the destination register and the other half in 32-bit register Y. GCC automatically generates the necessary code sequences to write register X and/or read register Y when double-precision floating-point instructions are used. ๐Ÿง

  • fwrx: Write src1 into the least significant half of X and src2 into the most significant half of X.
  • fwry: Write src1 into Y.
  • frdxhi, frdxlo: Read the most or least (respectively) significant half of X and store it in dest.
  • frdy: Read the value of Y and store it into dest.

Note that you can gain more local control over generation of Nios II custom instructions by using the target("custom-insn=N") and target("no-custom-insn") function attributes or pragmas. ๐ŸŽ€

  • -mcustom-fpu-cfg=name: This option enables a predefined, named set of custom instruction encodings (see -mcustom-insn above). Currently, the following sets are defined:
    • -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

Custom instruction assignments given by individual -mcustom-insn= options override those given by -mcustom-fpu-cfg=, regardless of the order of the options on the command line. ๐Ÿ‘‘

Okay so, you can get way more local control over which FPU configuration you're using by slapping target("custom-fpu-cfg=name") on as a function attribute or pragma ๐ŸŽ€โœจ

These additional -m options are available for the Altera Nios II ELF (bare-metal) target ๐Ÿงš

  • -mhal โ€” Links with the HAL BSP ๐Ÿ”— This skips linking the GCC-provided C runtime startup and termination code, and it's usually paired with -msys-crt0= so you can point at the alternate startup code the HAL BSP brings along ๐Ÿ’…
  • -msmallc โ€” Links with a limited C library, -lsmallc, instead of Newlib ๐ŸŒธ
  • -msys-crt0=startfile โ€” startfile is the name of the startfile (crt0) you want when linking ๐Ÿฆ‹ This only does anything alongside -mhal, so don't expect magic without it ๐Ÿ™ˆ
  • -msys-lib=systemlib โ€” systemlib is the name of the library that supplies the low-level system calls the C library needs, like read and write ๐Ÿซถ This is usually how you link against a library from a HAL BSP

โœจ Nvidia PTX Options โœจ

These options are defined for Nvidia PTX ๐Ÿ’œ

  • -m32, -m64 โ€” Generates code for the 32-bit or 64-bit ABI ๐Ÿ”ฅ
  • -misa=ISA-string โ€” Generates code for the PTX ISA you specify, like sm_35 ๐Ÿ’– ISA strings have to be lower-case, and valid ones include sm_30 and sm_35. The default is sm_30 ๐Ÿ‘‘
  • -mmainkernel โ€” Links in code for a __main kernel ๐Ÿงš This is for stand-alone execution rather than offloading ๐ŸŒˆ
  • -moptimize โ€” Applies partitioned execution optimizations โญ This is on by 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 gets maintained explicitly ๐Ÿฆ‹ This unlocks variable-length stack allocation (with variable-length arrays or alloca). When global memory is the underlying storage, it also makes it possible to access automatic variables from other threads, or with atomic instructions ๐Ÿ˜ญ This codegen 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 codegen variant that lets every thread in each warp execute, while memory state and side effects still look like only one thread per warp was active outside of OpenMP SIMD regions ๐Ÿ”ฅ All atomic operations and calls to runtime functions (malloc, free, vprintf) are conditionally executed (iff the current lane index equals the master lane index). The register being assigned gets copied from the master lane via a shuffle instruction ๐Ÿ’€ Outside of SIMD regions, lane 0 is the master. Inside them, each thread sees itself as the master ๐ŸŒธ A shared memory array int __nvptx_uni[] stores all-zeros or all-ones bitmasks for each warp, showing the current mode (0 outside of SIMD regions) โœจ Each thread can bitwise-and the bitmask at position tid.y with the current lane index to work out the master lane index ๐Ÿง 
  • -mgomp โ€” Generates code for OpenMP offloading ๐ŸŽ€ This enables -msoft-stack and -muniform-simt, and selects the matching 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 โ€” This option is ignored and only exists for compatibility purposes ๐Ÿ™ˆ It used to select linker and preprocessor options for use with newlib
  • -msoft-div, -mhard-div โ€” Selects software or hardware divide (l.div, l.divu) instructions. This default is hardware divide ๐Ÿฆ‹
  • -msoft-mul, -mhard-mul โ€” Selects software or hardware multiply (l.mul, l.muli) instructions. This default is hardware multiply ๐ŸŒˆ
  • -msoft-float, -mhard-float โ€” Selects software or hardware for floating point operations. The default is software ๐Ÿซถ
  • -mdouble-float โ€” When -mhard-float is selected, this enables generation of double-precision floating point instructions ๐Ÿ’– By default, functions from libgcc handle double-precision floating point operations ๐Ÿง 
  • -munordered-float โ€” When -mhard-float is selected, this enables generation of unordered floating point compare and set flag (lf.sfun*) instructions โœจ By default, functions from libgcc handle unordered floating point compare and set flag operations ๐Ÿ’…
  • -mcmov โ€” Enables generation of conditional move (l.cmov) instructions ๐ŸŽ€ By default, the equivalent gets generated using set and branch ๐Ÿฆ‹
  • -mror โ€” Enables generation of rotate right (l.ror) instructions ๐Ÿ”ฅ By default, functions from libgcc handle rotate right operations ๐Ÿ’€
  • -mrori โ€” Enables generation of rotate right with immediate (l.rori) instructions ๐ŸŒธ By default, functions from libgcc handle rotate right with immediate operations ๐Ÿ’œ
  • -msext โ€” Enables generation of sign extension (l.ext*) instructions โญ By default, memory loads are used to do 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 ๐Ÿซถ

โœจ PDP-11 Options โœจ

These options are defined for the PDP-11 ๐ŸŒˆ

  • -mfpu โ€” Uses hardware FPP floating point, and this is the default ๐Ÿ’– (FIS floating point on the PDP-11/40 isn't 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 โ€” Sets the instruction set, register set, and instruction scheduling parameters for array element type ae_type. Supported values for ae_type are ANY, MUL, and MAC โœจ
    • -mae=ANY โ€” Selects a completely generic AE type ๐ŸŒˆ Code generated with this option runs on any of the other AE types ๐Ÿง  It isn't as efficient as code compiled for a specific AE type, and some operations (e.g., multiplication) don't work properly on every type of AE ๐Ÿ’€
    • -mae=MUL โ€” Selects a MUL AE type. This is the most useful AE type for compiled code, and it's the default ๐Ÿ‘‘
    • -mae=MAC โ€” Selects a DSP-style MAC AE ๐Ÿ”ฅ Code compiled with this option may suffer from poor performance of byte (char) manipulation, since the DSP AE doesn't have hardware support for byte load/stores ๐Ÿ˜ญ
  • -msymbol-as-address โ€” Lets the compiler use a symbol name directly as an address in a load/store instruction, without loading it into a register first ๐Ÿฆ‹ This usually makes programs larger but faster, though results vary from program to program ๐Ÿซถ That's why it's left as a user option instead of being permanently enabled ๐Ÿ’…
  • -mno-inefficient-warnings โ€” Disables warnings about generating inefficient code ๐Ÿ™ˆ These warnings can show up when you compile code doing byte-level memory operations on the MAC AE type. The MAC AE has no hardware support for byte-level memory operations, so every byte load/store has to be synthesized from word load/store operations ๐Ÿ’€ That's inefficient, so GCC warns you to rewrite the code to avoid byte operations, or to target an AE type with the right hardware support. This option turns those warnings off ๐ŸŒธ

๐Ÿ‘‘ 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, with no support for static initializers and constructors ๐Ÿงš Using this can significantly shrink the final ELF binary ๐Ÿ“‰
Beware! The compiler could still generate code with static initializers and constructors. It's up to you, the programmer, to make sure your source program won't use those features ๐Ÿ’€
  • -mmcu=mcu โ€” Specifies the PRU MCU variant to use. Check Newlib for the exact list of supported MCUs ๐Ÿ”ฅ
  • -mno-relax โ€” Makes GCC pass the --no-relax command-line option to the linker instead of --relax ๐Ÿฆ‹
  • -mloop โ€” Allows (or doesn't allow) GCC to use the LOOP instruction โœจ
  • -mabi=variant โ€” Specifies the ABI variant to output code for. -mabi=ti selects the unmodified TI ABI, while -mabi=gnu selects a GNU variant that copes more naturally with certain GCC assumptions ๐ŸŽ€ These are the differences:
    • Function Pointer Size โ€” TI ABI specifies that function (code) pointers are 16-bit, whereas GNU supports only 32-bit data and code pointers ๐Ÿ’…
    • Optional Return Value Pointer โ€” Function return values larger than 64 bits get passed using a hidden pointer as the first argument of the function. TI ABI, though, mandates that the pointer can be NULL in case the caller isn't using the returned value. GNU always passes and expects a valid return value pointer ๐Ÿซถ
The current -mabi=ti implementation simply raises a compile error when any of the above code constructs is detected. As a consequence, the standard C library can't be built, and it's omitted when linking with -mabi=ti ๐Ÿ˜ญ

Okay so the TI relaxation thing is a whole vibe check ๐Ÿ™ˆ relaxation is a GNU feature, and for safety reasons it's switched off when you use -mabi=ti ๐Ÿ’…. The TI toolchain doesn't emit relocations for QBBx instructions, so the GNU linker can't adjust them when it shortens the adjacent LDI32 pseudo instructions. Not the vibe ๐Ÿ’€

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

These are the RISC-V flags ๐Ÿงš (only for RISC-V targets, so no mixing them up, bestie):

  • -mbranch-cost=n โ€” sets the cost of branches to roughly n instructions โœจ
  • -mplt, -mno-plt โ€” when you're making PIC code, these decide whether PLTs are allowed (-mplt) or kept out (-mno-plt) ๐ŸŒธ. They're ignored for non-PIC. The default is -mplt.
  • -mabi=ABI-string โ€” this 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 (so int is implicitly 32-bit), and floating-point values up to 64 bits wide get passed in F registers ๐Ÿ”ฅ.
    • Compare that with -march=rv64ifd -mabi=lp64f ๐Ÿ™ˆ. The compiler can still generate code that uses the F and D extensions, but only floating-point values up to 32 bits long get passed in registers.
    • Or -march=rv64ifd -mabi=lp64, where no floating-point arguments get passed in registers at all.
    • The default is system dependent, so if you want a specific calling convention, specify one explicitly ๐Ÿซถ.
    • The valid calling conventions are ilp32, ilp32f, ilp32d, lp64, lp64f, and lp64d.
    • Some conventions are impossible on some ISAs. For example, -march=rv32if -mabi=ilp32d is invalid, because the ABI requires 64-bit values to be passed in F registers, but F registers are only 32 bits wide ๐Ÿ’€.
    • There's also the ilp32e ABI, which can only be used with the rv32e architecture. It's not well specified at present and is subject to change.
  • -mfdiv, -mno-fdiv โ€” do or don'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 specified architecture has these instructions.
  • -mdiv, -mno-div โ€” do or don't use hardware instructions for integer division โž—. This needs the M extension. The default is to use them if the specified architecture has these instructions.
  • -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.
  • -mtune=processor-string โ€” optimizes the output for the given processor, specified by microarchitecture name ๐ŸŽ€. The permissible values are rocket, sifive-3-series, sifive-5-series, sifive-7-series, and size.
    • When -mtune= isn't specified, 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 provided by -mtune=, but it does not override the pipeline info. This helps reduce code size while still giving good performance.
  • -mpreferred-stack-boundary=num โ€” attempts to keep the stack boundary aligned to a 2 raised to num byte boundary ๐Ÿ“š. If -mpreferred-stack-boundary isn't specified, the default is 4 (16 bytes or 128-bits).
Warning: If you use this switch, then you must build all modules with the same value, including any libraries. This includes the system libraries and startup modules ๐Ÿšจ.
  • -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 โ€” do or don't use smaller but slower prologue and epilogue code that uses library function calls ๐Ÿข. The default is to use fast inline prologues and epilogues โšก.
  • -mstrict-align, -mno-strict-align โ€” do not or do generate unaligned memory accesses ๐Ÿงฑ. 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 must lie 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 โ€” use or don't use assembler relocation operators when dealing with symbolic addresses ๐Ÿ”—. The alternative is to use 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 linker relaxations.
  • -memit-attribute, -mno-emit-attribute โ€” emits (or doesn't emit) a RISC-V attribute to record extra information into ELF objects ๐Ÿท๏ธ. This feature requires at least binutils 2.32.
  • -malign-data=type โ€” controls how GCC aligns variables and constants of array, structure, or union types ๐Ÿ“. The supported values for type are xlen, which uses the x register width as the alignment value, and natural, which uses natural alignment. xlen is the default.

๐ŸŒธ RL78 Options ๐ŸŒธ

  • -msim โ€” links in additional target libraries so things can run inside a simulator ๐Ÿ–ฅ๏ธ.
  • -mmul=none, -mmul=g10, -mmul=g13, -mmul=g14, -mmul=rl78 โ€” picks the type of hardware multiplication and division support to use โœ–๏ธโž—. The simplest 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 selects the multiplication and division instructions supported by the RL78/G14 (S3 core) parts ๐Ÿ’–. The value "rl78" is an alias for "g14", and the value "mg10" is an alias for "none".
    • A C preprocessor macro is also 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 โ€” specifies the RL78 core to target ๐ŸŽฏ. The default is the G14 core, also known as an S3 core or just RL78 ๐Ÿ‘‘.
    • The G13 or S2 core doesn't have multiply or divide instructions. It uses a hardware peripheral for those operations instead.
    • The G10 or S1 core doesn't have register banks, so it uses a different calling convention.
    • If this option is set, it also selects the type of hardware multiply support to use, unless you override it with an explicit -mmul=none option on the command line. So -mcpu=g13 enables the G13 hardware multiply peripheral, and -mcpu=g10 disables hardware multiplications altogether ๐Ÿ™….
    • Heads up, although the RL78/G14 core is the default target, specifying -mcpu=g14 or -mcpu=rl78 on the command line does change the toolchain's behavior, since it also enables G14 hardware multiply support ๐Ÿ‘€. If these options aren't specified on the command line, software multiplication routines will be 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 ๐Ÿ•ฐ๏ธ.
    • A C preprocessor macro is also 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 here for backwards compatibility.
  • -mallregs โ€” lets the compiler use all of the available registers ๐ŸŒˆ. By default, registers "r24..r31" are reserved for interrupt handlers. With this option enabled, they can be used in ordinary functions too ๐Ÿ”“.
  • -m64bit-doubles, -m32bit-doubles โ€” makes the "double" data type 64 bits (-m64bit-doubles) or 32 bits (-m32bit-doubles) in size ๐Ÿ“. The default is -m32bit-doubles.
  • -msave-mduc-in-interrupts, -mno-save-mduc-in-interrupts โ€” specifies whether interrupt handler functions should preserve the MDUC registers ๐Ÿ›ก๏ธ. This is only necessary if normal code might use the MDUC registers, for example because it does multiplication and division operations. The default is to ignore the MDUC registers, because that makes interrupt handlers faster โšก. The target option -mg13 needs to be passed for this to work, since this feature is only available on the G13 target (S2 core). The MDUC registers will only be saved if the interrupt handler performs a multiplication or division operation, or if it calls another function.

โœจ IBM RS/6000 and PowerPC Options โœจ

These -m options are defined for the IBM RS/6000 and PowerPC ๐Ÿฆ‹:

-mpowerpc-gpopt
-mno-powerpc-gpopt
-mpowerpc-gfxopt
-mno-powerpc-gfxopt
-mpowerpc64
-mno-powerpc64
-mmfcrf
-mno-mfcrf
-mpopcntb
-mno-popcntb
-mpopcntd
-mno-popcntd
-mfprnd
-mno-fprnd
-mcmpb
-mno-cmpb
-mhard-dfp
-mno-hard-dfp

You use these options to specify which instructions are available on the processor you're using ๐Ÿ’…. The default value of these options is determined when GCC is configured. Specifying -mcpu=cpu_type overrides the specification of these options. We recommend using the -mcpu=cpu_type option rather than the options listed above ๐Ÿซถ.

Specifying -mpowerpc-gpopt allows GCC to use the optional PowerPC architecture instructions in the General Purpose group, including floating-point square root ๐Ÿ”ฅ. Specifying -mpowerpc-gfxopt allows GCC to use the optional PowerPC architecture instructions in the Graphics group, including floating-point select ๐ŸŒธ.

The -mmfcrf option lets GCC generate the move from condition register field instruction, which is implemented on the POWER4 processor and other processors that support the PowerPC V2.01 architecture. ๐Ÿ’… The -mpopcntb option lets GCC generate the popcount and double-precision FP reciprocal estimate instruction from the POWER5 processor and other processors with the PowerPC V2.02 architecture. ๐Ÿฆ‹ The -mpopcntd option lets GCC generate the popcount instruction from the POWER7 processor and other processors with the PowerPC V2.06 architecture. โœจ The -mfprnd option lets GCC generate the FP round to integer instructions from the POWER5+ processor and other processors with the PowerPC V2.03 architecture. ๐ŸŒธ The -mcmpb option lets GCC generate the compare bytes instruction from the POWER6 processor and other processors with the PowerPC V2.05 architecture. ๐Ÿซถ And the -mhard-dfp option lets GCC generate the decimal floating-point instructions that show up on some POWER processors. ๐Ÿ”ฅ

The -mpowerpc64 option lets GCC generate the extra 64-bit instructions found in the full PowerPC64 architecture, and it treats GPRs as 64-bit doubleword quantities. ๐Ÿ‘‘ GCC defaults to -mno-powerpc64, so you have to ask for it. ๐Ÿ™ˆ

  • -mcpu=cpu_type โ€” this sets the architecture type, register usage, and instruction scheduling parameters for the machine type cpu_type. ๐Ÿ’– The supported values are:
401, 403, 405, 405fp, 440, 440fp, 464, 464fp, 476, 476fp, 505,
601, 602, 603, 603e, 604, 604e, 620, 630, 740, 7400, 7450, 750, 801,
821, 823, 860, 970, 8540, a2, e300c2, e300c3, e500mc, e500mc64,
e5500, e6500, ec603e, G3, G4, G5, titan, power3, power4, power5,
power5+, power6, power6x, power7, power8, power9, power10, powerpc,
powerpc64, powerpc64le, rs64, and native

-mcpu=powerpc, -mcpu=powerpc64, and -mcpu=powerpc64le are the pure, generic options. โญ They give you pure 32-bit PowerPC (either endian), 64-bit big endian PowerPC, and 64-bit little endian PowerPC machine types, with a generic processor model assumed for scheduling. ๐Ÿงš

Picking native detects the host processor and selects the matching architecture option. ๐Ÿ” If GCC doesn't recognize the processor, -mcpu=native does absolutely nothing. ๐Ÿ’€

The other values pick one specific processor. ๐ŸŽ€ Code built for that chip runs its best on it, and it might not run at all on other chips. ๐Ÿ˜ญ

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

Heads up, the exact set of options for each CPU changes between compiler versions. ๐ŸŒˆ It's whatever GCC thinks produces the best code for that CPU, so it doesn't always match what the hardware can actually do. ๐Ÿคทโ€โ™€๏ธ If you want to set one individual option to a specific value, put it after the -mcpu option, like -mcpu=970 -mno-altivec. ๐Ÿ’…

On AIX, -maltivec and -mpowerpc64 are not enabled or disabled by the -mcpu option right now, because AIX doesn't have full support for these options. ๐Ÿšจ You can still turn them on or off individually, but only if you're sure it'll work in your environment.
  • -mtune=cpu_type โ€” this sets the instruction scheduling parameters for the machine type cpu_type, but it does NOT touch the architecture type or register usage the way -mcpu=cpu_type does. ๐ŸŽฏ It takes the same cpu_type values as -mcpu. If you specify both, the code uses the architecture and registers from -mcpu, but the scheduling parameters from -mtune. ๐Ÿซถ
  • -mcmodel=small โ€” this generates PowerPC64 code for the small model, where the TOC is limited to 64k. ๐Ÿ“
  • -mcmodel=medium โ€” this generates PowerPC64 code for the medium model, where the TOC and other static data can total up to 4G in size. โœจ This is the default for 64-bit Linux. ๐Ÿง
  • -mcmodel=large โ€” this generates PowerPC64 code for the large model, where the TOC can be up to 4G in size. ๐ŸŒŒ Other data and code are only limited by the 64-bit address space. ๐Ÿ‘‘
  • -maltivec, -mno-altivec โ€” these generate code that does (or doesn't) use AltiVec instructions, and they also turn on built-in functions that give you more direct access to the AltiVec instruction set. ๐Ÿ’œ You might also need to set -mabi=altivec to adjust the current ABI with AltiVec ABI enhancements. ๐Ÿฆ‹

When -maltivec is in use, the element order for AltiVec intrinsics like "vec_splat", "vec_extract", and "vec_insert" matches the array element order for the target's endianness. ๐Ÿง  So element zero is the leftmost element in a vector register on a big-endian target, and it's the rightmost element in a vector register on a little-endian target. ๐ŸŒธ

  • -mvrsave, -mno-vrsave โ€” these generate VRSAVE instructions when generating AltiVec code. ๐ŸŽ€
  • -msecure-plt โ€” this generates code that lets ld and ld.so build executables and shared libraries with non-executable ".plt" and ".got" sections. ๐Ÿ” It's a PowerPC 32-bit SYSV ABI option. ๐Ÿ™Œ
  • -mbss-plt โ€” this generates code that uses a BSS ".plt" section that ld.so fills in. ๐Ÿงฉ It needs ".plt" and ".got" sections that are both writable AND executable, so be careful with it. โš ๏ธ It's also a PowerPC 32-bit SYSV ABI option. ๐Ÿ’…
  • -misel, -mno-isel โ€” this switch enables or disables the generation of ISEL instructions. ๐Ÿ”€
  • -mvsx, -mno-vsx โ€” these generate code that does (or doesn't) use vector/scalar (VSX) instructions, and they turn on built-in functions for more direct access to the VSX instruction set. ๐Ÿ”ฅ
  • -mcrypto, -mno-crypto โ€” these enable (or disable) the built-in functions that give direct access to the cryptographic instructions added in version 2.07 of the PowerPC ISA. ๐Ÿ”
  • -mhtm, -mno-htm โ€” these enable (or disable) the built-in functions for direct access to the Hardware Transactional Memory (HTM) instructions added in version 2.07 of the PowerPC ISA. ๐Ÿง 
  • -mpower8-fusion, -mno-power8-fusion โ€” these generate code that keeps some integer operations next to each other, so the instructions can be fused together on POWER8 and later processors. ๐Ÿงฒ With -mno-power8-fusion, that adjacency isn't kept. ๐Ÿ™…โ€โ™€๏ธ
  • -mpower8-vector, -mno-power8-vector โ€” these generate code that does (or doesn't) use the vector and scalar instructions added in version 2.07 of the PowerPC ISA. ๐ŸŒˆ They also turn on built-in functions for more direct access to the vector instructions. ๐ŸŽ€
  • -mquad-memory, -mno-quad-memory โ€” these generate code that does (or doesn't) use the non-atomic quad word memory instructions. ๐Ÿ’œ The -mquad-memory option requires 64-bit mode. ๐Ÿ–ฅ๏ธ
  • -mquad-memory-atomic, -mno-quad-memory-atomic โ€” these generate code that does (or doesn't) use the atomic quad word memory instructions. โš›๏ธ The -mquad-memory-atomic option also requires 64-bit mode. ๐Ÿ–ฅ๏ธ
  • -mfloat128, -mno-float128 โ€” these enable or disable the __float128 keyword for IEEE 128-bit floating point. ๐ŸŒŸ They also choose between software emulation or hardware instructions for IEEE 128-bit floating point. ๐Ÿงช

You have to enable the VSX instruction set (-mvsx) to use the IEEE 128-bit floating point support. ๐Ÿซ  And the IEEE 128-bit floating point support is only supported on Linux. ๐Ÿง

By default, -mfloat128 is enabled on PowerPC Linux systems that use the VSX instruction set, and it's disabled on other systems. โœจ

If you use the ISA 3.0 instruction set (-mpower9-vector or -mcpu=power9) on a 64-bit system, the IEEE 128-bit floating point support also turns 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 โ€” these enable (or disable) using ISA 3.0 hardware instructions to support the __float128 data type. ๐Ÿ› ๏ธ

By default, -mfloat128-hardware is enabled on PowerPC Linux systems that use the ISA 3.0 instruction set, and it's disabled on other systems. ๐Ÿ’–

  • -m32, -m64 โ€” these generate code for 32-bit or 64-bit environments on Darwin and SVR4 targets (including GNU/Linux). ๐ŸŒ The 32-bit environment sets int, long, and pointer to 32 bits, and it generates code that runs on any PowerPC variant. ๐Ÿ’ซ The 64-bit environment sets int to 32 bits, sets long and pointer to 64 bits, and generates code for PowerPC64, just like -mpowerpc64. ๐Ÿงš
  • -mfull-toc, -mno-fp-in-toc, -mno-sum-in-toc, -mminimal-toc โ€” these modify how the TOC (Table Of Contents) is generated, and every executable file gets one. ๐Ÿ“– The -mfull-toc option is selected by default. ๐Ÿ™Œ In that case, GCC allocates at least one TOC entry for each unique non-automatic variable reference in your program, and it also puts floating-point constants in the TOC. ๐Ÿงพ The catch is that only 16,384 entries are available in the TOC. ๐Ÿ˜ฌ

If you get a linker error message saying 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. -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 of these options. Each one makes the code very slightly slower and larger, but it saves TOC space. ๐Ÿ’…

If you're STILL out of TOC space even with both of those options, use -mminimal-toc instead. ๐Ÿ˜ค This option makes GCC create only one TOC entry for every file. ๐Ÿ“„ The code gets slower and larger, but it uses extremely little TOC space. ๐ŸŒ You might want to use this option only on files with less frequently-executed code. ๐Ÿง

  • -maix64, -maix32 โ€” okay bestie, -maix64 turns on the 64-bit AIX ABI and calling convention ๐Ÿ’– so you get 64-bit pointers, a 64-bit "long" type, and all the infrastructure needed to make them work โœจ. -maix64 also implies -mpowerpc64. -maix32 goes the other way and disables the 64-bit ABI, implying -mno-powerpc64. GCC defaults to -maix32 ๐ŸŽ€
  • -mxl-compat, -mno-xl-compat โ€” this one makes your code act more like IBM XL compiler output when you're using the AIX-compatible ABI ๐Ÿฆ‹ It passes floating-point arguments to prototyped functions beyond the register save area (RSA) on the stack, in addition to argument FPRs. It also stops assuming that 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 the long double support routines ๐Ÿ’…

The AIX calling convention got extended, but that wasn't documented at first, all to handle an obscure K&R C case: calling a function that takes the address of its arguments with fewer arguments than it declared. IBM XL compilers read floating-point arguments that don't fit in the RSA from the stack when a subroutine is compiled without optimization. Always storing floating-point arguments on the stack is inefficient and rarely needed, so this option is not on by default. You only 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 that uses message passing with special startup code so it can actually run. Your system needs PE installed in the standard location (/usr/lpp/ppe.poe/). Otherwise, you have to override the specs file with -specs= to point at the right directory location โœจ
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 bigger 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 from the ABI ๐Ÿ’œ

On 64-bit Darwin, natural alignment is already the default, and -malign-power is not supported there ๐Ÿ™ƒ

  • -msoft-float, -mhard-float โ€” -msoft-float makes the code skip the floating-point register set, so you get software floating-point emulation. You have to pass the option to GCC when linking too ๐Ÿซถ -mhard-float is the opposite: the code does use the floating-point register set ๐Ÿ”ฅ
  • -mmultiple, -mno-multiple โ€” -mmultiple generates code that uses the load multiple word and store multiple word instructions, and -mno-multiple says "nah, skip those." These instructions are generated by default on POWER systems and not on PowerPC systems ๐ŸŒธ
Don't use -mmultiple on little-endian PowerPC systems, since those instructions don't work when the processor is in little-endian mode. The exceptions are PPC740 and PPC750, which permit them in little-endian mode ๐Ÿ‘‘
  • -mupdate, -mno-update โ€” -mupdate lets the code use load or store instructions that update the base register to the address of the calculated memory location. These are generated by default. -mno-update opts out of them โœจ
If you use -mno-update, there's a small window between when the stack pointer gets updated and when the address of the previous frame gets stored. That means code that walks the stack frame across interrupts or signals may end up with corrupted data ๐Ÿ˜ญ
  • -mavoid-indexed-addresses, -mno-avoid-indexed-addresses โ€” -mavoid-indexed-addresses tries to avoid indexed load or store instructions, and -mno-avoid-indexed-addresses lets them be used ๐Ÿงš Indexed instructions can cost you performance 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 โ€” -mfused-madd generates code that uses the floating-point multiply and accumulate instructions. -mno-fused-madd skips them. These are generated by default if hardware floating point is used ๐Ÿ’… Fun plot twist: 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 โ€” -mmulhw uses the half-word multiply and multiply-accumulate instructions on the IBM 405, 440, 464 and 476 processors, while -mno-mulhw does not. These instructions are generated by default when targeting those processors โญ
  • -mdlmzb, -mno-dlmzb โ€” -mdlmzb uses the string-search dlmzb instruction on the IBM 405, 440, 464 and 476 processors, and -mno-dlmzb doesn't. This instruction is generated by default when targeting those processors ๐Ÿ”

  • -mno-bit-align, -mbit-align โ€” on System V.4 and embedded PowerPC systems, -mno-bit-align does not force structures and unions containing bit-fields to be aligned to the base type of the bit-field, and -mbit-align does ๐Ÿ’–

Like, by default a structure containing nothing but 8 unsigned bit-fields of length 1 is aligned to a 4-byte boundary and has a size of 4 bytes ๐Ÿ™ˆ Use -mno-bit-align and that same structure is aligned to a 1-byte boundary and is only 1 byte in size. Iconic glow-up ๐ŸŽ€

  • -mno-strict-align, -mstrict-align โ€” on System V.4 and embedded PowerPC systems, -mno-strict-align does not assume that unaligned memory references are handled by the system. -mstrict-align does make that assumption ๐Ÿซถ
  • -mrelocatable, -mno-relocatable โ€” -mrelocatable generates code that lets a static executable be relocated to a different address at run time. -mno-relocatable does not allow that ๐Ÿงš A simple embedded PowerPC system loader should relocate the entire contents of .got2 and the 4-byte locations listed in the .fixup section, which is a table of 32-bit addresses this option generates. For this to work, every object you link together must be compiled with -mrelocatable or -mrelocatable-lib. Also, -mrelocatable code aligns the stack to an 8-byte boundary ๐Ÿ“š
  • -mrelocatable-lib, -mno-relocatable-lib โ€” like -mrelocatable, -mrelocatable-lib generates a .fixup section so static executables can be relocated at run time. The difference is that it does not use the smaller stack alignment that -mrelocatable uses ๐ŸŒธ Objects compiled with -mrelocatable-lib can be linked with objects compiled with any combination of the -mrelocatable options ๐Ÿฆ‹
  • -mno-toc, -mtoc โ€” on System V.4 and embedded PowerPC systems, -mno-toc does not assume that register 2 holds a pointer to a global area with the addresses used in the program. -mtoc does assume that ๐Ÿ’…
  • -mlittle, -mlittle-endian โ€” on System V.4 and embedded PowerPC systems, this compiles code for the processor in little-endian mode ๐ŸŒˆ -mlittle-endian is the same as -mlittle โœจ
  • -mbig, -mbig-endian โ€” on System V.4 and embedded PowerPC systems, this compiles code for the processor in big-endian mode ๐Ÿ‘‘ -mbig-endian is the same as -mbig ๐Ÿ“
  • -mdynamic-no-pic โ€” on Darwin and Mac OS X systems, this compiles code so it is not relocatable, but its external references are relocatable ๐Ÿ”ฅ The result is good for applications, but not shared libraries ๐Ÿ™…โ€โ™€๏ธ
  • -msingle-pic-base โ€” treats the register used for PIC addressing as read-only, instead of loading it in the prologue for each function ๐Ÿ’– The runtime system is responsible for initializing this register with an appropriate value before execution begins ๐Ÿงš
  • -mprioritize-restricted-insns=priority โ€” controls the priority given to dispatch-slot restricted instructions during the second scheduling pass โญ The argument priority takes the value 0, 1, or 2, which assigns no, highest, or second-highest priority to dispatch-slot restricted instructions, respectively ๐Ÿ“š
  • -msched-costly-dep=dependence_type โ€” controls which dependences the target considers costly during instruction scheduling ๐Ÿฆ‹ The argument dependence_type takes one of these values:
    • no โ€” no dependence is costly ๐Ÿ’…
    • all โ€” all dependences are costly ๐Ÿ”ฅ
    • true_store_to_load โ€” a true dependence from store to load is costly ๐ŸŒธ
    • store_to_load โ€” any dependence from store to load is costly ๐Ÿซถ
    • number โ€” any dependence whose latency is greater than or equal to number is costly โœจ
  • -minsert-sched-nops=scheme โ€” controls which NOP insertion scheme gets used during the second scheduling pass ๐ŸŽ€ The argument scheme takes one of these values:
    • no โ€” don't insert NOPs ๐Ÿ™ˆ
    • pad โ€” pad with NOPs any dispatch group that has vacant issue slots, according to the scheduler's grouping ๐Ÿงš
    • regroup_exact โ€” insert NOPs to force costly dependent insns into separate groups. It inserts exactly as many NOPs as needed to push an insn into a new group, according to the estimated processor grouping ๐Ÿ’œ
    • number โ€” insert NOPs to force costly dependent insns into separate groups. It inserts number NOPs to force an insn into a new group ๐ŸŒˆ

  • -mcall-sysv โ€” on System V.4 and embedded PowerPC systems, compiles code using calling conventions that follow the March 1995 draft of the System V Application Binary Interface, PowerPC processor supplement ๐Ÿ‘‘ This is the default unless you configured GCC using powerpc-*-eabiaix ๐Ÿ™ƒ
  • -mcall-sysv-eabi, -mcall-eabi โ€” specifies both -mcall-sysv and -meabi ๐Ÿ’–
  • -mcall-sysv-noeabi โ€” specifies both -mcall-sysv and -mno-eabi ๐Ÿซถ
  • -mcall-aixdesc โ€” on System V.4 and embedded PowerPC systems, compiles code for the AIX operating system ๐Ÿฆ‹
  • -mcall-linux โ€” on System V.4 and embedded PowerPC systems, compiles code for the Linux-based GNU system ๐Ÿง
  • -mcall-freebsd โ€” on System V.4 and embedded PowerPC systems, compiles code for the FreeBSD operating system ๐Ÿ˜ˆ
  • -mcall-netbsd โ€” on System V.4 and embedded PowerPC systems, compiles code for the NetBSD operating system ๐ŸŒธ
  • -mcall-openbsd โ€” on System V.4 and embedded PowerPC systems, compiles code for the OpenBSD operating system โœจ
  • -mtraceback=traceback_type โ€” selects the type of traceback table ๐Ÿงš Valid values for traceback_type are full, part, and no ๐Ÿ“š
  • -maix-struct-return โ€” returns all structures in memory, as the AIX ABI specifies ๐Ÿ“
  • -msvr4-struct-return โ€” returns structures smaller than 8 bytes in registers, as the SVR4 ABI specifies ๐Ÿ’…
  • -mabi=abi-type โ€” ๐Ÿ’… Glow up your ABI with an extension, or drop one you don't need. The valid picks are altivec, no-altivec, ibmlongdouble, ieeelongdouble, elfv1, and elfv2. On AIX you also get vec-extabi and vec-default โœจ
  • -mabi=ibmlongdouble โ€” ๐Ÿ“ Switches the ABI to IBM extended-precision long double. Bestie, this is not likely to work if your system defaults to IEEE extended-precision long double. If you switch away from IEEE extended-precision, the compiler will warn you unless you add -Wno-psabi. You also need -mlong-double-128 turned on.
  • -mabi=ieeelongdouble โ€” ๐ŸŒธ Switches the ABI to IEEE extended-precision long double. Same tea here: it's not likely to work if your system defaults to IBM extended-precision long double. Switching away from IBM extended-precision gets you a warning unless you use -Wno-psabi. This one also requires -mlong-double-128 to be enabled.
  • -mabi=elfv1 โ€” ๐Ÿงš Changes the ABI to ELFv1. This is the default for big-endian PowerPC 64-bit Linux. Overriding the default needs special system support and is likely to fail in spectacular ways ๐Ÿ’€
  • -mabi=elfv2 โ€” ๐Ÿฆ‹ Changes the ABI to ELFv2. This is the default for little-endian PowerPC 64-bit Linux. Overriding the default also needs special system support and is likely to fail in spectacular ways ๐Ÿ˜ญ
  • -mgnu-attribute, -mno-gnu-attribute โ€” ๐ŸŽ€ Emits .gnu_attribute assembly directives that set tag/value pairs in a .gnu.attributes section. These describe the ABI variations for function parameters or return values.
  • -mprototype, -mno-prototype โ€” ๐Ÿ‘‘ On System V.4 and embedded PowerPC, this tells the compiler to assume every call to a variable argument function is properly prototyped. Without it, the compiler has to slip in an instruction before every non-prototyped call to set or clear bit 6 of the condition code register (CR). That bit tells the function whether floating-point values are passed in the floating-point registers, in case it takes variable arguments. With -mprototype, only calls to prototyped variable argument functions set or clear that bit.
  • -msim โ€” ๐ŸŒˆ On embedded PowerPC, this assumes the startup module is sim-crt0.o and the standard C libraries are libsim.a and libc.a. It's the default for powerpc-*-eabisim configurations.
  • -mmvme โ€” ๐Ÿ“ On embedded PowerPC, this assumes the startup module is crt0.o and the standard C libraries are libmvme.a and libc.a.
  • -mads โ€” โญ On embedded PowerPC, this assumes the startup module is crt0.o and the standard C libraries are libads.a and libc.a.
  • -myellowknife โ€” ๐Ÿ’œ On embedded PowerPC, this assumes the startup module is crt0.o and the standard C libraries are libyk.a and libc.a.
  • -mvxworks โ€” ๐Ÿ”ฅ On System V.4 and embedded PowerPC, this tells GCC you're compiling for a VxWorks system.
  • -memb โ€” ๐Ÿซถ On embedded PowerPC, this sets the PPC_EMB bit in the ELF flags header, which indicates that eabi extended relocations are used.
  • -meabi, -mno-eabi โ€” ๐ŸŒธ On System V.4 and embedded PowerPC, -meabi makes the compiler adhere to the Embedded Applications Binary Interface (EABI), a set of tweaks to the System V.4 specs. -mno-eabi means it does not. With -meabi, the stack is aligned to an 8-byte boundary, a function __eabi is called from main to set up the EABI environment, and the -msdata option can use both r2 and r13 to point to two separate small data areas. With -mno-eabi, the stack is aligned to a 16-byte boundary, no EABI initialization function is called from main, and -msdata only uses r13 to point to a single small data area. -meabi is on by default if you configured GCC with one of the powerpc*-*-eabi* options.
  • -msdata=eabi โ€” ๐Ÿฆ‹ On System V.4 and embedded PowerPC, small initialized const global and static data goes in the .sdata2 section, pointed to by register r2. Small initialized non-const global and static data goes in the .sdata section, pointed to by register r13. Small uninitialized global and static data goes in the .sbss section, which sits right next to .sdata. This option is incompatible with -mrelocatable, and it also sets -memb.
  • -msdata=sysv โ€” ๐Ÿงš On System V.4 and embedded PowerPC, small global and static data goes in the .sdata section, pointed to by register r13. Small uninitialized global and static data goes in the .sbss section, next to .sdata. This option is incompatible with -mrelocatable.
  • -msdata=default, -msdata โ€” ๐Ÿ’– On System V.4 and embedded PowerPC, if -meabi is used, the code compiles the same as -msdata=eabi. Otherwise, it compiles the same as -msdata=sysv.
  • -msdata=data โ€” ๐Ÿ“ On System V.4 and embedded PowerPC, small global data goes in the .sdata section, and small uninitialized global data goes in the .sbss section. The one difference: register r13 is not used to address small data. This is the default unless other -msdata options are used.
  • -msdata=none, -mno-sdata โ€” ๐ŸŒˆ On embedded PowerPC, all initialized global and static data goes in the .data section, and all uninitialized data goes in the .bss section.
  • -mreadonly-in-sdata โ€” ๐ŸŽ€ Puts read-only objects in the .sdata section too. This is the default.
  • -mblock-move-inline-limit=num โ€” โœจ Inlines all block moves (like calls to memcpy or structure copies) that are less than or equal to num bytes. The minimum value for num is 32 bytes on 32-bit targets and 64 bytes on 64-bit targets. The default is target-specific.
  • -mblock-compare-inline-limit=num โ€” ๐Ÿ”ฅ Generates non-looping inline code for all block compares (like calls to memcmp or structure compares) that are less than or equal to num bytes. If num is 0, all inline expansion of block compare, both non-loop and loop, is disabled. The default is target-specific.
  • -mblock-compare-inline-loop-limit=num โ€” ๐Ÿ’œ Generates an inline expansion using loop code for all block compares that are less than or equal to num bytes but greater than the limit for non-loop inline block compare expansion. If the block length isn't constant, at most num bytes get compared before memcmp is called to compare the rest of the block. The default is target-specific.
  • -mstring-compare-inline-limit=num โ€” ๐Ÿฆ‹ Compares at most num string bytes with inline code. If the difference or end of string isn't found 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, puts global and static items less than or equal to num bytes into the small data or BSS sections, instead of the normal data or BSS section. By default, num is 8. The -G num switch also gets passed to the linker, so all modules should be compiled with the same -G num value ๐Ÿ”‘
  • -mregnames, -mno-regnames โ€” ๐Ÿซถ On System V.4 and embedded PowerPC, this makes the compiler emit (or not emit) register names in the assembly output using symbolic forms.
  • -mlongcall, -mno-longcall โ€” ๐Ÿ‘‘ By default, GCC assumes every call is far away, so it uses a longer, more expensive calling sequence. That's required for calls farther than 32 megabytes (33,554,432 bytes) from the current location. A short call is generated when 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. There are plans 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 generates bl callee if the PPC bl instruction reaches the callee directly. Otherwise, the linker generates bl L42 to call the branch island. The branch island 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 directs the compiler to emit the glue for every direct call, and the Darwin linker decides whether to use it or discard it ๐Ÿฆ‹

In the future, GCC may ignore all longcall specifications when the linker is known to generate glue โœจ

  • -mpltseq, -mno-pltseq โ€” ๐Ÿ’… Implements (or doesn't 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 on 32-bit PowerPC systems with newer GNU linkers. They're enabled by default if support is detected when configuring GCC, and, in the case of 32-bit PowerPC, if GCC is configured with --enable-secureplt. Be careful, bestie: -mpltseq code and -mbss-plt 32-bit PowerPC relocatable objects may not be linked together ๐Ÿ˜ฌ
  • -mtls-markers, -mno-tls-markers โ€” ๐Ÿ”ฅ Marks (or doesn't mark) calls to __tls_get_addr with a relocation that specifies the function argument. That relocation lets the linker reliably connect the function call with its argument setup instructions for TLS optimization. That in turn lets GCC schedule the sequence better ๐Ÿซถ

๐Ÿ’– Precision Stuff (Part 2) ๐Ÿ’–

Okay so bestie, -mrecip and -mno-recip are giving precision drama ๐Ÿ’…โœจ Turning -mrecip on lets the compiler use the reciprocal estimate and reciprocal square root estimate instructions, plus extra Newton-Raphson steps to boost precision, instead of doing a divide or a square root and divide for floating-point arguments ๐Ÿฆ‹

You should pair it with -ffast-math ๐Ÿ”ฅ (or at least -funsafe-math-optimizations, -ffinite-math-only, -freciprocal-math and -fno-trapping-math) when you use -mrecip. Lowkey non-negotiable ๐Ÿ™ˆ The sequence usually has higher throughput than the non-reciprocal instruction, but the precision can drop by up to 2 ulp ๐Ÿ˜ญ (like, the inverse of 1.0 comes out as 0.99999994) for reciprocal square roots.

  • -mrecip, -mno-recip โ€” turns the estimate-plus-Newton-Raphson trick on or off, as described above.
  • -mrecip=opt โ€” picks exactly which reciprocal estimate instructions are allowed. opt is a comma-separated list, and you can put a "!" in front of any option to invert it. The choices are:
    • all โ€” enables all estimate instructions.
    • default โ€” enables the default instructions, same as -mrecip.
    • none โ€” disables all estimate instructions, same as -mno-recip.
    • div โ€” enables the reciprocal approximation instructions for both single and double precision.
    • divf โ€” enables the single-precision reciprocal approximation instructions.
    • divd โ€” enables the double-precision reciprocal approximation instructions.
    • rsqrt โ€” enables the reciprocal square root approximation instructions for both single and double precision.
    • rsqrtf โ€” enables the single-precision reciprocal square root approximation instructions.
    • rsqrtd โ€” enables the double-precision reciprocal square root approximation instructions.

So, for example, -mrecip=all,!rsqrtd enables all of the reciprocal estimate instructions, except for the "FRSQRTE", "XSRSQRTEDP", and "XVRSQRTEDP" instructions, which handle the double-precision reciprocal square root calculations ๐Ÿงš

  • -mrecip-precision, -mno-recip-precision โ€” tells GCC to assume (or not assume) that the reciprocal estimate instructions give you higher precision than the PowerPC ABI requires. Picking -mcpu=power6, -mcpu=power7 or -mcpu=power8 automatically turns on -mrecip-precision โœจ The double-precision square root estimate instructions are not generated by default on low-precision machines, since they don't converge after three steps ๐Ÿ™ˆ
  • -mveclibabi=type โ€” chooses the ABI type 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 that job ๐ŸŽ€ 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 โ€” generates (or doesn't generate) the "friz" instruction when -funsafe-math-optimizations is used to optimize rounding floating-point values to 64-bit integers and back to floating point. Heads up: "friz" 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 โ€” generates (or doesn't generate) code that loads the static chain register ("r11") when calling through a pointer on AIX and 64-bit Linux systems, where a function pointer points to a 3-word descriptor giving the function address, the TOC value to load into register "r2", and the static chain value to load into register "r11". -mpointers-to-nested-functions is on by default ๐ŸŒธ If you use -mno-pointers-to-nested-functions, you can't call through pointers to nested functions, or through pointers to functions compiled in other languages that use the static chain.
  • -msave-toc-indirect, -mno-save-toc-indirect โ€” generates (or doesn't generate) code that saves the TOC value in the reserved stack location in the function prologue, if the function calls through a pointer on AIX and 64-bit Linux systems. If the TOC value isn't saved in the prologue, it gets saved just before the call through the pointer. -mno-save-toc-indirect is the default ๐Ÿ“
  • -mcompat-align-parm, -mno-compat-align-parm โ€” generates (or doesn't generate) code that passes structure parameters with a maximum alignment of 64 bits, for compatibility with older versions of GCC.

Older versions of GCC (prior to 4.9.0) incorrectly didn't align a structure parameter on a 128-bit boundary when that structure had a member requiring 128-bit alignment. This got fixed in more recent versions of GCC. Use this option if you need code that's compatible with functions compiled by older GCC versions ๐Ÿฆ‹ -mno-compat-align-parm is the default.

  • -mstack-protector-guard=guard, -mstack-protector-guard-reg=reg, -mstack-protector-guard-offset=offset, -mstack-protector-guard-symbol=symbol โ€” generates stack protection code that uses a canary at guard. The supported locations are global for a global canary, or tls for a per-thread canary in the TLS block (the default with GNU libc version 2.4 or later) ๐Ÿ›ก๏ธ

With the tls choice, -mstack-protector-guard-reg=reg and -mstack-protector-guard-offset=offset let you pick which register is the base register for reading the canary, and what offset from that base register to use. The defaults for those come from the relevant ABI. -mstack-protector-guard-symbol=symbol overrides the offset with a symbol reference to a canary in the TLS block โœจ

  • -mpcrel, -mno-pcrel โ€” generates (or doesn't generate) pc-relative addressing. -mpcrel needs the medium code model (-mcmodel=medium) and prefixed addressing (-mprefixed) to be enabled too ๐Ÿ‘‘
  • -mprefixed, -mno-prefixed โ€” generates (or doesn't generate) addressing modes that use prefixed load and store instructions. -mprefixed requires -mcpu=power10 (or later) to be enabled ๐ŸŒˆ
  • -mmma, -mno-mma โ€” generates (or doesn't generate) the MMA instructions. The -mma option requires -mcpu=power10 (or later) to be enabled ๐Ÿ’…

โœจ 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.
Note: RX floating-point hardware only works on 32-bit values, which is literally why the default is -m32bit-doubles ๐Ÿ™ˆ
  • -fpu, -nofpu โ€” enables (-fpu) or disables (-nofpu) the use of RX floating-point hardware. It's enabled by default for the RX600 series and disabled for the RX200 series ๐Ÿ’–

Floating-point instructions only get generated for 32-bit floating-point values, though, so the FPU hardware isn't used for doubles if -m64bit-doubles is used.

Note: If -fpu is enabled, then -funsafe-math-optimizations is also enabled automatically. This is because the RX FPU instructions are themselves unsafe ๐Ÿ’€
  • -mcpu=name โ€” selects the type of RX CPU to target. Three types are supported right now: the generic RX600 and RX200 series hardware, and the specific RX610 CPU. The default is RX600 ๐ŸŽ€

The only difference between RX600 and RX610 is that the RX610 doesn't support the "MVTIPL" instruction.

The RX200 series doesn't have a hardware floating-point unit, so -nofpu is enabled by default when this type is selected.

  • -mbig-endian-data, -mlittle-endian-data โ€” stores data (but not code) in the big-endian format. The default is -mlittle-endian-data, meaning data gets stored in the little-endian format ๐ŸŒธ
  • -msmall-data-limit=N โ€” specifies the maximum size in bytes of global and static variables that can be placed into the small data area. Using the small data area can lead to smaller and faster code, but the area is limited, and it's up to you to make sure it doesn't overflow ๐Ÿงš

When the small data area is used, one of the RX's registers (usually "r13") is reserved to point to this area, so the compiler can't use it anymore. This could result in slower and/or larger code if variables get pushed onto the stack instead of being held in that register.

Heads up: common variables (variables that haven't been initialized) and constants are not placed into the small data area, because they get assigned to other sections in the output executable.

The default value is zero, which disables this feature. This feature isn't enabled by default at higher optimization levels (-O2 etc.) because reserving a register can be detrimental. It's up to you to experiment and figure out whether it benefits your program. See the description of the -mpid option for how the actual register that holds 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 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: okay so this caps how big a constant can be (in bytes) when it's used as an operand in an RX instruction ๐Ÿ’…. RX can handle constants up to 4 bytes, but a longer value means a longer instruction, so sometimes it's lowkey smart to restrict the size ๐Ÿง . Anything too big gets tossed into a constant pool and reached through register indirection instead ๐Ÿงš. N can be between 0 and 4, and both 0 (the default) and 4 mean constants of any size are welcome โœจ.
  • -mrelax: enables linker relaxation, which is seriously shrink the program energy ๐Ÿฆ‹. The linker hunts for shorter versions of various instructions to trim your program down. It's disabled by default, so you have to opt in ๐Ÿ’œ.
  • -mint-register=N: reserves registers for fast interrupt handler functions ๐Ÿ‘‘. N can be between 0 and 4. A value of 1 reserves r13 for fast interrupt handlers only, 2 reserves r13 and r12, 3 reserves r13, r12 and r11, and 4 reserves r13 through r10 ๐ŸŒธ. The default, 0, doesn't reserve any registers at all.
  • -msave-acc-in-interrupts: tells interrupt handler functions to preserve the accumulator register ๐Ÿซถ. This only matters if normal code might be using the accumulator, like when it's doing 64-bit multiplications ๐Ÿ”ฅ. By default GCC ignores the accumulator, because that makes the interrupt handlers faster โญ.
  • -mpid, -mno-pid: turns on generation of position independent data ๐ŸŒˆ. When it's enabled, any access to constant data happens as an offset from a base address held in a register. That means the location of constant data can be figured out at run time without the executable needing to be relocated, which is a huge win for embedded apps with tight memory constraints ๐ŸŽ€. Data that can be modified isn't affected by this option.

Heads up, bestie: using this feature reserves a register, usually r13, for the constant data base address ๐Ÿ’€. That can make code slower and/or larger, especially in complicated functions.

Which register actually holds the constant data base address depends on whether -msmall-data-limit and/or -mint-register are turned on. Starting at r13 and working downwards, registers get allocated first for -mint-register, then -mpid, and finally -msmall-data-limit. So the small data area register could end up being r8 if both -mint-register=4 and -mpid are on the command line ๐Ÿ™ˆ.

By default this feature is not enabled. The default can be restored with the -mno-pid command-line option ๐Ÿ’….

  • -mno-warn-multiple-fast-interrupts, -mwarn-multiple-fast-interrupts: this pair is all about whether GCC yells at you when it finds more than one fast interrupt handler while compiling a file ๐Ÿ“ฃ. The -mno- version stops GCC from issuing that warning. The default is to warn for each extra fast interrupt handler it finds, since the RX only supports one such interrupt ๐Ÿšจ.
  • -mallow-string-insns, -mno-allow-string-insns: enables or disables the string manipulation instructions SMOVF, SCMPU, SMOVB, SMOVU, SUNTIL and SWHILE, plus the RMPA instruction ๐Ÿงต. These may prefetch data, which is not safe to do if you're accessing an I/O register ๐Ÿ˜ฌ (see section 12.2.7 of the RX62N Group User's Manual for more info).

They're allowed by default, but GCC can't reliably detect every situation where a string instruction might be used to access an I/O register, so they can't be turned off automatically ๐Ÿซ . Instead it's on the programmer: if your program accesses I/O space, use -mno-allow-string-insns.

When these are enabled, GCC defines the C preprocessor symbol __RX_ALLOW_STRING_INSNS__. Otherwise it defines __RX_DISALLOW_STRING_INSNS__ ๐Ÿงš.

  • -mjsr, -mno-jsr: use only (or not only) JSR instructions to access functions ๐Ÿ“ž. This is handy when your code size goes past the range of BSR instructions. Also, -mno-jsr doesn't mean "don't use JSR". It just means any type of branch may be used ๐Ÿ’….

Note: the generic GCC command-line option -ffixed-reg has special significance to the RX port when it's used with the interrupt function attribute ๐Ÿ‘‘. That attribute marks a function meant to process fast interrupts. GCC makes sure it only uses r10, r11, r12 and/or r13, and only if the normal use of the corresponding registers has been restricted via -ffixed-reg or -mint-register ๐Ÿซถ.


โœจ S/390 and zSeries Options โœจ

These are the -m options defined for the S/390 and zSeries architecture ๐ŸŒธ.

  • -mhard-float, -msoft-float: use (or don't use) hardware floating-point instructions and registers for floating-point operations ๐Ÿ”ฅ. With -msoft-float, functions in libgcc.a do the floating-point work. With -mhard-float, the compiler generates IEEE floating-point instructions. This is the default ๐Ÿ’–.
  • -mhard-dfp, -mno-hard-dfp: use (or skip) the hardware decimal-floating-point instructions for decimal-floating-point operations ๐Ÿงฎ. With -mno-hard-dfp, functions in libgcc.a are used to do the work. With -mhard-dfp, the compiler generates decimal-floating-point hardware instructions. This is the default for -march=z9-ec or higher โœจ.
  • -mlong-double-64, -mlong-double-128: these switches control the size of the long double type ๐Ÿ“. A size of 64 bits makes long double equivalent to double, and that's the default ๐Ÿ“.
  • -mbackchain, -mno-backchain: stores (or doesn't store) the address of the caller's frame as a backchain pointer in the callee's stack frame ๐Ÿฆ‹. A backchain may be needed to allow debugging with tools that don't understand DWARF call frame information. When -mno-packed-stack is in effect, the backchain pointer is stored at the bottom of the stack frame. When -mpacked-stack is in effect, the backchain goes into the topmost word of the 96/160 byte register save area.

In general, code compiled with -mbackchain is call-compatible with code compiled with -mmo-backchain (yes, that's the typo in the original, bestie ๐Ÿ™ˆ). However, using the backchain for debugging purposes usually requires the whole binary to be built with -mbackchain.

Not supported: the combination of -mbackchain, -mpacked-stack and -mhard-float ๐Ÿšซ. To build a Linux kernel, use -msoft-float.

The default is to not maintain the backchain.

  • -mpacked-stack, -mno-packed-stack: uses (or doesn't use) the packed stack layout ๐Ÿ“ฆ. With -mno-packed-stack, the compiler uses all the fields of the 96/160 byte register save area only for their default purpose, so unused fields still take up stack space ๐Ÿ™ƒ. With -mpacked-stack, register save slots are densely packed at the top of the register save area, and unused space gets reused for other purposes, which means more efficient use of the available stack space โœจ. However, when -mbackchain is also in effect, the topmost word of the save area is always used to store the backchain, and the return address register is always saved two words below the backchain.

As long as the stack frame backchain isn't used, code generated with -mpacked-stack is call-compatible with code generated with -mno-packed-stack. Some non-FSF releases of GCC 2.95 for S/390 or zSeries generated code that uses the stack frame backchain at run time, not just for debugging purposes. That code is not call-compatible with code compiled with -mpacked-stack.

Also a no-go: the combination of -mbackchain, -mpacked-stack and -mhard-float isn't supported ๐Ÿšซ. To build a Linux kernel, use -msoft-float.

The default is to not use the packed stack layout.

  • -msmall-exec, -mno-small-exec: generates (or doesn't generate) code using the bras instruction for subroutine calls ๐Ÿ“ž. This only works reliably if the total executable size doesn't exceed 64k. The default is to use the basr instruction instead, which doesn't have this limitation ๐Ÿ’….
  • -m64, -m31: when you pass -m31, the code is compliant with the GNU/Linux for S/390 ABI ๐Ÿงฉ. When you pass -m64, it's 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: -mzarch generates code using the instructions available on z/Architecture ๐ŸŒˆ. -mesa generates code using the instructions available on ESA/390 ๐Ÿฆ•. Note that -mesa is not possible with -m64 ๐Ÿšซ. When you're generating code compliant with the GNU/Linux for S/390 ABI, the default is -mesa. For the GNU/Linux for zSeries ABI, the default is -mzarch.
  • -mhtm, -mno-htm: -mhtm enables a set of builtins that use instructions from the transactional execution facility, introduced with the IBM zEnterprise EC12 machine generation. Go peek at S/390 System z Built-in Functions for the deets ๐Ÿ”. -mhtm is enabled by default when using -march=zEC12 ๐Ÿ’œ.
  • -mvx, -mno-vx: -mvx generates code using the instructions available with 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 being used in an ABI-relevant context, a GAS .gnu_attribute command will be added to mark the resulting binary with the ABI used ๐Ÿท๏ธ. -mvx is enabled by default when using -march=z13 ๐Ÿ‘‘.
  • -mzvector, -mno-zvector โ€” okay bestie, -mzvector switches on vector language extensions and builtins ๐Ÿ’… using the instructions from the vector extension facility that came with the IBM z13 machine generation โœจ. It lets vector work as a keyword for defining vector type variables and arguments ๐ŸŽ€. But vector only works when GNU extensions are enabled. It will NOT be expanded if you ask for strict standard compliance, like with -std=c99 ๐Ÿ˜ญ. On top of the GCC low-level builtins, -mzvector also adds a set of builtins made for compatibility with AltiVec-style implementations like Power and Cell ๐Ÿฆ‹. To actually use those, you need to include the header file vecintrin.h ๐Ÿซถ. -mzvector is disabled by default ๐Ÿ’€.
  • -mmvcle, -mno-mvcle โ€” generates (or skips) code using the mvcle instruction for block moves ๐Ÿงš. With -mno-mvcle, GCC uses an mvc loop instead ๐Ÿ“. This is the default unless you're optimizing for size โœจ.
  • -mdebug, -mno-debug โ€” prints (or doesn't print) extra debug info while compiling ๐Ÿ”. The default is to not print debug info ๐Ÿ’œ.
  • -march=cpu-type โ€” generates code that runs on cpu-type, which is the name of a system representing a certain processor type ๐ŸŒˆ. The possible values 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 ๐ŸŒธ.

Using native as the cpu type picks the best architecture option for your host processor ๐Ÿ”ฅ. But -march=native has no effect if GCC doesn't recognize the processor ๐Ÿ’€.

  • -mtune=cpu-type โ€” tunes everything applicable about the generated code to cpu-type ๐ŸŽฏ, except for the ABI and the set of available instructions ๐Ÿ™ˆ. The list of cpu-type values is the same as for -march โœจ. The default is whatever value is used for -march ๐Ÿ’–.
  • -mtpf-trace, -mno-tpf-trace โ€” adds (or doesn't add) TPF OS specific branches to trace routines in the operating system ๐Ÿฆ‹. This is off by default, even when you're compiling for the TPF OS ๐Ÿ˜ญ.
  • -mtpf-trace-skip, -mno-tpf-trace-skip โ€” changes (or doesn't change) the default branch targets enabled by -mtpf-trace so they point to specialized trace routines ๐Ÿงš. These let you selectively skip function trace entries for the TPF OS โœจ. It's off by default, even when you're compiling for the TPF OS and specifying -mtpf-trace ๐Ÿ’….
  • -mfused-madd, -mno-fused-madd โ€” generates code that uses (or doesn't use) the floating-point multiply and accumulate instructions ๐Ÿ”ฅ. These get generated by default if hardware floating point is used ๐Ÿซถ.
  • -mwarn-framesize=framesize โ€” emits a warning if the current function exceeds the given frame size โš ๏ธ. This is a compile-time check, so it doesn't have to be a real problem when the program runs ๐ŸŒธ. It's meant to spot functions that most probably cause a stack overflow ๐Ÿ‘€. It's super useful in environments with a limited stack size, like the Linux kernel ๐Ÿง.
  • -mwarn-dynamicstack โ€” emits a warning if the function calls alloca or uses dynamically-sized arrays ๐Ÿ™ˆ. This is generally a bad idea with a limited stack size ๐Ÿ’€.
  • -mstack-guard=stack-guard, -mstack-size=stack-size โ€” when these are provided, the S/390 back end adds extra instructions to the function prologue ๐Ÿ›ก๏ธ. These trigger a trap if the stack size is stack-guard bytes above the stack-size ๐Ÿ˜ค. (Remember, the stack on S/390 grows downward ๐Ÿง .) If you leave out stack-guard, GCC picks the smallest power of 2 that's larger than the frame size of the compiled function ๐Ÿ“.

These options are meant to help you debug stack overflow problems ๐Ÿ”. The extra code causes only little overhead, so it can also be used in production-like systems without a big performance hit ๐Ÿ’–. The values have to be exact powers of 2, and stack-size has to be greater than stack-guard without going over 64k ๐Ÿ‘‘. To be efficient, the extra code assumes the stack starts at an address aligned to the value given by stack-size โœจ. Also, stack-guard can only be used together with stack-size ๐Ÿซถ.

  • -mhotpatch=pre-halfwords,post-halfwords โ€” if hotpatch is enabled, a "hot-patching" function prologue is generated for all functions in the compilation unit ๐Ÿ”ฅ. The function label gets prepended with the given number of two-byte NOP instructions (pre-halfwords, maximum 1000000) ๐Ÿงš. After the label, 2 * post-halfwords bytes get appended, using the largest NOP-like instructions the architecture allows (maximum 1000000) โœจ.

If both arguments are zero, hotpatching is disabled ๐Ÿ™…โ€โ™€๏ธ.

You can override this option for individual functions with the hotpatch attribute ๐Ÿ’….


โœจ Score Options โœจ

These options are defined for Score implementations ๐ŸŒˆ:

  • -meb โ€” compiles code for big-endian mode ๐Ÿ’œ. This is the default ๐Ÿ’–.
  • -mel โ€” compiles code for little-endian mode ๐Ÿฆ‹.
  • -mnhwloop โ€” disables generation of bcnz instructions ๐Ÿ™…โ€โ™€๏ธ.
  • -muls โ€” enables generation of unaligned load and store instructions ๐Ÿซถ.
  • -mmac โ€” enables the use of multiply-accumulate instructions ๐Ÿ”ฅ. It's disabled by default ๐Ÿ’€.
  • -mscore5 โ€” specifies SCORE5 as the target architecture ๐Ÿ‘‘.
  • -mscore5u โ€” specifies SCORE5U as the target architecture ๐ŸŒธ.
  • -mscore7 โ€” specifies SCORE7 as the target architecture ๐Ÿ’…. This is the default โœจ.
  • -mscore7d โ€” specifies SCORE7D as the target architecture ๐Ÿงš.

๐ŸŒธ SH Options ๐ŸŒธ

These -m options are defined for the SH implementations ๐Ÿ’–:

  • -m1 โ€” generates code for the SH1 ๐Ÿ“.
  • -m2 โ€” generates code for the SH2 ๐Ÿ“.
  • -m2e โ€” generates code for the SH2e ๐Ÿ“.
  • -m2a-nofpu โ€” generates code for the SH2a without an FPU ๐Ÿ˜ค. Or, for a SH2a-FPU, it does this in such a way that the floating-point unit isn't used ๐Ÿ™ˆ.
  • -m2a-single-only โ€” generates code for the SH2a-FPU in such a way that no double-precision floating-point operations are used ๐Ÿฆ‹.
  • -m2a-single โ€” generates code for the SH2a-FPU, assuming the floating-point unit is in single-precision mode by default โœจ.
  • -m2a โ€” generates code for the SH2a-FPU, assuming the floating-point unit is in double-precision mode by default ๐Ÿ‘‘.
  • -m3 โ€” generates code for the SH3 ๐Ÿ“.
  • -m3e โ€” generates code for the SH3e ๐Ÿ“.
  • -m4-nofpu โ€” generates code for the SH4 without a floating-point unit ๐Ÿ™…โ€โ™€๏ธ.
  • -m4-single-only โ€” generates code for the SH4 with a floating-point unit that only supports single-precision arithmetic ๐Ÿซถ.
  • -m4-single โ€” generates code for the SH4, assuming the floating-point unit is in single-precision mode by default ๐Ÿ”ฅ.
  • -m4 โ€” generates code for the SH4 ๐Ÿ‘‘.
  • -m4-100 โ€” generates code for SH4-100 โœจ.
  • -m4-100-nofpu โ€” generates code for SH4-100 in such a way that the floating-point unit isn't used ๐Ÿ’….
  • -m4-100-single โ€” generates code for SH4-100, assuming the floating-point unit is in single-precision mode by default ๐ŸŒˆ.
  • -m4-100-single-only โ€” generates code for SH4-100 in such a way that no double-precision floating-point operations are used ๐Ÿฆ‹.
  • -m4-200 โ€” generates code for SH4-200 โœจ.
  • -m4-200-nofpu โ€” generates code for SH4-200 without, in such a way that the floating-point unit isn't used ๐Ÿ˜ญ.
  • -m4-200-single โ€” generates code for SH4-200, assuming the floating-point unit is in single-precision mode by default ๐ŸŒธ.
  • -m4-200-single-only โ€” generates code for SH4-200 in such a way that no double-precision floating-point operations are used ๐Ÿ’œ.
  • -m4-300 โ€” generates code for SH4-300 โœจ.
  • -m4-300-nofpu โ€” generates code for SH4-300 without, in such a way that the floating-point unit isn't used ๐Ÿ™ˆ.
  • -m4-300-single โ€” generates code for SH4-300 in such a way that no double-precision floating-point operations are used ๐Ÿฆ‹.
  • -m4-300-single-only โ€” generates code for SH4-300 in such a way that no double-precision floating-point operations are used ๐Ÿฆ‹.
  • -m4-340 โ€” generates code for SH4-340 (no MMU, no FPU) ๐Ÿงš.
  • -m4-500 โ€” generates code for SH4-500 (no FPU) ๐Ÿ“. It passes -isa=sh4-nofpu to the assembler ๐Ÿซถ.
  • -m4a-nofpu โ€” generates code for the SH4al-dsp, or for a SH4a in such a way that the floating-point unit isn't used ๐Ÿ’….
  • -m4a-single-only โ€” generates code for the SH4a in such a way that no double-precision floating-point operations are used ๐Ÿฆ‹.
  • -m4a-single โ€” generates code for the SH4a, assuming the floating-point unit is in single-precision mode by default โœจ.
  • -m4a โ€” generates code for the SH4a ๐Ÿ‘‘.
  • -m4al โ€” same as -m4a-nofpu, except it implicitly passes -dsp to the assembler ๐ŸŒˆ. GCC doesn't generate any DSP instructions at the moment ๐Ÿ˜ญ.
  • -mb โ€” compiles code for the processor in big-endian mode ๐Ÿ’œ.
  • -ml โ€” compiles code for the processor in little-endian mode ๐Ÿ’–.
  • -mdalign โ€” aligns doubles at 64-bit boundaries ๐Ÿ“. Heads up: this changes the calling conventions, so some functions from the standard C library won't work unless you recompile them first with -mdalign โš ๏ธ.
  • -mrelax โ€” shortens some address references at link time, when possible ๐Ÿ”—. It does this using the linker option -relax โœจ.
  • -mbigtable โ€” uses 32-bit offsets in switch tables ๐ŸŒธ. The default is 16-bit offsets ๐Ÿ™…โ€โ™€๏ธ.
  • -mbitops โ€” enables the use of bit manipulation instructions on SH2A ๐Ÿ”ฅ.
  • -mfmovd โ€” enables the use of the fmovd instruction ๐Ÿฆ‹. Check -mdalign for alignment constraints ๐Ÿ‘€.
  • -mrenesas โ€” complies with the calling conventions defined by Renesas ๐Ÿ‘‘.
  • -mno-renesas โ€” complies with the calling conventions defined for GCC before the Renesas conventions were available ๐Ÿงš. This option is the default for all targets of the SH toolchain ๐Ÿ’….
  • -mnomacsave โ€” marks the MAC register as call-clobbered, even if -mrenesas is given ๐Ÿ™ˆ.
  • -mieee, -mno-ieee โ€” controls the IEEE compliance of floating-point comparisons ๐Ÿงฎ. This affects how cases where the result of a comparison is unordered 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 these implicit settings by specifying either -mieee or -mno-ieee ๐Ÿซถ.
  • -minline-ic_invalidate โ€” okay so this one tells the compiler to inline code that invalidates instruction cache entries right after it sets up nested function trampolines ๐Ÿ’…. It does nothing if -musermode is active and your chosen code generation option (like -m4) doesn't allow the icbi instruction. If your code gen option doesn't allow icbi and -musermode isn't on, the inlined code pokes the instruction cache address array directly with an associative write ๐Ÿ˜ฌ. That needs privileged mode at run time, and it fails if the cache line was mapped through the TLB and has since become unmapped ๐Ÿ’€.
  • -misize โ€” dumps instruction size and location into the assembly output ๐Ÿงš
  • -mpadstruct โ€” โš ๏ธ deprecated, so please don't reach for it ๐Ÿ™ˆ. It pads structures out to a multiple of 4 bytes, which is incompatible with the SH ABI ๐Ÿ’€
  • -matomic-model=model โ€” sets the model for atomic operations, plus any extra parameters, as a comma separated list ๐Ÿ”ฅ. For the full scoop on the atomic built-in functions, check out __atomic Builtins โœจ. These are the models and parameters you can pick from:
    • none โ€” turns off compiler generated atomic sequences and emits library calls for atomic operations instead. This is the default when the target isn't sh*-*-linux* ๐ŸŒธ
    • soft-gusa โ€” generates GNU/Linux compatible gUSA software atomic sequences for the atomic built-ins ๐Ÿฆ‹. These need extra help from the system's interrupt/exception handling code and only work on SH3* and SH4* single-core systems. It's turned on by default when the target is sh*-*-linux* and the chip is SH3* or SH4*. On SH4A, it also partly uses the hardware movli.l and movco.l instructions for faster code, unless you specify strict ๐Ÿ”ฅ
    • soft-tcb โ€” generates software atomic sequences that use a variable in the thread control block ๐Ÿ‘‘. It's a spin on the gUSA sequences that also works on SH1* and SH2* targets. Like gUSA, it needs help from the interrupt/exception handling code and is only suitable for single-core systems. When you use this model, you have to specify the gbr-offset= parameter too โš ๏ธ
    • soft-imask โ€” generates software atomic sequences that temporarily turn off interrupts by setting SR.IMASK = 1111 ๐ŸŒˆ. This only works when the program runs in privileged mode and is only suitable for single-core systems. It doesn't need any extra help from the interrupt/exception handling code. It's enabled by default when the target is sh*-*-linux* and the chip is SH1* or SH2* โœจ
    • hard-llcs โ€” generates hardware atomic sequences using only movli.l and movco.l ๐Ÿ’œ. It's only available on SH4A and is great for multi-core systems. The hardware only handles 32 bit atomic variables, so 8 and 16 bit variables get emulated with 32 bit accesses. Code built with this is also compatible with other software atomic model interrupt/exception handling systems when it runs on an SH4A system. This model doesn't need any extra support from the interrupt/exception handling code ๐Ÿซถ
    • gbr-offset= โ€” the offset, in bytes, of the variable inside the thread control block structure that the generated atomic sequences should use when soft-tcb is selected ๐Ÿ“. Other models just ignore it. The value has to be an integer multiple of four and fall in the range 0-1020 ๐ŸŽ€
    • strict โ€” stops you from mixing multiple atomic models, even ones that are compatible with each other ๐Ÿ™…. It makes the compiler generate sequences for only the model you specified ๐Ÿ’…
  • -mtas โ€” generates the tas.b opcode for __atomic_test_and_set ๐Ÿซง. Heads up, though: depending on your hardware and software setup, this can drag down overall performance because of the operand cache line flushes that tas.b implies ๐Ÿ˜ญ. On multi-core SH4A processors, tas.b has to be used with caution, since it can cause data corruption with certain cache configurations โš ๏ธ
  • -mprefergot โ€” when you're making position-independent code, function calls get emitted through the Global Offset Table instead of the Procedure Linkage Table ๐Ÿงš
  • -musermode, -mno-usermode โ€” -musermode stops the compiler from generating privileged mode code, and -mno-usermode lets it generate that code ๐Ÿ”’. Using -musermode also implies -mno-inline-ic_invalidate if the inlined code wouldn't work in user mode ๐Ÿ’–. -musermode is the default when the target is sh*-*-linux*. If the target is SH1* or SH2*, -musermode does nothing, since those chips don't have a user mode ๐Ÿ™ƒ
  • -multcost=number โ€” sets the cost the compiler assumes for a multiply instruction ๐Ÿ”ข
  • -mdiv=strategy โ€” picks the division strategy for integer division operations ๐Ÿงฎ. The strategy can be one of:
    • call-div1 โ€” calls a library function that uses the single-step division instruction div1 to do the math. 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 an FPU. If you pick this on a target without a double precision FPU, it falls back to call-div1 ๐Ÿซ 
    • call-table โ€” calls a library function that uses a lookup table for small divisors, plus the div1 instruction with case distinction for bigger divisors ๐Ÿง . Dividing by zero gives an unspecified result and doesn't trap. This is the default for SH4. If you pick this on a target without dynamic shift instructions, it falls back to call-div1 ๐ŸŽ€

When you don't specify a strategy, the default is picked based on the current target. On SH2A, the default is to use the divs and divu instructions instead of library function calls โœจ

  • -maccumulate-outgoing-args โ€” reserves space for outgoing arguments once, in the function prologue, instead of around each call ๐Ÿ“ฆ. This is generally good for performance and size. It's also needed for unwinding, so the stack frame doesn't get changed around conditional code ๐Ÿฆ‹
  • -mdivsi3_libfunc=name โ€” sets the name of the library function used for 32-bit signed division to name ๐Ÿท๏ธ. This only changes the name used in the call division strategies. The compiler still expects the same sets of input, output and clobbered registers as if you hadn't used this option ๐Ÿ’…
  • -mfixed-range=register-range โ€” makes the compiler treat the given register range as fixed registers ๐Ÿ”’. A fixed register is one the register allocator isn't allowed to use. This comes in handy when you're compiling kernel code ๐Ÿซถ. A register range is written as two registers separated by a dash, and you can list multiple ranges separated by a comma ๐ŸŒˆ
  • -mbranch-cost=num โ€” tells the compiler to assume num is the cost of a branch instruction ๐ŸŒฟ. Higher numbers make the compiler try harder to generate 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 โ€” -mzdcbranch assumes that zero displacement conditional branch instructions bt and bf are fast, so the compiler prefers zero displacement branch code sequences โšก. -mno-zdcbranch says the opposite ๐Ÿ™…. It's enabled by default for SH4 and SH4A, and you can turn it off explicitly with -mno-zdcbranch ๐ŸŒธ
  • -mcbranch-force-delay-slot โ€” forces the use of delay slots for conditional branches ๐Ÿฆฅ. If no suitable instruction turns up, it fills the delay slot with a nop ๐Ÿ’ค. This option is disabled by default. Turn it on to work around the hardware bugs found in the original SH7055 ๐Ÿ”ง
  • -mfused-madd, -mno-fused-madd โ€” -mfused-madd generates code that uses the floating-point multiply and accumulate instructions, and -mno-fused-madd generates code that doesn't ๐Ÿงช. These instructions are generated by default if hardware floating point is in use. 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 -mfsca option has to be paired 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 โ€” same idea, but for the fsrra instruction and reciprocal square root approximations ๐ŸŒŸ. The -mfsrra option has to be paired with both -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 give you 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 ๐Ÿงน. You only need this when object files use ISA extensions the current machine doesn't support, but the code checks at runtime whether or not to use them ๐Ÿซถ
  • -mimpure-text โ€” used alongside -shared, this tells the compiler not to pass -z text to the linker when linking a shared object ๐Ÿฆ„. With this option, you can link position-dependent code into a shared object ๐Ÿ’œ

okay so -mimpure-text is giving "I know what I'm doing" energy ๐Ÿ’… It shuts up the linker complaint about "relocations remain against allocatable but non-writable sections" ๐Ÿ™ˆ BUT ngl this is a trap, bestie. The relocations trigger copy-on-write, so the shared object is not actually shared across processes anymore ๐Ÿ˜ญ The real move is to compile all your source code with -fpic or -fPIC instead ๐Ÿซถ

These switches are also supported on Solaris 2, so you get these extras too:

  • -pthreads โ€” literally just a synonym for -pthread ๐Ÿงต

โœจ SPARC Options โœจ

These -m options are supported on the SPARC ๐ŸŒธ

  • -mno-app-regs, -mapp-regs โ€” -mapp-regs makes the output use global registers 2 through 4, which the SPARC SVR4 ABI reserves for applications ๐ŸŽ€ Like global register 1, each of global registers 2 through 4 then gets treated as an allocable register that function calls clobber. This one is the default. If you want to be fully SVR4 ABI-compliant (with a bit of a performance hit), go with -mno-app-regs. You should compile libraries and system software with this option ๐Ÿ’–
  • -mflat, -mno-flat โ€” With -mflat, the compiler skips the save/restore instructions and uses a "flat" or single register window model ๐Ÿฆ‹ This is compatible with the regular register window model. The local registers and the input registers (0--5) are still treated as "call-saved" registers, so they 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 with floating-point instructions. This is the default ๐Ÿ”ฅ
  • -mno-fpu, -msoft-float โ€” Generates output that uses library calls for floating point instead ๐Ÿ’…
โš ๏ธ Warning: the requisite libraries are not available for all SPARC targets ๐Ÿ˜ญ Normally the facilities of the machine's usual C compiler get used, but that can't be done directly in cross-compilation. You have to make your own arrangements to provide suitable library functions for cross-compilation. The embedded targets sparc-*-aout and sparclite-*-* do provide software floating-point support.

-msoft-float changes the calling convention in the output file, so it's only useful if you compile 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 with quad-word (long double) floating-point instructions ๐Ÿ‘‘
  • -msoft-quad-float โ€” Generates output that uses 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. Because of that trap handler overhead, this is much slower than calling the ABI library routines, so -msoft-quad-float is the default ๐Ÿ™ˆ
  • -mno-unaligned-doubles, -munaligned-doubles โ€” -mno-unaligned-doubles assumes that doubles have 8-byte alignment, and this is the default ๐Ÿ’œ With -munaligned-doubles, GCC only assumes 8-byte alignment for doubles if they're contained in another type or if they have an absolute address. Otherwise, it assumes 4-byte alignment. Using this option avoids some rare compatibility problems with code generated by other compilers. It isn't the default because it results in a performance loss, especially for floating-point code ๐Ÿ“‰
  • -muser-mode, -mno-user-mode โ€” Does not generate code that can only run in supervisor mode ๐Ÿงš This is only relevant to the casa instruction emitted for the LEON3 processor. This is the default.
  • -mfaster-structs, -mno-faster-structs โ€” With -mfaster-structs, the compiler assumes structures should have 8-byte alignment ๐Ÿ“ This enables pairs of ldd and std instructions for copies in structure assignment, in place of twice as many ld and st pairs. However, this changed alignment directly violates the SPARC ABI. So it's only meant for targets where the developer acknowledges that their resulting code isn't directly in line with the ABI rules ๐Ÿ™ˆ
  • -mstd-struct-return, -mno-std-struct-return โ€” With -mstd-struct-return, the compiler generates checking code in functions returning structures or unions. This detects size mismatches between the two sides of function calls, as per the 32-bit ABI ๐Ÿ” The default is -mno-std-struct-return. This option has no effect in 64-bit mode.
  • -mlra, -mno-lra โ€” Enables Local Register Allocation ๐ŸŒธ This has been the default for SPARC since GCC 7, so you need to pass -mno-lra if you want the old Reload.
  • -mcpu=cpu_type โ€” Sets the instruction set, register set, and instruction scheduling parameters for machine type cpu_type ๐Ÿ‘‘ Supported values for cpu_type 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 accept 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 get used for values that select an architecture and not a specific implementation. Those are v7, v8, sparclite, sparclet, and v9.

Here's the lineup of each supported architecture and its implementations:

  • v7 โ€” cypress, leon3v7
  • v8 โ€” supersparc, hypersparc, leon, leon3, leon5
  • sparclite โ€” f930, f934, sparclite86x
  • sparclet โ€” tsc701
  • v9 โ€” ultrasparc, ultrasparc3, niagara, niagara2, niagara3, niagara4, niagara7, m8

By default (unless configured otherwise), GCC generates code for the V7 variant of the SPARC architecture ๐Ÿฆ‹ With -mcpu=cypress, the compiler additionally optimizes for the Cypress CY7C602 chip, as used in the SPARCStation/SPARCServer 3xx series. This is also appropriate for the older SPARCStation 1, 2, IPX etc.

With -mcpu=v8, GCC generates code for the V8 variant. The only difference from V7 code is that the compiler emits the integer multiply and integer divide instructions that exist in SPARC-V8 but not in SPARC-V7 โœจ With -mcpu=supersparc, the compiler additionally optimizes for the SuperSPARC chip, as used in the SPARCStation 10, 1000 and 2000 series.

With -mcpu=sparclite, GCC generates code for the SPARClite variant. 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 additionally 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 FPU.

With -mcpu=sparclet, GCC generates code for the SPARClet variant. 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 additionally optimizes for the TEMIC SPARClet chip.

With -mcpu=v9, GCC generates code for the V9 variant. 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 additionally 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 doesn't touch the instruction set or register set the way -mcpu=cpu_type does ๐ŸŽ€

The same values for -mcpu=cpu_type work for -mtune=cpu_type, but the only useful ones are the values that select 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, such as UltraSPARC-III and later. Setting -mvis2 also sets -mvis.
  • -mvis3, -mno-vis3 โ€” With -mvis3, GCC generates code that takes advantage of version 3.0 of the UltraSPARC Visual Instruction Set extensions โญ The default is -mvis3 when targeting a CPU that supports such instructions, such as niagara-3 and later. Setting -mvis3 also sets -mvis2 and -mvis.

-mvis4, -mno-vis4 โ€” okay so -mvis4 makes GCC write code that uses version 4.0 of the UltraSPARC Visual Instruction Set extensions ๐Ÿ’…. The default is -mvis4 when you're targeting a cpu that supports these, like niagara-7 and later. Setting -mvis4 also turns on -mvis3, -mvis2 and -mvis โœจ

  • -mvis4b, -mno-vis4b โ€” With -mvis4b, GCC uses version 4.0 of the UltraSPARC Visual Instruction Set extensions, plus the extra VIS instructions introduced in the Oracle SPARC Architecture 2017 ๐Ÿ”ฅ. The default is -mvis4b when targeting a cpu that supports these, like m8 and later. Setting -mvis4b also sets -mvis4, -mvis3, -mvis2 and -mvis ๐Ÿ’œ
  • -mcbcond, -mno-cbcond โ€” With -mcbcond, GCC takes advantage of the UltraSPARC Compare-and-Branch-on-Condition instructions ๐Ÿฆ‹. The default is -mcbcond when targeting a CPU that supports these, like Niagara-4 and later.
  • -mfmaf, -mno-fmaf โ€” With -mfmaf, GCC takes advantage of the UltraSPARC Fused Multiply-Add Floating-point instructions ๐ŸŒธ. The default is -mfmaf when targeting a CPU that supports these, like Niagara-3 and later.
  • -mfsmuld, -mno-fsmuld โ€” With -mfsmuld, GCC uses the Floating-point Multiply Single to Double (FsMULd) instruction ๐Ÿงš. The default is -mfsmuld when targeting a CPU that supports the architecture versions V8 or V9 with FPU, except -mcpu=leon.
  • -mpopc, -mno-popc โ€” With -mpopc, GCC takes advantage of the UltraSPARC Population Count instruction ๐Ÿ“. The default is -mpopc when targeting a CPU that supports it, like Niagara-2 and later.
  • -msubxc, -mno-subxc โ€” With -msubxc, GCC takes advantage of the UltraSPARC Subtract-Extended-with-Carry instruction โญ. The default is -msubxc when targeting a CPU that supports it, like Niagara-7 and later.
  • -mfix-at697f โ€” Turns on the documented workaround for the single erratum of the Atmel AT697F processor, which is erratum #13 of the AT697E processor ๐Ÿ› ๏ธ.
  • -mfix-ut699 โ€” Turns on the documented workarounds for the floating-point errata and the data cache nullify errata of the UT699 processor ๐Ÿซถ.
  • -mfix-ut700 โ€” Turns on the documented workaround for the back-to-back store errata of the UT699E/UT700 processor ๐Ÿ’….
  • -mfix-gr712rc โ€” Turns on the documented workaround for the back-to-back store errata of the GR712RC processor ๐Ÿ‘‘.

These -m options are supported in addition to the above on SPARC-V9 processors in 64-bit environments, and they're lowkey essential if that's your setup โœจ

  • -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, and yes, it's giving main character energy ๐Ÿ‘‘:
    • 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: 64-bit addresses, and programs may be linked anywhere in 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.
    • embmedany โ€” The Medium/Anywhere code model for embedded systems: 64-bit addresses. The text and data segments must be less than 2GB in size, both starting anywhere in memory (determined at link time). The global register %g4 points to the base of the data segment. Programs are statically linked, and PIC is not supported.
  • -mmemory-model=mem-model โ€” Sets the memory model in force on the processor to one of these ๐Ÿง :
    • default โ€” The default memory model for the processor and operating system.
    • rmo โ€” Relaxed Memory Order
    • pso โ€” Partial Store Order
    • tso โ€” Total Store Order
    • sc โ€” Sequential Consistency

These memory models are formally defined in Appendix D of the SPARC-V9 architecture manual, as set in the processor's "PSTATE.MM" field ๐Ÿ“š.

  • -mstack-bias, -mno-stack-bias โ€” With -mstack-bias, GCC assumes that the stack pointer, and the frame pointer if there is one, are offset by -2047, which must be added back when making stack frame references. This is the default in 64-bit mode. Otherwise, GCC assumes no such offset is present ๐Ÿ™ˆ.

โœจ Options for System V โœจ

These additional options are available on System V Release 4 for compatibility with other compilers on those systems ๐Ÿ’–.

  • -G โ€” Creates a shared object. It is recommended that -symbolic or -shared be used instead.
  • -Qy โ€” Identifies the versions of each tool used by the compiler, in a .ident assembler directive in the output ๐Ÿ”.
  • -Qn โ€” Refrains from adding .ident directives to the output file. This is the default.
  • -YP,dirs โ€” Searches the directories dirs, and no others, for libraries specified with -l ๐Ÿ“‚.
  • -Ym,dir โ€” Looks in the directory dir to find the M4 preprocessor. The assembler uses this option ๐Ÿงš.

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

These -m options are supported on the TILE-Gx ๐Ÿ’…:

  • -mcmodel=small โ€” Generates code for the small model. The distance for direct calls is limited to 500M in either direction. PC-relative addresses are 32 bits. Absolute addresses support the full address range.
  • -mcmodel=large โ€” Generates code for the large model. There is no limitation on call distance, pc-relative addresses, or absolute addresses ๐Ÿฆ‹.
  • -mcpu=name โ€” Selects the type of CPU to be targeted. Currently the only supported type is tilegx.
  • -m32, -m64 โ€” Generates code for a 32-bit or 64-bit environment. The 32-bit environment sets int, long, and pointer to 32 bits. The 64-bit environment sets int to 32 bits and long and pointer to 64 bits.
  • -mbig-endian, -mlittle-endian โ€” Generates code in big or little endian mode, respectively ๐Ÿซถ.

๐ŸŽ€ TILEPro Options ๐ŸŽ€

These -m options are supported on the TILEPro ๐ŸŒธ:

  • -mcpu=name โ€” Selects the type of CPU to be targeted. Currently the only supported type is tilepro.
  • -m32 โ€” Generates code for a 32-bit environment, which sets int, long, and pointer to 32 bits. This is the only supported behavior, so the flag is essentially ignored ๐Ÿ™ƒ.

๐Ÿ’œ V850 Options ๐Ÿ’œ

These -m options are defined for V850 implementations ๐Ÿ“:

  • -mlong-calls, -mno-long-calls โ€” Treats all calls as being far away (or near). If calls are assumed to be far away, the compiler always loads the function's address into a register, and calls indirect through the pointer ๐Ÿ“ž.
  • -mno-ep, -mep โ€” Does not 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 use the shorter "sld" and "sst" instructions. The -mep option is on by default if you optimize โœจ.
  • -mno-prolog-function, -mprolog-function โ€” Does not use (or does use) external functions to save and restore registers at the prologue and epilogue of a function. The external functions are slower, but use less code space if more than one function saves the same number of registers. The -mprolog-function option is on by default if you optimize ๐Ÿง .
  • -mspace โ€” Tries to make the code as small as possible. At present, this just turns on the -mep and -mprolog-function options ๐ŸŒˆ.
  • -mtda=n โ€” Puts static or global variables whose size is n bytes or less into the tiny data area that register "ep" points to. The tiny data area can hold up to 256 bytes in total (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 register "gp" points to. The small data area can hold up to 64 kilobytes ๐Ÿ’–.
  • -mzda=n โ€” Puts static or global variables whose size is n bytes or less into the first 32 kilobytes of memory ๐ŸŒธ.
  • -mv850 โ€” Specifies that the target processor is the V850 ๐Ÿฆ‹.
  • -mv850e3v5 โ€” Specifies that the target processor is the V850E3V5. The preprocessor constant "__v850e3v5__" is defined if this option is used ๐Ÿ”ฅ.
  • -mv850e2v4 โ€” Specifies that the target processor is the V850E3V5. This is an alias for the -mv850e3v5 option ๐Ÿซถ.
  • -mv850e2v3 โ€” Specifies that the target processor is the V850E2V3. The preprocessor constant "__v850e2v3__" is defined if this option is used ๐ŸŒŸ.
  • -mv850e2 โ€” Specifies that the target processor is the V850E2. The preprocessor constant "__v850e2__" is defined if this option is used ๐Ÿ’….
  • -mv850e1 โ€” Specifies that the target processor is the V850E1. The preprocessor constants "__v850e1__" and "__v850e__" are defined if this option is used ๐Ÿ‘‘.
  • -mv850es โ€” Specifies that the target processor is the V850ES. This is an alias for the -mv850e1 option ๐ŸŽ€.
  • -mv850e โ€” Specifies that the target processor is the V850E. The preprocessor constant "__v850e__" is defined if this option is used ๐Ÿ“.

If neither -mv850 nor -mv850e nor -mv850e1 nor -mv850e2 nor -mv850e2v3 nor -mv850e3v5 are defined, then a default target processor is chosen and the relevant __v850*__ preprocessor constant is defined ๐Ÿคทโ€โ™€๏ธ.

The preprocessor constants "__v850" and "__v851__" are always defined, regardless of which processor variant is the target ๐Ÿงš.

  • -mdisable-callt, -mno-disable-callt โ€” This option suppresses generation of the "CALLT" instruction for the v850e, v850e1, v850e2, v850e2v3 and v850e3v5 flavors 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 does not 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 โ€” okay so these two let you switch the generation of hardware floating point instructions off (or back on) ๐Ÿ”ฅ. This only matters when the target architecture is V850E2V3 or higher. If hardware floating point instructions are being generated, the C preprocessor symbol __FPU_OK__ gets defined, and if they aren't, __NO_FPU__ gets defined instead ๐Ÿ’–.
  • -mloop โ€” enables the e3v5 LOOP instruction ๐ŸŒ€. Heads up bestie: this one is NOT on by default when you pick the e3v5 architecture, because its use is still experimental ๐Ÿงช.
  • -mrh850-abi, -mghs โ€” turns on support for the RH850 version of the V850 ABI ๐Ÿ‘‘. This is the default, and with it the following rules apply:
    • Integer sized structures and unions get returned via a memory pointer instead of a register.
    • Large structures and unions (more than 8 bytes in size) are passed by value.
    • Functions are aligned to 16-bit boundaries.
    • The -m8byte-align command-line option is supported.
    • The -mdisable-callt command-line option is enabled by default. The -mno-disable-callt command-line option is not supported.

When this version of the ABI is enabled, the C preprocessor symbol __V850_RH850_ABI__ gets defined โœจ.

  • -mgcc-abi โ€” the old-school GCC version of the V850 ABI ๐Ÿฆ•. With this one, the rules are:
    • Integer sized structures and unions come back 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 not enabled by default.

When this version of the ABI is enabled, the C preprocessor symbol __V850_GCC_ABI__ gets defined ๐ŸŒธ.

  • -m8byte-align, -mno-8byte-align โ€” lets double and long long types get aligned on 8-byte boundaries ๐Ÿ“. The default is to keep the alignment of all objects at 4 bytes max. When -m8byte-align is in effect, the C preprocessor symbol __V850_8BYTE_ALIGN__ gets defined.
  • -mbig-switch โ€” generates code that's suitable for big switch tables ๐Ÿง. Only reach for this one if the assembler or linker starts complaining about out of range branches within a switch table ๐Ÿ™ˆ.
  • -mapp-regs โ€” makes the generated code use r2 and r5 ๐Ÿ’…. This is the default setting.
  • -mno-app-regs โ€” makes r2 and r5 get treated as fixed registers.

๐ŸŽ€ VAX Options ๐ŸŽ€

These -m options are defined for the VAX ๐ŸŒท:

  • -munix โ€” skips outputting certain jump instructions (aobleq and so on) that the Unix assembler for the VAX can't handle across long ranges ๐Ÿ™…โ€โ™€๏ธ.
  • -mgnu โ€” nope, the opposite! This one DOES output those jump instructions, on the assumption that the GNU assembler is being used ๐Ÿซถ.
  • -mg โ€” outputs code for G-format floating-point numbers instead of D-format ๐Ÿ”ข.

๐Ÿฆ‹ Visium Options ๐Ÿฆ‹

  • -mdebug โ€” if your program does file I/O and is destined to run on an MCM target, link it with this one ๐Ÿ’œ. It causes the libraries libc.a and libdebug.a to get linked. You run the program on the target under the control of the GDB remote debugging stub ๐Ÿ› ๏ธ.
  • -msim โ€” same vibe, but for the simulator ๐Ÿงช. If your program does file I/O and is going to run on the simulator, link it with option (the manual forgot a word here, bestie ๐Ÿ’€). This causes the libraries libc.a and libsim.a to get linked.
  • -mfpu, -mhard-float โ€” generates code containing floating-point instructions โšก. This is the default.
  • -mno-fpu, -msoft-float โ€” generates code containing library calls for floating-point ๐Ÿ“ž.
Warning, this one is a whole vibe: -msoft-float changes the calling convention in the output file ๐Ÿ˜ญ. That means it's only useful if you compile ALL of a program with this option. In particular, you need to compile libgcc.a, the library that comes with GCC, with -msoft-float for this to work.
  • -mcpu=cpu_type โ€” sets the instruction set, register set, and instruction scheduling parameters for the machine type cpu_type ๐Ÿง . The supported values for cpu_type are mcm, gr5 and gr6.
    • mcm is a synonym of gr5, kept around for backward compatibility ๐Ÿ•ฐ๏ธ.
    • By default (unless configured otherwise), GCC generates code for the GR5 variant of the Visium architecture ๐Ÿ‘‘.
    • With -mcpu=gr6, GCC generates code for the GR6 variant of the Visium architecture. The only difference from GR5 code is that the compiler will generate block move instructions ๐Ÿšš.
  • -mtune=cpu_type โ€” sets the instruction scheduling parameters for the machine type cpu_type, but doesn't touch the instruction set or register set that -mcpu=cpu_type would ๐ŸŽฏ.
  • -msv-mode โ€” generates code for supervisor mode, where there are no restrictions on access to general registers ๐Ÿ”“. This is the default.
  • -muser-mode โ€” generates code for user mode, where access to some general registers is forbidden ๐Ÿšซ. On the GR5, registers r24 to r31 can't be accessed in this mode. On the GR6, only registers r29 to r31 are affected.

๐ŸŒˆ VMS Options ๐ŸŒˆ

These -m options are defined for the VMS implementations ๐Ÿ’ซ:

  • -mvms-return-codes โ€” returns VMS condition codes from main. The default is to return POSIX-style condition (e.g. error) codes ๐ŸŽŸ๏ธ.
  • -mdebug-main=prefix โ€” flags the first routine whose name starts with prefix as the main routine for the debugger ๐Ÿ”.
  • -mmalloc64 โ€” defaults to 64-bit memory allocation routines ๐Ÿงฎ.
  • -mpointer-size=size โ€” sets the default size of pointers ๐Ÿ“. The possible options for size are 32 or short for 32-bit pointers, 64 or long for 64-bit pointers, and no for supporting only 32-bit pointers. The latter option disables pragma pointer_size.

โญ VxWorks Options โญ

The options in this section are defined for all VxWorks targets ๐Ÿงš. Options specific to the target hardware are listed with the other options for that target.

  • -mrtp โ€” GCC can generate code for both VxWorks kernels and real time processes (RTPs) ๐Ÿš€. This option switches from the former to the latter. It also defines the preprocessor macro __RTP__.
  • -non-static โ€” links an RTP executable against shared libraries rather than static libraries ๐Ÿ”—. The options -static and -shared can also be used for RTPs, and -static is the default.
  • -Bstatic, -Bdynamic โ€” these get passed down to the linker ๐Ÿ“จ. They're defined for compatibility with Diab.
  • -Xbind-lazy โ€” enables lazy binding of function calls ๐Ÿ˜ด. This option is equivalent to -Wl,-z,now and is defined for compatibility with Diab.
  • -Xbind-now โ€” disables lazy binding of function calls ๐Ÿƒโ€โ™€๏ธ. This option is the default and is defined for compatibility with Diab.

๐Ÿ’œ x86 Options ๐Ÿ’œ

These -m options are defined for the x86 family of computers ๐Ÿ’ป.

  • -march=cpu-type โ€” generates instructions for the machine type cpu-type ๐Ÿ”ฅ. Unlike -mtune=cpu-type, which merely tunes the generated code for the specified cpu-type, -march=cpu-type allows GCC to generate code that may not run at all on processors other than the one indicated ๐Ÿ˜ฌ. Specifying -march=cpu-type implies -mtune=cpu-type, except where noted otherwise.

The choices for cpu-type are:

  • native โ€” selects the CPU to generate code for at compilation time by figuring out the processor type of the compiling machine ๐Ÿ–ฅ๏ธ. Using -march=native enables all instruction subsets supported by the local machine (hence 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 select the corresponding micro-architecture level from the x86-64 psABI ๐Ÿ“š. On ABIs other than the x86-64 psABI, they select the same CPU features as the x86-64 psABI documents for that particular micro-architecture level. Since these cpu-type values don't have a corresponding -mtune setting, using -march with them enables generic tuning. You can enable specific tuning with the -mtune=other-cpu-type option and 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 ๐Ÿ’ป. It's a low-power version of the Intel Pentium III CPU with MMX, SSE and SSE2 instruction set support, and 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 โ€” ๐ŸŒธ Intel Sandy Bridge CPU, so you get 64-bit extensions plus MMX, SSE, SSE2, SSE3, SSSE3, SSE4.1, SSE4.2, POPCNT, AVX, AES and PCLMUL instruction set support. โœจ
  • ivybridge โ€” ๐Ÿฆ‹ Intel Ivy Bridge CPU with 64-bit extensions, MMX, SSE, SSE2, SSE3, SSSE3, SSE4.1, SSE4.2, POPCNT, AVX, AES, PCLMUL, FSGSBASE, RDRND and F16C instruction set support. ๐Ÿ’–
  • haswell โ€” ๐Ÿ’… Intel Haswell CPU, slaying with 64-bit extensions, MOVBE, MMX, SSE, SSE2, SSE3, SSSE3, SSE4.1, SSE4.2, POPCNT, AVX, AVX2, AES, PCLMUL, FSGSBASE, RDRND, FMA, BMI, BMI2 and F16C instruction set support. ๐Ÿ”ฅ
  • broadwell โ€” ๐ŸŽ€ Intel Broadwell CPU with 64-bit extensions, MOVBE, MMX, SSE, SSE2, SSE3, SSSE3, SSE4.1, SSE4.2, POPCNT, AVX, AVX2, AES, PCLMUL, FSGSBASE, RDRND, FMA, BMI, BMI2, F16C, RDSEED ADCX and PREFETCHW instruction set support. ๐ŸŒˆ
  • skylake โ€” ๐Ÿ‘‘ Intel Skylake CPU with 64-bit extensions, MOVBE, MMX, SSE, SSE2, SSE3, SSSE3, SSE4.1, SSE4.2, POPCNT, AVX, AVX2, AES, PCLMUL, FSGSBASE, RDRND, FMA, BMI, BMI2, F16C, RDSEED, ADCX, PREFETCHW, CLFLUSHOPT, XSAVEC and XSAVES instruction set support. ๐Ÿ’œ
  • bonnell โ€” ๐Ÿงš Intel Bonnell CPU, a little more chill, with 64-bit extensions, MOVBE, MMX, SSE, SSE2, SSE3 and SSSE3 instruction set support. ๐Ÿ“
  • silvermont โ€” โญ Intel Silvermont CPU with 64-bit extensions, MOVBE, MMX, SSE, SSE2, SSE3, SSSE3, SSE4.1, SSE4.2, POPCNT, AES, PREFETCHW, PCLMUL and RDRND instruction set support. ๐Ÿซถ
  • goldmont โ€” ๐Ÿ’– Intel Goldmont CPU with 64-bit extensions, MOVBE, MMX, SSE, SSE2, SSE3, SSSE3, SSE4.1, SSE4.2, POPCNT, AES, PREFETCHW, PCLMUL, RDRND, XSAVE, XSAVEC, XSAVES, XSAVEOPT and FSGSBASE instruction set support. โœจ
  • goldmont-plus โ€” ๐ŸŒธ Intel Goldmont Plus CPU, the glow-up version, with 64-bit extensions, MOVBE, MMX, SSE, SSE2, SSE3, SSSE3, SSE4.1, SSE4.2, POPCNT, AES, PREFETCHW, PCLMUL, RDRND, XSAVE, XSAVEC, XSAVES, XSAVEOPT, FSGSBASE, PTWRITE, RDPID, SGX and UMIP instruction set support. ๐Ÿ’…
  • tremont โ€” ๐Ÿฆ‹ Intel Tremont CPU with 64-bit extensions, MOVBE, MMX, SSE, SSE2, SSE3, SSSE3, SSE4.1, SSE4.2, POPCNT, AES, PREFETCHW, PCLMUL, RDRND, XSAVE, XSAVEC, XSAVES, XSAVEOPT, FSGSBASE, PTWRITE, RDPID, SGX, UMIP, GFNI-SSE, CLWB, MOVDIRI, MOVDIR64B, CLDEMOTE and WAITPKG instruction set support. ๐Ÿ”ฅ
  • knl โ€” ๐ŸŽ€ Intel Knight's Landing CPU with 64-bit extensions, MOVBE, MMX, SSE, SSE2, SSE3, SSSE3, SSE4.1, SSE4.2, POPCNT, AVX, AVX2, AES, PCLMUL, FSGSBASE, RDRND, FMA, BMI, BMI2, F16C, RDSEED, ADCX, PREFETCHW, PREFETCHWT1, AVX512F, AVX512PF, AVX512ER and AVX512CD instruction set support. ๐ŸŒˆ
  • knm โ€” ๐Ÿ‘‘ Intel Knights Mill CPU with 64-bit extensions, MOVBE, MMX, SSE, SSE2, SSE3, SSSE3, SSE4.1, SSE4.2, POPCNT, AVX, AVX2, AES, PCLMUL, FSGSBASE, RDRND, FMA, BMI, BMI2, F16C, RDSEED, ADCX, PREFETCHW, PREFETCHWT1, AVX512F, AVX512PF, AVX512ER, AVX512CD, AVX5124VNNIW, AVX5124FMAPS and AVX512VPOPCNTDQ instruction set support. ๐Ÿ’œ
  • skylake-avx512 โ€” ๐Ÿ”ฅ Intel Skylake Server CPU with 64-bit extensions, MOVBE, MMX, SSE, SSE2, SSE3, SSSE3, SSE4.1, SSE4.2, POPCNT, PKU, AVX, AVX2, AES, PCLMUL, FSGSBASE, RDRND, FMA, BMI, BMI2, F16C, RDSEED, ADCX, PREFETCHW, CLFLUSHOPT, XSAVEC, XSAVES, AVX512F, CLWB, AVX512VL, AVX512BW, AVX512DQ and AVX512CD instruction set support. ๐Ÿ’€
  • cannonlake โ€” ๐Ÿซถ Intel Cannonlake Server CPU with 64-bit extensions, MOVBE, MMX, SSE, SSE2, SSE3, SSSE3, SSE4.1, SSE4.2, POPCNT, PKU, AVX, AVX2, AES, PCLMUL, FSGSBASE, RDRND, FMA, BMI, BMI2, F16C, RDSEED, ADCX, PREFETCHW, CLFLUSHOPT, XSAVEC, XSAVES, AVX512F, AVX512VL, AVX512BW, AVX512DQ, AVX512CD, AVX512VBMI, AVX512IFMA, SHA and UMIP instruction set support. ๐ŸŒธ
  • icelake-client โ€” โœจ Intel Icelake Client CPU with 64-bit extensions, MOVBE, MMX, SSE, SSE2, SSE3, SSSE3, SSE4.1, SSE4.2, POPCNT, PKU, AVX, AVX2, AES, PCLMUL, FSGSBASE, RDRND, FMA, BMI, BMI2, F16C, RDSEED, ADCX, PREFETCHW, CLFLUSHOPT, XSAVEC, XSAVES, AVX512F, AVX512VL, AVX512BW, AVX512DQ, AVX512CD, AVX512VBMI, AVX512IFMA, SHA, CLWB, UMIP, RDPID, GFNI, AVX512VBMI2, AVX512VPOPCNTDQ, AVX512BITALG, AVX512VNNI, VPCLMULQDQ and VAES instruction set support. ๐Ÿฆ‹
  • icelake-server โ€” ๐ŸŒˆ Intel Icelake Server CPU with 64-bit extensions, MOVBE, MMX, SSE, SSE2, SSE3, SSSE3, SSE4.1, SSE4.2, POPCNT, PKU, AVX, AVX2, AES, PCLMUL, FSGSBASE, RDRND, FMA, BMI, BMI2, F16C, RDSEED, ADCX, PREFETCHW, CLFLUSHOPT, XSAVEC, XSAVES, AVX512F, AVX512VL, AVX512BW, AVX512DQ, AVX512CD, AVX512VBMI, AVX512IFMA, SHA, CLWB, UMIP, RDPID, GFNI, AVX512VBMI2, AVX512VPOPCNTDQ, AVX512BITALG, AVX512VNNI, VPCLMULQDQ, VAES, PCONFIG and WBNOINVD instruction set support. ๐Ÿ“
  • cascadelake โ€” ๐Ÿ’– Intel Cascadelake CPU with 64-bit extensions, MOVBE, MMX, SSE, SSE2, SSE3, SSSE3, SSE4.1, SSE4.2, POPCNT, PKU, AVX, AVX2, AES, PCLMUL, FSGSBASE, RDRND, FMA, BMI, BMI2, F16C, RDSEED, ADCX, PREFETCHW, CLFLUSHOPT, XSAVEC, XSAVES, AVX512F, CLWB, AVX512VL, AVX512BW, AVX512DQ, AVX512CD and AVX512VNNI instruction set support. ๐ŸŽ€
  • cooperlake โ€” ๐Ÿงš Intel cooperlake CPU with 64-bit extensions, MOVBE, MMX, SSE, SSE2, SSE3, SSSE3, SSE4.1, SSE4.2, POPCNT, PKU, AVX, AVX2, AES, PCLMUL, FSGSBASE, RDRND, FMA, BMI, BMI2, F16C, RDSEED, ADCX, PREFETCHW, CLFLUSHOPT, XSAVEC, XSAVES, AVX512F, CLWB, AVX512VL, AVX512BW, AVX512DQ, AVX512CD, AVX512VNNI and AVX512BF16 instruction set support. ๐Ÿ’œ
  • tigerlake โ€” ๐Ÿ‘‘ Intel Tigerlake CPU with 64-bit extensions, MOVBE, MMX, SSE, SSE2, SSE3, SSSE3, SSE4.1, SSE4.2, POPCNT, PKU, AVX, AVX2, AES, PCLMUL, FSGSBASE, RDRND, FMA, BMI, BMI2, F16C, RDSEED, ADCX, PREFETCHW, CLFLUSHOPT, XSAVEC, XSAVES, AVX512F, AVX512VL, AVX512BW, AVX512DQ, AVX512CD, AVX512VBMI, AVX512IFMA, SHA, CLWB, UMIP, RDPID, GFNI, AVX512VBMI2, AVX512VPOPCNTDQ, AVX512BITALG, AVX512VNNI, VPCLMULQDQ, VAES, PCONFIG, WBNOINVD, MOVDIRI, MOVDIR64B, AVX512VP2INTERSECT and KEYLOCKER instruction set support. ๐Ÿ”ฅ
  • k6 โ€” ๐ŸŒธ AMD K6 CPU with MMX instruction set support. Vintage, but iconic. ๐Ÿ™ˆ
  • k6-2, k6-3 โ€” ๐Ÿ’… Improved versions of AMD K6 CPU with MMX and 3DNow! instruction set support. โœจ
  • athlon, athlon-tbird โ€” ๐Ÿฆ‹ AMD Athlon CPU with MMX, 3dNOW!, enhanced 3DNow! and SSE prefetch instructions support. ๐Ÿ’–
  • athlon-4, athlon-xp, athlon-mp โ€” ๐Ÿ”ฅ Improved AMD Athlon CPU with MMX, 3DNow!, enhanced 3DNow! and full SSE instruction set support. ๐Ÿ‘‘
  • 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.) ๐Ÿ“
  • k8-sse3, opteron-sse3, athlon64-sse3 โ€” ๐ŸŽ€ Improved versions of AMD K8 cores with SSE3 instruction set support. ๐Ÿ’œ
  • amdfam10, barcelona โ€” ๐Ÿงš CPUs based on AMD Family 10h cores with x86-64 instruction set support. (This supersets MMX, SSE, SSE2, SSE3, SSE4A, 3DNow!, enhanced 3DNow!, ABM and 64-bit instruction set extensions.) ๐Ÿซถ
  • bdver1 โ€” โญ CPUs based on AMD Family 15h cores with x86-64 instruction set support. (This supersets FMA4, AVX, XOP, LWP, AES, 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.) โœจ
  • 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.) ๐Ÿ’–
  • 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.) ๐Ÿงš
  • 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. ๐ŸŒธ
  • winchip-c6 โ€” ๐Ÿ™ˆ IDT WinChip C6 CPU, dealt in same way as i486 with additional MMX instruction set support. ๐Ÿ“
  • winchip2 โ€” ๐Ÿซถ IDT WinChip 2 CPU, dealt in same way as i486 with additional MMX and 3DNow! instruction set support. โœจ
  • c3: VIA C3 chip with MMX and 3DNow! support ๐Ÿ’– (ngl no scheduling is implemented for this one)
  • c3-2: VIA C3-2 (Nehemiah/C5XL) with MMX and SSE ๐ŸŒธ (no scheduling is implemented here either)
  • c7: VIA C7 (Esther) with MMX, SSE, SSE2 and SSE3 โœจ (no scheduling implemented, bestie)
  • samuel-2: VIA Eden Samuel 2 with MMX and 3DNow! ๐Ÿฆ‹ (no scheduling is implemented for this chip)
  • nehemiah: VIA Eden Nehemiah with MMX and SSE ๐ŸŽ€ (no scheduling is implemented for this chip)
  • esther: VIA Eden Esther with MMX, SSE, SSE2 and SSE3 ๐Ÿ’… (no scheduling is implemented for this chip)
  • eden-x2: VIA Eden X2 with x86-64, MMX, SSE, SSE2 and SSE3 ๐Ÿงš (no scheduling is implemented for this chip)
  • eden-x4: VIA Eden X4 with x86-64, MMX, SSE, SSE2, SSE3, SSSE3, SSE4.1, SSE4.2, AVX and AVX2 ๐Ÿ‘‘ (no scheduling is implemented for this chip, it's giving a lot)
  • nano: the generic VIA Nano with x86-64, MMX, SSE, SSE2, SSE3 and SSSE3 ๐ŸŒˆ (no scheduling is implemented for this chip)
  • nano-1000: VIA Nano 1xxx with x86-64, MMX, SSE, SSE2, SSE3 and SSSE3 ๐Ÿ“ (no scheduling is implemented for this chip)
  • nano-2000: VIA Nano 2xxx with x86-64, MMX, SSE, SSE2, SSE3 and SSSE3 โญ (no scheduling is implemented for this chip)
  • nano-3000: VIA Nano 3xxx with x86-64, MMX, SSE, SSE2, SSE3, SSSE3 and SSE4.1 ๐Ÿ”ฅ (no scheduling is implemented for this chip)
  • nano-x2: VIA Nano Dual Core with x86-64, MMX, SSE, SSE2, SSE3, SSSE3 and SSE4.1 ๐Ÿซถ (no scheduling is implemented for this chip)
  • nano-x4: VIA Nano Quad Core with x86-64, MMX, SSE, SSE2, SSE3, SSSE3 and SSE4.1 ๐Ÿ’œ (no scheduling is implemented for this chip)
  • geode: AMD Geode embedded processor with MMX and 3DNow! ๐ŸŒธ

โœจ -mtune=cpu-type โœจ

Okay so -mtune=cpu-type tells GCC to tune everything that can be tuned 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 generate any code that can't run on the default machine type, unless you also use a -march=cpu-type option. For example, if GCC is configured for i686-pc-linux-gnu, then -mtune=pentium4 generates code tuned for Pentium 4 that still runs on i686 machines ๐Ÿ’–.

The choices for cpu-type are the same as for -march. On top of that, -mtune has 2 extra choices, and they're iconic ๐Ÿ‘‘:

  • generic โ€” produces code optimized for the most common IA32/AMD64/EM64T processors ๐ŸŒˆ. If you know the CPU your code will run on, use the matching -mtune or -march option instead of -mtune=generic. But if you have no idea what CPU your users will have, this is the one to use ๐Ÿซถ.

As new processors get deployed in the marketplace, the behavior of this option will change. So if you upgrade to a newer version of GCC, the code generation controlled by this option will change to match whatever processors are most common when that GCC version gets released ๐Ÿฆ‹.

There is no -march=generic option, because -march indicates the instruction set the compiler can use, and there's no generic instruction set that applies to all processors. -mtune, on the other hand, indicates the processor (or, in this case, the collection of processors) the code is optimized for โœจ.

  • intel โ€” produces code optimized for the most current Intel processors, which for this version of GCC are Haswell and Silvermont ๐Ÿ’…. If you know the CPU your code will run on, use the matching -mtune or -march option instead of -mtune=intel. But if you want your application to perform better on both Haswell and Silvermont, this is your option ๐Ÿ”ฅ.

As new Intel processors get deployed, the behavior of this option will change. So if you upgrade to a newer GCC, the code generation controlled by this option will reflect the most current Intel processors at the time that version of GCC is released ๐ŸŒธ.

There is no -march=intel option, because -march indicates the instruction set the compiler can use, and there's no common instruction set that applies to all processors. -mtune indicates the processor (or collection of processors) the code is optimized for, which is the vibe here ๐Ÿ’œ.

โœจ -mcpu=cpu-type โœจ

This is a deprecated synonym for -mtune. Bestie, just use -mtune instead ๐Ÿ™ˆ.

โœจ -mfpmath=unit โœจ

This option generates floating-point arithmetic for the selected unit. The choices for unit are:

  • 387 โ€” uses the standard 387 floating-point coprocessor, which is on the majority of chips and emulated otherwise ๐Ÿงš. Code compiled this way runs almost everywhere. The temporary results are computed in 80-bit precision instead of the precision set by the type, so you can get slightly different results than most other chips. See -ffloat-store for a more detailed description ๐ŸŽ€.

This is the default choice for non-Darwin x86-32 targets ๐Ÿ‘‘.

  • sse โ€” uses the scalar floating-point instructions from the SSE instruction set ๐Ÿ’–. This set is supported by Pentium III and newer chips, and on the AMD side by Athlon-4, Athlon XP and Athlon MP chips ๐Ÿฆ‹. The earlier version of SSE only supports single-precision arithmetic, so double and extended-precision arithmetic are still done with 387 ๐Ÿซถ. A later version, which only shows up in Pentium 4 and AMD x86-64 chips, supports double-precision arithmetic too โœจ.

For the x86-32 compiler, you must use -march=cpu-type, -msse or -msse2 switches to enable the SSE extensions and make this option work ๐ŸŒˆ. For the x86-64 compiler, these extensions are enabled by default ๐Ÿ“.

The resulting code should be considerably faster in most cases and avoid the numerical instability problems of 387 code. But it may break some existing code that expects temporaries to be 80 bits ๐Ÿ™ˆ.

This is the default choice for the x86-64 compiler, for Darwin x86-32 targets, and for x86-32 targets with the SSE2 instruction set when -ffast-math is enabled ๐Ÿ’….

  • sse,387, sse+387, both โ€” attempts to use both instruction sets at once ๐Ÿ”ฅ. This effectively doubles the number of available registers, and on chips with separate execution units for 387 and SSE, it doubles the execution resources too โญ. Use this option with care, because it's still experimental. The GCC register allocator doesn't model separate functional units well, which leads to unstable performance ๐Ÿ’€.

โœจ -masm=dialect โœจ

This outputs assembly instructions using the selected dialect, and it also affects which dialect gets used for basic asm and extended asm ๐Ÿงš. The supported choices, in dialect order, are att or intel. The default is att. Darwin does not support intel ๐Ÿ“.

โœจ -mieee-fp / -mno-ieee-fp โœจ

These control whether or not the compiler uses IEEE floating-point comparisons ๐ŸŒธ. IEEE comparisons correctly handle the case where the result of a comparison is unordered ๐Ÿ’œ.

โœจ -m80387 / -mhard-float โœจ

This generates output containing 80387 instructions for floating point ๐ŸŽ€.

โœจ -mno-80387 / -msoft-float โœจ

This generates output containing library calls for floating point instead ๐Ÿฆ‹.

Warning: the requisite libraries are not part of GCC ๐Ÿ˜ญ. Normally the facilities of the machine's usual C compiler get used, but that can't be done directly in cross-compilation. You have to make your own arrangements to provide suitable library functions for cross-compilation, no shortcuts ๐Ÿ’€.

On machines where a function returns floating-point results in the 80387 register stack, some floating-point opcodes may still be emitted even if -msoft-float is used ๐Ÿ™ˆ.

โœจ -mno-fp-ret-in-387 โœจ

This stops the compiler from using 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 ๐Ÿงš.

-mno-fp-ret-in-387 instead makes those values get returned in ordinary CPU registers ๐Ÿซถ.

โœจ -mno-fancy-math-387 โœจ

Some 387 emulators don't support the sin, cos and sqrt instructions for the 387 ๐Ÿ˜ญ. Specify this option to avoid generating those instructions ๐Ÿ’….

This option gets overridden when -march indicates that the target CPU always has an FPU, so the instruction doesn't need emulating โœจ. These instructions also aren't generated unless you use the -funsafe-math-optimizations switch too โญ.

โœจ -malign-double / -mno-align-double โœจ

These control whether GCC aligns double, long double, and long long variables on a two-word boundary or a one-word boundary ๐Ÿ‘‘. Aligning double variables on a two-word boundary produces code that runs somewhat faster on a Pentium, at the expense of more memory ๐Ÿ“.

On x86-64, -malign-double is enabled by default ๐Ÿฆ‹.

Warning: if you use the -malign-double switch, structures containing the above types are aligned differently than the published application binary interface specifications for x86-32. They are not binary compatible with structures in code compiled without that switch ๐Ÿ™ˆ๐Ÿ’€.

โœจ -m96bit-long-double / -m128bit-long-double โœจ

These switches control the size of the long double type ๐Ÿ’œ. The x86-32 application binary interface specifies the size as 96 bits, so -m96bit-long-double is the default in 32-bit mode ๐ŸŽ€.

Okay so modern chips (Pentium and newer) really want long double lined up on an 8- or 16-byte boundary ๐Ÿซถ but inside arrays and structs that follow the ABI, that's just not happening ๐Ÿ˜ญ. So -m128bit-long-double pads each long double with an extra 32-bit zero to get it onto a 16-byte boundary โœจ.

On x86-64, -m128bit-long-double is the default, because that ABI says long double gets 16-byte alignment ๐Ÿ‘‘.

Ngl, neither of these flags gives you any extra precision past the x87 standard of 80 bits for a long double ๐Ÿ’…

Warning: if you override the default for your target ABI, you change the size of structures and arrays containing long double variables, and you also change the function calling convention for functions that take long double. That means the code isn't binary-compatible with code compiled without that switch ๐Ÿ’€
  • -mlong-double-64, -mlong-double-80, -mlong-double-128 โ€” these three control how big the long double type is ๐Ÿ“. -mlong-double-64 makes it equivalent to double (and it's the default for the 32-bit Bionic C library ๐ŸŒธ). -mlong-double-128 makes it equivalent to __float128 (and that's the default for the 64-bit Bionic C library ๐Ÿฆ‹).
Warning: if you override the default for your target ABI, you change the size of structures and arrays containing long double variables, and you also change the function calling convention for functions that take long double. That means the code isn't binary-compatible with code compiled without that switch ๐Ÿ’€
  • -malign-data=type โ€” this one decides how GCC aligns variables ๐Ÿงฉ. The supported values for type are compat, which uses the increased alignment that's compatible with GCC 4.8 and earlier; abi, which uses the alignment value from the psABI; and cacheline, which uses increased alignment to match the cache line size. compat is the default, so it's the main character unless you say otherwise ๐Ÿ‘‘.
  • -mlarge-data-threshold=threshold โ€” when -mcmodel=medium is on, data objects bigger than threshold get tossed into the large data section ๐Ÿ“ฆ. This value has to be the same across every object linked into the binary, and it defaults to 65535 ๐Ÿ”ข.
  • -mrtd โ€” this swaps in a different function-calling convention ๐Ÿ”„. Functions that take a fixed number of arguments return with the ret num instruction, which pops their arguments on the way out. That saves one instruction in the caller, since the caller doesn't have to pop them anymore โœจ.

You can make one specific function use this calling sequence with the function attribute stdcall. You can also override -mrtd for a function by using the function attribute cdecl ๐ŸŽ€.

Warning: this calling convention is incompatible with the one normally used on Unix, so you can't use it if you need to call libraries compiled with the Unix compiler ๐Ÿ™ˆ You must also provide function prototypes for every function that takes a variable number of arguments (including printf). If you don't, incorrect code gets generated for calls to those functions ๐Ÿ˜ญ On top of that, seriously incorrect code results if you call a function with too many arguments. Normally, extra arguments are harmlessly ignored, but not here ๐Ÿ’€
  • -mregparm=num โ€” this controls how many registers get used to pass integer arguments ๐Ÿง . By default, no registers are used for passing arguments, and at most 3 registers can be used. You can control this for one specific function with the function attribute regparm ๐Ÿฆ‹.
Warning: if you use this switch and num is nonzero, then you must build all modules with the same value, including any libraries. That includes the system libraries and startup modules ๐Ÿšจ
  • -msseregparm โ€” this uses SSE register passing conventions for float and double arguments and return values โšก. You can control this for a specific function with the function attribute sseregparm ๐Ÿ’œ.
Warning: if you use this switch, you must build all modules with the same value, including any libraries. That includes the system libraries and startup modules ๐Ÿšจ
  • -mvect8-ret-in-mem โ€” returns 8-byte vectors in memory instead of MMX registers ๐Ÿงบ. This is the default on VxWorks, so it matches the ABI of the Sun Studio compilers until version 12. Only use this option if you need to stay compatible with existing code made by those older compiler versions or older versions of GCC ๐Ÿ•ฐ๏ธ.
  • -mpc32, -mpc64, -mpc80 โ€” these set the 80387 floating-point precision to 32, 64 or 80 bits ๐ŸŽš๏ธ. With -mpc32, the significands of floating-point results get rounded to 24 bits (single precision). With -mpc64, they get rounded to 53 bits (double precision). With -mpc80, they get rounded to 64 bits (extended double precision), which is the default ๐Ÿ’….

When you use one of these, higher-precision floating-point operations aren't available to the programmer unless you set the FPU control word yourself ๐Ÿ”ง.

Setting the rounding to less than the default 80 bits can speed some programs up by 2% or more ๐ŸŽ๏ธ. But heads up: some math libraries assume extended-precision (80-bit) floating-point operations are on by default. Routines in those libraries could lose a lot of accuracy, typically through so-called "catastrophic cancellation," when this option sets the precision to less than extended precision ๐Ÿ˜ฑ.

  • -mstackrealign โ€” this realigns the stack at entry ๐Ÿชž. On x86, it generates an alternate prologue and epilogue that realigns the run-time stack if it's needed. That lets legacy code that keeps 4-byte stack alignment play nicely with modern code that keeps 16-byte stack alignment for SSE compatibility ๐Ÿซถ. See also the attribute force_align_arg_pointer, which works on individual functions โœจ.
  • -mpreferred-stack-boundary=num โ€” this tries to keep the stack boundary aligned to a 2 raised to num byte boundary ๐Ÿ“. If you don't specify -mpreferred-stack-boundary, the default is 4, which is 16 bytes or 128 bits ๐Ÿ’–.
Warning: when you generate 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. But the x86-64 ABI requires 16-byte stack alignment, so this is ABI incompatible ๐Ÿ™…โ€โ™€๏ธ It's only meant for a controlled environment where stack space is a seriously important limitation. This option leads to wrong code when functions compiled with 16-byte stack alignment (like functions from a standard library) get called with a misaligned stack. In that case, SSE instructions may cause 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 โ€” this tells GCC to assume 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 gets used instead.

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 some serious run-time performance penalties ๐Ÿข. On Pentium III, the Streaming SIMD Extension (SSE) data type __m128 may not work properly if it isn't 16-byte aligned ๐Ÿ™ˆ.

To make sure these values are aligned properly on the stack, the stack boundary has to be as aligned as whatever value needs the most alignment on the stack. Also, every function 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 which 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 ๐Ÿงš.

  • The big ISA squad โ€” these switches enable the use of a whole crew of instructions ๐ŸŒˆ. Here's the full list, all of them, no skipping:
-mmmx
-msse
-msse2
-msse3
-mssse3
-msse4
-msse4a
-msse4.1
-msse4.2
-mavx
-mavx2
-mavx512f
-mavx512pf
-mavx512er
-mavx512cd
-mavx512vl
-mavx512bw
-mavx512dq
-mavx512ifma
-mavx512vbmi
-msha
-maes
-mpclmul
-mclflushopt
-mclwb
-mfsgsbase
-mptwrite
-mrdrnd
-mf16c
-mfma
-mpconfig
-mwbnoinvd
-mfma4
-mprfchw
-mrdpid
-mprefetchwt1
-mrdseed
-msgx
-mxop
-mlwp
-m3dnow
-m3dnowa
-mpopcnt
-mabm
-madx
-mbmi
-mbmi2
-mlzcnt
-mfxsr
-mxsave
-mxsaveopt
-mxsavec
-mxsaves
-mrtm
-mhle
-mtbm
-mmwaitx
-mclzero
-mpku
-mavx512vbmi2
-mavx512bf16
-mgfni
-mvaes
-mwaitpkg
-mvpclmulqdq
-mavx512bitalg
-mmovdiri
-mmovdir64b
-menqcmd
-mavx512vpopcntdq
-mavx512vp2intersect
-mavx5124fmaps
-mavx512vnni
-mavx5124vnniw
-mcldemote

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, or CLDEMOTE extended instruction sets. Each one has a matching -mno- option to switch off those instructions ๐Ÿ™…โ€โ™€๏ธ

These extensions also show up as built-in functions! Check out x86 Built-in Functions for the details on which functions get enabled and disabled by these switches ๐Ÿงš๐Ÿ’œ

Okay so if you want SSE/SSE2 instructions generated automatically from floating-point code (instead of the 387 ones), go check out -mfpmath=sse ๐Ÿฆ‹

ngl GCC kinda depresses SSEx instructions ๐Ÿ˜ญ when -mavx is on. Instead, it spits out brand-new AVX instructions, or AVX equivalents for all the SSEx instructions when needed ๐Ÿ’…

These options let GCC use these extended instructions in the generated code, even without -mfpmath=sse โœจ Bestie, heads up: apps that do run-time CPU detection need to compile separate files for each supported architecture, using the right flags ๐Ÿซถ And the file with the CPU detection code specifically should be compiled without these options ๐Ÿ™ˆ

  • -mdump-tune-features โ€” GCC dumps the names of the x86 performance tuning features and their default settings ๐Ÿ“‹ You can use those names in -mtune-ctrl=feature-list.
  • -mtune-ctrl=feature-list โ€” fine-grain control over x86 code generation features ๐ŸŽ›๏ธ feature-list is a comma-separated list of feature names. See also -mdump-tune-features. A feature gets turned on if it isn't preceded by ^, and turned off if it is. This one is really meant for GCC developers ๐Ÿง‘โ€๐Ÿ’ป
โš ๏ธ Bestie, be careful! Using -mtune-ctrl=feature-list may lead to code paths that aren't covered by testing, and it can potentially result in compiler ICEs or runtime errors ๐Ÿ’€
  • -mno-default โ€” turns off all tunable features ๐Ÿ™… See also -mtune-ctrl=feature-list and -mdump-tune-features.
  • -mcld โ€” GCC emits a cld instruction in the prologue of functions that use string instructions ๐Ÿงน String instructions depend on the DF flag to pick autoincrement or autodecrement mode. The ABI says DF gets cleared on function entry, but some operating systems don't clear it in their exception dispatchers ๐Ÿ˜ฌ So the exception handler can be invoked with DF set, which leads to the wrong direction mode when string instructions are used. This option can be enabled by default on 32-bit x86 targets by configuring GCC with the --enable-cld configure option. Generation of cld instructions can be suppressed with the -mno-cld compiler option in this case.
  • -mvzeroupper โ€” emits a vzeroupper instruction before control flow leaves the function ๐Ÿงผ This minimizes the AVX to SSE transition penalty, and also removes unnecessary zeroupper intrinsics.
  • -mprefer-avx128 โ€” uses 128-bit AVX instructions instead of 256-bit AVX instructions in the auto-vectorizer ๐Ÿ“
  • -mprefer-vector-width=opt โ€” uses opt-bit vector width in instructions instead of the default on the selected platform ๐Ÿ“
    • none โ€” no extra limits on GCC beyond what the selected platform already defines
    • 128 โ€” prefer 128-bit vector width
    • 256 โ€” prefer 256-bit vector width
    • 512 โ€” prefer 512-bit vector width
  • -mcx16 โ€” enables CMPXCHG16B instructions in 64-bit code ๐Ÿ”’ These do compare-and-exchange operations on 16-byte aligned 128-bit objects, which is super useful for atomic updates of data structures bigger than one machine word ๐Ÿ’œ The compiler uses this instruction to implement __sync Builtins. For __atomic Builtins operating on 128-bit integers, though, a library call is always used.
  • -msahf โ€” enables generation of SAHF instructions in 64-bit code ๐Ÿง  Early Intel Pentium 4 CPUs with Intel 64 support, before the Pentium 4 G1 step in December 2005, lacked the LAHF and SAHF instructions that AMD64 supports. These are load and store instructions, respectively, for certain status flags. In 64-bit mode, 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 the shadow stack built-in functions from x86 Control-flow Enforcement Technology (CET) ๐Ÿ›ก๏ธ
  • -mcrc32 โ€” makes the built-in functions __builtin_ia32_crc32qi, __builtin_ia32_crc32hi, __builtin_ia32_crc32si and __builtin_ia32_crc32di generate the crc32 machine instruction ๐Ÿงฎ
  • -mrecip โ€” enables use of RCPSS and RSQRTSS instructions (and their vectorized variants RCPPS and RSQRTPS) with an additional Newton-Raphson step to increase precision, instead of DIVSS and SQRTSS (and their vectorized variants) for single-precision floating-point arguments ๐ŸŽฏ These instructions are only generated when -funsafe-math-optimizations is enabled together with -ffinite-math-only and -fno-trapping-math. Note that while the throughput of the sequence is higher than the throughput of the non-reciprocal instruction, the precision of the sequence can be decreased by up to 2 ulp (i.e. the inverse of 1.0 equals 0.99999994).

Note that GCC implements 1.0f/sqrtf(x) in terms of RSQRTSS (or RSQRTPS) already with -ffast-math (or the above option combination), and doesn't need -mrecip.

Also note that GCC emits the above sequence with an additional Newton-Raphson step for vectorized single-float division and vectorized sqrtf(x) already with -ffast-math (or the above option combination), and doesn't need -mrecip.


  • -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 the option:
    • all โ€” enable all estimate instructions
    • default โ€” enable the default instructions, equivalent to -mrecip
    • none โ€” disable all estimate instructions, equivalent to -mno-recip
    • div โ€” enable the approximation for scalar division
    • vec-div โ€” enable the approximation for vectorized division
    • sqrt โ€” enable the approximation for scalar square root
    • vec-sqrt โ€” enable the approximation for vectorized square root

So, for example, -mrecip=all,!sqrt enables all of the reciprocal approximations, except for square root โœจ

  • -mveclibabi=type โ€” specifies the ABI type to use for vectorizing intrinsics using an external library ๐Ÿ“š Supported values for type are svml 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 must be specified at link time.

GCC currently emits calls to vmldExp2, vmldLn2, vmldLog102, vmldPow2, vmldTanh2, vmldTan2, vmldAtan2, vmldAtanh2, vmldCbrt2, vmldSinh2, vmldSin2, vmldAsinh2, vmldAsin2, vmldCosh2, vmldCos2, vmldAcosh2, vmldAcos2, vmlsExp4, vmlsLn4, vmlsLog104, vmlsPow4, vmlsTanh4, vmlsTan4, vmlsAtan4, vmlsAtanh4, vmlsCbrt4, vmlsSinh4, vmlsSin4, vmlsAsinh4, vmlsAsin4, vmlsCosh4, vmlsCos4, vmlsAcosh4 and vmlsAcos4 for the corresponding function type when -mveclibabi=svml is used, and __vrd2_sin, __vrd2_cos, __vrd2_exp, __vrd2_log, __vrd2_log2, __vrd2_log10, __vrs4_sinf, __vrs4_cosf, __vrs4_expf, __vrs4_logf, __vrs4_log2f, __vrs4_log10f and __vrs4_powf for the corresponding function type when -mveclibabi=acml is used.

  • -mabi=name โ€” 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 useful with Intel Processor Trace, where it generates more precise timing information for function calls.
  • -mmanual-endbr โ€” inserts an ENDBR instruction at function entry only via the cf_check function attribute ๐Ÿ” This is useful when used with the option -fcf-protection=branch to control ENDBR insertion at the function entry.
  • -mcall-ms2sysv-xlogues โ€” due to differences in 64-bit ABIs, any Microsoft ABI function that calls a System V ABI function must consider RSI, RDI and XMM6-15 as clobbered (aka overwritten, bestie) ๐Ÿง  By default, the code for saving and restoring these registers is emitted inline, which makes the prologues and epilogues pretty lengthy. Using -mcall-ms2sysv-xlogues emits prologues and epilogues that use stubs in the static portion of libgcc to do these saves and restores. That reduces function size at the cost of a few extra instructions โœจ
  • -mtls-dialect=type โ€” generates code to access thread-local storage using the gnu or gnu2 conventions ๐Ÿงต gnu is the conservative default. gnu2 is more efficient, but it may add compile- and run-time requirements that cannot be satisfied on all systems โš ๏ธ
  • -mpush-args, -mno-push-args โ€” uses PUSH operations to store outgoing parameters ๐Ÿ“ฅ This method is shorter and usually equally fast as the method using SUB/MOV operations, and it is enabled by default. In some cases, disabling it may improve performance because of improved scheduling and reduced dependencies.
  • -maccumulate-outgoing-args โ€” if enabled, the maximum amount of space required for outgoing arguments is computed in the function prologue ๐Ÿ—๏ธ This is faster on most modern CPUs because of reduced dependencies, improved scheduling, and reduced stack usage when the preferred stack boundary is not equal to 2. The drawback is a notable increase in code size. This switch implies -mno-push-args.
  • -mthreads โ€” supports thread-safe exception handling on MinGW ๐Ÿงต Programs that rely on thread-safe exception handling must compile and link all code with the -mthreads option. When compiling, -mthreads defines -D_MT. When linking, it links in a special thread helper library, -lmingwthrd, which cleans up per-thread exception-handling data.
  • -mms-bitfields, -mno-ms-bitfields โ€” enables or disables bit-field layout compatible with the native Microsoft Windows compiler ๐ŸชŸ

okay so if you slap "packed" on a struct, or use bit-fields, the Microsoft ABI might lay that struct out totally differently from how GCC does it ๐Ÿ’€ this is lowkey a big deal, especially when you're moving packed data between functions compiled with GCC and the native Microsoft compiler (through a function call or as data in a file), because you may need to access either format ๐Ÿซถ

This option is enabled by default for Microsoft Windows targets ๐ŸชŸ but you can control it locally with variable or type attributes. For the full tea, check out x86 Variable Attributes and x86 Type Attributes ๐ŸŽ€

The Microsoft struct layout algorithm is pretty simple โœจ except for bit-field packing ๐Ÿ™ˆ Here's how it decides the padding and alignment of struct members, plus whether a bit-field can straddle a storage-unit boundary:

  1. Structure members are stored in the order they're declared ๐Ÿ“‹ the first member sits at the lowest memory address and the last member sits at the highest ๐Ÿงš
  2. Every data object has an alignment requirement. For everything except structs, unions, and arrays, it's whichever is less: the size of the object, or the current packing size (set with the "aligned" attribute or the "pack" pragma). For structs, unions, and arrays, it's the largest alignment requirement of any of its members. Every object gets an offset so that:
offset % alignment_requirement == 0
  1. Adjacent bit-fields get packed into the same 1-, 2-, or 4-byte allocation unit if their integral types are the same size, AND the next bit-field fits in the current allocation unit without crossing the boundary imposed by the bit-fields' common alignment requirements ๐Ÿ’…

MSVC interprets zero-length bit-fields in the following ways ๐Ÿคฏ

  1. If a zero-length bit-field is inserted between two bit-fields that would normally be coalesced, those bit-fields are not coalesced anymore. 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 zero-length bit-field's alignment 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 instead of offset 1, so the size of "t2" is 4 ๐Ÿซ  For "t3", the zero-length bit-field doesn't affect the alignment of "bar" or, as a result, the size of the struct.

Taking this into account, it's important to note the following:

  1. If a zero-length bit-field follows a normal bit-field, the type of that zero-length bit-field may affect the alignment of the whole structure. 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 can still affect the alignment of the structure:
struct
 {
   char foo : 6;
   long : 0;
 } t4;

Here, "t4" takes up 4 bytes.

  1. Zero-length bit-fields following non-bit-field members are ignored:
struct
 {
   char foo;
   long : 0;
   char bar;
 } t5;

Here, "t5" takes up 2 bytes. Ignored, bestie ๐Ÿ™„

  • -mno-align-stringops โ€” don't align the destination of inlined string operations ๐ŸŒธ this makes code smaller and can speed things up if the destination is already aligned but GCC doesn't know that.
  • -minline-all-stringops โ€” by default GCC only inlines string operations when the destination is known to be aligned to at least a 4-byte boundary. This turns on way more inlining (bigger code, but it may boost short memcpy and memset calls ๐Ÿš€). It also enables inline expansion of "strlen" for all pointer alignments.
  • -minline-stringops-dynamically โ€” for string operations of unknown size, it adds run-time checks: inline code for small blocks, and a library call for large ones ๐Ÿง 
  • -mstringop-strategy=alg โ€” overrides GCC's internal heuristic for which algorithm to use when inlining string operations. The allowed values for alg are:
    • rep_byte, rep_4byte, rep_8byte โ€” expand using the i386 "rep" prefix 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 heuristic that decides whether __builtin_memcpy gets inlined, and which inline algorithm to use when the expected copy size is known. strategy is a comma-separated list of alg:max_size:dest_align triplets. alg is one of the values from -mstringop-strategy, and max_size is the biggest byte size that inline algorithm alg is allowed for. The last triplet must have max_size set to -1. The max_size values in the list have to be 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 โ€” same vibe as -mmemcpy-strategy=, except it 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 too, but it 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 that's 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 holds pointers to each profiling call. This is super useful for automatically patching (and patching out) calls ๐Ÿฉน
  • -mnop-mcount, -mno-nop-mcount โ€” if profiling is active (-pg), generate the calls to the profiling functions as NOPs. This is handy when they should get patched in later, dynamically. This is likely only useful together with -mrecord-mcount ๐Ÿงฉ
  • -minstrument-return=type โ€” instruments function exit in -pg -mfentry instrumented functions by calling the specified function. This only instruments true returns ending with ret, not sibling calls ending with a jump. Valid types are none (don't instrument), call (generate a call to __return__), or nop5 (generate a 5 byte nop) ๐Ÿ”š
  • -mrecord-return, -mno-record-return โ€” generates a __return_loc section pointing to all the return instrumentation code ๐Ÿ“
  • -mfentry-name=name โ€” sets the name of the __fentry__ symbol that gets called at function entry for -pg -mfentry functions ๐Ÿท๏ธ
  • -mfentry-section=name โ€” sets the name of the section where -mrecord-mcount calls get recorded (default __mcount_loc) ๐Ÿ“‚
  • -mskip-rax-setup, -mno-skip-rax-setup โ€” when generating code for the x86-64 architecture with SSE extensions disabled, -mskip-rax-setup can skip setting up the RAX register when no variable arguments are passed in vector registers ๐Ÿฆ‹
โš ๏ธ Warning: the RAX register is used to avoid unnecessarily saving vector registers on the stack when passing variable arguments, so the impacts of this option are that callees may waste some stack space, misbehave, or jump to a random location. GCC 4.4 or newer doesn't have those issues, regardless of the RAX register value.
  • -m8bit-idiv, -mno-8bit-idiv โ€” on some processors, like Intel Atom, 8-bit unsigned integer divide is way faster than 32-bit/64-bit integer divide ๐ŸŽ๏ธ This option generates a run-time check. If both the dividend and the divisor are within the range of 0 to 255, 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, which is the default) ๐Ÿ›ก๏ธ This option only has an effect when -fstack-protector or -fstack-protector-all is specified.

Okay so with that second route, the options -mstack-protector-guard-reg=reg and -mstack-protector-guard-offset=offset get to decide which segment register (%fs or %gs) is the base for reading the canary ๐Ÿงš, and how far from that base to read. If you don't pick anything, you get whatever the relevant ABI says. Iconic. ๐Ÿ’…

  • -mgeneral-regs-only โ€” Only use the general-purpose registers. The compiler is banned from touching floating-point, vector, mask, and bound registers, so no sneaky extras ๐Ÿฆ‹
  • -mindirect-branch=choice โ€” Converts indirect call and jump based on choice. The default is keep, which leaves indirect call and jump 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 also control this for one specific function with the function attribute "indirect_branch" ๐Ÿ’œ
๐Ÿšจ Heads up: -mcmodel=large is incompatible with -mindirect-branch=thunk and -mindirect-branch=thunk-extern, since the thunk function may not be reachable in the large code model.

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 return based on choice. The default is keep, which keeps function return unmodified ๐ŸŽ€ thunk converts function return to call and return thunk. thunk-inline converts it to an inlined call and return thunk. thunk-extern converts it to an external call and return thunk 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 ๐Ÿซถ

๐Ÿšจ Heads up: -mcmodel=large is incompatible with -mfunction-return=thunk and -mfunction-return=thunk-extern, since the thunk function may not be reachable in the large code model.
  • -mindirect-branch-register โ€” Forces indirect call and jump to go through a register ๐Ÿ”ฅ
  • -mharden-sls=choice โ€” Generates code that mitigates straight line speculation (SLS), based on 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 SLS hardening option ๐Ÿ‘‘
  • -mindirect-branch-cs-prefix โ€” Adds a CS prefix to call and jmp going to an indirect thunk, where the branch target is in the r8-r15 registers. This makes the call and jmp instructions 6 bytes long, so they can be 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.

Pick one of these to set the 16-bit, 32-bit, or 64-bit environment you're building for ๐Ÿ“

  • -m32 โ€” Sets int, long, and pointer types to 32 bits, and generates code that runs in 32-bit mode ๐Ÿ’–
  • -m64 โ€” Sets int to 32 bits and long and pointer types to 64 bits, and generates code for the x86-64 architecture ๐ŸŒŸ For Darwin only, -m64 also turns off the -fno-pic and -mdynamic-no-pic options ๐ŸŽ
  • -mx32 โ€” Sets int, long, and pointer types to 32 bits, and generates code for the x86-64 architecture ๐Ÿฆ„
  • -m16 โ€” Same as -m32, except it outputs the .code16gcc assembly directive at the beginning of the assembly output, so the binary can run in 16-bit mode ๐Ÿงธ
  • -miamcu โ€” Generates code that conforms to the Intel MCU psABI. It requires -m32 to be turned on ๐ŸŒท
  • -mno-red-zone โ€” Do not use a so-called "red zone" for x86-64 code. The red zone is mandated by the x86-64 ABI. 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 turns that red zone off ๐Ÿ™ˆ
  • -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, and 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, and it's the default address mode for 32-bit and x32 environments ๐Ÿฆ‹

โœจ x86 Windows Options โœจ

These additional options are available for Microsoft Windows targets ๐ŸชŸ

  • -mconsole โ€” Generates a console application by telling the linker to set the PE header subsystem type required for console applications. This option is available for Cygwin and MinGW targets, and it's enabled by default on those targets ๐Ÿ’ป
  • -mdll โ€” Available for Cygwin and MinGW targets. Generates a DLL, which is a dynamic link library, and enables selection of the required runtime startup object and entry point ๐Ÿงฉ
  • -mnop-fun-dllimport โ€” Available for Cygwin and MinGW targets. The "dllimport" attribute gets ignored ๐Ÿ™…โ€โ™€๏ธ
  • -mthread โ€” Available for MinGW targets. Uses MinGW-specific thread support ๐Ÿงต
  • -municode โ€” Available for MinGW-w64 targets. Predefines the "UNICODE" preprocessor macro and chooses Unicode-capable runtime startup code ๐ŸŒ
  • -mwin32 โ€” Available for Cygwin and MinGW targets. Sets the typical Microsoft Windows predefined macros in the pre-processor, but doesn't influence the choice of runtime library or startup code ๐Ÿช„
  • -mwindows โ€” Available for Cygwin and MinGW targets. Generates a GUI application by telling the linker to set the PE header subsystem type appropriately ๐ŸชŸโœจ
  • -fno-set-stack-executable โ€” Available for MinGW targets. The executable flag for the stack used by nested functions isn't set. This is necessary for binaries running in kernel mode of Microsoft Windows, since the User32 API (used to set executable privileges) isn't available there ๐Ÿšซ
  • -fwritable-relocated-rdata โ€” Available for MinGW and Cygwin targets. Relocated data in a read-only section gets put into the ".data" section. This is necessary for older runtimes that don't support modifying ".rdata" sections for pseudo-relocation ๐Ÿง
  • -mpe-aligned-commons โ€” Available for Cygwin and MinGW targets. Uses the GNU extension to the PE file format that permits correct alignment of COMMON variables 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 the 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 the 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 may be desirable when strict IEEE 754-compliant results are required, since the fused multiply add/subtract instructions don't round the intermediate result, which produces results with more bits of precision than the IEEE standard specifies. Disabling fused multiply add/subtract instructions 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 how literal pools get treated ๐ŸŽ€ The default is -mno-text-section-literals, which tucks literals into their own separate section in the output file ๐Ÿ“ฆ That means the literal pool can live in data RAM/ROM, and the linker can merge literal pools from separate object files to kill redundant literals and improve code size โœจ Flip it with -mtext-section-literals and the literals get interspersed right in the text section, so they sit as close as possible to their references ๐Ÿฆ‹ This might be necessary for large assembly files ๐Ÿ’… With that flag on, the literals for each function go right before that function ๐Ÿ’–
  • -mauto-litpools, -mno-auto-litpools โ€” 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 is the one that interleaves literals into the text section ๐Ÿงš The compiler doesn't produce explicit .literal directives and instead loads literals into registers with MOVI instructions rather than 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 automatically align instructions to reduce branch penalties, at the cost of some code density ๐Ÿซถ The assembler tries to widen density instructions to align branch targets and the instructions following call instructions ๐ŸŽฏ If there aren't enough preceding safe density instructions to align a target, no widening happens ๐Ÿ™ˆ The default is -mtarget-align. These options don't affect auto-aligned instructions like LOOP, which the assembler always aligns, either by widening density instructions or by inserting NOP instructions ๐Ÿ’œ
  • -mlongcalls, -mno-longcalls โ€” When this is enabled, GCC tells the assembler to translate direct calls into indirect calls, unless it can tell that the target of a direct call is in range of the call instruction ๐Ÿ˜ญ This translation usually happens for calls to functions in other source files ๐Ÿ“ Specifically, the assembler turns a direct CALL into an L32R followed by a CALLX ๐Ÿฆ‹ The default is -mno-longcalls. Use this option in programs where the call target might be out of range ๐ŸŒธ It's implemented in the assembler, not the compiler, so the assembly code GCC generates still shows direct call instructions. Look at the disassembled object code to see the actual instructions ๐Ÿ” Also, the assembler uses an indirect call for every cross-file call, not just the ones that really are out of range ๐Ÿ’€

๐ŸŒธ zSeries Options ๐ŸŒธ

These are listed under ๐Ÿงš

โœจ ENVIRONMENT โœจ

okay bestie, this is the part where GCC lets you sneak in environment variables to tweak how it behaves ๐Ÿ’… Some of them point it at directories or prefixes to hunt for files, and others just set the overall vibe of the compilation ๐ŸŒธ

Quick heads up: you can also tell GCC where to search with options like -B, -I and -L. Those win over environment variables, and environment variables in turn win over whatever GCC's configuration says ๐Ÿ‘‘


๐ŸŒ LANG, LC_CTYPE, LC_MESSAGES, LC_ALL

These four are all about localization, so GCC can handle different national conventions ๐ŸŒˆ GCC checks the LC_CTYPE and LC_MESSAGES locale categories if it's been configured to do so. You can set them to any value your installation supports. A typical one is en_GB.UTF-8, which is English from the UK encoded in UTF-8. It's giving British English ๐Ÿ‡ฌ๐Ÿ‡ง

  • LC_CTYPE โ€” this one handles character classification. GCC uses it to figure out where characters start and stop in a string. That matters for some multibyte encodings that have quote and escape characters which would otherwise be read as the end of a string or as an escape ๐Ÿ˜ญ
  • LC_MESSAGES โ€” this sets the language used in diagnostic messages ๐Ÿ’ฌ
  • LC_ALL โ€” if this is set, it overrides both LC_CTYPE and LC_MESSAGES. If it isn't, then LC_CTYPE and LC_MESSAGES default to whatever LANG says. If none of these are set at all, GCC falls back to traditional C English behavior ๐Ÿงš

๐Ÿ“ TMPDIR

If TMPDIR is set, it tells GCC which directory to use for temporary files ๐Ÿ—‚๏ธ GCC uses temp files to hold the output of one stage of compilation so the next stage can read it. For example, the output of the preprocessor is the input to the compiler proper ๐Ÿ”

๐Ÿ” GCC_COMPARE_DEBUG

Setting GCC_COMPARE_DEBUG is nearly the same as passing -fcompare-debug to the compiler driver. Check that option's docs for the full tea โ˜•

๐Ÿงญ GCC_EXEC_PREFIX

If GCC_EXEC_PREFIX is set, it gives a prefix to put in front of the names of the subprograms the compiler runs. No slash gets added when the prefix is joined with a subprogram name, so if you want one, end your prefix with a slash yourself ๐Ÿฆ‹

If GCC_EXEC_PREFIX isn't set, GCC tries to work out a sensible prefix based on the pathname it was invoked with ๐Ÿ•ต๏ธโ€โ™€๏ธ If it can't find the subprogram using the prefix you gave, it checks the usual places instead.

The default value is prefix/lib/gcc/, where prefix is the prefix of the installed compiler. Most of the time that's whatever "prefix" was set to when you ran the configure script ๐Ÿ› ๏ธ

Prefixes passed with -B beat this one. This prefix is also used to find linking files like crt0.o โœจ

Now for the unusual part ๐ŸŒˆ It also affects where GCC looks for header files. For each standard directory that normally starts with /usr/local/lib/gcc (more precisely, with the value of GCC_INCLUDE_DIR), GCC tries swapping that beginning out for your prefix to make an alternate directory name. So with -Bfoo/, GCC searches foo/bar just before it searches the standard /usr/local/lib/bar. If a standard directory starts with the configured prefix, the prefix gets replaced by GCC_EXEC_PREFIX when GCC looks for headers ๐ŸŽ€

๐Ÿงบ COMPILER_PATH

The value of COMPILER_PATH is a colon-separated list of directories, very much like PATH ๐Ÿงƒ If GCC can't find subprograms using GCC_EXEC_PREFIX, it tries these directories when searching for subprograms.

๐Ÿ”— LIBRARY_PATH

The value of LIBRARY_PATH is also a colon-separated list of directories, like PATH ๐Ÿ”— When GCC is configured as a native compiler, it tries these directories when hunting for special linker files, if it can't find them with GCC_EXEC_PREFIX. Linking with GCC also searches these directories for ordinary libraries used with the -l option, but anything specified with -L comes first ๐Ÿฅ‡

๐Ÿˆถ LANG (multibyte characters)

This is the second LANG moment, and it's about passing locale info to the compiler ๐Ÿ‡ฏ๐Ÿ‡ต One thing it controls is which character set gets used when character literals, string literals and comments are 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 ๐ŸŒธ


Some more environment variables affect the preprocessor ๐Ÿงšโ€โ™€๏ธ

๐Ÿ“š CPATH, C_INCLUDE_PATH, CPLUS_INCLUDE_PATH, OBJC_INCLUDE_PATH

Each of these holds a list of directories to look for header files in, separated by a special character, much like PATH ๐Ÿฆ‹ That special character, PATH_SEPARATOR, depends on the target and gets decided when GCC is built. On Microsoft Windows-based targets it's a semicolon, and on almost every other target it's a colon.

CPATH works like -I, but its directories get searched after any paths given with -I on the command line. This one is used no matter which language is being preprocessed ๐Ÿ’–

The other three only apply when preprocessing their particular language. Each one lists directories searched as if you'd used -isystem, 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 start or end of a path. For example, if CPATH is ":/special/include", that's the same as -I. -I/special/include ๐Ÿ™ˆ

๐Ÿ“œ DEPENDENCIES_OUTPUT

If this variable is set, its value says how to output dependencies for Make, based on the non-system header files the compiler processes. System header files get ignored in the dependency output ๐Ÿšซ

The value can be just a file name. In that case, the Make rules get written to that file, and the target name is guessed from the source file name. Or the value can look like file target, in which case the rules get written to file using target as the target name.

Basically, this variable is the same as combining -MM and -MF, with an optional -MT switch too ๐Ÿ’…

๐Ÿงพ SUNPRO_DEPENDENCIES

This one is the same as DEPENDENCIES_OUTPUT, except system header files are not ignored. So it implies -M rather than -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 stay reproducible ๐Ÿ”โœจ

The value has to be a UNIX timestamp, meaning the number of seconds (leap seconds excluded) since 01 Jan 1970 00:00:00, written in ASCII. It's the same as the output of date +%s on GNU/Linux and other systems that support the %s extension in date ๐Ÿงฎ

Pick a known timestamp, like the last modification time of the source or package, and let the build process set it ๐Ÿ› ๏ธ


๐Ÿ› BUGS

For instructions on reporting bugs, check out file:///usr/share/doc/gcc-10/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

gpl(7), gfdl(7), fsf-funding(7), cpp(1), gcov(1), as(1), ld(1), gdb(1), dbx(1) and the Info entries for gcc, cpp, as, ld, binutils and gdb ๐Ÿ“–

๐Ÿ‘ฉโ€๐Ÿ’ป AUTHOR

See the Info entry for gcc, or http://gcc.gnu.org/onlinedocs/gcc/Contributors.html, for the legends who contributed to GCC ๐Ÿ‘‘

Copyright (c) 1988-2020 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; with the Invariant Sections being "GNU General Public License" and "Funding Free Software", the Front-Cover texts being (a) (see below), and with the Back-Cover Texts being (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.

That's the whole page, bestie! ๐ŸŽ€๐Ÿ’– This one came from the gcc-10 build, dated 2023-07-07, and it's filed under GCC(1). Go compile something iconic ๐Ÿฆ‹โœจ

๐Ÿ“ฆ where this page comes from