GCC(1)

๐Ÿ“ฆ
version 14-20240412 ยท 5 versions
, in ubuntu noble

โœจ GCC(1) โœจ

Manual name: GNU ๐ŸŒˆ This is the GNU project's page for gcc, and it's honestly such a classic ๐Ÿ’…

โœจ NAME โœจ

Okay so the name is gcc, and it's the GNU project C and C++ compiler ๐Ÿ”ฅ

โœจ SYNOPSIS โœจ

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

Only the most useful options are listed up there ๐Ÿ‘€ Check below for the rest ๐Ÿฆ‹ And g++ accepts mostly the same options as gcc, so you're basically set ๐Ÿ’–

โœจ DESCRIPTION โœจ

When you invoke GCC, it normally does preprocessing, compilation, assembly, and linking, all in one go ๐Ÿงš The "overall options" let you stop that process at an intermediate stage. For example, -c says don't run the linker, so what you get back is object files from the assembler ๐Ÿ“

Other options get passed along to one or more stages. Some control the preprocessor, some control the compiler itself, and some control the assembler and linker. Most of those last ones aren't documented here, since you rarely need them ๐Ÿ˜ญ

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

The usual move is to run the executable called gcc. When you're cross-compiling, it's machine-gcc instead, and if you want one specific version, it's machine-gcc-version. 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 bundle single-letter options together. -dv is very different from -d -v, so don't try to be clever ๐Ÿ™ˆ

You can mix options and other arguments. For the most part, the order doesn't matter ๐Ÿซถ But 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. Also, where you put the -l option is 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 have both positive and negative forms, and the negative form of -ffoo is -fno-foo. This manual only documents one of the two forms, whichever one isn't the default ๐Ÿง 

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

Arguments to options that set a size threshold can be arbitrarily large decimal or hexadecimal integers, followed by a byte size suffix for a multiple of bytes. That includes kB and KiB for kilobyte and kibibyte, MB and MiB for megabyte and mebibyte, and GB and GiB for gigabyte and gigibyte, and so on ๐Ÿ’œ These get called byte-size in the rest of the text. If you want the full scoop on the binary and decimal byte size prefixes, check the NIST, IEC, and other relevant national and international standards ๐Ÿค“

โœจ OPTIONS โœจ

๐Ÿ’… Option Summary ๐Ÿ’…

Here's a quick glance at all the options, grouped by type ๐ŸŒˆ The explanations come in the sections that follow.

๐Ÿฆ‹ Overall Options

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

๐ŸŒธ C Language Options

-ansi  -std=standard  -aux-info filename -fno-asm -fno-builtin
-fno-builtin-function  -fcond-mismatch -ffreestanding  -fgimple
-fgnu-tm  -fgnu89-inline  -fhosted -flax-vector-conversions
-fms-extensions -foffload=arg  -foffload-options=arg -fopenacc
-fopenacc-dim=geom -fopenmp  -fopenmp-simd
-fopenmp-target-simd-clone[=device-type]
-fpermitted-flt-eval-methods=standard -fplan9-extensions
-fsigned-bitfields  -funsigned-bitfields -fsigned-char
-funsigned-char  -fstrict-flex-arrays[=n] -fsso-struct=endianness

๐Ÿ‘‘ C++ Language Options

-fabi-version=n  -fno-access-control -faligned-new=n
-fargs-in-order=n  -fchar8_t  -fcheck-new -fconstexpr-depth=n
-fconstexpr-cache-depth=n -fconstexpr-loop-limit=n
-fconstexpr-ops-limit=n -fno-elide-constructors
-fno-enforce-eh-specs -fno-gnu-keywords -fno-immediate-escalation
-fno-implicit-templates -fno-implicit-inline-templates
-fno-implement-inlines -fmodule-header[=kind] -fmodule-only
-fmodules-ts -fmodule-implicit-inline -fno-module-lazy
-fmodule-mapper=specification -fmodule-version-ignore
-fms-extensions -fnew-inheriting-ctors -fnew-ttp-matching
-fno-nonansi-builtins  -fnothrow-opt  -fno-operator-names
-fno-optional-diags -fno-pretty-templates -fno-rtti
-fsized-deallocation -ftemplate-backtrace-limit=n -ftemplate-depth=n
-fno-threadsafe-statics  -fuse-cxa-atexit -fno-weak  -nostdinc++
-fvisibility-inlines-hidden -fvisibility-ms-compat
-fext-numeric-literals -flang-info-include-translate[=header]
-flang-info-include-translate-not -flang-info-module-cmi[=module]
-stdlib=libstdc++,libc++ -Wabi-tag  -Wcatch-value  -Wcatch-value=n
-Wno-class-conversion  -Wclass-memaccess -Wcomma-subscript
-Wconditionally-supported -Wno-conversion-null
-Wctad-maybe-unsupported -Wctor-dtor-privacy  -Wdangling-reference
-Wno-delete-incomplete -Wdelete-non-virtual-dtor
-Wno-deprecated-array-compare -Wdeprecated-copy
-Wdeprecated-copy-dtor -Wno-deprecated-enum-enum-conversion
-Wno-deprecated-enum-float-conversion -Weffc++
-Wno-elaborated-enum-base -Wno-exceptions -Wextra-semi
-Wno-global-module -Wno-inaccessible-base
-Wno-inherited-variadic-ctor  -Wno-init-list-lifetime
-Winvalid-constexpr -Winvalid-imported-macros -Wno-invalid-offsetof
-Wno-literal-suffix -Wmismatched-new-delete -Wmismatched-tags
-Wmultiple-inheritance  -Wnamespaces  -Wnarrowing -Wnoexcept
-Wnoexcept-type  -Wnon-virtual-dtor -Wpessimizing-move
-Wno-placement-new  -Wplacement-new=n -Wrange-loop-construct
-Wredundant-move -Wredundant-tags -Wreorder  -Wregister
-Wstrict-null-sentinel  -Wno-subobject-linkage  -Wtemplates
-Wno-non-template-friend  -Wold-style-cast -Woverloaded-virtual
-Wno-pmf-conversions -Wself-move -Wsign-promo -Wsized-deallocation
-Wsuggest-final-methods -Wsuggest-final-types  -Wsuggest-override
-Wno-template-id-cdtor -Wno-terminate  -Wno-vexing-parse
-Wvirtual-inheritance -Wno-virtual-move-assign  -Wvolatile
-Wzero-as-null-pointer-constant

๐Ÿงš Objective-C and Objective-C++ Language Options

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

๐Ÿ’– Diagnostic Message Formatting Options

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

โœจ Warning Options โœจ

okay bestie, this is the whole gossip squad ๐Ÿ—ฃ๏ธ๐Ÿ’… every single warning option lives here, and I'm not cutting a single one ๐Ÿ˜ญ๐Ÿซถ

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

๐Ÿ”ฌ Static Analyzer Options ๐Ÿ”ฌ

the analyzer crew ๐Ÿ”๐Ÿฆ‹ here's the full roster, flags exactly as they appear, no skipping ๐Ÿ’œ

-fanalyzer -fanalyzer-call-summaries -fanalyzer-checker=name
-fno-analyzer-feasibility -fanalyzer-fine-grained
-fanalyzer-show-events-in-system-headers -fno-analyzer-state-merge
-fno-analyzer-state-purge -fno-analyzer-suppress-followups
-fanalyzer-transitivity -fno-analyzer-undo-inlining
-fanalyzer-verbose-edges -fanalyzer-verbose-state-changes
-fanalyzer-verbosity=level -fdump-analyzer -fdump-analyzer-callgraph
-fdump-analyzer-exploded-graph -fdump-analyzer-exploded-nodes
-fdump-analyzer-exploded-nodes-2 -fdump-analyzer-exploded-nodes-3
-fdump-analyzer-exploded-paths -fdump-analyzer-feasibility
-fdump-analyzer-infinite-loop -fdump-analyzer-json
-fdump-analyzer-state-purge -fdump-analyzer-stderr
-fdump-analyzer-supergraph -fdump-analyzer-untracked
-Wno-analyzer-double-fclose -Wno-analyzer-double-free
-Wno-analyzer-exposure-through-output-file
-Wno-analyzer-exposure-through-uninit-copy
-Wno-analyzer-fd-access-mode-mismatch -Wno-analyzer-fd-double-close
-Wno-analyzer-fd-leak -Wno-analyzer-fd-phase-mismatch
-Wno-analyzer-fd-type-mismatch -Wno-analyzer-fd-use-after-close
-Wno-analyzer-fd-use-without-check -Wno-analyzer-file-leak
-Wno-analyzer-free-of-non-heap -Wno-analyzer-imprecise-fp-arithmetic
-Wno-analyzer-infinite-loop -Wno-analyzer-infinite-recursion
-Wno-analyzer-jump-through-null -Wno-analyzer-malloc-leak
-Wno-analyzer-mismatching-deallocation -Wno-analyzer-null-argument
-Wno-analyzer-null-dereference -Wno-analyzer-out-of-bounds
-Wno-analyzer-overlapping-buffers
-Wno-analyzer-possible-null-argument
-Wno-analyzer-possible-null-dereference
-Wno-analyzer-putenv-of-auto-var -Wno-analyzer-shift-count-negative
-Wno-analyzer-shift-count-overflow -Wno-analyzer-stale-setjmp-buffer
-Wno-analyzer-tainted-allocation-size
-Wno-analyzer-tainted-assertion -Wno-analyzer-tainted-array-index
-Wno-analyzer-tainted-divisor -Wno-analyzer-tainted-offset
-Wno-analyzer-tainted-size -Wanalyzer-symbol-too-complex
-Wanalyzer-too-complex -Wno-analyzer-undefined-behavior-strtok
-Wno-analyzer-unsafe-call-within-signal-handler
-Wno-analyzer-use-after-free
-Wno-analyzer-use-of-pointer-in-stale-stack-frame
-Wno-analyzer-use-of-uninitialized-value
-Wno-analyzer-va-arg-type-mismatch -Wno-analyzer-va-list-exhausted
-Wno-analyzer-va-list-leak -Wno-analyzer-va-list-use-after-va-end
-Wno-analyzer-write-to-const -Wno-analyzer-write-to-string-literal

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

these ones are for the C and Objective-C crowd only ๐ŸŽ€ here they are, all of them โœจ

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

๐Ÿ› Debugging Options ๐Ÿ›

okay the debugging section is giving detective energy ๐Ÿ•ต๏ธโ€โ™€๏ธ๐Ÿ’– every flag, exactly as written ๐Ÿซถ

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

โœจ Optimization Options โœจ

okay bestie, this is the glow-up squad ๐Ÿ’… The page doesn't describe these ones, so I'm keeping every flag exactly as written ๐Ÿซถ

  • -faggressive-loop-optimizations
  • -falign-functions[=n[:m:[n2[:m2]]]]
  • -falign-jumps[=n[:m:[n2[:m2]]]]
  • -falign-labels[=n[:m:[n2[:m2]]]]
  • -falign-loops[=n[:m:[n2[:m2]]]]
  • -fmin-function-alignment=[n]
  • -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
  • -ffold-mem-offsets
  • -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-stringops[=fn]
  • -finline-functions
  • -finline-functions-called-once
  • -finline-limit=n
  • -finline-small-functions
  • -fipa-modref
  • -fipa-cp
  • -fipa-cp-clone
  • -fipa-bit-cp
  • -fipa-vrp
  • -fipa-pta
  • -fipa-profile
  • -fipa-pure-const
  • -fipa-reference
  • -fipa-reference-addressable
  • -fipa-stack-alignment
  • -fipa-icf
  • -fira-algorithm=algorithm
  • -flive-patching=level
  • -fira-region=region
  • -fira-hoist-pressure
  • -fira-loop-pressure
  • -fno-ira-share-save-slots
  • -fno-ira-share-spill-slots
  • -fisolate-erroneous-paths-dereference
  • -fisolate-erroneous-paths-attribute
  • -fivopts
  • -fkeep-inline-functions
  • -fkeep-static-functions
  • -fkeep-static-consts
  • -flimit-function-alignment
  • -flive-range-shrinkage
  • -floop-block
  • -floop-interchange
  • -floop-strip-mine
  • -floop-unroll-and-jam
  • -floop-nest-optimize
  • -floop-parallelize-all
  • -flra-remat
  • -flto
  • -flto-compression-level
  • -flto-partition=alg
  • -fmerge-all-constants
  • -fmerge-constants
  • -fmodulo-sched
  • -fmodulo-sched-allow-regmoves
  • -fmove-loop-invariants
  • -fmove-loop-stores
  • -fno-branch-count-reg
  • -fno-defer-pop
  • -fno-fp-int-builtin-inexact
  • -fno-function-cse
  • -fno-guess-branch-probability
  • -fno-inline
  • -fno-math-errno
  • -fno-peephole
  • -fno-peephole2
  • -fno-printf-return-value
  • -fno-sched-interblock
  • -fno-sched-spec
  • -fno-signed-zeros
  • -fno-toplevel-reorder
  • -fno-trapping-math
  • -fno-zero-initialized-in-bss
  • -fomit-frame-pointer
  • -foptimize-sibling-calls
  • -fpartial-inlining
  • -fpeel-loops
  • -fpredictive-commoning
  • -fprefetch-loop-arrays
  • -fprofile-correction
  • -fprofile-use
  • -fprofile-use=path
  • -fprofile-partial-training
  • -fprofile-values
  • -fprofile-reorder-functions
  • -freciprocal-math
  • -free
  • -frename-registers
  • -freorder-blocks
  • -freorder-blocks-algorithm=algorithm
  • -freorder-blocks-and-partition
  • -freorder-functions
  • -frerun-cse-after-loop
  • -freschedule-modulo-scheduled-loops
  • -frounding-math
  • -fsave-optimization-record
  • -fsched2-use-superblocks
  • -fsched-pressure
  • -fsched-spec-load
  • -fsched-spec-load-dangerous
  • -fsched-stalled-insns-dep[=n]
  • -fsched-stalled-insns[=n]
  • -fsched-group-heuristic
  • -fsched-critical-path-heuristic
  • -fsched-spec-insn-heuristic
  • -fsched-rank-heuristic
  • -fsched-last-insn-heuristic
  • -fsched-dep-count-heuristic
  • -fschedule-fusion
  • -fschedule-insns
  • -fschedule-insns2
  • -fsection-anchors
  • -fselective-scheduling
  • -fselective-scheduling2
  • -fsel-sched-pipelining
  • -fsel-sched-pipelining-outer-loops
  • -fsemantic-interposition
  • -fshrink-wrap
  • -fshrink-wrap-separate
  • -fsignaling-nans
  • -fsingle-precision-constant
  • -fsplit-ivs-in-unroller
  • -fsplit-loops
  • -fsplit-paths
  • -fsplit-wide-types
  • -fsplit-wide-types-early
  • -fssa-backprop
  • -fssa-phiopt
  • -fstdarg-opt
  • -fstore-merging
  • -fstrict-aliasing
  • -fipa-strict-aliasing
  • -fthread-jumps
  • -ftracer
  • -ftree-bit-ccp
  • -ftree-builtin-call-dce
  • -ftree-ccp
  • -ftree-ch
  • -ftree-coalesce-vars
  • -ftree-copy-prop
  • -ftree-dce
  • -ftree-dominator-opts
  • -ftree-dse
  • -ftree-forwprop
  • -ftree-fre
  • -fcode-hoisting
  • -ftree-loop-if-convert
  • -ftree-loop-im
  • -ftree-phiprop
  • -ftree-loop-distribution
  • -ftree-loop-distribute-patterns
  • -ftree-loop-ivcanon
  • -ftree-loop-linear
  • -ftree-loop-optimize
  • -ftree-loop-vectorize
  • -ftree-parallelize-loops=n
  • -ftree-pre
  • -ftree-partial-pre
  • -ftree-pta
  • -ftree-reassoc
  • -ftree-scev-cprop
  • -ftree-sink
  • -ftree-slsr
  • -ftree-sra
  • -ftree-switch-conversion
  • -ftree-tail-merge
  • -ftree-ter
  • -ftree-vectorize
  • -ftree-vrp
  • -ftrivial-auto-var-init
  • -funconstrained-commons
  • -funit-at-a-time
  • -funroll-all-loops
  • -funroll-loops
  • -funsafe-math-optimizations
  • -funswitch-loops
  • -fipa-ra
  • -fvariable-expansion-in-unroller
  • -fvect-cost-model
  • -fvpt
  • -fweb
  • -fwhole-program
  • -fwpa
  • -fuse-linker-plugin
  • -fzero-call-used-regs
  • --param name=value
  • -O
  • -O0
  • -O1
  • -O2
  • -O3
  • -Os
  • -Ofast
  • -Og
  • -Oz

โœจ Program Instrumentation Options โœจ

this squad is all about watching the code so you can see what it's up to ๐Ÿ”๐Ÿฆ‹

  • -p
  • -pg
  • -fprofile-arcs
  • --coverage
  • -ftest-coverage
  • -fcondition-coverage
  • -fprofile-abs-path
  • -fprofile-dir=path
  • -fprofile-generate
  • -fprofile-generate=path
  • -fprofile-info-section
  • -fprofile-info-section=name
  • -fprofile-note=path
  • -fprofile-prefix-path=path
  • -fprofile-update=method
  • -fprofile-filter-files=regex
  • -fprofile-exclude-files=regex
  • -fprofile-reproducible=[multithreaded|parallel-runs|serial]
  • -fsanitize=style
  • -fsanitize-recover
  • -fsanitize-recover=style
  • -fsanitize-trap
  • -fsanitize-trap=style
  • -fasan-shadow-offset=number
  • -fsanitize-sections=s1,s2,...
  • -fsanitize-undefined-trap-on-error
  • -fbounds-check
  • -fcf-protection=[full|branch|return|none|check]
  • -fharden-compares
  • -fharden-conditional-branches
  • -fhardened
  • -fharden-control-flow-redundancy
  • -fhardcfr-skip-leaf
  • -fhardcfr-check-exceptions
  • -fhardcfr-check-returning-calls
  • -fhardcfr-check-noreturn-calls=[always|no-xthrow|nothrow|never]
  • -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
  • -fstrub=disable
  • -fstrub=strict
  • -fstrub=relaxed
  • -fstrub=all
  • -fstrub=at-calls
  • -fstrub=internal
  • -fvtable-verify=[std|preinit|none]
  • -fvtv-counts
  • -fvtv-debug
  • -finstrument-functions
  • -finstrument-functions-once
  • -finstrument-functions-exclude-function-list=sym,sym,...
  • -finstrument-functions-exclude-file-list=file,file,...
  • -fprofile-prefix-map=old=new
  • -fpatchable-function-entry=N[,M]

โœจ Preprocessor Options โœจ

the preprocessor is the pre-game warm-up before the compiler even shows up ๐ŸŒธ

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

โœจ Assembler Options โœจ

a quick stop at the assembler, bestie ๐Ÿงš

  • -Wa,option
  • -Xassembler option

โœจ Linker Options โœจ

the linker is where everything gets tied together ๐ŸŽ€

  • object-file-name
  • -fuse-ld=linker
  • -llibrary
  • -nostartfiles
  • -nodefaultlibs
  • -nolibc
  • -nostdlib
  • -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 GCC goes looking for stuff, the treasure map era ๐Ÿ—บ๏ธ๐Ÿ’–

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

the code generation crew, where the machine code gets made ๐Ÿ’…๐Ÿ”ฅ

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

โœจ Developer Options โœจ

last stop, the developer zone, for when you want to see what's happening behind the curtain ๐Ÿ’œ๐Ÿงช

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

Okay bestie, this is the chaotic part ๐Ÿ™ˆ Every chip family gets its own squad of flags, so I'll go target by target. Don't worry, I'm just listing them out so you can find your fave ๐Ÿ’…

๐Ÿฆ‹ AArch64 Options

AArch64 is absolutely stacked with flags ๐Ÿ˜ญ๐Ÿ”ฅ

-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 -mearly-ldp-fusion -mlate-ldp-fusion

๐Ÿ Adapteva Epiphany Options

Buzzing in with the Epiphany crew ๐Ÿโœจ

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

๐ŸŽฎ AMD GCN Options

Only three, but they're iconic ๐Ÿ‘‘

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

๐ŸŒธ ARC Options

The ARC section is giving main character energy, and it goes on for ages ๐Ÿ’€๐ŸŒธ

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

๐Ÿ’ช ARM Options

ARM is the OG and it's still serving ๐Ÿ”ฅ

-mapcs-frame -mno-apcs-frame -mabi=name
-mapcs-stack-check -mno-apcs-stack-check -mapcs-reentrant
-mno-apcs-reentrant -mgeneral-regs-only -msched-prolog
-mno-sched-prolog -mlittle-endian -mbig-endian -mbe8 -mbe32
-mfloat-abi=name -mfp16-format=name -mthumb-interwork
-mno-thumb-interwork -mcpu=name -march=name -mfpu=name -mtune=name
-mprint-tune-info -mstructure-size-boundary=n -mabort-on-noreturn
-mlong-calls -mno-long-calls -msingle-pic-base
-mno-single-pic-base -mpic-register=reg -mnop-fun-dllimport
-mpoke-function-name -mthumb -marm -mflip-thumb -mtpcs-frame
-mtpcs-leaf-frame -mcaller-super-interworking
-mcallee-super-interworking -mtp=name -mtls-dialect=dialect
-mword-relocations -mfix-cortex-m3-ldrd -mfix-cortex-a57-aes-1742098
-mfix-cortex-a72-aes-1655431 -munaligned-access -mneon-for-64bits
-mslow-flash-data -masm-syntax-unified -mrestrict-it
-mverbose-cost-dump -mpure-code -mcmse -mfix-cmse-cve-2021-35465
-mstack-protector-guard=guard -mstack-protector-guard-offset=offset
-mfdpic -mbranch-protection=none|standard|pac-ret[+leaf] [+bti]|bti[+pac-ret[+leaf]]

โšก AVR Options

Tiny chips, big energy โœจ

-mmcu=mcu -mabsdata -maccumulate-args
-mbranch-cost=cost -mfuse-add=level -mcall-prologues
-mgas-isr-prologues -mint8 -mflmap -mdouble=bits
-mlong-double=bits -mn_flash=size -mno-interrupts -mmain-is-OS_task
-mrelax -mrmw -mstrict-X -mtiny-stack -mrodata-in-ram
-mfract-convert-truncate -mshort-calls -mskip-bug -nodevicelib
-nodevicespecs -Waddr-space-convert -Wmisspelled-isr

๐ŸŽต Blackfin Options

Vibing with the Blackfin set ๐ŸŽต

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

๐Ÿงš C6X Options

Small list, sweet vibes ๐Ÿงš

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

๐Ÿ“ CRIS Options

Ooh, CRIS is full of little details ๐Ÿ“

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

๐ŸŒ™ C-SKY Options

The C-SKY list is serving a whole buffet ๐ŸŒ™

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

๐ŸŽ Darwin Options

Darwin is the longest list here and it's not even close ๐Ÿ˜ญ๐ŸŽ

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

๐Ÿ’ฟ DEC Alpha Options

Retro queen energy, no cap ๐Ÿ‘‘๐Ÿ’ฟ

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

๐Ÿš eBPF Options

eBPF is literally so cute ๐Ÿš๐Ÿ’œ

-mbig-endian -mlittle-endian -mframe-limit=bytes -mxbpf
-mco-re -mno-co-re -mjmpext -mjmp32 -malu32 -mv3-atomics -mbswap
-msdiv -msmov -mcpu=version -masm=dialect
-minline-memops-threshold=bytes

๐Ÿง FR30 Options

Sweet and simple ๐Ÿง

-msmall-model -mno-lsim

๐ŸŽ€ FT32 Options

Bow on top ๐ŸŽ€

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

๐ŸŒบ FRV Options

FRV is a whole mood ๐ŸŒบ

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

๐Ÿง GNU/Linux Options

Penguin pride ๐Ÿง๐Ÿซถ

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

๐Ÿ•น๏ธ H8/300 Options

Retro gaming era ๐Ÿ•น๏ธ

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

๐Ÿ—๏ธ HPPA Options

HPPA is so detailed it's giving architect ๐Ÿ—๏ธ

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

๐Ÿง  IA-64 Options

The IA-64 list is a full brain workout ๐Ÿง ๐Ÿ”ฅ

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

๐ŸŒท LM32 Options

And last but not least, the LM32 finale ๐ŸŒท๐Ÿ’–

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

๐Ÿฆ‹ LoongArch Options

  • -march=cpu-type โ€” pick the CPU type to target ๐Ÿ’…
  • -mtune=cpu-type โ€” tune for a CPU type โœจ
  • -mabi=base-abi-type โ€” choose the base ABI type ๐ŸŽ€
  • -mfpu=fpu-type โ€” pick the FPU type ๐ŸŒธ
  • -msimd=simd-type โ€” pick the SIMD type ๐Ÿ”ฅ
  • -msoft-float โ€” soft float vibes ๐Ÿงš
  • -msingle-float โ€” single float ๐Ÿฆ‹
  • -mdouble-float โ€” double float ๐Ÿ’œ
  • -mlsx โ€” turn on LSX ๐ŸŒˆ
  • -mno-lsx โ€” the opposite of -mlsx ๐Ÿ™ˆ
  • -mlasx โ€” turn on LASX โญ
  • -mno-lasx โ€” the opposite of -mlasx ๐Ÿ’€
  • -mbranch-cost=n โ€” set the branch cost to n ๐Ÿ“
  • -mcheck-zero-division โ€” check for zero division ๐Ÿซถ
  • -mno-check-zero-division โ€” skip that check ๐Ÿ™…
  • -mcond-move-int โ€” conditional move for ints ๐Ÿ‘‘
  • -mno-cond-move-int โ€” the opposite of -mcond-move-int ๐Ÿ’…
  • -mcond-move-float โ€” conditional move for floats ๐Ÿฆ‹
  • -mno-cond-move-float โ€” the opposite of -mcond-move-float ๐ŸŒธ
  • -memcpy โ€” use memcpy โœจ
  • -mno-memcpy โ€” the opposite of -memcpy ๐Ÿ™ˆ
  • -mstrict-align โ€” strict alignment ๐Ÿ”ฅ
  • -mno-strict-align โ€” the opposite of -mstrict-align ๐Ÿงš
  • -mmax-inline-memcpy-size=n โ€” set the max inline memcpy size to n ๐Ÿ’œ
  • -mexplicit-relocs=style โ€” pick an explicit relocs style ๐ŸŒˆ
  • -mexplicit-relocs โ€” explicit relocs on โญ
  • -mno-explicit-relocs โ€” explicit relocs off ๐Ÿ’€
  • -mdirect-extern-access โ€” direct extern access ๐Ÿ“
  • -mno-direct-extern-access โ€” the opposite of -mdirect-extern-access ๐Ÿซถ
  • -mcmodel=code-model โ€” pick the code model ๐Ÿ‘‘
  • -mrelax โ€” relax it ๐Ÿ’…
  • -mpass-mrelax-to-as โ€” pass the relax to as ๐Ÿฆ‹
  • -mrecip โ€” reciprocal approximations ๐ŸŒธ
  • -mrecip=opt โ€” reciprocal approximations, with options โœจ
  • -mfrecipe โ€” frecipe on ๐Ÿ”ฅ
  • -mno-frecipe โ€” frecipe off ๐Ÿ™ˆ
  • -mdiv32 โ€” 32-bit div ๐Ÿงš
  • -mno-div32 โ€” the opposite of -mdiv32 ๐Ÿ’œ
  • -mlam-bh โ€” lam-bh on ๐ŸŒˆ
  • -mno-lam-bh โ€” lam-bh off โญ
  • -mlamcas โ€” lamcas on ๐Ÿ’€
  • -mno-lamcas โ€” lamcas off ๐Ÿ“
  • -mld-seq-sa โ€” ld-seq-sa on ๐Ÿซถ
  • -mno-ld-seq-sa โ€” ld-seq-sa off ๐Ÿ‘‘
  • -mtls-dialect=opt โ€” pick the TLS dialect ๐Ÿ’…

๐Ÿฆ‹ M32R/D Options

  • -m32r2 โ€” target M32R2 ๐ŸŒธ
  • -m32rx โ€” target M32RX โœจ
  • -m32r โ€” target M32R ๐Ÿ”ฅ
  • -mdebug โ€” debug mode ๐Ÿงš
  • -malign-loops โ€” align loops ๐Ÿ’œ
  • -mno-align-loops โ€” don't align loops ๐ŸŒˆ
  • -missue-rate=number โ€” set the issue rate to number โญ
  • -mbranch-cost=number โ€” set the branch cost to number ๐Ÿ’€
  • -mmodel=code-size-model-type โ€” pick the code-size model type ๐Ÿ“
  • -msdata=sdata-type โ€” pick the sdata type ๐Ÿซถ
  • -mno-flush-func โ€” no flush function ๐Ÿ‘‘
  • -mflush-func=name โ€” flush function named name ๐Ÿ’…
  • -mno-flush-trap โ€” no flush trap ๐Ÿฆ‹
  • -mflush-trap=number โ€” flush trap number number ๐ŸŒธ
  • -G num โ€” the -G size limit, set to num โœจ

๐Ÿฆ‹ M32C Options

  • -mcpu=cpu โ€” pick the CPU ๐Ÿ”ฅ
  • -msim โ€” simulator mode ๐Ÿงš
  • -memregs=number โ€” set the number of memregs ๐Ÿ’œ

๐Ÿฆ‹ M680x0 Options

  • -march=arch โ€” pick the arch ๐ŸŒˆ
  • -mcpu=cpu โ€” pick the CPU โญ
  • -mtune=tune โ€” tune it ๐Ÿ’€
  • -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 on ๐Ÿซถ
  • -mno-bitfield โ€” bitfield off ๐Ÿ‘‘
  • -mc68000 โ€” C68000 ๐Ÿ’…
  • -mc68020 โ€” C68020 ๐Ÿฆ‹
  • -mnobitfield โ€” bitfield off (the no-bitfield spelling) ๐ŸŒธ
  • -mrtd โ€” rtd on โœจ
  • -mno-rtd โ€” rtd off ๐Ÿ”ฅ
  • -mdiv โ€” div on ๐Ÿงš
  • -mno-div โ€” div off ๐Ÿ’œ
  • -mshort โ€” short ints ๐ŸŒˆ
  • -mno-short โ€” no short ints โญ
  • -mhard-float โ€” hard float ๐Ÿ’€
  • -m68881 โ€” 68881 FPU ๐Ÿ“
  • -msoft-float โ€” soft float ๐Ÿซถ
  • -mpcrel โ€” PC-relative ๐Ÿ‘‘
  • -malign-int โ€” align ints ๐Ÿ’…
  • -mstrict-align โ€” strict alignment ๐Ÿฆ‹
  • -msep-data โ€” separate data ๐ŸŒธ
  • -mno-sep-data โ€” the opposite of -msep-data โœจ
  • -mshared-library-id=n โ€” shared library ID n ๐Ÿ”ฅ
  • -mid-shared-library โ€” ID shared library on ๐Ÿงš
  • -mno-id-shared-library โ€” ID shared library off ๐Ÿ’œ
  • -mxgot โ€” xgot on ๐ŸŒˆ
  • -mno-xgot โ€” xgot off โญ
  • -mlong-jump-table-offsets โ€” long jump table offsets ๐Ÿ’€

๐Ÿฆ‹ MCore Options

  • -mhardlit โ€” hardlit on ๐Ÿ“
  • -mno-hardlit โ€” hardlit off ๐Ÿซถ
  • -mdiv โ€” div on ๐Ÿ‘‘
  • -mno-div โ€” div off ๐Ÿ’…
  • -mrelax-immediates โ€” relax immediates ๐Ÿฆ‹
  • -mno-relax-immediates โ€” the opposite of -mrelax-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 simulator ๐Ÿซถ
  • -mlittle-endian โ€” little endian ๐Ÿ‘‘
  • -mbig-endian โ€” big endian ๐Ÿ’…
  • -m210 โ€” 210 ๐Ÿฆ‹
  • -m340 โ€” 340 ๐ŸŒธ
  • -mstack-increment โ€” stack increment โœจ

๐Ÿฆ‹ MicroBlaze Options

  • -msoft-float โ€” soft float ๐Ÿ”ฅ
  • -mhard-float โ€” hard float ๐Ÿงš
  • -msmall-divides โ€” small divides ๐Ÿ’œ
  • -mcpu=cpu โ€” pick the CPU ๐ŸŒˆ
  • -mmemcpy โ€” memcpy โญ
  • -mxl-soft-mul โ€” XL soft mul ๐Ÿ’€
  • -mxl-soft-div โ€” XL soft div ๐Ÿ“
  • -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 clearbss ๐ŸŒธ
  • -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 ๐Ÿ“

๐Ÿฆ‹ MIPS Options

  • -EL โ€” little endian ๐Ÿซถ
  • -EB โ€” big endian ๐Ÿ‘‘
  • -march=arch โ€” pick the arch ๐Ÿ’…
  • -mtune=arch โ€” tune for the arch ๐Ÿฆ‹
  • -mips1 โ€” MIPS I ๐ŸŒธ
  • -mips2 โ€” MIPS II โœจ
  • -mips3 โ€” MIPS III ๐Ÿ”ฅ
  • -mips4 โ€” MIPS IV ๐Ÿงš
  • -mips32 โ€” MIPS32 ๐Ÿ’œ
  • -mips32r2 โ€” MIPS32 Release 2 ๐ŸŒˆ
  • -mips32r3 โ€” MIPS32 Release 3 โญ
  • -mips32r5 โ€” MIPS32 Release 5 ๐Ÿ’€
  • -mips32r6 โ€” MIPS32 Release 6 ๐Ÿ“
  • -mips64 โ€” MIPS64 ๐Ÿซถ
  • -mips64r2 โ€” MIPS64 Release 2 ๐Ÿ‘‘
  • -mips64r3 โ€” MIPS64 Release 3 ๐Ÿ’…
  • -mips64r5 โ€” MIPS64 Release 5 ๐Ÿฆ‹
  • -mips64r6 โ€” MIPS64 Release 6 ๐ŸŒธ
  • -mips16 โ€” MIPS16 โœจ
  • -mno-mips16 โ€” no MIPS16 ๐Ÿ”ฅ
  • -mflip-mips16 โ€” flip MIPS16 ๐Ÿงš
  • -minterlink-compressed โ€” interlink compressed ๐Ÿ’œ
  • -mno-interlink-compressed โ€” no interlink compressed ๐ŸŒˆ
  • -minterlink-mips16 โ€” interlink MIPS16 โญ
  • -mno-interlink-mips16 โ€” no interlink MIPS16 ๐Ÿ’€
  • -mabi=abi โ€” pick the ABI ๐Ÿ“
  • -mabicalls โ€” abicalls on ๐Ÿซถ
  • -mno-abicalls โ€” abicalls off ๐Ÿ‘‘
  • -mshared โ€” shared on ๐Ÿ’…
  • -mno-shared โ€” shared off ๐Ÿฆ‹
  • -mplt โ€” PLT on ๐ŸŒธ
  • -mno-plt โ€” PLT off โœจ
  • -mxgot โ€” xgot on ๐Ÿ”ฅ
  • -mno-xgot โ€” xgot off ๐Ÿงš
  • -mgp32 โ€” GP32 ๐Ÿ’œ
  • -mgp64 โ€” GP64 ๐ŸŒˆ
  • -mfp32 โ€” FP32 โญ
  • -mfpxx โ€” FPXX ๐Ÿ’€
  • -mfp64 โ€” FP64 ๐Ÿ“
  • -mhard-float โ€” hard float ๐Ÿซถ
  • -msoft-float โ€” soft float ๐Ÿ‘‘
  • -mno-float โ€” no float ๐Ÿ’…
  • -msingle-float โ€” single float ๐Ÿฆ‹
  • -mdouble-float โ€” double float ๐ŸŒธ
  • -modd-spreg โ€” odd single regs on โœจ
  • -mno-odd-spreg โ€” odd single regs off ๐Ÿ”ฅ
  • -mabs=mode โ€” pick the abs mode ๐Ÿงš
  • -mnan=encoding โ€” pick the NaN encoding ๐Ÿ’œ
  • -mdsp โ€” DSP on ๐ŸŒˆ
  • -mno-dsp โ€” DSP off โญ
  • -mdspr2 โ€” DSP Rev 2 on ๐Ÿ’€
  • -mno-dspr2 โ€” DSP Rev 2 off ๐Ÿ“
  • -mmcu โ€” MCU on ๐Ÿซถ
  • -mmno-mcu โ€” MCU off ๐Ÿ‘‘
  • -meva โ€” EVA on ๐Ÿ’…
  • -mno-eva โ€” EVA off ๐Ÿฆ‹
  • -mvirt โ€” virt on ๐ŸŒธ
  • -mno-virt โ€” virt off โœจ
  • -mxpa โ€” XPA on ๐Ÿ”ฅ
  • -mno-xpa โ€” XPA off ๐Ÿงš
  • -mcrc โ€” CRC on ๐Ÿ’œ
  • -mno-crc โ€” CRC off ๐ŸŒˆ
  • -mginv โ€” ginv on โญ
  • -mno-ginv โ€” ginv off ๐Ÿ’€
  • -mmicromips โ€” microMIPS on ๐Ÿ“
  • -mno-micromips โ€” microMIPS off ๐Ÿซถ
  • -mmsa โ€” MSA on ๐Ÿ‘‘
  • -mno-msa โ€” MSA off ๐Ÿ’…
  • -mloongson-mmi โ€” Loongson MMI on ๐Ÿฆ‹
  • -mno-loongson-mmi โ€” Loongson MMI off ๐ŸŒธ
  • -mloongson-ext โ€” Loongson EXT on โœจ
  • -mno-loongson-ext โ€” Loongson EXT off ๐Ÿ”ฅ
  • -mloongson-ext2 โ€” Loongson EXT2 on ๐Ÿงš
  • -mno-loongson-ext2 โ€” Loongson EXT2 off ๐Ÿ’œ
  • -mfpu=fpu-type โ€” pick the FPU type ๐ŸŒˆ
  • -msmartmips โ€” SmartMIPS on โญ
  • -mno-smartmips โ€” SmartMIPS off ๐Ÿ’€
  • -mpaired-single โ€” paired single on ๐Ÿ“
  • -mno-paired-single โ€” paired single off ๐Ÿซถ
  • -mdmx โ€” DMX on ๐Ÿ‘‘
  • -mno-mdmx โ€” DMX off ๐Ÿ’…
  • -mips3d โ€” MIPS-3D on ๐Ÿฆ‹
  • -mno-mips3d โ€” MIPS-3D off ๐ŸŒธ
  • -mmt โ€” MT on โœจ
  • -mno-mt โ€” MT off ๐Ÿ”ฅ
  • -mllsc โ€” LLSC on ๐Ÿงš
  • -mno-llsc โ€” LLSC off ๐Ÿ’œ
  • -mlong64 โ€” long is 64-bit ๐ŸŒˆ
  • -mlong32 โ€” long is 32-bit โญ
  • -msym32 โ€” sym32 on ๐Ÿ’€
  • -mno-sym32 โ€” sym32 off ๐Ÿ“
  • -Gnum โ€” the -G size limit, set to num ๐Ÿซถ
  • -mlocal-sdata โ€” local sdata on ๐Ÿ‘‘
  • -mno-local-sdata โ€” local sdata off ๐Ÿ’…
  • -mextern-sdata โ€” extern sdata on ๐Ÿฆ‹
  • -mno-extern-sdata โ€” extern sdata off ๐ŸŒธ
  • -mgpopt โ€” gpopt on โœจ
  • -mno-gopt โ€” gopt off ๐Ÿ”ฅ
  • -membedded-data โ€” embedded data on ๐Ÿงš
  • -mno-embedded-data โ€” embedded data off ๐Ÿ’œ
  • -muninit-const-in-rodata โ€” uninit const in rodata on ๐ŸŒˆ
  • -mno-uninit-const-in-rodata โ€” uninit const in rodata off โญ
  • -mcode-readable=setting โ€” pick the code-readable setting ๐Ÿ’€
  • -msplit-addresses โ€” split addresses on ๐Ÿ“
  • -mno-split-addresses โ€” split addresses off ๐Ÿซถ
  • -mexplicit-relocs โ€” explicit relocs on ๐Ÿ‘‘
  • -mno-explicit-relocs โ€” explicit relocs off ๐Ÿ’…
  • -mexplicit-relocs=release โ€” explicit relocs with release ๐Ÿฆ‹
  • -mcheck-zero-division โ€” check for zero division ๐ŸŒธ
  • -mno-check-zero-division โ€” skip that check โœจ
  • -mdivide-traps โ€” divide traps ๐Ÿ”ฅ
  • -mdivide-breaks โ€” divide breaks ๐Ÿงš
  • -mload-store-pairs โ€” load-store pairs on ๐Ÿ’œ
  • -mno-load-store-pairs โ€” load-store pairs off ๐ŸŒˆ
  • -mstrict-align โ€” strict alignment โญ
  • -mno-strict-align โ€” no strict alignment ๐Ÿ’€
  • -mno-unaligned-access โ€” no unaligned access ๐Ÿ“
  • -munaligned-access โ€” unaligned access ๐Ÿซถ
  • -mmemcpy โ€” memcpy on ๐Ÿ‘‘
  • -mno-memcpy โ€” memcpy off ๐Ÿ’…
  • -mlong-calls โ€” long calls on ๐Ÿฆ‹
  • -mno-long-calls โ€” long calls off ๐ŸŒธ
  • -mmad โ€” MAD on โœจ
  • -mno-mad โ€” MAD off ๐Ÿ”ฅ
  • -mimadd โ€” imadd on ๐Ÿงš
  • -mno-imadd โ€” imadd off ๐Ÿ’œ
  • -mfused-madd โ€” fused madd on ๐ŸŒˆ
  • -mno-fused-madd โ€” fused madd off โญ
  • -nocpp โ€” no preprocessing ๐Ÿ’€
  • -mfix-24k โ€” fix the 24K ๐Ÿ“
  • -mno-fix-24k โ€” don't fix the 24K ๐Ÿซถ
  • -mfix-r4000 โ€” fix the R4000 ๐Ÿ‘‘
  • -mno-fix-r4000 โ€” don't fix the R4000 ๐Ÿ’…
  • -mfix-r4400 โ€” fix the R4400 ๐Ÿฆ‹
  • -mno-fix-r4400 โ€” don't fix the R4400 ๐ŸŒธ
  • -mfix-r5900 โ€” fix the R5900 โœจ
  • -mno-fix-r5900 โ€” don't fix the R5900 ๐Ÿ”ฅ
  • -mfix-r10000 โ€” fix the R10000 ๐Ÿงš
  • -mno-fix-r10000 โ€” don't fix the R10000 ๐Ÿ’œ
  • -mfix-rm7000 โ€” fix the RM7000 ๐ŸŒˆ
  • -mno-fix-rm7000 โ€” don't fix the RM7000 โญ
  • -mfix-vr4120 โ€” fix the VR4120 ๐Ÿ’€
  • -mno-fix-vr4120 โ€” don't fix the VR4120 ๐Ÿ“
  • -mfix-vr4130 โ€” fix the VR4130 ๐Ÿซถ
  • -mno-fix-vr4130 โ€” don't fix the VR4130 ๐Ÿ‘‘
  • -mfix-sb1 โ€” fix the SB-1 ๐Ÿ’…
  • -mno-fix-sb1 โ€” don't fix the SB-1 ๐Ÿฆ‹
  • -mflush-func=func โ€” flush function named func ๐ŸŒธ
  • -mno-flush-func โ€” no flush function โœจ
  • -mbranch-cost=num โ€” set the branch cost to num ๐Ÿ”ฅ
  • -mbranch-likely โ€” branch likely on ๐Ÿงš
  • -mno-branch-likely โ€” branch likely off ๐Ÿ’œ
  • -mcompact-branches=policy โ€” pick the compact branches policy ๐ŸŒˆ
  • -mfp-exceptions โ€” FP exceptions on โญ
  • -mno-fp-exceptions โ€” FP exceptions off ๐Ÿ’€
  • -mvr4130-align โ€” VR4130 align on ๐Ÿ“
  • -mno-vr4130-align โ€” VR4130 align off ๐Ÿซถ
  • -msynci โ€” synci on ๐Ÿ‘‘
  • -mno-synci โ€” synci off ๐Ÿ’…
  • -mlxc1-sxc1 โ€” lxc1/sxc1 on ๐Ÿฆ‹
  • -mno-lxc1-sxc1 โ€” lxc1/sxc1 off ๐ŸŒธ
  • -mmadd4 โ€” madd4 on โœจ
  • -mno-madd4 โ€” madd4 off ๐Ÿ”ฅ
  • -mrelax-pic-calls โ€” relax PIC calls on ๐Ÿงš
  • -mno-relax-pic-calls โ€” relax PIC calls off ๐Ÿ’œ
  • -mmcount-ra-address โ€” mcount RA address ๐ŸŒˆ
  • -mframe-header-opt โ€” frame header opt on โญ
  • -mno-frame-header-opt โ€” frame header opt off ๐Ÿ’€

๐Ÿฆ‹ MMIX Options

  • -mlibfuncs โ€” library functions on ๐Ÿ“
  • -mno-libfuncs โ€” library functions off ๐Ÿซถ
  • -mepsilon โ€” epsilon on ๐Ÿ‘‘
  • -mno-epsilon โ€” epsilon off ๐Ÿ’…
  • -mabi=gnu โ€” the GNU ABI ๐Ÿฆ‹
  • -mabi=mmixware โ€” the mmixware ABI ๐ŸŒธ
  • -mzero-extend โ€” zero extend โœจ
  • -mknuthdiv โ€” Knuth div ๐Ÿ”ฅ
  • -mtoplevel-symbols โ€” top-level symbols ๐Ÿงš
  • -melf โ€” ELF ๐Ÿ’œ
  • -mbranch-predict โ€” branch predict on ๐ŸŒˆ
  • -mno-branch-predict โ€” branch predict off โญ
  • -mbase-addresses โ€” base addresses on ๐Ÿ’€
  • -mno-base-addresses โ€” base addresses off ๐Ÿ“
  • -msingle-exit โ€” single exit ๐Ÿซถ
  • -mno-single-exit โ€” no single exit ๐Ÿ‘‘

๐Ÿฆ‹ MN10300 Options

  • -mmult-bug โ€” mult bug on ๐Ÿ’…
  • -mno-mult-bug โ€” mult bug off ๐Ÿฆ‹
  • -mno-am33 โ€” no AM33 ๐ŸŒธ
  • -mam33 โ€” AM33 โœจ
  • -mam33-2 โ€” AM33-2 ๐Ÿ”ฅ
  • -mam34 โ€” AM34 ๐Ÿงš
  • -mtune=cpu-type โ€” tune for the CPU type ๐Ÿ’œ
  • -mreturn-pointer-on-d0 โ€” return pointer on D0 ๐ŸŒˆ
  • -mno-crt0 โ€” no crt0 โญ
  • -mrelax โ€” relax ๐Ÿ’€
  • -mliw โ€” LIW on ๐Ÿ“
  • -msetlb โ€” SETLB on ๐Ÿซถ

๐Ÿฆ‹ Moxie Options

  • -meb โ€” big endian ๐Ÿ‘‘
  • -mel โ€” little endian ๐Ÿ’…
  • -mmul.x โ€” mul.x on ๐Ÿฆ‹
  • -mno-crt0 โ€” no crt0 ๐ŸŒธ

๐Ÿฆ‹ MSP430 Options

  • -msim โ€” simulator mode โœจ
  • -masm-hex โ€” assembler hex ๐Ÿ”ฅ
  • -mmcu= โ€” pick the MCU ๐Ÿงš
  • -mcpu= โ€” pick the CPU ๐Ÿ’œ
  • -mlarge โ€” large model ๐ŸŒˆ
  • -msmall โ€” small model โญ
  • -mrelax โ€” relax ๐Ÿ’€
  • -mwarn-mcu โ€” warn about the MCU ๐Ÿ“
  • -mcode-region= โ€” code region ๐Ÿซถ
  • -mdata-region= โ€” data region ๐Ÿ‘‘
  • -msilicon-errata= โ€” silicon errata ๐Ÿ’…
  • -msilicon-errata-warn= โ€” silicon errata warnings ๐Ÿฆ‹
  • -mhwmult= โ€” hardware multiply ๐ŸŒธ
  • -minrt โ€” minimal runtime โœจ
  • -mtiny-printf โ€” tiny printf ๐Ÿ”ฅ
  • -mmax-inline-shift= โ€” max inline shift ๐Ÿงš

๐Ÿฆ‹ NDS32 Options

  • -mbig-endian โ€” big endian ๐Ÿ’œ
  • -mlittle-endian โ€” little endian ๐ŸŒˆ
  • -mreduced-regs โ€” reduced regs โญ
  • -mfull-regs โ€” full regs ๐Ÿ’€
  • -mcmov โ€” cmov on ๐Ÿ“
  • -mno-cmov โ€” cmov off ๐Ÿซถ
  • -mext-perf โ€” ext-perf on ๐Ÿ‘‘
  • -mno-ext-perf โ€” ext-perf off ๐Ÿ’…
  • -mext-perf2 โ€” ext-perf2 on ๐Ÿฆ‹
  • -mno-ext-perf2 โ€” ext-perf2 off ๐ŸŒธ
  • -mext-string โ€” ext-string on โœจ
  • -mno-ext-string โ€” ext-string off ๐Ÿ”ฅ
  • -mv3push โ€” v3push on ๐Ÿงš
  • -mno-v3push โ€” v3push off ๐Ÿ’œ
  • -m16bit โ€” 16-bit on ๐ŸŒˆ
  • -mno-16bit โ€” 16-bit off โญ
  • -misr-vector-size=num โ€” ISR vector size num ๐Ÿ’€
  • -mcache-block-size=num โ€” cache block size num ๐Ÿ“
  • -march=arch โ€” pick the arch ๐Ÿซถ
  • -mcmodel=code-model โ€” pick the code model ๐Ÿ‘‘
  • -mctor-dtor โ€” ctor/dtor on ๐Ÿ’…
  • -mrelax โ€” relax ๐Ÿฆ‹

๐Ÿฆ‹ Nios II Options

  • -G num โ€” the -G size limit, set to num ๐ŸŒธ
  • -mgpopt=option โ€” gpopt with option โœจ
  • -mgpopt โ€” gpopt on ๐Ÿ”ฅ
  • -mno-gpopt โ€” gpopt off ๐Ÿงš
  • -mgprel-sec=regexp โ€” gprel section matching regexp ๐Ÿ’œ
  • -mr0rel-sec=regexp โ€” r0rel section matching regexp ๐ŸŒˆ
  • -mel โ€” little endian โญ
  • -meb โ€” big endian ๐Ÿ’€
  • -mno-bypass-cache โ€” bypass cache off ๐Ÿ“
  • -mbypass-cache โ€” bypass cache on ๐Ÿซถ
  • -mno-cache-volatile โ€” cache volatile off ๐Ÿ‘‘
  • -mcache-volatile โ€” cache volatile on ๐Ÿ’…
  • -mno-fast-sw-div โ€” fast software div off ๐Ÿฆ‹
  • -mfast-sw-div โ€” fast software div on ๐ŸŒธ
  • -mhw-mul โ€” hardware mul on โœจ
  • -mno-hw-mul โ€” hardware mul off ๐Ÿ”ฅ
  • -mhw-mulx โ€” hardware mulx on ๐Ÿงš
  • -mno-hw-mulx โ€” hardware mulx off ๐Ÿ’œ
  • -mno-hw-div โ€” hardware div off ๐ŸŒˆ
  • -mhw-div โ€” hardware div on โญ
  • -mcustom-insn=N โ€” custom instruction N ๐Ÿ’€
  • -mno-custom-insn โ€” no custom instructions ๐Ÿ“
  • -mcustom-fpu-cfg=name โ€” custom FPU config name ๐Ÿซถ
  • -mhal โ€” HAL on ๐Ÿ‘‘
  • -msmallc โ€” smallc on ๐Ÿ’…
  • -msys-crt0=name โ€” sys crt0 named name ๐Ÿฆ‹
  • -msys-lib=name โ€” sys lib named name ๐ŸŒธ
  • -march=arch โ€” pick the arch โœจ
  • -mbmx โ€” BMX on ๐Ÿ”ฅ
  • -mno-bmx โ€” BMX off ๐Ÿงš
  • -mcdx โ€” CDX on ๐Ÿ’œ
  • -mno-cdx โ€” CDX off ๐ŸŒˆ

๐Ÿฆ‹ Nvidia PTX Options

  • -m64 โ€” 64-bit ๐Ÿ’…
  • -mmainkernel โ€” main kernel โœจ
  • -moptimize โ€” optimize ๐Ÿ”ฅ

๐Ÿฆ‹ OpenRISC Options

  • -mboard=name โ€” board named name ๐Ÿงš
  • -mnewlib โ€” newlib ๐Ÿ’œ
  • -mhard-mul โ€” hard mul ๐ŸŒˆ
  • -mhard-div โ€” hard div โญ
  • -msoft-mul โ€” soft mul ๐Ÿ’€
  • -msoft-div โ€” soft div ๐Ÿ“
  • -msoft-float โ€” soft float ๐Ÿซถ
  • -mhard-float โ€” hard float ๐Ÿ‘‘
  • -mdouble-float โ€” double float ๐Ÿ’…
  • -munordered-float โ€” unordered float ๐Ÿฆ‹
  • -mcmov โ€” cmov ๐ŸŒธ
  • -mror โ€” ror โœจ
  • -mrori โ€” rori ๐Ÿ”ฅ
  • -msext โ€” sext ๐Ÿงš
  • -msfimm โ€” sfimm ๐Ÿ’œ
  • -mshftimm โ€” shftimm ๐ŸŒˆ
  • -mcmodel=code-model โ€” pick the code model โญ

๐Ÿฆ‹ PDP-11 Options

  • -mfpu โ€” FPU on ๐Ÿ’€
  • -msoft-float โ€” soft float ๐Ÿ“
  • -mac0 โ€” ac0 on ๐Ÿซถ
  • -mno-ac0 โ€” ac0 off ๐Ÿ‘‘
  • -m40 โ€” 40 ๐Ÿ’…
  • -m45 โ€” 45 ๐Ÿฆ‹
  • -m10 โ€” 10 ๐ŸŒธ
  • -mint32 โ€” int32 โœจ
  • -mno-int16 โ€” no int16 ๐Ÿ”ฅ
  • -mint16 โ€” int16 ๐Ÿงš
  • -mno-int32 โ€” no int32 ๐Ÿ’œ
  • -msplit โ€” split ๐ŸŒˆ
  • -munix-asm โ€” Unix assembler โญ
  • -mdec-asm โ€” DEC assembler ๐Ÿ’€
  • -mgnu-asm โ€” GNU assembler ๐Ÿ“
  • -mlra โ€” LRA ๐Ÿซถ

๐Ÿฆ‹ PowerPC Options

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


๐Ÿฆ‹ PRU Options

  • -mmcu=mcu โ€” pick the MCU mcu ๐Ÿ’…
  • -minrt โ€” minimal runtime ๐Ÿฆ‹
  • -mno-relax โ€” relax off ๐ŸŒธ
  • -mloop โ€” loop on โœจ
  • -mabi=variant โ€” pick the ABI variant ๐Ÿ”ฅ

๐Ÿฆ‹ RISC-V Options

  • -mbranch-cost=N-instruction โ€” branch cost in N-instruction ๐Ÿงš
  • -mplt โ€” PLT on ๐Ÿ’œ
  • -mno-plt โ€” PLT off ๐ŸŒˆ
  • -mabi=ABI-string โ€” pick the ABI string โญ
  • -mfdiv โ€” fdiv on ๐Ÿ’€
  • -mno-fdiv โ€” fdiv off ๐Ÿ“
  • -mdiv โ€” div on ๐Ÿซถ
  • -mno-div โ€” div off ๐Ÿ‘‘
  • -misa-spec=ISA-spec-string โ€” pick the ISA spec string ๐Ÿ’…
  • -march=ISA-string โ€” pick the ISA string ๐Ÿฆ‹
  • -mtune=processor-string โ€” tune for the processor string ๐ŸŒธ
  • -mpreferred-stack-boundary=num โ€” preferred stack boundary num โœจ
  • -msmall-data-limit=N-bytes โ€” small data limit in N-bytes ๐Ÿ”ฅ
  • -msave-restore โ€” save/restore on ๐Ÿงš
  • -mno-save-restore โ€” save/restore off ๐Ÿ’œ
  • -mshorten-memrefs โ€” shorten memrefs on ๐ŸŒˆ
  • -mno-shorten-memrefs โ€” shorten memrefs off โญ
  • -mstrict-align โ€” strict alignment ๐Ÿ’€
  • -mno-strict-align โ€” no strict alignment ๐Ÿ“
  • -mcmodel=medlow โ€” medlow code model ๐Ÿซถ
  • -mcmodel=medany โ€” medany code model ๐Ÿ‘‘
  • -mexplicit-relocs โ€” explicit relocs on ๐Ÿ’…
  • -mno-explicit-relocs โ€” explicit relocs off ๐Ÿฆ‹
  • -mrelax โ€” relax on ๐ŸŒธ
  • -mno-relax โ€” relax off โœจ
  • -mriscv-attribute โ€” RISC-V attributes on ๐Ÿ”ฅ
  • -mno-riscv-attribute โ€” RISC-V attributes off ๐Ÿงš
  • -malign-data=type โ€” align data by type ๐Ÿ’œ
  • -mbig-endian โ€” big endian ๐ŸŒˆ
  • -mlittle-endian โ€” little endian โญ
  • -mstack-protector-guard=guard โ€” stack protector guard guard ๐Ÿ’€
  • -mstack-protector-guard-reg=reg โ€” stack protector guard register reg ๐Ÿ“
  • -mstack-protector-guard-offset=offset โ€” stack protector guard offset offset ๐Ÿซถ
  • -mcsr-check โ€” CSR check on ๐Ÿ‘‘
  • -mno-csr-check โ€” CSR check off ๐Ÿ’…
  • -mmovcc โ€” movcc on ๐Ÿฆ‹
  • -mno-movcc โ€” movcc off ๐ŸŒธ
  • -minline-atomics โ€” inline atomics on โœจ
  • -mno-inline-atomics โ€” inline atomics off ๐Ÿ”ฅ
  • -minline-strlen โ€” inline strlen on ๐Ÿงš
  • -mno-inline-strlen โ€” inline strlen off ๐Ÿ’œ
  • -minline-strcmp โ€” inline strcmp on ๐ŸŒˆ
  • -mno-inline-strcmp โ€” inline strcmp off โญ
  • -minline-strncmp โ€” inline strncmp on ๐Ÿ’€
  • -mno-inline-strncmp โ€” inline strncmp off ๐Ÿ“
  • -mtls-dialect=desc โ€” TLS dialect desc ๐Ÿซถ
  • -mtls-dialect=trad โ€” TLS dialect trad ๐Ÿ‘‘

๐Ÿฆ‹ RL78 Options

  • -msim โ€” simulator mode ๐Ÿ’…
  • -mmul=none โ€” no multiply ๐Ÿฆ‹
  • -mmul=g13 โ€” multiply for G13 ๐ŸŒธ
  • -mmul=g14 โ€” multiply for G14 โœจ
  • -mallregs โ€” all regs ๐Ÿ”ฅ
  • -mcpu=g10 โ€” CPU G10 ๐Ÿงš
  • -mcpu=g13 โ€” CPU G13 ๐Ÿ’œ
  • -mcpu=g14 โ€” CPU G14 ๐ŸŒˆ
  • -mg10 โ€” G10 โญ
  • -mg13 โ€” G13 ๐Ÿ’€
  • -mg14 โ€” G14 ๐Ÿ“
  • -m64bit-doubles โ€” 64-bit doubles ๐Ÿซถ
  • -m32bit-doubles โ€” 32-bit doubles ๐Ÿ‘‘
  • -msave-mduc-in-interrupts โ€” save MDUC in interrupts ๐Ÿ’…

๐Ÿฆ‹ RS/6000 and PowerPC Options

  • -mcpu=cpu-type โ€” pick the CPU type ๐Ÿฆ‹
  • -mtune=cpu-type โ€” tune for the CPU type ๐ŸŒธ
  • -mcmodel=code-model โ€” pick the code model โœจ
  • -mpowerpc64 โ€” PowerPC64 ๐Ÿ”ฅ
  • -maltivec โ€” AltiVec on ๐Ÿงš
  • -mno-altivec โ€” AltiVec off ๐Ÿ’œ
  • -mpowerpc-gpopt โ€” PowerPC gpopt on ๐ŸŒˆ
  • -mno-powerpc-gpopt โ€” PowerPC gpopt off โญ
  • -mpowerpc-gfxopt โ€” PowerPC gfxopt on ๐Ÿ’€
  • -mno-powerpc-gfxopt โ€” PowerPC gfxopt off ๐Ÿ“
  • -mmfcrf โ€” mfcrf on ๐Ÿซถ
  • -mno-mfcrf โ€” mfcrf off ๐Ÿ‘‘
  • -mpopcntb โ€” popcntb on ๐Ÿ’…
  • -mno-popcntb โ€” popcntb off ๐Ÿฆ‹
  • -mpopcntd โ€” popcntd on ๐ŸŒธ
  • -mno-popcntd โ€” popcntd off โœจ
  • -mfprnd โ€” fprnd on ๐Ÿ”ฅ
  • -mno-fprnd โ€” fprnd off ๐Ÿงš
  • -mcmpb โ€” cmpb on ๐Ÿ’œ
  • -mno-cmpb โ€” cmpb off ๐ŸŒˆ
  • -mhard-dfp โ€” hard DFP on โญ
  • -mno-hard-dfp โ€” hard DFP off ๐Ÿ’€
  • -mfull-toc โ€” full TOC ๐Ÿ“
  • -mminimal-toc โ€” minimal TOC ๐Ÿซถ
  • -mno-fp-in-toc โ€” no FP in TOC ๐Ÿ‘‘
  • -mno-sum-in-toc โ€” no sum in TOC ๐Ÿ’…
  • -m64 โ€” 64-bit ๐Ÿฆ‹
  • -m32 โ€” 32-bit ๐ŸŒธ
  • -mxl-compat โ€” XL compat on โœจ
  • -mno-xl-compat โ€” XL compat off ๐Ÿ”ฅ
  • -mpe โ€” PE on ๐Ÿงš
  • -malign-power โ€” align power ๐Ÿ’œ
  • -malign-natural โ€” align natural ๐ŸŒˆ
  • -msoft-float โ€” soft float โญ
  • -mhard-float โ€” hard float ๐Ÿ’€
  • -mmultiple โ€” multiple on ๐Ÿ“
  • -mno-multiple โ€” multiple off ๐Ÿซถ
  • -mupdate โ€” update on ๐Ÿ‘‘
  • -mno-update โ€” update off ๐Ÿ’…
  • -mavoid-indexed-addresses โ€” avoid indexed addresses ๐Ÿฆ‹
  • -mno-avoid-indexed-addresses โ€” don't avoid indexed addresses ๐ŸŒธ
  • -mfused-madd โ€” fused madd on โœจ
  • -mno-fused-madd โ€” fused madd off ๐Ÿ”ฅ
  • -mbit-align โ€” bit align on ๐Ÿงš
  • -mno-bit-align โ€” bit align off ๐Ÿ’œ
  • -mstrict-align โ€” strict alignment ๐ŸŒˆ
  • -mno-strict-align โ€” no strict alignment โญ
  • -mrelocatable โ€” relocatable on ๐Ÿ’€
  • -mno-relocatable โ€” relocatable off ๐Ÿ“
  • -mrelocatable-lib โ€” relocatable lib on ๐Ÿซถ
  • -mno-relocatable-lib โ€” relocatable lib off ๐Ÿ‘‘
  • -mtoc โ€” TOC on ๐Ÿ’…
  • -mno-toc โ€” TOC off ๐Ÿฆ‹
  • -mlittle โ€” little ๐ŸŒธ
  • -mlittle-endian โ€” little endian โœจ
  • -mbig โ€” big ๐Ÿ”ฅ
  • -mbig-endian โ€” big endian ๐Ÿงš
  • -mdynamic-no-pic โ€” dynamic no PIC ๐Ÿ’œ
  • -mswdiv โ€” swdiv on ๐ŸŒˆ
  • -msingle-pic-base โ€” single PIC base โญ
  • -mprioritize-restricted-insns=priority โ€” prioritize restricted insns by priority ๐Ÿ’€
  • -msched-costly-dep=dependence_type โ€” costly dependence type dependence_type ๐Ÿ“
  • -minsert-sched-nops=scheme โ€” insert sched nops with scheme ๐Ÿซถ
  • -mcall-aixdesc โ€” AIX descriptors ๐Ÿ‘‘
  • -mcall-eabi โ€” EABI ๐Ÿ’…
  • -mcall-freebsd โ€” FreeBSD calls ๐Ÿฆ‹
  • -mcall-linux โ€” Linux calls ๐ŸŒธ
  • -mcall-netbsd โ€” NetBSD calls โœจ
  • -mcall-openbsd โ€” OpenBSD calls ๐Ÿ”ฅ
  • -mcall-sysv โ€” SysV calls ๐Ÿงš
  • -mcall-sysv-eabi โ€” SysV EABI calls ๐Ÿ’œ
  • -mcall-sysv-noeabi โ€” SysV no-EABI calls ๐ŸŒˆ
  • -mtraceback=traceback_type โ€” traceback type traceback_type โญ
  • -maix-struct-return โ€” AIX struct return ๐Ÿ’€
  • -msvr4-struct-return โ€” SVR4 struct return ๐Ÿ“
  • -mabi=abi-type โ€” pick the ABI type ๐Ÿซถ
  • -msecure-plt โ€” secure PLT ๐Ÿ‘‘
  • -mbss-plt โ€” BSS PLT ๐Ÿ’…
  • -mlongcall โ€” long call on ๐Ÿฆ‹
  • -mno-longcall โ€” long call off ๐ŸŒธ
  • -mpltseq โ€” PLT seq on โœจ
  • -mno-pltseq โ€” PLT seq off ๐Ÿ”ฅ
  • -mblock-move-inline-limit=num โ€” block move inline limit num ๐Ÿงš
  • -mblock-compare-inline-limit=num โ€” block compare inline limit num ๐Ÿ’œ
  • -mblock-compare-inline-loop-limit=num โ€” block compare inline loop limit num ๐ŸŒˆ
  • -mno-block-ops-unaligned-vsx โ€” no unaligned VSX block ops โญ
  • -mstring-compare-inline-limit=num โ€” string compare inline limit num ๐Ÿ’€
  • -misel โ€” isel on ๐Ÿ“
  • -mno-isel โ€” isel off ๐Ÿซถ
  • -mvrsave โ€” vrsave on ๐Ÿ‘‘
  • -mno-vrsave โ€” vrsave off ๐Ÿ’…
  • -mmulhw โ€” mulhw on ๐Ÿฆ‹
  • -mno-mulhw โ€” mulhw off ๐ŸŒธ
  • -mdlmzb โ€” dlmzb on โœจ
  • -mno-dlmzb โ€” dlmzb off ๐Ÿ”ฅ
  • -mprototype โ€” prototype on ๐Ÿงš
  • -mno-prototype โ€” prototype off ๐Ÿ’œ
  • -msim โ€” simulator mode ๐ŸŒˆ
  • -mmvme โ€” MVME โญ
  • -mads โ€” ADS ๐Ÿ’€
  • -myellowknife โ€” Yellowknife ๐Ÿ“
  • -memb โ€” EMB ๐Ÿซถ
  • -msdata โ€” sdata on ๐Ÿ‘‘
  • -msdata=opt โ€” sdata with opt ๐Ÿ’…
  • -mreadonly-in-sdata โ€” readonly in sdata ๐Ÿฆ‹
  • -mvxworks โ€” VxWorks ๐ŸŒธ
  • -G num โ€” the -G size limit, set to num โœจ
  • -mrecip โ€” reciprocal approximations ๐Ÿ”ฅ
  • -mrecip=opt โ€” reciprocal approximations, with options ๐Ÿงš
  • -mno-recip โ€” reciprocal approximations off ๐Ÿ’œ
  • -mrecip-precision โ€” reciprocal precision on ๐ŸŒˆ
  • -mno-recip-precision โ€” reciprocal precision off โญ
  • -mveclibabi=type โ€” vector lib ABI type ๐Ÿ’€
  • -mfriz โ€” friz on ๐Ÿ“
  • -mno-friz โ€” friz off ๐Ÿซถ
  • -mpointers-to-nested-functions โ€” pointers to nested functions on ๐Ÿ‘‘
  • -mno-pointers-to-nested-functions โ€” pointers to nested functions off ๐Ÿ’…
  • -msave-toc-indirect โ€” save TOC indirect on ๐Ÿฆ‹
  • -mno-save-toc-indirect โ€” save TOC indirect off ๐ŸŒธ
  • -mpower8-fusion โ€” POWER8 fusion on โœจ
  • -mno-mpower8-fusion โ€” POWER8 fusion off ๐Ÿ”ฅ
  • -mcrypto โ€” crypto on ๐Ÿงš
  • -mno-crypto โ€” crypto off ๐Ÿ’œ
  • -mhtm โ€” HTM on ๐ŸŒˆ
  • -mno-htm โ€” HTM off โญ
  • -mquad-memory โ€” quad memory on ๐Ÿ’€
  • -mno-quad-memory โ€” quad memory off ๐Ÿ“
  • -mquad-memory-atomic โ€” quad memory atomic on ๐Ÿซถ
  • -mno-quad-memory-atomic โ€” quad memory atomic off ๐Ÿ‘‘
  • -mcompat-align-parm โ€” compat align parm on ๐Ÿ’…
  • -mno-compat-align-parm โ€” compat align parm off ๐Ÿฆ‹
  • -mfloat128 โ€” float128 on ๐ŸŒธ
  • -mno-float128 โ€” float128 off โœจ
  • -mfloat128-hardware โ€” float128 hardware on ๐Ÿ”ฅ
  • -mno-float128-hardware โ€” float128 hardware off ๐Ÿงš
  • -mgnu-attribute โ€” GNU attribute on ๐Ÿ’œ
  • -mno-gnu-attribute โ€” GNU attribute off ๐ŸŒˆ
  • -mstack-protector-guard=guard โ€” stack protector guard guard โญ
  • -mstack-protector-guard-reg=reg โ€” stack protector guard register reg ๐Ÿ’€
  • -mstack-protector-guard-offset=offset โ€” stack protector guard offset offset ๐Ÿ“
  • -mprefixed โ€” prefixed on ๐Ÿซถ
  • -mno-prefixed โ€” prefixed off ๐Ÿ‘‘
  • -mpcrel โ€” PC-relative on ๐Ÿ’…
  • -mno-pcrel โ€” PC-relative off ๐Ÿฆ‹
  • -mmma โ€” MMA on ๐ŸŒธ
  • -mno-mmma โ€” MMA off โœจ
  • -mrop-protect โ€” ROP protect on ๐Ÿ”ฅ
  • -mno-rop-protect โ€” ROP protect off ๐Ÿงš
  • -mprivileged โ€” privileged on ๐Ÿ’œ
  • -mno-privileged โ€” privileged off ๐ŸŒˆ

โœจ RX Options โœจ

RX gets its whole own little flex list ๐ŸŽ€ every flag, no skipping ๐Ÿ’…

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

the S/390 crew is giving main character energy ๐Ÿฆ‹

-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

โœจ SH Options โœจ

SH has so many flags it's lowkey a whole lifestyle ๐Ÿ’…๐ŸŒˆ

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

Solaris 2 keeping it short and sweet ๐ŸŒธ

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

โœจ SPARC Options โœจ

SPARC is a big one, bestie, so grab a snack ๐Ÿ“

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

โœจ System V Options โœจ

old school but still iconic ๐Ÿ‘‘

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

โœจ V850 Options โœจ

the V850 list is giving lots of options, babe ๐Ÿ’–

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

VAX is tiny and cute ๐Ÿงš

-mg  -mgnu  -munix  -mlra

โœจ Visium Options โœจ

Visium, you're so put together ๐Ÿ’…

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

โœจ VMS Options โœจ

VMS flags, serving return codes and malloc drama ๐ŸŽ€

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

โœจ VxWorks Options โœจ

VxWorks is lowkey a vibe check ๐Ÿฆ‹

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

โœจ x86 Options โœจ

x86 is the biggest girlie of them all and it's not even close ๐Ÿ‘‘๐Ÿ’…โœจ

-mtune=cpu-type  -march=cpu-type -mtune-ctrl=feature-list  -mdump-tune-features  -mno-default -mfpmath=unit -masm=dialect
-mno-fancy-math-387 -mno-fp-ret-in-387  -m80387  -mhard-float
-msoft-float -mno-wide-multiply  -mrtd  -malign-double
-mpreferred-stack-boundary=num -mincoming-stack-boundary=num -mcld
-mcx16  -msahf  -mmovbe  -mcrc32 -mmwait -mrecip  -mrecip=opt
-mvzeroupper  -mprefer-avx128  -mprefer-vector-width=opt
-mpartial-vector-fp-math -mmove-max=bits -mstore-max=bits
-mnoreturn-no-callee-saved-registers -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 -mcet-switch -mforce-indirect-call
-mavx512vbmi2 -mavx512bf16 -menqcmd -mvpclmulqdq  -mavx512bitalg
-mmovdiri  -mmovdir64b  -mavx512vpopcntdq -mavx5124fmaps
-mavx512vnni  -mavx5124vnniw  -mprfchw  -mrdpid -mrdseed  -msgx
-mavx512vp2intersect -mserialize -mtsxldtrk -mamx-tile  -mamx-int8
-mamx-bf16 -muintr -mhreset -mavxvnni -mavx512fp16 -mavxifma
-mavxvnniint8 -mavxneconvert -mcmpccxadd -mamx-fp16 -mprefetchi
-mraoint -mamx-complex -mavxvnniint16 -msm3 -msha512 -msm4 -mapxf
-musermsr -mavx10.1 -mavx10.1-256 -mavx10.1-512 -mevex512 -mcldemote
-mms-bitfields  -mno-align-stringops  -minline-all-stringops
-minline-stringops-dynamically  -mstringop-strategy=alg -mkl
-mwidekl -mmemcpy-strategy=strategy  -mmemset-strategy=strategy
-mpush-args  -maccumulate-outgoing-args  -m128bit-long-double
-m96bit-long-double  -mlong-double-64  -mlong-double-80
-mlong-double-128 -mregparm=num  -msseregparm -mveclibabi=type
-mvect8-ret-in-mem -mpc32  -mpc64  -mpc80  -mdaz-ftz -mstackrealign
-momit-leaf-frame-pointer  -mno-red-zone  -mno-tls-direct-seg-refs
-mcmodel=code-model  -mabi=name  -maddress-mode=mode -m32  -m64
-mx32  -m16  -miamcu  -mlarge-data-threshold=num -msse2avx  -mfentry
-mrecord-mcount  -mnop-mcount  -m8bit-idiv -minstrument-return=type
-mfentry-name=name -mfentry-section=name
-mavx256-split-unaligned-load  -mavx256-split-unaligned-store
-malign-data=type  -mstack-protector-guard=guard
-mstack-protector-guard-reg=reg
-mstack-protector-guard-offset=offset
-mstack-protector-guard-symbol=symbol -mgeneral-regs-only
-mcall-ms2sysv-xlogues -mrelax-cmpxchg-loop -mindirect-branch=choice
-mfunction-return=choice -mindirect-branch-register
-mharden-sls=choice -mindirect-branch-cs-prefix -mneeded
-mno-direct-extern-access -munroll-only-small-loops -mlam=choice

โœจ x86 Windows Options โœจ

Windows x86 bringing the drama ๐ŸŒˆ

-mconsole  -mcrtdll=library  -mdll
-mnop-fun-dllimport  -mthread -municode  -mwin32  -mwindows
-fno-set-stack-executable

โœจ Xstormy16 Options โœจ

Xstormy16 just has the one, but it's a good one ๐Ÿซถ

-msim

โœจ Xtensa Options โœจ

Xtensa has a whole collection going on ๐Ÿงš๐Ÿ’œ

-mconst16  -mno-const16 -mfused-madd  -mno-fused-madd
-mforce-no-pic -mserialize-volatile  -mno-serialize-volatile
-mtext-section-literals  -mno-text-section-literals -mauto-litpools
-mno-auto-litpools -mtarget-align  -mno-target-align -mlongcalls
-mno-longcalls -mabi=abi-type -mextra-l32r-costs=cycles
-mstrict-align  -mno-strict-align

โœจ zSeries Options โœจ

zSeries is just S/390 in a new outfit, so no need to repeat yourself ๐Ÿ™ˆ

See S/390 and zSeries Options.


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

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

For any given input file, the file name suffix decides what kind of compilation happens:

  • file.c โ€” C source code that must be preprocessed.
  • file.i โ€” C source code that should not be preprocessed.
  • file.ii โ€” C++ source code that should not be preprocessed.
  • file.m โ€” Objective-C source code. Note that you must link with the libobjc library to make an Objective-C program work.
  • file.mi โ€” Objective-C source code that should not be preprocessed.
  • file.mm, file.M โ€” Objective-C++ source code. Note that you must link with the libobjc library to make an Objective-C++ program work. Note that .M refers to a literal capital M.
  • file.mii โ€” Objective-C++ source code that should not be preprocessed.
  • file.h โ€” C, C++, Objective-C or Objective-C++ header file to be turned into a precompiled header (default), or C, C++ header file to be turned into an Ada spec (via the -fdump-ada-spec switch).
  • file.cc, file.cp, file.cxx, file.cpp, file.CPP, file.c++, file.C โ€” C++ source code that must be preprocessed. Note that in .cxx, the last two letters must both be literally x. Likewise, .C refers to a literal capital C.
  • file.mm, file.M โ€” Objective-C++ source code that must be preprocessed.
  • file.mii โ€” Objective-C++ source code that should not be preprocessed.
  • file.hh, file.H, file.hp, file.hxx, file.hpp, file.HPP, file.h++, file.tcc โ€” C++ header file to be turned into a precompiled header or Ada spec.
  • file.f, file.for, file.ftn, file.fi โ€” Fixed form Fortran source code that should not be preprocessed.
  • file.F, file.FOR, file.fpp, file.FPP, file.FTN โ€” Fixed form Fortran source code that must be preprocessed (with the traditional preprocessor).
  • file.f90, file.f95, file.f03, file.f08, file.fii โ€” Free form Fortran source code that should not be preprocessed.
  • file.F90, file.F95, file.F03, file.F08 โ€” Free form Fortran source code that must be preprocessed (with the traditional preprocessor).
  • file.go โ€” Go source code.
  • file.d โ€” D source code.
  • file.di โ€” D interface file.
  • file.dd โ€” D documentation code (Ddoc).
  • file.ads โ€” Ada source code file that contains a library unit declaration (a declaration of a package, subprogram, or generic, or a generic instantiation), or a library unit renaming declaration (a package, generic, or subprogram renaming declaration). Such files are also called specs.
  • file.adb โ€” Ada source code file containing a library unit body (a subprogram or package body). Such files are also called bodies.
  • file.s โ€” Assembler code.
  • file.S, file.sx โ€” Assembler code that must be preprocessed.
  • other โ€” An object file to be fed straight into linking. Any file name with no recognized suffix is treated this way.

You can specify the input language explicitly with the -x option:

  • -x language โ€” okay bestie, this one lets you spill the tea on what language your next input files are written in, so gcc doesn't have to guess from the file name suffix ๐Ÿ”ฎ It sticks for every input file after it until the next -x shows up. Your choices for language are:
    • c, c-header, cpp-output
    • c++, c++-header, c++-system-header, c++-user-header, c++-cpp-output
    • objective-c, objective-c-header, objective-c-cpp-output
    • objective-c++, objective-c++-header, objective-c++-cpp-output
    • assembler, assembler-with-cpp
    • ada
    • d
    • f77, f77-cpp-input, f95, f95-cpp-input
    • go
  • -x none โ€” the main character move to undo all that ๐Ÿ’… It turns off any language specification, so the files after it get handled by their file name suffixes again, exactly like -x never existed. โœจ

Okay so if you only want some of the compilation stages ๐Ÿงš, you can use -x (or filename suffixes) to tell gcc where to start, and then pick one of -c, -S, or -E to say where it should stop. Heads up though, some combos (like -x cpp-output -E) literally make gcc do nothing at all ๐Ÿ’€

  • -c โ€” compile or assemble the source files, but don't link ๐ŸŒธ The linking stage just gets skipped, and you end up with an object file for each source file.
    • By default, the object file name for a source file is made by swapping the suffix .c, .i, .s, etc. for .o.
    • Unrecognized input files, which don't need compiling or assembling, get ignored.
  • -S โ€” stop after the compilation proper and don't assemble ๐Ÿฆ‹ You get an assembler code file for each non-assembler input file you gave it.
    • By default, the assembler file name is made by swapping the suffix .c, .i, etc. for .s.
    • Input files that don't need compilation are ignored.
  • -E โ€” stop after preprocessing and skip the compiler proper ๐Ÿ“ The preprocessed source code gets sent to the standard output.
    • Input files that don't need preprocessing are ignored.
  • -o file โ€” put the primary output into file ๐Ÿ’– This works for whatever you're making: an executable, an object file, an assembler file, or preprocessed C code.
    • If you don't specify -o, here's where things land: an executable goes in a.out, the object file for source.suffix goes in source.o, its assembler file goes in source.s, a precompiled header file goes in source.suffix.gch, and all the preprocessed C source gets printed to standard output.

Okay, the tea is that -o only names the primary output, but it also changes what your auxiliary and dump outputs get called ๐Ÿ‘€ See the examples below for the full picture. Unless you override it, both auxiliary and dump outputs get dropped into the same directory as the primary output. For auxiliary outputs, the input file's suffix gets swapped for the suffix of the auxiliary file type. For dump outputs, the dump file's suffix gets tacked onto the input file suffix. In compilation commands, the base name of both auxiliary and dump outputs is the primary output's base name. In compile and link commands, the primary output name (minus the executable suffix) gets combined with the input file name. If both share the same base name, ignoring the suffix, the result is just that base name. Otherwise they get smooshed together with a dash in between ๐Ÿซถ

gcc -c foo.c ...

This uses foo.o as the primary output and puts the aux outputs and dumps right next to it. For example, you'd get the aux file foo.dwo for -gsplit-dwarf, and the dump file foo.c.???r.final for -fdump-rtl-final โœจ

If you explicitly name a non-linker output file, aux and dump files take the same base name by default:

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

This names the aux outputs dir/foobar.* and the dump outputs dir/foobar.c.* ๐ŸŒˆ

A linker output does things a little differently, prefixing the aux and dump outputs instead:

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

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

The one exception is when the executable shares its base name with the single input:

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

In this case the aux outputs are named dir/foo.* and the dump outputs are named dir/foo.c.* ๐ŸŽ€

Want more control over where these land? You can adjust the location and names of auxiliary and dump outputs with -dumpbase, -dumpbase-ext, -dumpdir, -save-temps=cwd, and -save-temps=obj ๐Ÿ”ฅ

  • -dumpbase dumpbase โ€” this sets the base name for auxiliary and dump output files ๐Ÿง It does not touch the name of the primary output. Intermediate outputs, if you choose to keep them, aren't considered primary outputs. They count as auxiliary outputs instead.
gcc -save-temps -S foo.c

This one saves the (no longer) temporary preprocessed file as foo.i, then compiles to the (implied) output file foo.s. Meanwhile:

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

This preprocesses to save-foo.i, compiles to save-foo.s (which is now an intermediate, so it counts as an auxiliary output), and then assembles to the (implied) output file foo.o ๐Ÿฆ‹

Without this option, dump and aux files take their names from the input file, or from the (non-linker) output file if you explicitly gave one. Dump output files, like the ones requested by -fdump-* options, keep the input name suffix. Aux output files, like the ones requested by other non-dump options (for example -save-temps, -gsplit-dwarf, and -fcallgraph-info), drop it.

You can get similar suffix differentiation for dump and aux outputs with an explicitly given -dumpbase basename.suf by also specifying -dumpbase-ext .suf ๐Ÿซถ

If dumpbase is explicitly given with any directory component, then any dumppfx specification (like -dumpdir or -save-temps=*) gets ignored. Instead of being appended to it, dumpbase fully overrides it:

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

This creates aux and dump outputs named alt/foo.*, ignoring dir/ from -o, the ./ prefix implied by -save-temps=cwd, and pfx- from -dumpdir ๐Ÿ’œ

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

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

This creates foo.o and bar.o as primary outputs. To avoid overwriting the aux and dump outputs, it uses the dumpbase as a prefix, so the outputs are named main-foo.* and main-bar.* ๐ŸŒธ

An empty string given as dumpbase avoids the influence of the output basename on naming aux and dump outputs during compilation, so the default values get computed instead:

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

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

The empty-string dumpbase doesn't stop the output basename from being used for outputs during linking, though:

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

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

  • -dumpbase-ext auxdropsuf โ€” when forming the name of an auxiliary output file (but not a dump output), this drops the trailing auxdropsuf from dumpbase before any suffixes get appended ๐Ÿ’– If you don't specify it, it defaults to the suffix of a default dumpbase. That means the input file's suffix when -dumpbase isn't on the command line, or when the dumpbase is combined with a dumppfx.
gcc foo.c -c -o dir/foo.o -dumpbase x-foo.c -dumpbase-ext .c ...

This creates dir/foo.o as the main output and generates aux outputs in dir/x-foo.*. They take the location of the primary output and drop the .c suffix from the dumpbase. Dump outputs keep the suffix, so they land in dir/x-foo.c.* โœจ

This option gets ignored if it doesn't match the suffix of a specified dumpbase. The one exception is when it's used as an alternative to the executable suffix while appending the linker output base name to dumppfx, as described below:

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

This creates main.out as the primary output. To avoid overwriting the aux and dump outputs, it uses the executable name minus auxdropsuf as a prefix. So the aux outputs get named main-foo.* and main-bar.*, and the dump outputs get named main-foo.c.* and main-bar.c.* ๐Ÿฆ‹

  • -dumpdir dumppfx โ€” when forming the name of an auxiliary or dump output file, this uses dumppfx as a prefix ๐ŸŒˆ
gcc -dumpdir pfx- -c foo.c ...

This creates foo.o as the primary output and names the auxiliary outputs pfx-foo.*. It combines the given dumppfx with the default dumpbase, which comes from the default primary output, which in turn comes from the input name. Dump outputs also take the input name suffix, so they become pfx-foo.c.* ๐Ÿ’…

If you want to use dumppfx as a directory name, it has to end with a directory separator:

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

This creates obj/bar.o as the primary output and names the auxiliary outputs dir/bar.*. It combines the given dumppfx with the default dumpbase derived from the primary output name. Dump outputs take the input name suffix too, so they land in dir/bar.c.* ๐ŸŽ€

By default it points at the location of the output file, unless the output file is a special file like /dev/null. The options -save-temps=cwd and -save-temps=obj override this default, just like an explicit -dumpdir option does. If you give multiple of these, the last one wins:

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

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

When you compile from multiple input files and -dumpbase is set, the dumpbase name gets glued onto the dumppfx ๐Ÿ’…. You drop an auxdropsuf suffix and add a dash. If the name has any directory components, it straight up overrides the explicit or defaulted dumppfx instead ๐Ÿซถ. Either way, each compilation gets differently-named aux and dump outputs โœจ, which is giving organized.

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

This one sends auxiliary dumps to dir/pfx-main-foo.* and dir/pfx-main-bar.*, because dumpbase- gets appended to dumppfx ๐Ÿฆ‹. The dump outputs keep the input file suffix instead: dir/pfx-main-foo.c.* and dir/pfx-main-bar.c.*, respectively.

Now compare that with the single-input version:

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

Here -dumpbase is applied to one source, so it doesn't compute and append a separate dumpbase per input file ๐Ÿ™ˆ. Its auxiliary and dump outputs just go in dir/pfx-main.*.

When you compile and then link from multiple input files, a defaulted or explicitly specified dumppfx also gets the dumpbase- transformation from above (like the foo.c and bar.c compile, but without -c). If you don't give -dumpdir or -dumpbase, the linker output base name gets the same treatment instead. You subtract auxdropsuf if it's specified, or the executable suffix otherwise, then add a dash and append the result to the default dumppfx. But heads up, this is different from the earlier linking cases:

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

does not append the output name main to dumppfx, because -dumpdir is explicitly specified ๐Ÿ’€. The vibe is that an explicit dumppfx can already include the output name in the prefix if you want it there โœจ. Only an explicitly specified -dumpbase gets combined with it, so a meaningful option doesn't just get tossed out ๐Ÿ’œ.

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

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

Auxiliary outputs are named foo.*, and dump outputs foo.c.*, in the current working directory, as ultimately requested by -save-temps=cwd ๐ŸŒธ.

Summing it all up for an intuitive (though slightly imprecise) data flow ๐Ÿง : the primary output name gets split into a directory part and a basename part. dumppfx is set to the directory part, unless -dumpdir or -save-temps=* overrides it. dumpbase is set to the basename, unless -dumpbase overrides it. If there are multiple inputs or linking, this dumpbase may be combined with dumppfx and taken from each input file. Auxiliary output names for each input are formed by combining dumppfx, dumpbase minus its suffix, and the auxiliary output suffix. Dump output names only differ in that they keep the suffix from dumpbase.

When it comes to auxiliary and dump outputs created during LTO recompilation, a combination of dumppfx and dumpbase gets passed down to lto-wrapper as a -dumpdir option ๐Ÿ’…. This happens whether it's given or derived from the linker output name (but not from the inputs), even in cases where that combination wouldn't otherwise get used. A trailing period replaces the compiler-added dash, if there is one. Since lto-wrapper is involved in linking, it doesn't normally get any -dumpbase or -dumpbase-ext, and it ignores them if it does.

When running sub-compilers, lto-wrapper appends the LTO stage names to the dumppfx it received. It makes sure that prefix contains a directory component, so it overrides any -dumpdir. Then it passes that along as -dumpbase to the sub-compilers ๐ŸŽ€.

  • -v โ€” Prints the commands executed to run each stage of compilation to standard error. It also prints the version number of the compiler driver program, plus the version of the preprocessor and the compiler proper ๐ŸŒˆ.
  • -### โ€” Like -v, except the commands never actually run, and arguments get quoted unless they only contain alphanumeric characters or "./-_". This is perfect for shell scripts that want to capture the driver-generated command lines ๐Ÿงš.
  • --help โ€” 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 display the options they accept ๐Ÿซถ. If -Wextra was specified prior to --help on the command line, options with no documentation attached get displayed too ๐Ÿ”.
  • --target-help โ€” Prints a description of the target-specific command-line options for each tool to standard output. For some targets, extra target-specific information may also get printed โœจ.

--help={class|[^]qualifier}[,...]

Print (to standard output) a description of the command-line options the compiler understands that fit into all of the specified classes and qualifiers ๐Ÿ’–. These are the supported classes:

  • optimizers โ€” Displays all of the optimization options the compiler supports ๐Ÿš€.
  • warnings โ€” Displays all of the options that control warning messages the compiler produces โš ๏ธ.
  • target โ€” Displays target-specific options. Unlike --target-help, target-specific options of the linker and assembler are not displayed, because those tools don't currently support the extended --help= syntax ๐Ÿ™ƒ.
  • params โ€” Displays the values recognized by the --param option ๐Ÿ”ข.
  • language โ€” Displays the options supported for language, where language is the name of one of the languages supported in this version of GCC. If an option is supported by all languages, you need to select the common class ๐ŸŒ.
  • common โ€” Displays the options common to all languages ๐Ÿค.

These are the supported qualifiers:

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

Thus, for example, to display all the undocumented target-specific switches the compiler supports, use:

--help=target,undocumented

The sense of a qualifier can be flipped by prefixing it with the ^ character. So, for example, to display all binary warning options (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 ๐Ÿ™….

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

--help=target,optimizers

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

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

Here 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 โ€” Normally, gcc exits with the code 1 if any phase of the compiler returns a non-success return code. With -pass-exit-codes, it returns the numerically highest error produced by any phase that returned an error indication instead. The C, C++, and Fortran front ends return 4 if they run into 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 ๐Ÿงƒ.
  • -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, and so on ๐ŸŽฏ. You can specify more than one -specs=file on the command line. They get processed in order, from left to right ๐Ÿ‘€.
  • -wrapper โ€” Invokes all subcommands under a wrapper program. The name of the wrapper program and its parameters get passed as a comma-separated list ๐ŸŽ:
gcc -c t.c -wrapper gdb,--args

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

  • -ffile-prefix-map=old=new โ€” okay so this one is a whole glow-up for file paths ๐Ÿ—บ๏ธโœจ When you compile files living in directory old, any references to them in the compilation result get recorded as if they lived in new instead. Specifying it is equivalent to specifying all the individual -f*-prefix-map options at once ๐Ÿ’… It's giving reproducible builds that are location independent ๐Ÿฆ‹ Directories referenced by directives are not affected by these options. See also -fmacro-prefix-map, -fdebug-prefix-map, -fprofile-prefix-map and -fcanon-prefix-map ๐ŸŒธ
  • -fcanon-prefix-map โ€” ngl this one is a detail-oriented queen ๐Ÿ‘‘ Normally, for the -f*-prefix-map options, the old prefix gets compared against the filename that would normally be referenced using a textual comparison. That means ignoring character case on case-insensitive filesystems, and treating slashes and backslashes as equal on DOS-based filesystems. -fcanon-prefix-map makes those comparisons happen on canonicalized paths of old and the referenced filename instead ๐Ÿงš
  • -fplugin=name.so โ€” load the plugin code from the file name.so ๐Ÿ”Œ It's assumed to be a shared object that the compiler will dlopen. The base name of the shared object is used to identify the plugin when parsing arguments (see -fplugin-arg-name-key=value below) ๐Ÿ’– Each plugin should define the callback functions specified in the Plugins API โœจ
  • -fplugin-arg-name-key=value โ€” defines an argument called key with a value of value for the plugin called name ๐ŸŽ€
  • -fdump-ada-spec[-slim] โ€” for C and C++ source and include files, generate corresponding Ada specs ๐Ÿ’…๐ŸŒˆ
  • -fada-spec-parent=unit โ€” when used with -fdump-ada-spec[-slim] above, this generates Ada specs as child units of the parent unit ๐Ÿฆ‹
  • -fdump-go-spec=file โ€” for input files in any language, generate corresponding Go declarations in file ๐Ÿน This makes Go const, type, var, and func declarations, which is lowkey a really useful way to start writing a Go interface to code written in some other language ๐Ÿซถ
  • @file โ€” read command-line options from file ๐Ÿ“œ The options read get inserted right where the original @file option was. If file doesn't exist or can't be read, then the option gets treated literally and is not removed ๐Ÿ˜ญ

Options inside file are separated by whitespace. If you want a whitespace character inside an option, wrap the entire option in either single or double quotes ๐ŸŽ€ Any character (including a backslash) can be included by prefixing it with a backslash ๐Ÿ’œ The file can even contain more @file options of its own, and those get processed recursively ๐ŸŒ€


โœจ Compiling C++ Programs โœจ

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

However, using gcc does not add the C++ library ๐Ÿ˜ฌ g++ is a program that calls GCC and automatically specifies linking against the C++ library, so it's the main character for C++ ๐Ÿ‘‘ It treats .c, .h and .i files as C++ source files instead of C source files, unless -x is used ๐Ÿ“ This program is also useful when precompiling a C header file with a .h extension for use in C++ compilations ๐Ÿงš On many systems, g++ is also installed with the name c++ โœจ

When you compile C++ programs, you can specify many of the same command-line options you use for compiling programs in any language ๐ŸŒˆ You can also use 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 ๐Ÿ’…

This turns off certain GCC features that are incompatible with ISO C90 (when compiling C code), or with standard C++ (when compiling C++ code) ๐Ÿ™ˆ Examples are 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 would not want to use them in an ISO C program, of course, but it's useful to put them in header files that might be 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. This is to avoid interfering with any programs that might use these names for other things ๐Ÿ›ก๏ธ

Functions that are normally built in but do not 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++ ๐Ÿง

The compiler can accept several base standards, such as c90 or c++98, and GNU dialects of those standards, such as gnu90 or gnu++98 ๐ŸŒˆ When a base standard is specified, the compiler accepts all programs following that standard, plus those using GNU extensions that don't contradict it. For example, -std=c90 turns off certain GCC features that are incompatible with ISO C90, such as the asm and typeof keywords ๐Ÿ™ƒ It does not turn off other GNU extensions that have no meaning in ISO C90, such as omitting the middle term of a ?: expression ๐Ÿญ

On the other hand, when a GNU dialect of a standard is specified, all features supported by the compiler are enabled, even when those features change the meaning of the base standard ๐Ÿ˜ค As a result, some strict-conforming programs may get rejected ๐Ÿšจ The particular standard is used by -Wpedantic to identify which features are GNU extensions given that version of the standard. For example, -std=gnu90 -Wpedantic warns about C++ style // comments, while -std=gnu99 -Wpedantic does not ๐Ÿ•ต๏ธโ€โ™€๏ธ

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

  • c90, c89, iso9899:1990 โ€” supports all ISO C90 programs (certain GNU extensions that conflict with ISO C90 are disabled). Same as -ansi for C code ๐Ÿ’–
  • iso9899:199409 โ€” ISO C90 as modified in amendment 1 ๐ŸŒท
  • c99, c9x, iso9899:1999, iso9899:199x โ€” ISO C99 ๐ŸŒธ This standard is substantially completely supported, modulo bugs and floating-point issues (mainly, but not entirely, relating to optional C99 features from Annexes F and G). See <https://gcc.gnu.org/c99status.html> for more information ๐Ÿ“– The names c9x and iso9899:199x are deprecated ๐Ÿฅ€
  • c11, c1x, iso9899:2011 โ€” ISO C11, the 2011 revision of the ISO C standard ๐ŸŽ‰ This standard is substantially completely supported, modulo bugs, and floating-point issues (mainly, but not entirely, relating to optional C11 features from Annexes F and G). It also covers the optional Annexes K (Bounds-checking interfaces) and L (Analyzability) ๐Ÿค“ The name c1x is deprecated ๐Ÿฅ€
  • c17, c18, iso9899:2017, iso9899:2018 โ€” ISO C17, the 2017 revision of the ISO C standard (published in 2018) ๐Ÿ“ This standard is the same as C11 except for corrections of defects (all of which are also applied with -std=c11) and a new value of __STDC_VERSION__, so it's supported to the same extent as C11 ๐Ÿ’…
  • c23, c2x, iso9899:2024 โ€” ISO C23, the 2023 revision of the ISO C standard (expected to be published in 2024) ๐Ÿ”ฎ Support for this version is experimental and incomplete ๐Ÿงช The name c2x is deprecated ๐Ÿฅ€
  • gnu90, gnu89 โ€” GNU dialect of ISO C90 (including some C99 features) ๐ŸŒˆ
  • gnu99, gnu9x โ€” GNU dialect of ISO C99. The name gnu9x is deprecated ๐Ÿฅ€
  • gnu11, gnu1x โ€” GNU dialect of ISO C11. The name gnu1x is deprecated ๐Ÿฅ€
  • gnu17, gnu18 โ€” GNU dialect of ISO C17. This is the default for C code ๐Ÿ‘‘
  • gnu23, gnu2x โ€” the next version of the ISO C standard, still under development, plus GNU extensions ๐Ÿšง Support for this version is experimental and incomplete ๐Ÿงช The name gnu2x is deprecated ๐Ÿฅ€
  • c++98, c++03 โ€” the 1998 ISO C++ standard plus the 2003 technical corrigendum and some additional defect reports. Same as -ansi for C++ code ๐Ÿ’œ
  • gnu++98, gnu++03 โ€” GNU dialect of -std=c++98 ๐ŸŒธ
  • c++11, c++0x โ€” the 2011 ISO C++ standard plus amendments ๐ŸŽถ The name c++0x is deprecated ๐Ÿฅ€
  • gnu++11, gnu++0x โ€” GNU dialect of -std=c++11. The name gnu++0x is deprecated ๐Ÿฅ€
  • c++14, c++1y โ€” the 2014 ISO C++ standard plus amendments. The name c++1y is deprecated ๐Ÿฅ€
  • gnu++14, gnu++1y โ€” GNU dialect of -std=c++14. The name gnu++1y is deprecated ๐Ÿฅ€
  • c++17, c++1z โ€” the 2017 ISO C++ standard plus amendments. The name c++1z is deprecated ๐Ÿฅ€
  • gnu++17, gnu++1z โ€” GNU dialect of -std=c++17. This is the default for C++ code ๐Ÿ‘‘ The name gnu++1z is deprecated ๐Ÿฅ€
  • c++20, c++2a โ€” the 2020 ISO C++ standard plus amendments ๐Ÿš€ Support is experimental, and could change in incompatible ways in future releases โš ๏ธ The name c++2a is deprecated ๐Ÿฅ€
  • gnu++20, gnu++2a โ€” GNU dialect of -std=c++20. Support is experimental, and could change in incompatible ways in future releases โš ๏ธ The name gnu++2a is deprecated ๐Ÿฅ€
  • c++2b, c++23 โ€” okay bestie, this is the next revision of the ISO C++ standard, planned for 2023 ๐Ÿ“…โœจ Support is highly experimental and will almost certainly change in incompatible ways in future releases ๐Ÿ’€
  • gnu++2b, gnu++23 โ€” the GNU dialect of -std=c++2b. Same energy: highly experimental and almost certainly going to change in incompatible ways later on ๐Ÿ™ˆ
  • c++2c, c++26 โ€” the next revision of the ISO C++ standard, planned for 2026 ๐Ÿฆ‹ Also highly experimental, and it will almost certainly change in incompatible ways in future releases. Don't get too attached ๐Ÿฅบ
  • gnu++2c, gnu++26 โ€” the GNU dialect of -std=c++2c ๐Ÿ’œ Highly experimental, and almost certainly going to change in incompatible ways in future releases.
  • -aux-info filename โ€” this one is giving documentation energy ๐Ÿ“ It outputs prototyped declarations for all functions declared and/or defined in a translation unit, including the ones in header files, into the given filename. It's silently ignored in any language other than C, so don't stress if nothing happens in C++ ๐Ÿซถ

The file also drops comments that tell you where each declaration came from (source file and line). The character right after the line number and colon tells you whether the declaration was implicit, prototyped or unprototyped: I for implicit, N for new (prototyped) or O for old (unprototyped). The character after that tells you whether it came from a declaration or a definition: C for declaration or F for definition ๐Ÿ“ For function definitions, you also get a K&R-style list of arguments followed by their declarations, all inside comments, placed after the declaration.

  • -fno-asm โ€” the keyword cleanup switch ๐Ÿงน This stops asm, inline and typeof from being treated as keywords, so your code can use those words as identifiers. You can use __asm__, __inline__ and __typeof__ instead. In C, -ansi implies -fno-asm.

In C++, inline is a standard keyword and isn't affected by this switch. If you want, you can use -fno-gnu-keywords instead, which disables typeof but leaves asm and inline alone ๐Ÿ’… In C99 mode (-std=c99 or -std=gnu99), this switch only affects asm and typeof, since inline is a standard keyword in ISO C99. In C23 mode (-std=c23 or -std=gnu23), it only affects asm, since typeof is a standard keyword in ISO C23.

  • -fno-builtin, -fno-builtin-function โ€” this one's a bit of a plot twist ๐ŸŽญ It stops GCC from recognizing built-in functions that don't begin with __builtin_ as a prefix.

GCC normally generates special code for certain built-in functions so they run more efficiently. For example, calls to alloca may become single instructions that adjust the stack directly, and calls to memcpy may become inline copy loops. The resulting code is often smaller and faster ๐Ÿš€ But since the function calls don't show up as calls anymore, you can't set a breakpoint on them, and you can't change what the functions do by linking against a different library. Also, when a function is recognized as built-in, GCC may use info about it to warn about problems with calls to it, or to generate better code, even if the result still contains calls to that function. For instance, you get warnings with -Wformat for bad calls to printf when printf is built in and strlen is known not to modify global memory.

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

#define abs(n)          __builtin_abs ((n))
#define strcpy(d, s)    __builtin_strcpy ((d), (s))
  • -fcond-mismatch โ€” lowkey chaotic ๐ŸŒ€ It allows conditional expressions with mismatched types in the second and third arguments. The value of such an expression is void. This option is not supported for C++ ๐Ÿ™…โ€โ™€๏ธ
  • -ffreestanding โ€” assert the vibe: freestanding ๐Ÿ•๏ธ It asserts that compilation targets a freestanding environment, which 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.
  • -fgimple โ€” experimental era ๐Ÿงช It enables parsing of function definitions marked with __GIMPLE. This is an experimental feature that allows unit testing of GIMPLE passes.
  • -fgnu-tm โ€” transactional memory, but make it spicy ๐Ÿ”ฅ When you specify -fgnu-tm, the compiler generates code for the Linux variant of Intel's current Transactional Memory ABI specification document (Revision 1.1, May 6 2009). This is an experimental feature, and its interface may change in future versions of GCC as the official specification changes. Please note that not all architectures are supported for this feature โš ๏ธ

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

Note that the transactional memory feature is not supported with non-call exceptions (-fnon-call-exceptions) ๐Ÿ’€

  • -fgnu89-inline โ€” the throwback option ๐Ÿ“ผ It tells GCC to use the traditional GNU semantics for inline functions when in C99 mode.

Using this option is roughly equivalent to adding the gnu_inline function attribute to all inline functions โœจ

The option -fno-gnu89-inline explicitly tells GCC to use the C99 semantics for inline when in C99 or gnu99 mode. In other words, it specifies the default behavior. This option is not supported in -std=c90 or -std=gnu90 mode.

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

  • -fhosted โ€” the opposite of freestanding, obviously ๐Ÿ  It asserts that compilation targets a hosted environment, which implies -fbuiltin. A hosted environment is one where the entire standard library is available, and where main has a return type of int. Examples are nearly everything except a kernel ๐ŸŒธ This is equivalent to -fno-freestanding.
  • -flax-vector-conversions โ€” not for new code, bestie ๐Ÿšซ It allows implicit conversions between vectors with differing numbers of elements and/or incompatible element types. This option should not be used for new code.
  • -fms-extensions โ€” Microsoft header energy ๐ŸชŸ It accepts some non-standard constructs that are used in Microsoft header files.

In C++ code, this allows member names in structures to be similar to 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 ๐Ÿซ  Note that this option is off for all targets except for x86 targets using ms-abi.

  • -foffload=disable, -foffload=default, -foffload=target-list โ€” offload era unlocked ๐Ÿš€ This decides which OpenMP and OpenACC offload targets get code generated for them. The default behavior, which is the same as -foffload=default, is to generate code for all supported offload targets. -foffload=disable generates code only for the host fallback, while -foffload=target-list generates code only for the specified comma-separated list of offload targets.

Offload targets are specified in GCC's internal target-triplet format. To see the list of configured offload targets, run the compiler with -v. They're listed under OFFLOAD_TARGET_NAMES ๐Ÿ‘€

  • -foffload-options=options, -foffload-options=target-triplet-list=options โ€” pass the good stuff along ๐ŸŽ€ With -foffload-options=options, GCC passes the specified options to the compilers for all enabled offloading targets. If you want options that only apply to a specific target or targets, use the -foffload-options=target-list=options form. The target-list is a comma-separated list in the same format as for the -foffload= option.

Typical command lines look like this:

-foffload-options='-fno-math-errno -ffinite-math-only' -foffload-options=nvptx-none=-latomic
-foffload-options=amdgcn-amdhsa=-march=gfx906
  • -fopenacc โ€” OpenACC is giving main character ๐ŸŽฌ It enables handling of OpenACC directives: #pragma acc in C/C++, and !$acc in free-form Fortran, plus !$acc, c$acc and *$acc in fixed-form Fortran. When you specify -fopenacc, the compiler generates accelerated code according to the OpenACC Application Programming Interface v2.6 (https://www.openacc.org). This option implies -pthread, so it's only supported on targets that have support for -pthread โœจ
  • -fopenacc-dim=geom โ€” set your compute dimensions ๐Ÿ“ This specifies default compute dimensions for parallel offload regions that don't explicitly specify their own. The geom value is a triple of ':'-separated sizes, in order 'gang', 'worker' and 'vector'. You can leave a size out to use a target-specific default value ๐Ÿงš
  • -fopenmp โ€” the big OpenMP moment ๐ŸŒˆ It enables handling of OpenMP directives: #pragma omp, [[omp::directive(...)]], [[omp::sequence(...)]] and [[omp::decl(...)]] in C/C++, and !$omp in Fortran. It also enables the conditional compilation sentinel !$ in Fortran. In fixed source form Fortran, the sentinels can also start with c or *.

When you specify -fopenmp, the compiler generates parallel code according to the OpenMP Application Program Interface v4.5 (https://www.openmp.org) ๐Ÿ’– This option implies -pthread, so it's only supported on targets that have support for -pthread. -fopenmp also implies -fopenmp-simd ๐Ÿซถ

  • -fopenmp-simd โ€” the simd-only starter pack ๐Ÿ’œ It enables handling of OpenMP's simd, declare simd, declare reduction, assume, ordered, scan and loop directives, plus combined or composite directives that have simd as a constituent. That covers #pragma omp, [[omp::directive(...)]], [[omp::sequence(...)]] and [[omp::decl(...)]] in C/C++, and !$omp in Fortran. It also enables the conditional compilation sentinel !$ in Fortran. In fixed source form Fortran, the sentinels can also start with c or *. Other OpenMP directives are ignored ๐Ÿ™ˆ

Unless -fopenmp is also specified, the loop region binds to the current task region, no matter what bind clause you gave it ๐Ÿ’…

โœจ -fopenmp-target-simd-clone ๐Ÿฆ‹

Okay so, GCC already makes SIMD clones for functions marked with declare simd, but bestie, it also makes clones for functions marked with the OpenMP declare target directive that are suitable for vectorization, as long as this option is in effect ๐Ÿ’…. The device-type can be none, host, nohost, or any. Those map to the keywords for the device_type clause of declare target, and clones get generated for the intersection of the devices you specify ๐Ÿ”ฅ.

Fun fact: -fopenmp-target-simd-clone is the same as -fopenmp-target-simd-clone=any, and -fno-openmp-target-simd-clone is the same as -fopenmp-target-simd-clone=none ๐ŸŒธ.

At -O2 and higher (but not -Os or -Og), this optimization defaults to -fopenmp-target-simd-clone=nohost. Otherwise it's disabled by default, so it's not going to sneak up on you ๐Ÿ™ˆ.

โœจ -fpermitted-flt-eval-methods=style ๐ŸŒˆ

ISO/IEC TS 18661-3 adds brand-new permissible values for FLT_EVAL_METHOD. These say that operations and constants with a semantic type that is an interchange or extended format should be evaluated to the precision and range of that type ๐Ÿงš. The new values are a superset of what C99/C11 allows, and C99/C11 doesn't say what any other positive value of FLT_EVAL_METHOD means. So code that conforms to C11 may never have been written with the new values in mind ๐Ÿ˜ญ.

This flag decides whether the compiler allows only the FLT_EVAL_METHOD values from C99/C11, or the extended set from ISO/IEC TS 18661-3. The style is either c11 or ts-18661-3, whichever fits ๐Ÿ’–.

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

The -fdeps-* options are the squad that pulls structured dependency information out of a source file. That means figuring out what resources from other source files the source needs to compile, plus what resources the source itself provides ๐Ÿ‘‘. You can use that info to add dependencies between compilation rules based on what the sources actually contain, instead of making the build tools spell it all out too ๐Ÿซถ.

โœจ -fdeps-file=file ๐ŸŽ€

This is where the structured dependency information gets written ๐Ÿ“.

โœจ -fdeps-format=format ๐Ÿ“

This sets the format for structured dependency information. p1689r5 is the only supported format right now ๐Ÿ’…. Heads up: when this argument is specified, the output of -MF gets stripped of some information (namely C++ modules). That's so it doesn't use extended makefile syntax that most tools won't understand ๐Ÿ˜ญ.

โœจ -fdeps-target=file ๐Ÿฆ‹

This is the -MT equivalent for structured dependency information. It names the target that will eventually need any required resources, and that will provide any resources extracted from the source that other sources might need ๐ŸŒธ.

โœจ -fplan9-extensions ๐Ÿงš

This accepts some non-standard constructs used in Plan 9 code ๐Ÿ“.

It enables -fms-extensions. It also lets you pass pointers to structures with anonymous fields to functions that expect pointers to elements of the field's type, and it lets you refer to anonymous fields declared using a typedef ๐Ÿ’œ. Note that this is only supported for C, not C++ ๐Ÿ™ˆ.

โœจ -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, a bit-field like that is signed, which makes sense since basic integer types like int are signed too ๐Ÿซถ.

โœจ -fsigned-char ๐ŸŒˆ

Lets the type char be signed, just like signed char โญ.

This is equivalent to -fno-unsigned-char, which is the negative form of -funsigned-char. And -fno-signed-char is equivalent to -funsigned-char ๐Ÿ’….

โœจ -funsigned-char ๐Ÿ‘‘

Lets the type char be unsigned, just like unsigned char ๐ŸŒธ.

Every kind of machine has a default for what char should be. It's either like unsigned char or like signed char by default ๐Ÿฆ‹.

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

The type char is always a distinct type from both signed char and unsigned char, even though it always behaves just like one of those two ๐Ÿ™ˆ.

โœจ -fstrict-flex-arrays (C and C++ only) and -fstrict-flex-arrays=level (C and C++ only) ๐ŸŽ€

These control when the trailing array of a structure gets treated as a flexible array member for the purpose of accessing its elements. The value of level sets how strict that is ๐Ÿ’–.

-fstrict-flex-arrays is the same as -fstrict-flex-arrays=3, which is the strictest. Every trailing array of a structure is treated as a flexible array member ๐Ÿ”ฅ.

The negative form, -fno-strict-flex-arrays, is the same as -fstrict-flex-arrays=0, which is the least strict. Here, a trailing array only counts as a flexible array member when it's declared as one per the C99 standard and onward ๐Ÿงš.

The possible values of level are the same as for the strict_flex_array attribute. You can also control this for one specific trailing array field of a structure by using the variable attribute strict_flex_array ๐Ÿ“.

Also, the -fstrict_flex_arrays option interacts with the -Wstrict-flex-arrays option ๐Ÿซถ.

โœจ -fsso-struct=endianness ๐Ÿ’œ

This 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, which is the native endianness of the target and the default โœจ. This option isn't supported for C++ ๐Ÿ™ˆ.

โš ๏ธ Bestie, be careful here! Using -fsso-struct causes GCC to generate code that is NOT binary compatible with code generated without it, if the endianness you specified isn't the native endianness of the target ๐Ÿ’€.

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

This section covers the command-line options that only matter 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 that example, only -fstrict-enums is an option meant only for C++ programs ๐Ÿงš. You can use the other options with any language GCC supports ๐Ÿซถ.

Some options for compiling C programs, such as -std, are also relevant for C++ programs ๐Ÿ”ฅ.

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

โœจ -fabi-version=n ๐Ÿฆ‹

Uses version n of the C++ ABI. The default is version 0 ๐ŸŒธ.

Version 0 refers to the version that conforms most closely to the C++ ABI specification. So the ABI you get with version 0 will change between versions of G++ as ABI bugs get fixed ๐Ÿ˜ญ.

Here's the version rundown, bestie ๐Ÿ’…:

  • Version 1 โ€” the first version of the C++ ABI, which first appeared in G++ 3.2 ๐ŸŽ€.
  • Version 2 โ€” 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 that are declared in different scopes, the mangling now changes starting with the twelfth occurrence. It also implies -fnew-inheriting-ctors ๐Ÿซถ.
  • Version 12 โ€” first appeared in G++ 8, and 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 from version 12 ๐Ÿ™Œ.
  • Version 14 โ€” first appeared in G++ 10, and corrects the mangling of the nullptr expression ๐ŸŒธ.
  • Version 15 โ€” first appeared in G++ 10.3, and corrects a G++ 10 ABI tag regression ๐Ÿฆ‹.
  • Version 16 โ€” first appeared in G++ 11, and changes the mangling of "__alignof__" so it's distinct from that of "alignof", plus dependent operator names ๐Ÿ’….
  • Version 17 โ€” first appeared in G++ 12, and fixes the layout of classes that inherit from aggregate classes with default member initializers in C++14 and up ๐Ÿ‘‘.
  • Version 18 โ€” first appeared in G++ 13, and fixes manglings of lambdas that have additional context ๐ŸŽ€.
  • Version 19 โ€” first appeared in G++ 14, and fixes manglings of structured bindings to include ABI tags ๐ŸŒˆ.

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 whenever it defines a symbol with an incorrect mangled name ๐Ÿ”ฅ. This switch specifies which ABI version to use for that alias ๐Ÿซถ.

okay so with -fabi-version=0 (the default) this one defaults to 13, which is GCC 8.2 compatibility ๐Ÿ’… . if you explicitly pick a different ABI version, it defaults to 0 instead โœจ . need compatibility with GCC versions 3.2 through 4.9? then use -fabi-compat-version=2 ๐Ÿซถ

if you skip this option but do pass -Wabi=n, that version gets used for the compatibility aliases ๐Ÿฆ‹ . and if you pass this option alongside plain -Wabi (no version attached), the version from this option is what the warning uses ๐Ÿ”ฅ

-fno-access-control

turns off all access checking, full stop ๐Ÿ™…โ€โ™€๏ธ . this one is mainly handy for working around bugs in the access control code ๐Ÿ’€

-faligned-new

this is for C++17 new on types that need more alignment than void* ::operator new(std::size_t) provides ๐Ÿงš . you can pass a number like -faligned-new=32 to say how much alignment (in bytes) that function gives you, but honestly few people need to override the default of alignof(std::max_align_t) ๐Ÿ’–

it's on by default when you're using -std=c++17 โœจ

-fchar8_t, -fno-char8_t

bestie, this turns on char8_t support as adopted for C++20 ๐ŸŒˆ . you get a brand new char8_t fundamental type, the types of UTF-8 string and character literals change, there are new signatures for user-defined literals, standard library updates, and new __cpp_char8_t and __cpp_lib_char8_t feature test macros ๐Ÿ“š

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

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

and it introduces new signatures for user-defined literals:

int operator""_udl1(char8_t);
int v3 = u8'x'_udl1;
int operator""_udl2(const char8_t*, std::size_t);
int v4 = u8"text"_udl2;
template<typename T, T...> int operator""_udl3();
int v5 = u8"text"_udl3;
โš ๏ธ heads up: the change to the types of UTF-8 string and character literals creates incompatibilities with ISO C++11 and later standards ๐Ÿ˜ญ . for example, this code is well-formed under ISO C++11, but it's ill-formed when -fchar8_t is specified:
const char *cp = u8"xx";// error: invalid conversion from
                        //        `const char8_t*' to `const char*'
int f(const char*);
auto v = f(u8"xx");     // error: invalid conversion from
                        //        `const char8_t*' to `const char*'
std::string s{u8"xx"};  // error: no matching function for call to
                        //        `std::basic_string<char>::basic_string()'
using namespace std::literals;
s = u8"xx"s;            // error: conversion from
                        //        `basic_string<char8_t>' to non-scalar
                        //        type `basic_string<char>' requested

-fcheck-new

this makes sure the pointer returned by operator new isn't null before you start poking at the storage it allocated ๐Ÿ” . honestly it's 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, running out of memory gets signalled by throwing std::bad_alloc ๐Ÿ’ฅ

see also new (nothrow) ๐Ÿซง

-fconcepts, -fconcepts-ts

this turns on support for the C++ Concepts feature, which lets you constrain template arguments ๐Ÿฆ‹ . with -std=c++20 and above, Concepts are part of the language standard, so -fconcepts defaults to on โœจ

some constructs that got allowed by the earlier C++ Extensions for Concepts Technical Specification, ISO 19217 (2015), but never made it into the standard can be enabled with -fconcepts-ts ๐Ÿงฉ

๐Ÿšจ -fconcepts-ts was deprecated in GCC 14 and may be removed in GCC 15. users are expected to convert their code to C++20 concepts, so start the glow-up now ๐Ÿ’…

-fconstexpr-depth=n

sets the max nested evaluation depth for C++11 constexpr functions to n ๐ŸŒ€ . you need a limit here to catch endless recursion during constant expression evaluation. the minimum the standard specifies is 512 ๐Ÿงฎ

-fconstexpr-cache-depth=n

sets the max nesting level of constexpr evaluation depth that gets cached to n ๐Ÿง  . it's a heuristic, so you're trading compilation speed (when the cache skips repeated calculations) against memory consumption (when the cache gets huge from highly recursive evaluations) โš–๏ธ . the default is 8. very few users are likely to want to adjust it, but if your code does heavy constexpr calculations, feel free to experiment and see which value works best for you ๐Ÿ’œ

-fconstexpr-fp-except

okay so Annex F of the C standard says IEC559 floating point exceptions hit at compile time should not stop compilation ๐Ÿค“ . C++ compilers have historically not followed that, and instead treat floating point division by zero as non-constant even though it has a well-defined value ๐Ÿ™ƒ . this flag tells the compiler to give Annex F priority over other rules saying a particular operation is undefined โœจ

constexpr float inf = 1./0.; // OK with -fconstexpr-fp-except

-fconstexpr-loop-limit=n

sets the max number of iterations for a loop in C++14 constexpr functions to n ๐Ÿ” . a limit is needed to catch infinite loops during constant expression evaluation. the default is 262144 (1<<18)

-fconstexpr-ops-limit=n

sets the max number of operations during a single constexpr evaluation ๐Ÿงฎ . even when a single loop's iterations are capped by the limit above, you can still get stuck: if there are several nested loops, each with lots of iterations that are still under that limit, or if a loop body (or even code outside a loop) has too many expressions to evaluate, the constexpr evaluation might take too long ๐Ÿ˜ฉ . the default is 33554432 (1<<25)

-fcontracts

this enables experimental support for the C++ Contracts feature ๐Ÿงช . it was briefly added to and then removed from the C++20 working paper (N4820). the implementation also includes proposed enhancements from papers P1290, P1332, and P1429. this is mostly for people experimenting to refine the feature so it's ready for a future C++ standard ๐Ÿ”ฌ

on a violation of a checked contract, the violation handler gets called. you can replace the violation handler by defining:

void
handle_contract_violation (const std::experimental::contract_violation&);

there are different sets of additional flags for N4820 contracts, P1332 contracts, or P1429 contracts, and these sets cannot be used together โ›” . the flags are:

  • -fcontract-mode=[on|off] โ€” controls whether any contracts have any semantics at all. defaults to on.
  • -fcontract-assumption-mode=[on|off] โ€” [N4820] controls whether contracts with level axiom should have the assume semantic. defaults to on.
  • -fcontract-build-level=[off|default|audit] โ€” [N4820] specifies which level of contracts to generate checks for. defaults to default.
  • -fcontract-continuation-mode=[on|off] โ€” [N4820] controls whether the program is allowed to keep executing after a contract violation. that is, checked contracts have the maybe semantic (described below) rather than the never semantic. defaults to off.
  • -fcontract-role=<name>:<default>,<audit>,<axiom> โ€” [P1332] specifies the concrete semantics for each contract level of a particular contract role.
  • -fcontract-semantic=[default|audit|axiom]:<semantic> โ€” [P1429] specifies the concrete semantic for a particular contract level.
  • -fcontract-strict-declarations=[on|off] โ€” controls whether adding contracts to a function after its first declaration gets rejected. defaults to off.

the possible concrete semantics you can set with -fcontract-role or -fcontract-semantic are:

  • ignore โ€” this contract has no effect.
  • assume โ€” this contract is treated like C++23 [[assume]].
  • check_never_continue, never, abort โ€” this contract is checked. if it fails, the violation handler is called. if the handler returns, std::terminate is called.
  • check_maybe_continue, maybe โ€” this contract is checked. if it fails, the violation handler is called. if the handler returns, execution continues normally.

-fcoroutines

enables support for the C++ coroutines extension ๐Ÿงต . just know it's experimental โš—๏ธ

-fdiagnostics-all-candidates

lets the C++ front end note all candidates during an overload resolution failure, including when a deleted function gets selected ๐Ÿ”Ž

-fno-elide-constructors

so the C++ standard lets an implementation skip creating a temporary that's only used to initialize another object of the same type ๐Ÿ—‘๏ธ . specifying this option disables that optimization and forces G++ to call the copy constructor in all cases ๐Ÿ“‹ . it also causes G++ to call trivial member functions that would otherwise get expanded inline ๐Ÿ™ˆ

in C++17, the compiler is required to omit these temporaries, but this option still affects trivial member functions ๐Ÿ’…

-fno-enforce-eh-specs

this tells the compiler not to generate code that checks for violations of exception specifications at run time ๐Ÿšซ . it violates the C++ standard, but it can be useful for shrinking code size in production builds, kinda like defining NDEBUG ๐Ÿงน

๐Ÿ’€ this does NOT give your code permission to throw exceptions in violation of the exception specifications! the compiler still optimizes based on those specs, so throwing an unexpected exception results in undefined behavior at run time
  • -fextern-tls-init, -fno-extern-tls-init โ€” okay bestie, C++11 and OpenMP let thread_local and threadprivate variables do dynamic (runtime) initialization ๐Ÿงš. To make that work, every use of one of these variables goes through a wrapper function that handles any setup it needs ๐Ÿ’…. When the use and the definition live in the same translation unit, the compiler can optimize that overhead away โœจ. But if the use is in a different translation unit, you eat significant overhead even when the variable doesn't actually need dynamic initialization ๐Ÿ˜ญ. If you can be sure that no use in a non-defining TU needs to trigger dynamic initialization (because the variable is statically initialized, or because a use in the defining TU runs 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 ๐ŸŽ€.
  • -ffold-simple-inlines, -fno-fold-simple-inlines โ€” this lets the C++ frontend fold calls to std::move, std::forward, std::addressof and std::as_const ๐ŸŒธ. Unlike regular inlining, no debug information gets generated for these calls. Since they're rarely interesting to debug, this is enabled by default unless -fno-inline is active ๐Ÿ’œ.
  • -fno-gnu-keywords โ€” don't treat typeof as a keyword, so your code can use that word as an identifier ๐Ÿ™ˆ. You can use the keyword __typeof__ instead. This option is implied by the strict ISO C++ dialects: -ansi, -std=c++98, -std=c++11, etc. ๐Ÿ“
  • -fno-immediate-escalation โ€” this turns off immediate function escalation, where certain functions get promoted to consteval, as specified in P2564R3 ๐Ÿ”ฅ. Here's an example:
consteval int id(int i) { return i; }

constexpr int f(auto t)
{
  return t + id(t); // id causes f<int> to be promoted to consteval
}

void g(int i)
{
  f (3);
}

This compiles in C++20 ๐Ÿ‘‘. f is an immediate-escalating function (because of the auto it's a function template, and it's declared constexpr), and id(t) is an immediate-escalating expression, so f gets promoted to consteval โœจ. That means the call to id(t) is in an immediate context, so it doesn't have to produce a constant (this is the mechanism that allows consteval function composition) ๐Ÿงš. However, with -fno-immediate-escalation, f is not promoted to consteval, and since the call to the consteval function id(t) is not a constant expression, the compiler rejects the code ๐Ÿ’€. This option is turned on by default, and it's only effective in C++20 mode or later ๐ŸŒˆ.

  • -fimplicit-constexpr โ€” make inline functions implicitly constexpr if they meet the requirements for a constexpr function ๐ŸŒŸ. This option can be used in C++14 mode or later. It can change initialization from dynamic to static, along with other optimizations โญ.
  • -fno-implicit-templates โ€” never emit code for non-inline templates that get instantiated implicitly (aka by use), and only emit code for explicit instantiations ๐Ÿซถ. If you use this option, you have to be careful to structure your code so it includes all the explicit instantiations it needs, or you'll get undefined symbols at link time ๐Ÿ˜ญ.
  • -fno-implicit-inline-templates โ€” don't emit code for implicit instantiations of inline templates either ๐Ÿ’…. By default, inlines are handled differently so that compiles with and without optimization need the same set of explicit instantiations ๐Ÿฆ‹.
  • -fno-implement-inlines โ€” to save space, don'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 ๐Ÿ™ˆ.
  • -fmodules-ts, -fno-modules-ts โ€” enable support for C++20 modules ๐Ÿงš. You usually won't need -fno-modules-ts, since that's already the default. Even though modules are a C++20 feature, they aren't implicitly enabled just by selecting that standard version ๐Ÿ’œ.
  • -fmodule-header, -fmodule-header=user, -fmodule-header=system โ€” compile a header file so it becomes an importable header unit ๐ŸŒธ.
  • -fmodule-implicit-inline โ€” member functions defined inside their class definitions are not implicitly inline for modular code ๐Ÿค”. This is different from traditional C++ behavior, and there are good reasons for it, but it can be a headache when porting code ngl ๐Ÿ˜ญ. This option makes those function definitions implicitly inline. Just know it generates an ABI incompatibility, so you have to use it everywhere or nowhere โš ๏ธ. (Definitions outside of a named module stay implicitly inline regardless โœจ.)
  • -fno-module-lazy โ€” disable lazy module importing and module mapper creation ๐Ÿ’ค.
  • -fmodule-mapper=[hostname]:port[?ident], -fmodule-mapper=|program[?ident] args..., -fmodule-mapper==socket[?ident], -fmodule-mapper=<>[inout][?ident], -fmodule-mapper=<in>out[?ident], -fmodule-mapper=file[?ident] โ€” this is an oracle you can query for module name to filename mappings ๐Ÿ”ฎ. If you don't specify one, the CXX_MODULE_MAPPER environment variable gets used, and if that's unset, an in-process default is provided ๐ŸŒˆ.
  • -fmodule-only โ€” only emit the Compiled Module Interface, and skip any object file ๐Ÿฆ‹.
  • -fms-extensions โ€” disable 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 โ€” enable the P0136 adjustment to the semantics of C++11 constructor inheritance โœจ. This is part of C++17, but it's also considered a Defect Report against C++11 and C++14 ๐Ÿงš. This flag is enabled by default unless -fabi-version=10 or lower is specified ๐Ÿ’….
  • -fnew-ttp-matching โ€” enable the P0522 resolution to Core issue 150, which covers template template parameters and default arguments ๐ŸŒธ. This allows a template with default template arguments to be used as an argument for a template template parameter with fewer template parameters ๐ŸŽ€. This flag is enabled by default for -std=c++17 โญ.
  • -fno-nonansi-builtins โ€” disable 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 โ€” treat a throw() exception specification as if it were a noexcept specification ๐Ÿ”ฅ. This reduces or eliminates 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 actually makes 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 such an exception specification results in a call to terminate rather than unexpected ๐Ÿ’€.
  • -fno-operator-names โ€” don't treat the operator name keywords and, bitand, bitor, compl, not, or and xor as synonyms for keywords ๐Ÿ™….
  • -fno-optional-diags โ€” disable diagnostics that the standard says a compiler doesn't need to issue ๐Ÿซ . Right now, the only one G++ issues in that category is the one for a name having multiple meanings within a class ๐Ÿคท.
  • -fno-pretty-templates โ€” when an error message mentions a specialization of a function template, the compiler normally prints the template's signature, followed by the template arguments and any typedefs or typenames in the signature ๐ŸŽ€. For example, you get void f(T) [with T = int] instead of void f(int), so it's clear which template is involved ๐Ÿ‘€. When an error message mentions 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 errors harder to understand instead of easier, you can use -fno-pretty-templates to turn them off ๐Ÿซถ.
  • -fno-rtti โ€” disable generation of information about every class with virtual functions, which C++ run-time type identification (dynamic_cast and typeid) uses ๐Ÿงš. If you don't use those parts of the language, you can save some space with this flag ๐Ÿ’…. Exception handling uses the same information, but G++ generates it as needed ๐ŸŒธ. The dynamic_cast operator can still be used for casts that don't require run-time type information, i.e. casts to void * or to unambiguous base classes ๐Ÿฆ‹.

Mixing code compiled with -frtti 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 โš ๏ธ.

  • -fsized-deallocation โ€” enable the built-in global declarations introduced in C++14 ๐ŸŒŸ:
void operator delete (void *, std::size_t) noexcept;
void operator delete[] (void *, std::size_t) noexcept;

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

  • -fstrict-enums โ€” lets the compiler optimize using the assumption that a value of an enumerated type can only be one of the values in the enumeration ๐Ÿง . (Per the C++ standard, that's basically a value that fits in the minimum number of bits needed to represent all the enumerators.) This assumption may not hold if the program uses a cast to convert an arbitrary integer value to the enumerated type ๐Ÿ˜ฌ. This option has no effect for an enumeration type with a fixed underlying type ๐Ÿซ .
  • -fstrong-eval-order โ€” evaluate member access, array subscripting, and shift expressions in left-to-right order, and evaluate assignment in right-to-left order, as adopted for C++17 ๐Ÿ’–. It's enabled by default with -std=c++17 โœจ. -fstrong-eval-order=some enables just the ordering of member access and shift expressions, and it's the default without -std=c++17 ๐ŸŒธ.
  • -ftemplate-backtrace-limit=n โ€” set the maximum number of template instantiation notes for a single warning or error to n ๐Ÿงš. The default value is 10 ๐Ÿ”ข.
  • -ftemplate-depth=n โ€” ๐ŸŒ€ okay so this sets the max instantiation depth for template classes to n. That limit is what lets the compiler catch endless recursion during template class instantiation, which is honestly a lifesaver. ANSI/ISO C++ conforming programs must not rely on a max depth greater than 17 (it got bumped to 1024 in C++11). The default is 900, because the compiler can run out of stack space before it ever reaches 1024 in some situations ๐Ÿ˜ญ
  • -fno-threadsafe-statics โ€” skip the extra code that uses the C++ ABI's thread-safe initialization routines for local statics โœจ If your code doesn't need to be thread-safe, this can shave a little off code size.
  • -fuse-cxa-atexit โ€” registers destructors for objects with static storage duration using __cxa_atexit 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 โ€” don't use the __cxa_get_exception_ptr runtime routine. ๐Ÿ’€ This makes std::uncaught_exception incorrect, but it's necessary if that runtime routine isn't available.
  • -fvisibility-inlines-hidden โ€” ๐Ÿ‘‘ this switch tells GCC that you won't try to compare pointers to inline functions or methods when their addresses are taken in different shared objects.

GCC can then effectively mark inline methods with __attribute__ ((visibility ("hidden"))), so they don't show up in a DSO's export table and don't need a PLT indirection when used inside that DSO. This can have a dramatic effect on load and link times for a DSO, because it massively shrinks the dynamic export table when a library leans hard on templates ๐Ÿ”ฅ

This isn't quite the same as marking methods hidden directly, because 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 mark a method with an 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 flag 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 is 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 when this option isn't used.

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

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

โš ๏ธ When this flag is given, defining types with the same name differently is a violation of the ODR. Be careful, bestie.
  • -fno-weak โ€” do not 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) โ€” ๐Ÿงš this accepts imaginary, fixed-point, or machine-defined literal number suffixes as GNU extensions. When it's 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++ โ€” don't search for header files in the standard directories specific to C++, but still search the other standard directories. (This option is used when building the C++ library.) ๐ŸŒธ
  • -flang-info-include-translate, -flang-info-include-translate-not, -flang-info-include-translate=header โ€” ๐Ÿฆ‹ these inform you of include translation events. The first one notes accepted include translations, the second notes declined ones. The header form informs you about include translations relating to that specific header. If header is of the form "user" or "<system>", it gets resolved to a specific user or system header using the include path.
  • -flang-info-module-cmi, -flang-info-module-cmi=module โ€” ๐Ÿ’œ these inform you of Compiled Module Interface (CMI) pathnames. The first one notes all read CMI pathnames. The module form notes reading a specific module's CMI. module may be a named module or a header-unit. A header-unit is indicated by either being a pathname containing directory separators, or by being enclosed in <> or "".
  • -stdlib=libstdc++,libc++ โ€” ๐ŸŒˆ when G++ is configured to support this option, you can pick an alternate C++ runtime library. There are two choices: libstdc++ (the default, native C++ runtime for G++) and libc++, which is the C++ runtime installed on some operating systems (e.g. Darwin versions from Darwin11 onwards). This switches G++ to use the headers from the specified library, and to emit -lstdc++ or -lc++ respectively when a C++ runtime is required for linking.

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 information about ABI tags.
  • -Wcomma-subscript (C++ and Objective-C++ only) โ€” ๐Ÿ™ˆ warns about uses of a comma expression within a subscripting expression. This usage was deprecated in C++20 and is going to be removed in C++23. A comma expression wrapped in ( ) is not deprecated. Example:
    void f(int *a, int b, int c) {
        a[b,c];     // deprecated in C++20, invalid in C++23
        a[(b,c)];   // OK
    }

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

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

This warning is upgraded to an error by -pedantic-errors in C++23 mode or later.

  • -Wctad-maybe-unsupported (C++ and Objective-C++ only) โ€” ๐Ÿ” warns when performing class template argument deduction (CTAD) on a type with no explicitly written deduction guides. This points out cases where CTAD succeeded only because the compiler synthesized the implicit deduction guides, which might not be what the programmer intended. Certain style guides allow CTAD only on types that specifically "opt-in", i.e. types designed to support CTAD. This warning can be suppressed with the following pattern:
    struct allow_ctad_t; // any name works
    template <typename T> struct S {
      S(T) { }
    };
    // Guide with incomplete parameter type will never be considered.
    S(allow_ctad_t) -> S<void>;
  • -Wctor-dtor-privacy (C++ and Objective-C++ only) โ€” ๐Ÿ”’ warns when a class seems unusable because all of its constructors or destructors are private, and it has neither friends nor public static member functions. It also warns if there are no non-private methods, and there's at least one private member function that isn't a constructor or destructor.
  • -Wdangling-reference (C++ and Objective-C++ only) โ€” ๐Ÿฅ€ warns when a reference is bound to a temporary whose lifetime has ended. For example:
    int n = 1;
    const int& r = std::max(n - 1, n + 1); // r is dangling

In the example above, two temporaries are created, one for each argument, and a reference to one of the temporaries is returned. However, both temporaries are destroyed at the end of the full expression, so the reference r is dangling. This warning also detects dangling references in member initializer lists:

    const int& f(const int& i) { return i; }
    struct S {
      const int &r; // r is dangling
      S() : r(f(10)) { }
    };

Member functions are checked as well, but only their object argument:

    struct S {
       const S& self () { return *this; }
    };
    const S& s = S().self(); // s is dangling

Certain functions are safe in this respect, for example std::use_facet: they take and return a reference, but they don't return one of its arguments, which can fool the warning. Such functions can be excluded from the warning by wrapping them in a #pragma:

    #pragma GCC diagnostic push
    #pragma GCC diagnostic ignored "-Wdangling-reference"
    const T& foo (const T&) { ... }
    #pragma GCC diagnostic pop

The #pragma can also surround the class. In that case, the warning will be disabled for all the member functions.

-Wdangling-reference also warns about code like:

    auto p = std::minmax(1, 2);

Okay so the std::minmax situation is a whole trap, bestie ๐Ÿ˜ญ It returns a std::pair<const int&, const int&>, and both of those references dangle once the full expression that contains the std::minmax call ends ๐Ÿ’€

This warning doesn't go off for "std::span"-like classes ๐Ÿฆ‹ So what counts as span-like? We're talking about a class that looks something like this:

template<typename T>
struct Span {
  T* data_;
  std::size len_;
};

So basically, a non-union class with a pointer data member and a trivial destructor is span-like ๐ŸŒธ If you really need the warning gone, the gnu::no_dangling attribute turns it off ๐Ÿ™ˆ

And yes, this warning is on under -Wall ๐Ÿ’–


  • -Wdelete-non-virtual-dtor (C++ and Objective-C++ only) โ€” Okay, this one is a red flag ๐Ÿšฉ It warns when delete destroys an instance of a class that has virtual functions but a non-virtual destructor. Deleting a derived object through a base-class pointer is unsafe when the base doesn't have a virtual destructor ๐Ÿ˜ฌ Enabled by -Wall โœจ
  • -Wdeprecated-copy (C++ and Objective-C++ only) โ€” This one warns that the implicit copy constructor or copy assignment operator is deprecated when the class has a user-provided copy constructor or copy assignment operator (C++11 and up) ๐Ÿ’… It's enabled by -Wextra. Add -Wdeprecated-copy-dtor and it also deprecates the implicit version when the class has a user-provided destructor ๐ŸŽ€
  • -Wno-deprecated-enum-enum-conversion (C++ and Objective-C++ only) โ€” This turns off the warning for when the usual arithmetic conversions hit operands where one is an enum and the other is a different enum. That conversion got deprecated in C++20 ๐Ÿฅ€ For example:
enum E1 { e };
enum E2 { f };
int k = f - e;

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

  • -Wno-deprecated-enum-float-conversion (C++ and Objective-C++ only) โ€” Same energy, but this time the warning is for an enum mixed with a floating-point type in the usual arithmetic conversions. Also deprecated in C++20 ๐Ÿงš For example:
enum E1 { e };
enum E2 { f };
bool b = e <= 3.7;

-Wdeprecated-enum-float-conversion is on by default with -std=c++20. In pre-C++20 dialects, use -Wenum-conversion to enable it ๐Ÿ’œ

  • -Wno-elaborated-enum-base โ€” For C++11 and above, this warns if an (invalid) extra enum-base shows up in an elaborated-type-specifier. Basically, that's an enum with a given underlying type and no enumerator list, used in a declaration that isn't just a standalone declaration of the enum ๐Ÿ™ƒ It's on by default, and -pedantic-errors upgrades it to an error ๐Ÿ”ฅ
  • -Wno-init-list-lifetime (C++ and Objective-C++ only) โ€” Do not warn about std::initializer_list uses that are likely to leave you with dangling pointers. The array behind an initializer_list is treated like a normal C++ temporary, so it's super easy to accidentally hold a pointer to it after it's gone ๐Ÿ˜ญ Here are the main ways that goes wrong:
  • 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 gets assigned from a brace-enclosed initializer list, the temporary array made for the right side only lives until the end of the full-expression. So by the next statement, that variable is dangling ๐Ÿฅบ
// 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 an initializer_list argument, that does not extend the array's lifetime. So if a class variable gets constructed from a temporary initializer_list, the pointer is left dangling by the end of the variable declaration statement ๐Ÿฆ‹
  • -Winvalid-constexpr (C++ and Objective-C++ only) โ€” This warns when a function never actually produces a constant expression โœจ In C++20 and earlier, every constexpr function and function template needs at least one set of arguments, in at least one instantiation, where an invocation could be an evaluated subexpression of a core constant expression. C++23 dropped that requirement, so a constexpr function or template might end up with no invocation that qualifies, and that's allowed now ๐ŸŒธ This warning is on by default as a pedantic warning in C++20 and earlier. In C++23, you can turn on -Winvalid-constexpr, and then it's an ordinary warning. For example:
void f (int& i);
constexpr void
g (int& i)
{
  // Warns by default in C++20, in C++23 only with -Winvalid-constexpr.
  f(i);
}
  • -Winvalid-imported-macros โ€” This checks that all imported macro definitions are valid at the end of compilation ๐Ÿ” It's not on by default, because it needs extra processing to figure out. It's handy when you're preparing sets of header-units and want your macros to stay consistent ๐ŸŽ€
  • -Wno-literal-suffix (C++ and Objective-C++ only) โ€” This stops the warning when a string or character literal is followed by a ud-suffix that doesn't start with an underscore ๐Ÿ™ˆ GCC treats those suffixes as separate preprocessing tokens. It's a conforming extension, done so older code that uses formatting macros from <inttypes.h> keeps working ๐Ÿ’– For example:
#define __STDC_FORMAT_MACROS
#include <inttypes.h>
#include <stdio.h>

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

In this case, PRId64 is treated as a separate preprocessing token ๐Ÿงš

This option also handles warnings when a user-defined literal operator is declared with a literal suffix identifier that doesn't begin with an underscore. Those identifiers are reserved for future standardization, so these warnings are enabled by default ๐ŸŒˆ

  • -Wno-narrowing (C++ and Objective-C++ only) โ€” For C++11 and later, narrowing conversions get diagnosed by default, because the standard requires it ๐Ÿ“ A narrowing conversion from a constant is an error, and a narrowing conversion from a non-constant is a warning. -Wno-narrowing suppresses that diagnostic. Heads up though, this doesn't change the meaning of well-formed code, since narrowing conversions are still ill-formed in SFINAE contexts ๐Ÿ’… With -Wnarrowing in C++98, you get a warning when a narrowing conversion that C++11 prohibits happens inside { }, like this:
int i = { 2.2 }; // error: narrowing from double to int

This flag is included in -Wall and -Wc++11-compat โœจ

  • -Wnoexcept (C++ and Objective-C++ only) โ€” This warns when a noexcept expression evaluates to false because of a call to a function that lacks a non-throwing exception specification (throw() or noexcept), even though the compiler knows that function never throws ๐Ÿค”
  • -Wnoexcept-type (C++ and Objective-C++ only) โ€” This warns if the C++17 feature that makes noexcept part of a function type changes the mangled name of a symbol compared to C++14 ๐Ÿงฌ It's enabled by -Wabi and -Wc++17-compat. As an example:
template <class T> void f(T t) { t(); };
void g() noexcept;
void h() { f(g); }

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

  • -Wclass-memaccess (C++ and Objective-C++ only) โ€” This warns when the destination of a raw memory function call, like memset or memcpy, is an object of class type. It also warns when writing into that object might skip 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 violate invariants the member functions rely on. For example, the memset call below is undefined because it modifies a non-trivial class object, so GCC flags it ๐Ÿšจ
std::string str = "abc";
memset (&str, 0, sizeof str);

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

  • -Wnon-virtual-dtor (C++ and Objective-C++ only) โ€” This warns when a class has virtual functions and an accessible non-virtual destructor, either on itself or on an accessible polymorphic base class. Deleting a derived instance through a pointer to the class or its base is possible but unsafe in that case ๐Ÿ™ƒ This warning is automatically enabled if -Weffc++ is specified. Honestly, -Wdelete-non-virtual-dtor (enabled by -Wall) is the one to prefer, because it warns about the unsafe cases without false positives ๐Ÿ‘‘
  • -Wregister (C++ and Objective-C++ only) โ€” This warns on uses of the register storage class specifier, except when it's part of the GNU Explicit Register Variables extension. The register keyword got deprecated in C++11 and removed in C++17 ๐Ÿฅ€ It's enabled by default with -std=c++17 ๐Ÿ’€
  • -Wreorder (C++ and Objective-C++ only) โ€” okay bestie, this one is SO relatable ๐Ÿ™ˆ It warns when the member initializers you wrote are in a different order than they actually run in. You typed them one way and the compiler is like "nah, declaration order only ๐Ÿ’…" For instance:
struct A {
  int i;
  int j;
  A(): j (0), i (1) { }
};

The compiler rearranges the initializers for i and j so they match the order the members are declared in, and it warns you about it with a little ๐Ÿซถ This warning is enabled by -Wall.

  • -Wno-pessimizing-move (C++ and Objective-C++ only) โ€” this one warns when a call to std::move stops copy elision from happening ๐Ÿ˜ญ A typical copy elision moment is returning from a function with a class return type, where the expression being returned is the name of a non-volatile automatic object, it's not a function parameter, and it has the same type as the function return type. Here's the tea:
struct T {
...
};
T fn()
{
  T t;
  ...
  return std::move (t);
}

But in this example, the std::move call prevents copy elision, so it's giving main character energy in the wrong way ๐Ÿ’€ This warning is enabled by -Wall.

  • -Wno-redundant-move (C++ and Objective-C++ only) โ€” this one catches redundant calls to std::move, aka the ones where a move would have happened anyway without the std::move call ๐Ÿฆ‹ That happens because the compiler is forced to treat the object as an rvalue in certain situations, like returning a local variable where copy elision isn't applicable. Consider:
struct T {
...
};
T fn(T t)
{
  ...
  return std::move (t);
}

Here, the std::move call is redundant. Because G++ implements Core Issue 1579, another example is:

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

In this example, copy elision isn't applicable because the type of the expression being returned and the function return type differ, yet G++ still treats the return value as if it were designated by an rvalue ๐ŸŒธ This warning is enabled by -Wextra.

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

It does not warn when the type being copied is a trivially-copyable type whose size is less than 64 bytes, so no need to panic over tiny stuff ๐Ÿ“

It also warns when a loop variable in a range-based for-loop is initialized with a value of a different type, which results in a copy. For example:

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

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

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

On the other hand, in this example there is no warning, because the keyword is actually needed:

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) โ€” this one says "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" ๐Ÿ™…โ€โ™€๏ธ Here's why it matters: if a type A depends on a type B with no or internal linkage, defining it in multiple translation units would be an ODR violation, because the meaning of B is different in each translation unit. If A only shows up in a single translation unit, the best way to silence the warning is to give it internal linkage by putting it in an anonymous namespace as well. The compiler doesn't give this warning for types defined in the main .C file, since those are unlikely to have multiple definitions. -Wsubobject-linkage is enabled by default โœจ
  • -Weffc++ (C++ and Objective-C++ only) โ€” this one warns about violations of the following style guidelines from Scott Meyers' Effective C++ series of books ๐Ÿ“š Respect the vibes:
    • Define a copy constructor and an assignment operator for classes with dynamically-allocated memory.
    • Prefer initialization to assignment in constructors.
    • Have operator= return a reference to *this.
    • Don't try to return a reference when you must return an object.
    • Distinguish between prefix and postfix forms of increment and decrement operators.
    • Never overload &&, ||, or ,.

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

When you select this option, be aware that the standard library headers don't obey all of these guidelines, so you can use grep -v to filter out those warnings. Not your problem, not your fault ๐Ÿ™„

  • -Wno-exceptions (C++ and Objective-C++ only) โ€” disables the warning about an exception handler being shadowed by another handler ๐Ÿซฃ That one can point out a wrong ordering of exception handlers, so it's a whole vibe check.
  • -Wstrict-null-sentinel (C++ and Objective-C++ only) โ€” this one warns about using an uncasted NULL as a sentinel ๐Ÿ’ When you're compiling only with GCC, it's a valid sentinel, since NULL is defined to __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. But this use isn't portable across different compilers, so bestie, be careful ๐Ÿฅบ
  • -Wno-non-template-friend (C++ and Objective-C++ only) โ€” disables warnings when non-template friend functions are declared within a template ๐ŸŒˆ In very old versions of GCC, from before the ISO standard was implemented, declarations like friend int foo(int), where the name of the friend is an unqualified-id, could be read as a particular specialization of a template function. The warning exists to diagnose those compatibility problems, and it's enabled by default.
  • -Wold-style-cast (C++ and Objective-C++ only) โ€” warns if an old-style (C-style) cast to a non-void type is used in a C++ program ๐Ÿ’… The new-style casts (dynamic_cast, static_cast, reinterpret_cast, and const_cast) are way less vulnerable to unintended effects and much easier to search for, so switch over, no cap โœจ
  • -Woverloaded-virtual, -Woverloaded-virtual=n (C++ and Objective-C++ only) โ€” these warn when a function declaration hides virtual functions from a base class ๐Ÿ‘€ Check this drama:
struct A {
  virtual void f();
};

struct B: public A {
  void f(int); // does not override
};

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

B* b;
b->f();

fails to compile ๐Ÿ˜ญ If the different signatures aren't an accident, the simplest fix is to add a using-declaration to the derived class to un-hide the base function, e.g. add using A::f; to B.

The optional level suffix controls the behavior when all the declarations in the derived class override virtual functions in the base class, even if not all of the base functions are overridden:

struct C {
  virtual void f();
  virtual void f(int);
};

struct D: public C {
  void f(int); // does override
}

This pattern is less likely to be a mistake. If D is only used virtually, the user might have decided that the base class semantics for some of the overloads are fine ๐Ÿงš

At level 1, this case does not warn. At level 2, it does. -Woverloaded-virtual by itself selects level 2. Level 1 is included in -Wall.

  • -Wno-pmf-conversions (C++ and Objective-C++ only) โ€” disables the diagnostic for converting a bound pointer to member function to a plain pointer ๐Ÿ™ˆ
  • -Wsign-promo (C++ and Objective-C++ only) โ€” warns when overload resolution picks a promotion from an unsigned or enumerated type to a signed type, over a conversion to an unsigned type of the same size ๐Ÿ”ฅ Older versions of G++ tried to preserve unsignedness, but the standard mandates the current behavior, so it is what it is.
  • -Wtemplates (C++ and Objective-C++ only) โ€” warns when a primary template declaration is encountered ๐ŸŽ€ Some coding rules disallow templates, and this can be used to enforce that rule. The warning is inactive inside a system header file, like the STL, so you can still use the STL. You may also instantiate or specialize templates.
  • -Wmismatched-new-delete (C++ and Objective-C++ only) โ€” warns about mismatches between calls to operator new or operator delete and the corresponding call to the allocation or deallocation function ๐Ÿซถ This includes invocations of C++ operator delete with pointers returned from either mismatched forms of operator new, or from other functions that allocate objects for which operator delete isn't a suitable deallocator. It also covers calls to other deallocation functions with pointers returned from operator new for which the deallocation function isn't suitable.

For example, the delete expression in the function below gets diagnosed because it doesn't match the array form of the new expression the pointer argument was returned from. Similarly, the call to free is also diagnosed:

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

Okay so the new/free mix-up above is exactly what this one catches ๐Ÿ˜ญ The related option -Wmismatched-dealloc ๐Ÿฆ‹ handles mismatches for allocation and deallocation functions other than operator new and operator delete. Different vibe, same energy. Also, -Wmismatched-new-delete is included in -Wall ๐Ÿ’…

  • -Wmismatched-tags (C++ and Objective-C++ only) โ€” ๐ŸŽ€ Warns when a struct, class, or class template (or one of its specializations) gets declared with a class-key that doesn't match the definition, or the first declaration if there's no definition. In this example, the struct Object in the argument list of draw sets it off. To dodge the warning, either drop the redundant struct or swap it for class so it matches the definition.
class Object {
public:
  virtual ~Object () = 0;
};
void draw (struct Object*);

Using struct as a class-key is totally legal, 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, it also helps prevent unresolved references caused by different mangling of symbols declared with different class-keys โœจ You can use it on its own or together with -Wredundant-tags.

  • -Wmultiple-inheritance (C++ and Objective-C++ only) โ€” ๐Ÿฆ‹ Warns when a class is defined with multiple direct base classes. Some coding rules ban multiple inheritance, so this lets you enforce that rule. It stays quiet inside system headers like the STL, so you can still use the STL ๐Ÿ’œ You can also define classes that indirectly use multiple inheritance.
  • -Wvirtual-inheritance โ€” ๐ŸŒธ Warns when a class is defined with a virtual direct base class. Same deal: some coding rules disallow multiple inheritance, so this can enforce that. It's inactive inside system headers like the STL, so the STL is still fair game. You can also define classes that indirectly use virtual inheritance.
  • -Wno-virtual-move-assign โ€” Suppresses warnings about inheriting from a virtual base with a non-trivial C++11 move assignment operator.
๐Ÿ’€ This 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 to avoid moving from a moved-from object, you can disable this warning.
  • -Wnamespaces โ€” โœจ Warns when a namespace definition is opened. Some coding rules ban namespaces, so this can enforce that. It's inactive inside system headers like the STL, so you can still use the STL. You can also use using directives and qualified names.
  • -Wno-template-id-cdtor (C++ and Objective-C++ only) โ€” Disables the warning about using a simple-template-id as the declarator-id of a constructor or destructor. That became invalid in C++20 via DR 2237. Here's an example:
template<typename T> struct S {
  S<T>(); // should be S();
  ~S<T>();  // should be ~S();
};

-Wtemplate-id-cdtor is enabled by default with -std=c++20, and it's also enabled by -Wc++20-compat.

  • -Wno-terminate (C++ and Objective-C++ only) โ€” ๐Ÿ”ฅ Disables the warning about a throw-expression that will immediately result in a call to terminate.
  • -Wno-vexing-parse (C++ and Objective-C++ only) โ€” ๐Ÿ™ˆ Warns about the most vexing parse ambiguity. This is when a declaration looks like a variable definition, but C++ requires it to be read as a function declaration. For instance:
void f(double a) {
  int i();        // extern int i (void);
  int n(int(a));  // extern int n (int);
}

Another example:

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

The warning will suggest ways to deal with the ambiguity, like removing the parentheses or using braces instead. This warning is enabled by default ๐Ÿซถ

  • -Wno-class-conversion (C++ and Objective-C++ only) โ€” Don't warn when a conversion function converts an object to the same type, to a base class of that type, or to void. That kind of conversion function will never be called, so the warning is skipped.
  • -Wvolatile (C++ and Objective-C++ only) โ€” ๐Ÿ‘‘ Warns about deprecated uses of the volatile qualifier. That covers:
    • postfix and prefix ++ and -- expressions of volatile-qualified types
    • simple assignments used for their value, where the left operand is a volatile-qualified non-class type
    • compound assignments where the left operand is a volatile-qualified non-class type
    • volatile-qualified function return types
    • volatile-qualified parameter types
    • structured bindings of a volatile-qualified type

This usage was deprecated in C++20. It's enabled by default with -std=c++20 ๐Ÿ’…

  • -Wzero-as-null-pointer-constant (C++ and Objective-C++ only) โ€” Warns when a literal 0 gets used as a null pointer constant. This can help you move 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, the placement new expression below gets flagged, because it tries to construct an array of 64 integers in a buffer that's only 64 bytes large:
char buf [64];
new (buf) int[64];

This warning is enabled by default.

  • -Wplacement-new=1 โ€” This is the default level for -Wplacement-new. At this level, the warning isn't issued for some strictly undefined constructs that GCC allows as extensions for compatibility with legacy code. For example, the following new expression isn't diagnosed at this level, even though the C++ standard says it has undefined behavior, 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 a diagnostic for placement new expressions that construct an object in the last member of a structure. That member has to be an array of a single element, and its size has to be smaller than the object being constructed. The previous example gets flagged here, but the following construct uses the flexible member array extension to avoid the warning at level 2:
struct S { int n, a[]; };
S *s = (S *)malloc (sizeof *s + 32 * sizeof s->a[0]);
new (s->a)int [32]();
  • -Wcatch-value, -Wcatch-value=n (C++ and Objective-C++ only) โ€” ๐ŸŽ€ Warns about catch handlers that don't catch via reference. With -Wcatch-value=1 (or just -Wcatch-value), it warns about polymorphic class types caught by value. With -Wcatch-value=2, it warns about all class types caught by value. With -Wcatch-value=3, it warns about all types that aren't caught by reference. -Wcatch-value is enabled by -Wall.
  • -Wconditionally-supported (C++ and Objective-C++ only) โ€” Warns for conditionally-supported constructs (C++11 [intro.defs]).
  • -Wno-delete-incomplete (C++ and Objective-C++ only) โ€” Don't warn when deleting a pointer to an incomplete type, which may cause undefined behavior at runtime. This warning is enabled by default.
  • -Wextra-semi (C++, Objective-C++ only) โ€” Warns about redundant semicolons after in-class function definitions ๐Ÿงš
  • -Wno-global-module (C++ and Objective-C++ only) โ€” Disables the diagnostic for when the global module fragment of a module unit doesn't consist only of preprocessor directives.
  • -Wno-inaccessible-base (C++, Objective-C++ only) โ€” ๐ŸŒˆ Controls warnings when a base class is inaccessible in a class derived from it because of ambiguity. This warning is enabled by default. The warning for ambiguous virtual bases is enabled by -Wextra. Here's an example:
struct A { int a; };

struct B : A { };

struct C : B, A { };
  • -Wno-inherited-variadic-ctor โ€” Suppresses warnings about using C++11 inheriting constructors when the base class being inherited from has a C variadic constructor. The warning is on by default because the ellipsis is not inherited.
  • -Wno-invalid-offsetof (C++ and Objective-C++ only) โ€” ๐Ÿ™ˆ Suppresses warnings from applying the offsetof macro to a non-POD type. According to the 2014 ISO C++ standard, applying offsetof to a non-standard-layout type is undefined. In existing C++ implementations, though, offsetof typically gives meaningful results. This flag is for people who know they're writing nonportable code and have deliberately chosen to ignore the warning about it. The restrictions on offsetof may be relaxed in a future version of the C++ standard.
  • -Wsized-deallocation (C++ and Objective-C++ only) โ€” โญ Warns about a definition of an unsized deallocation function:
void operator delete (void *) noexcept;
void operator delete[] (void *) noexcept;

without a definition of the corresponding 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: okay bestie, this one warns you about types with virtual methods that would be cleaner marked with the C++11 final specifier, or, if possible, declared in an anonymous namespace ๐Ÿฆ‹. It lets GCC devirtualize polymorphic calls more aggressively โœจ. It works best with link-time optimization, since LTO has a fuller picture of the class hierarchy graph ๐Ÿ”ฅ.
  • -Wsuggest-final-methods: same energy, but for individual virtual methods ๐Ÿ’…. It warns when a method would be improved by the final specifier, or when its type could go in an anonymous namespace or get final ๐ŸŒธ. Again, LTO makes this more accurate because it knows more about the class hierarchy graph ๐Ÿงš. The move is to check the -Wsuggest-final-types suggestions first, then rebuild with the new annotations ๐Ÿ’–.
  • -Wsuggest-override: flags virtual functions that override something without the override keyword ๐ŸŽ€.
  • -Wno-conversion-null (C++ and Objective-C++ only): turns off warnings for conversions between NULL and non-pointer types ๐Ÿ™ˆ. Heads up, -Wconversion-null is already on by default ๐Ÿ‘‘.

๐ŸŒˆ Options Controlling Objective-C and Objective-C++ Dialects ๐ŸŒˆ

NOTE: this manual doesn't teach you the Objective-C and Objective-C++ languages themselves ๐Ÿ™ˆ. What it does cover is the command-line options that only matter for those languages. You can still use most of the language-independent GNU compiler options too ๐Ÿ’œ.

Here's a quick example of compiling a file called some_class.m:

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

In that example, -fgnu-runtime is only meant for Objective-C and Objective-C++ ๐Ÿ’…. The other options work with any language GCC supports โœจ.

Since Objective-C is basically an extension of C, Objective-C compiles can also use C front-end options, like -Wtraditional ๐Ÿฆ‹. Objective-C++ compiles can use C++-specific options too, like -Wabi ๐Ÿ”ฅ.

Here's the list of options that are only for Objective-C and Objective-C++ programs ๐Ÿซถ:

  • -fconstant-string-class=class-name: picks the class that gets instantiated for each literal string written as "@"..."" ๐Ÿ’–. The default is NXConstantString with the GNU runtime and NSConstantString with the NeXT runtime ๐Ÿ“. On Darwin / macOS, if -fconstant-cfstrings is also present, it overrides this setting and makes "@"..."" literals laid out as constant CoreFoundation strings ๐ŸŒˆ. Also, -fconstant-cfstrings is just an alias for the target-specific -mconstant-cfstrings โœจ.
  • -fgnu-runtime: generates object code that works with the standard GNU Objective-C runtime ๐Ÿ’œ. This is the default on most systems ๐Ÿ‘‘.
  • -fnext-runtime: generates output that works with the NeXT runtime ๐ŸŽ. It's the default on NeXT-based systems, including Darwin / macOS ๐ŸŒธ. The macro __NEXT_RUNTIME__ is predefined if, and only if, you use this option ๐Ÿงš.
  • -fno-nil-receivers: tells the compiler to assume every Objective-C message dispatch ([receiver message:arg]) in this translation unit has a receiver that isn't nil ๐Ÿ™ˆ. That lets the runtime use more efficient entry points ๐Ÿ”ฅ. It only works with the NeXT runtime and ABI version 0 or 1 ๐Ÿซถ.
  • -fobjc-abi-version=n: uses version n of the Objective-C ABI for the selected runtime ๐Ÿ’…. Right now this is only supported for the NeXT runtime ๐Ÿฆ‹. Version 0 is the traditional (32-bit) ABI with no support for properties or other Objective-C 2.0 additions ๐Ÿฅบ. Version 1 is the traditional (32-bit) ABI with properties and other Objective-C 2.0 additions ๐Ÿ’–. Version 2 is the modern (64-bit) ABI โœจ. If you don't specify anything, the default is Version 0 on 32-bit targets and Version 2 on 64-bit targets ๐Ÿ‘‘.
  • -fobjc-call-cxx-cdtors: for each Objective-C class, it checks whether any instance variable is a C++ object with a non-trivial default constructor ๐ŸŽ€. If one is, it synthesizes a special - (id) .cxx_construct instance method that runs those constructors in order, then returns self ๐ŸŒˆ. It also checks for C++ objects with a non-trivial destructor, and if it finds any, synthesizes a - (void) .cxx_destruct method that runs those destructors in reverse order ๐Ÿ’€.

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

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

  • -fobjc-direct-dispatch: allows fast jumps to the message dispatcher โšก. On Darwin, this happens through the comm page ๐ŸŒธ.
  • -fobjc-exceptions: turns on syntax for structured exception handling in Objective-C, kind of like C++ ๐Ÿฆ‹. You need this to use the Objective-C keywords @try, @throw, @catch, @finally and @synchronized ๐Ÿ’…. It works with both the GNU runtime and the NeXT runtime, but not with the NeXT runtime on Mac OS X 10.2 and earlier ๐Ÿ™ˆ.
  • -fobjc-gc: enables garbage collection (GC) in Objective-C and Objective-C++ programs ๐Ÿ—‘๏ธ. This is only available with the NeXT runtime ๐ŸŽ. The GNU runtime has its own, different garbage collection setup that doesn't need special compiler flags ๐Ÿ’–.
  • -fobjc-nilcheck: for the NeXT runtime with version 2 of the ABI, checks for a nil receiver in method invocations before making the actual call ๐Ÿซถ. This is the default, and you can turn it off with -fno-objc-nilcheck ๐Ÿ™…. Class methods and super calls never get this nil check, no matter what this flag is set to ๐Ÿ’…. Right now this flag does nothing with the GNU runtime or an older version of the NeXT runtime ABI ๐Ÿฅฒ.
  • -fobjc-std=objc1: makes the compiler follow the language syntax of Objective-C 1.0, the one GCC 4.0 recognized ๐Ÿ•ฐ๏ธ. This only affects the Objective-C additions to C/C++, so it doesn't change conformance to C/C++ standards, which the separate C/C++ dialect flags control ๐ŸŒˆ. With this option on, any Objective-C or Objective-C++ syntax that GCC 4.0 doesn't recognize gets rejected ๐Ÿ™…. It's super handy if you need to be sure your Objective-C code compiles with older versions of GCC ๐ŸŽ€.
  • -freplace-objc-classes: emits a special marker that tells ld(1) not to statically link the resulting object file, and lets dyld(1) load it at run time instead ๐Ÿงš. This pairs with the Fix-and-Continue debugging mode, where the object file can be recompiled and dynamically reloaded while the program is running, no restart needed ๐Ÿ”„. For now, Fix-and-Continue only works with the NeXT runtime on Mac OS X 10.3 and later ๐ŸŽ.
  • -fzero-link: when compiling for the NeXT runtime, the compiler 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 makes things faster โšก. Using -fzero-link turns that off and keeps the objc_getClass("...") calls ๐Ÿซถ. That's useful in Zero-Link debugging mode, since it lets you modify individual class implementations while the program runs ๐Ÿ› ๏ธ. The GNU runtime always keeps objc_get_class("...") calls, no matter what command-line options you pass ๐Ÿ’€.
  • -fno-local-ivars: by default, Objective-C instance variables can be accessed like 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, whether they're declared locally in a class method or globally ๐Ÿ˜ญ. Using -fno-local-ivars turns this behavior off and avoids those shadowing problems ๐Ÿซถ.
  • -fivar-visibility=[public|protected|private|package]: sets the default instance variable visibility to whichever option you pick ๐Ÿฆ‹. Any instance variables declared outside the scope of an access modifier directive will default to that visibility ๐Ÿ’….
  • -gen-decls: dumps the interface declarations for all classes seen in the source file into a file named sourcename.decl ๐Ÿ“œ.
  • -Wassign-intercept (Objective-C and Objective-C++ only): warns whenever the garbage collector intercepts an Objective-C assignment ๐Ÿ—‘๏ธ.
  • -Wno-property-assign-default (Objective-C and Objective-C++ only): stops the warning for an Objective-C object property that doesn't have assign semantics specified ๐Ÿ™ˆ.
  • -Wno-protocol (Objective-C and Objective-C++ only): if a class says it implements a protocol, GCC normally warns for every protocol method the class doesn't implement ๐Ÿง. Even if a method is inherited from the superclass, that still counts as a warning by default ๐Ÿ˜ค. With -Wno-protocol, inherited methods count as implemented, so no warning shows up for them ๐Ÿซถ.
  • -Wobjc-root-class (Objective-C and Objective-C++ only): warns if a class interface has no superclass ๐ŸŒณ. Most classes inherit from NSObject (or Object), for example ๐Ÿ’œ. If you're declaring classes that are meant to be root classes, you can silence the warning by marking their interfaces with __attribute__((objc_root_class)) ๐Ÿ‘‘.

๐Ÿ’– Objective-C Warnings ๐Ÿ’–

  • -Wselector (Objective-C and Objective-C++ only) โ€” okay so this one warns you if the same selector shows up with different method types during compilation ๐Ÿ‘€. The check runs on the method list at the very end of compilation. It also checks every selector used in a @selector(...) expression that matches a method found during compilation ๐Ÿงš. Since all of this only happens at the end, these warnings won't show up if the final stage never gets reached, like when an error stops compilation early, or when -fsyntax-only is in use ๐Ÿ˜ญ.
  • -Wstrict-selector-match (Objective-C and Objective-C++ only) โ€” this one is giving strict ๐Ÿ’…. It warns when you send a message with a selector to a receiver of type id or Class, and multiple methods for that selector have different argument and/or return types. By default this flag is off ๐Ÿ™ˆ, and when it's off the compiler skips these warnings if the only differences are between types that share the same size and alignment.
  • -Wundeclared-selector (Objective-C and Objective-C++ only) โ€” warns if you use a @selector(...) expression for a selector that was never declared ๐Ÿซถ. A selector counts as undeclared if no method with that name was declared before the @selector(...) expression, whether explicitly in an @interface or @protocol declaration, or implicitly in an @implementation section. This one checks right away when it spots a @selector(...) expression, while -Wselector waits until the final stage of compilation ๐Ÿฆ‹. It also backs up the coding style rule that methods and selectors need to be declared before they're used. Main character energy ๐Ÿ‘‘.
  • -print-objc-runtime-info โ€” generates a C header describing the largest structure that gets passed by value, if there is one ๐ŸŒˆ.

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

Okay so traditionally, diagnostic messages were formatted without caring what the output device looked like (its width, and so on) ๐Ÿ’€. These options let you control the formatting algorithm, like how many characters go on each line and how often source location info gets reported ๐ŸŽ€. Heads up that some language front ends might not honor these options ๐Ÿ™ˆ.

  • -fmessage-length=n โ€” tries to format error messages so they fit on lines about n characters wide ๐Ÿ“. If n is zero, no line-wrapping happens, and each error message stays 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 affect the pragma GCC warning and pragma GCC error pragmas ๐Ÿ˜ญ.
  • -fdiagnostics-plain-output โ€” requests that diagnostic output look as plain as possible ๐Ÿงผ. This is handy when you're running dejagnu or other tools that parse diagnostics and need the output to stay stable over time. -fdiagnostics-plain-output is currently equivalent to these options:
-fno-diagnostics-show-caret -fno-diagnostics-show-line-numbers
-fdiagnostics-color=never -fdiagnostics-urls=never
-fdiagnostics-path-format=separate-events
-fdiagnostics-text-art-charset=none

If GCC ever changes the default look of its diagnostics in the future, the matching option to turn off the new behavior will get added to this list ๐Ÿ”ฎ.

  • -fdiagnostics-show-location=once โ€” only matters in line-wrapping mode ๐ŸŒธ. It tells the reporter to emit source location info once. So if a message is too long and has to be wrapped, the location won't get repeated as a prefix on every continuation line. This is the default behavior.
  • -fdiagnostics-show-location=every-line โ€” also only matters in line-wrapping mode โœจ. This one tells the reporter to put the same source location info (as a prefix) on every physical line created when a too-long message gets broken up.
  • -fdiagnostics-color[=WHEN], -fno-diagnostics-color โ€” turns colors on in diagnostics ๐ŸŒˆ. WHEN can be never, always, or auto. The default depends on how the compiler was configured. It can be any of those WHEN options, or never if the GCC_COLORS environment variable isn't in the environment, and auto otherwise. auto only uses color when standard error is a terminal and you're not running in an emacs shell ๐Ÿงš. The forms -fdiagnostics-color and -fno-diagnostics-color are aliases for -fdiagnostics-color=always and -fdiagnostics-color=never, respectively.

The colors are set by the GCC_COLORS environment variable ๐Ÿ’…. Its value is a colon-separated list of capabilities and Select Graphic Rendition (SGR) substrings. SGR commands get interpreted by the terminal or terminal emulator. Check the section in your text terminal's documentation for the permitted values and what they mean as character attributes ๐Ÿ“–. These substring values are integers written in decimal, and they can be stacked together with semicolons. Common ones you might stack include:

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

The default GCC_COLORS is this giant vibe ๐ŸŽจ:

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:fnname=01;32:targs=35:valid=01;31:invalid=01;32

Here 01;31 is bold red, 01;35 is bold magenta, 01;36 is bold cyan, 32 is green, 34 is blue, 01 is bold, and 31 is red. Setting GCC_COLORS to the empty string turns colors off completely ๐Ÿšซ. These are the supported capabilities:

  • error= โ€” SGR substring for error: markers.
  • warning= โ€” SGR substring for warning: markers.
  • note= โ€” SGR substring for note: markers.
  • path= โ€” SGR substring for coloring paths of control-flow events printed via -fdiagnostics-path-format=, like the identifiers of individual events and the lines showing interprocedural calls and returns.
  • range1= โ€” SGR substring for the first additional range.
  • range2= โ€” SGR substring for the second additional range.
  • locus= โ€” SGR substring for location info, like file:line or file:line:column etc.
  • quote= โ€” SGR substring for info printed within quotes.
  • fnname= โ€” SGR substring for names of C++ functions.
  • targs= โ€” SGR substring for C++ function template parameter bindings.
  • 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.
  • valid= โ€” SGR substring for highlighting valid elements within text art diagrams.
  • invalid= โ€” SGR substring for highlighting invalid elements within text art diagrams.
  • -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 the docs for that option.

WHEN can be never, always, or auto. auto only uses URL escape sequences when standard error is a terminal, and you're not running in an emacs shell or any graphical terminal known to be incompatible with this feature (see below) ๐Ÿ™…โ€โ™€๏ธ.

The default depends on how the compiler was configured, and it can be any of the WHEN options above. GCC can also be configured with the --with-diagnostics-urls=auto-if-env configure-time option, so the default depends on environment variables. In that setup, GCC defaults to auto if either the GCC_URLS or TERM_URLS environment variable is present and non-empty in the compiler's environment, or 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, 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.

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

At this point GCC also tries to detect a few terminals that don't implement the URL feature, and that have had bugs in some versions still in use, where URL escapes are likely to misbehave and print garbage on the screen ๐Ÿ˜ญ. That list currently includes xfce4-terminal, certain known-buggy gnome-terminal versions, the linux console, and mingw. You can skip this check with -fdiagnostics-urls=always.

  • -fno-diagnostics-show-option โ€” by default, every diagnostic emitted includes text showing the command-line option that directly controls it (if that option is known to the diagnostic machinery) ๐Ÿงพ. Using -fno-diagnostics-show-option turns that off.
  • -fno-diagnostics-show-caret โ€” bye, source line and caret ๐Ÿ™ˆ

By default, every diagnostic comes with the original source line and a caret ^ pointing at the column ๐Ÿ’… This option suppresses that info. If you pass -fmessage-length=n, the source line gets chopped to n characters โœ‚๏ธ When the output goes to the terminal, the width is limited by the COLUMNS environment variable or, if that isn't set, the terminal width ๐Ÿ–ฅ๏ธ

  • -fno-diagnostics-show-labels โ€” no more little labels on the code ๐Ÿท๏ธ

By default, when printing source code (via -fdiagnostics-show-caret), diagnostics can label ranges of source code with useful info, like the types of expressions. It's giving detective energy ๐Ÿ”

printf ("foo %s bar", long_i + long_j);
             ~^       ~~~~~~~~~~~~~~~
              |              |
              char *         long int

This option suppresses those labels (in the example above, the vertical bars and the "char *" and "long int" text) ๐Ÿ™…

  • -fno-diagnostics-show-cwe โ€” hide the CWE tags ๐ŸŽ€

Diagnostic messages can optionally have a CWE identifier attached (see https://cwe.mitre.org/index.html) โœจ GCC itself only provides that metadata for some -fanalyzer diagnostics, and GCC plugins may also add it. By default, if the info is there, it gets printed with the diagnostic. This option suppresses the printing of this metadata ๐Ÿซถ

  • -fno-diagnostics-show-rules โ€” no rule tags either ๐Ÿ“œ

Diagnostic messages can optionally have rules attached to them, like rules from a coding standard or a specification. GCC itself doesn't do this for any of its diagnostics, but plugins can. By default, if that info is present, it gets printed with the diagnostic. This option suppresses the printing of this metadata ๐Ÿ’–

  • -fno-diagnostics-show-line-numbers โ€” kill the left margin ๐ŸŒธ

By default, when printing source code (via -fdiagnostics-show-caret), a left margin is printed, showing line numbers. This option suppresses that left margin ๐Ÿฆ‹

  • -fdiagnostics-minimum-margin-width=width โ€” set the minimum margin width ๐Ÿ“

This option controls the minimum width of the left margin printed by -fdiagnostics-show-line-numbers. It defaults to 6 ๐Ÿ“

  • -fdiagnostics-parseable-fixits โ€” fix-its that IDEs can actually read ๐Ÿงš

This one is for IDEs, bestie ๐Ÿ’ป Fix-it hints get emitted in a machine-parseable format. 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, expressed as a count of bytes, starting at byte 1 for the initial column. In the example above, bytes 3 through 20 of line 45 of "test.c" get replaced with the given string ๐Ÿ”„

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

The filename and replacement string escape backslash as "\\", tab as "\t", newline as "\n", double quotes as "\"", and non-printable characters as octal (for example, vertical tab as "\013") ๐Ÿซง

An empty replacement string means the given range gets removed ๐Ÿ—‘๏ธ An empty range (for example "45:3-45:3") means the string gets inserted at the given position โž•

  • -fdiagnostics-generate-patch โ€” get a diff, no cap ๐Ÿ“

This prints fix-it hints to stderr in unified diff format, after any diagnostics are printed. For example:

--- test.c
+++ test.c
@ -42,5 +42,5 @

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

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


  • -fdiagnostics-show-template-tree โ€” C++ template types, but make it a tree ๐ŸŒณ

In the C++ frontend, when printing diagnostics about mismatching template types, such as:

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

this flag enables printing a tree-like structure that shows the common and differing parts of the types, like this:

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

The parts that differ are highlighted with color ("double" and "float" in this case) ๐ŸŽจ

  • -fno-elide-type โ€” stop the [...] shortcuts ๐Ÿ™…โ€โ™€๏ธ

By default, when the C++ frontend prints diagnostics about mismatching template types, the common parts of the types get printed as "[...]" to keep the error message short. For example:

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

Specifying -fno-elide-type suppresses that behavior ๐Ÿ’… This flag also affects the output of the -fdiagnostics-show-template-tree flag โœจ

  • -fdiagnostics-path-format=KIND โ€” how control-flow paths get shown ๐Ÿ›ค๏ธ

This specifies how to print paths of control-flow events for diagnostics that have one attached. KIND is none, separate-events, or inline-events, which is the default ๐Ÿ‘‘

none means don't print diagnostic paths at all ๐Ÿšซ

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

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

inline-events means print the events "inline" within the source code. This view tries to consolidate the events into runs of sufficiently close events, printing them as labelled ranges within the source ๐Ÿช„

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

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

Interprocedural control flow is shown by grouping the events by stack frame, and using indentation to show how stack frames are nested, pushed, and popped ๐Ÿง 

'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 โ€” extra depth info for path debugging ๐Ÿ”ฌ

This option provides additional info when printing control-flow paths associated with a diagnostic ๐Ÿฆ‹

If this option is provided, the stack depth will be printed for each run of events within -fdiagnostics-path-format=inline-events. If it's provided with -fdiagnostics-path-format=separate-events, then the stack depth and function declaration will be appended when printing each event ๐Ÿชœ

This one is intended for GCC developers and plugin developers who are debugging diagnostics that report interprocedural control flow ๐Ÿ› ๏ธ

  • -fno-show-column โ€” no column numbers, please ๐Ÿ™ˆ

Do not print column numbers in diagnostics. This may be necessary if diagnostics are being scanned by a program that doesn't understand column numbers, such as dejagnu ๐Ÿค–

  • -fdiagnostics-column-unit=UNIT โ€” pick how columns get counted ๐Ÿ”ข

This selects the units for the column number. It affects traditional diagnostics (when -fno-show-column isn't in play), as well as JSON format diagnostics if requested ๐Ÿ“Š

The default UNIT, display, counts the number of display columns each character occupies. That can be bigger than the number of bytes needed to encode the character (like with tab characters), or smaller (like with multibyte characters). For example, the character "GREEK SMALL LETTER PI (U+03C0)" occupies one display column, but its UTF-8 encoding needs two bytes. The character "SLIGHTLY SMILING FACE (U+1F642)" occupies two display columns, and its UTF-8 encoding needs four bytes ๐ŸŒˆ

Setting UNIT to byte makes the column number count raw bytes in every case, which is how GCC did it before version 11.1.0. ๐Ÿงฎ Very old-school, bestie. ๐Ÿ•ฐ๏ธ

  • -fdiagnostics-column-origin=ORIGIN โ€” picks which number the first column gets ๐Ÿฆ‹

The default of 1 is the classic GCC vibe and matches the GNU style guide, so it's the safe pick โœจ. Some utilities actually work better with an origin of 0, and any non-negative value is allowed, so you have options ๐Ÿ’….

  • -fdiagnostics-escape-format=FORMAT โ€” decides how weird bytes get displayed when GCC prints source lines ๐ŸŒธ

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

The default FORMAT is unicode. It shows non-printable-ASCII Unicode characters as <U+XXXX>, and any bytes that don't form a validly UTF-8-encoded Unicode character show up as hex in the form <XX> ๐Ÿ“.

For example, say a source line has the string before, then the Unicode character U+03C0 ("GREEK SMALL LETTER PI", with UTF-8 encoding 0xCF 0x80), then the byte 0xBF (a stray UTF-8 trailing byte), then the string after. For that diagnostic, you'd get:

before<U+03C0><BF>after

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

before<CF><80><BF>after
  • -fdiagnostics-text-art-charset=CHARSET โ€” picks which characters get used for "text art" diagrams ๐ŸŽจ

Some diagnostics include text art, which are visualizations made out of text and meant to be viewed in a monospaced font ๐Ÿงš. This option picks the characters used for those diagrams, if any. CHARSET can be none, ascii, unicode, or emoji.

none turns the diagrams off completely. ascii keeps everything pure ASCII, aka "ASCII art" ๐Ÿ–ค. unicode lets the diagrams use a conservative amount of Unicode drawing characters, like box-drawing characters ๐Ÿ“ฆ. emoji goes further and adds emoji to the mix too, like emitting U+26A0 WARNING SIGN followed by U+FE0F VARIATION SELECTOR-16 to select the emoji variant of the character โš ๏ธ.

The default is emoji, except when the environment variable LANG is set to C. In that case the default is ascii ๐ŸŒˆ.

  • -fdiagnostics-format=FORMAT โ€” switches up how diagnostics get printed ๐Ÿ’œ

FORMAT can be text, sarif-stderr, sarif-file, json, json-stderr, or json-file. The default is text ๐Ÿ’–.

The sarif-stderr and sarif-file formats both emit diagnostics in SARIF Version 2.1.0 format. sarif-stderr sends them to stderr, and sarif-file writes them to a file named source.sarif โœจ.

json is just a synonym for json-stderr. The json-stderr and json-file formats are identical, apart from where the JSON goes: the former emits to stderr, while json-file writes it to source.gcc.json ๐ŸŽ€.

The emitted JSON is a top-level JSON array, and inside it are JSON objects representing the diagnostics ๐Ÿซถ.

Diagnostics can have child diagnostics too. For example, this error and note:

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

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

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

Here the "note" is a child of the "warning" ๐ŸŒท.

A diagnostic has a "kind". If that's "warning", then there's an "option" key describing the command-line option controlling the warning ๐Ÿšจ.

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

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

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

For example, this error:

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

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

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

If a diagnostic contains fix-it hints, it has a "fixits" array made of half-open intervals, similar to the output of -fdiagnostics-parseable-fixits ๐Ÿ”ง. For example, this diagnostic with a replacement fix-it hint:

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

might be printed in JSON form as:

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

okay so the fix-it hint is basically saying "swap this chunk out for that." ๐Ÿ’… It replaces the text from "start" up to but not including "next" with the "string" value. Want to delete something? Give "string" an empty value ๐Ÿงน. Want to insert something? Make "start" equal "next" โœจ. So cute, so precise, no notes.

If the diagnostic has a path of control-flow events attached to it, you'll see a "path" array full of event objects ๐Ÿฆ‹. Each event has a "description" string, a "location" object, plus a "function" string and a "depth" number for tracking interprocedural paths. The "function" tells you which function is running at that event, and the "depth" is the stack depth relative to some baseline. Higher depth means more frames on the stack. Main character stack energy ๐ŸŒธ.

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

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

Diagnostics also have a boolean attribute called escape-source ๐Ÿ™ˆ. It's a hint for whether non-ASCII bytes should be escaped when the pertinent lines of source code get printed. It's true for diagnostics involving source encoding issues, so that's your red flag, bestie ๐Ÿšฉ.

  • -fno-diagnostics-json-formatting โ€” okay so by default, when JSON gets emitted for diagnostics (via -fdiagnostics-format=sarif-stderr, -fdiagnostics-format=sarif-file, -fdiagnostics-format=json, -fdiagnostics-format=json-stderr, or -fdiagnostics-format=json-file), GCC adds newlines and indentation so the hierarchy looks pretty and readable ๐Ÿ’–. Use -fno-diagnostics-json-formatting to strip that whitespace out. It must be passed before the option it is to affect โš ๏ธ. This is meant for tools that don't expect newlines in the output, like the kind older GCC releases spit out ๐Ÿง“.

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

Okay, warnings are diagnostic messages about stuff that isn't technically broken but is risky or hints that there might be a mistake lurking ๐Ÿ‘€.

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

  • -fsyntax-only โ€” checks your code for syntax errors and then stops right there. No extra fuss ๐Ÿงผ.
  • -fmax-errors=n โ€” caps the number of error messages at n, and once you hit that, GCC bails instead of trying to keep going through the source code ๐Ÿ›‘. If n is 0 (the default), there's no limit on how many error messages get printed. If -Wfatal-errors is also specified, then -Wfatal-errors takes precedence over this option ๐Ÿ‘‘.
  • -w โ€” inhibits all warning messages. Silence is golden ๐Ÿคซ.
  • -Werror โ€” turns every warning into an error ๐Ÿ˜ค.
  • -Werror= โ€” turns one specific warning into an error. You append the warning's specifier, so for example -Werror=switch turns the warnings controlled by -Wswitch into errors. This one also has a negative form, used to negate -Werror for specific warnings. For example, -Wno-error=switch makes -Wswitch warnings not be errors, even when -Werror is in effect ๐Ÿ™…โ€โ™€๏ธ.
  • -Wfatal-errors โ€” makes the compiler abort compilation on the first error it runs into, instead of trying to keep going and printing more error messages ๐Ÿ›‘.

The warning message for each controllable warning includes the option that controls it ๐Ÿ”. You can then use that option with -Werror= and -Wno-error= like we just covered. (Printing of the option in the warning message can be disabled using the -fno-diagnostics-show-option flag.)

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

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

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

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

The effectiveness of some warnings depends on optimizations also being enabled. For example, -Wsuggest-final-types is more effective with link-time optimization, and some instances of other warnings may not be issued at all unless optimization is enabled ๐Ÿ”ฅ. While optimization in general improves the efficacy of control and data flow sensitive warnings, in some cases it may also cause false positives ๐Ÿ’€.

  • -Wpedantic, -pedantic โ€” issues all the warnings demanded by strict ISO C and ISO C++, and diagnoses all programs that use forbidden extensions, plus some other programs that don't follow ISO C and ISO C++ ๐Ÿ“. This follows the version of the ISO C or C++ standard specified by any -std option used.

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

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

Some warnings about non-conforming programs are controlled by options other than -Wpedantic. In many cases they're implied by -Wpedantic but can be disabled separately by their specific option, e.g. -Wpedantic -Wno-pointer-sign ๐Ÿงš.

Where the standard specified with -std represents a GNU extended dialect of C, such as gnu90 or gnu99, there is a corresponding base standard: the version of ISO C that the GNU extended dialect is based on. Warnings from -Wpedantic are given where the base standard requires them. (It doesn't make sense for those warnings to only be given for features outside the specified GNU C dialect, since by definition the GNU dialects of C include every feature the compiler supports with the given option, so there would be nothing to warn about ๐Ÿค“.)

  • -pedantic-errors โ€” okay bestie, this one is STRICT ๐Ÿ’… It turns the stuff the base standard (see -Wpedantic) says must be diagnosed into errors. That covers some spots with undefined behavior at compile-time, plus some other spots that won't stop a program that's valid under the standard from compiling ๐Ÿซถ

Heads up, this is not the same as -Werror=pedantic ๐Ÿ‘€ ngl that one is kinda pointless, since it only turns -Wpedantic diagnostics into errors. -pedantic-errors goes further and also hits the required diagnostics that are always on, or controlled by options other than -Wpedantic. Main character energy ๐Ÿ‘‘

Want the required diagnostics that are warnings by default to become errors, but without turning on the -Wpedantic diagnostics? Then use -pedantic-errors -Wno-pedantic. Or -pedantic-errors -Wno-error=pedantic if you want those enabled but still just as warnings ๐ŸŒธ

Some required diagnostics are errors by default, but you can knock them down to warnings with -fpermissive or their own specific warning option, like -Wno-error=narrowing ๐Ÿฆ‹

Some diagnostics for non-ISO practices are controlled by specific warning options other than -Wpedantic, but -pedantic-errors makes those into errors too. For instance:

-Wattributes (for standard attributes), -Wchanges-meaning (C++), -Wcomma-subscript (C++23 or later), -Wdeclaration-after-statement (C90 or earlier), -Welaborated-enum-base (C++11 or later), -Wimplicit-int (C99 or later), -Wimplicit-function-declaration (C99 or later), -Wincompatible-pointer-types, -Wint-conversion, -Wlong-long (C90 or earlier), -Wmain, -Wnarrowing (C++11 or later), -Wpointer-arith, -Wpointer-sign, -Wincompatible-pointer-types, -Wregister (C++17 or later), -Wvla (C90 or earlier), -Wwrite-strings (C++11 or later)


  • -fpermissive โ€” the chill option ๐Ÿงš It downgrades some required diagnostics about nonconformant code from errors to warnings, so yes, it lets some nonconforming code compile. Some C++ diagnostics are controlled only by this flag, and it also downgrades some C and C++ diagnostics that have their own flag:

-Wdeclaration-missing-parameter-type (C and Objective-C only), -Wimplicit-function-declaration (C and Objective-C only), -Wimplicit-int (C and Objective-C only), -Wincompatible-pointer-types (C and Objective-C only), -Wint-conversion (C and Objective-C only), -Wnarrowing (C++ and Objective-C++ only), -Wreturn-mismatch (C and Objective-C only)

-fpermissive is the default for the historic C language modes (-std=c89, -std=gnu89, -std=c90, -std=gnu90) ๐Ÿ•ฐ๏ธ


  • -Wall โ€” this one flags all the warnings about constructions some users find questionable, and that are easy to avoid (or easy to tweak so the warning goes away), even when macros are involved ๐Ÿ”ฅ It also turns on some language-specific warnings described in the C++ Dialect Options and the Objective-C and Objective-C++ Dialect Options sections.

-Wall turns on the following warning flags:

-Waddress, -Waligned-new (C++ and Objective-C++ only), -Warray-bounds=1 (only with -O2), -Warray-compare, -Warray-parameter=2, -Wbool-compare, -Wbool-operation, -Wc++11-compat, -Wc++14-compat, -Wc++17compat, -Wc++20compat, -Wcatch-value (C++ and Objective-C++ only), -Wchar-subscripts, -Wclass-memaccess (C++ and Objective-C++ only), -Wcomment, -Wdangling-else, -Wdangling-pointer=2, -Wdelete-non-virtual-dtor (C++ and Objective-C++ only), -Wduplicate-decl-specifier (C and Objective-C only), -Wenum-compare (in C/ObjC; this is on by default in C++), -Wenum-int-mismatch (C and Objective-C only), -Wformat=1, -Wformat-contains-nul, -Wformat-diag, -Wformat-extra-args, -Wformat-overflow=1, -Wformat-truncation=1, -Wformat-zero-length, -Wframe-address, -Wimplicit (C and Objective-C only), -Wimplicit-function-declaration (C and Objective-C only), -Wimplicit-int (C and Objective-C only), -Winfinite-recursion, -Winit-self (C++ and Objective-C++ only), -Wint-in-bool-context, -Wlogical-not-parentheses, -Wmain (only for C/ObjC and unless -ffreestanding), -Wmaybe-uninitialized, -Wmemset-elt-size, -Wmemset-transposed-args, -Wmisleading-indentation (only for C/C++), -Wmismatched-dealloc, -Wmismatched-new-delete (C++ and Objective-C++ only), -Wmissing-attributes, -Wmissing-braces (only for C/ObjC), -Wmultistatement-macros, -Wnarrowing (C++ and Objective-C++ only), -Wnonnull, -Wnonnull-compare, -Wopenmp-simd (C and C++ only), -Woverloaded-virtual=1 (C++ and Objective-C++ only), -Wpacked-not-aligned, -Wparentheses, -Wpessimizing-move (C++ and Objective-C++ only), -Wpointer-sign (only for C/ObjC), -Wrange-loop-construct (C++ and Objective-C++ only), -Wreorder (C++ and Objective-C++ only), -Wrestrict, -Wreturn-type, -Wself-move (C++ and Objective-C++ only), -Wsequence-point, -Wsign-compare (C++ and Objective-C++ only), -Wsizeof-array-div, -Wsizeof-pointer-div, -Wsizeof-pointer-memaccess, -Wstrict-aliasing, -Wstrict-overflow=1, -Wswitch, -Wtautological-compare, -Wtrigraphs, -Wuninitialized, -Wunknown-pragmas, -Wunused, -Wunused-but-set-variable, -Wunused-const-variable=1 (only for C/ObjC), -Wunused-function, -Wunused-label, -Wunused-local-typedefs, -Wunused-value, -Wunused-variable, -Wuse-after-free=2, -Wvla-parameter, -Wvolatile-register-var, -Wzero-length-bounds

Now, a fair warning ๐Ÿ™ˆ some warning flags are not implied by -Wall. Some of them flag stuff users generally don't see as questionable, but which you might occasionally want to check for. Others flag constructions that are necessary or hard to avoid in some cases, with no simple way to rewrite the code to shush the warning. Some of them are turned on by -Wextra, but lots of them have to be enabled one by one ๐Ÿ’–


  • -Wextra โ€” this turns on some extra warning flags that -Wall doesn't enable โœจ (Fun fact: this option used to be called -W. The older name still works, but -Wextra is way more descriptive, so we stan ๐ŸŽ€)

-Wabsolute-value (only for C/ObjC), -Walloc-size, -Wcalloc-transposed-args, -Wcast-function-type, -Wclobbered, -Wdeprecated-copy (C++ and Objective-C++ only), -Wempty-body, -Wenum-conversion (only for C/ObjC), -Wexpansion-to-defined, -Wignored-qualifiers (only for C/C++), -Wimplicit-fallthrough=3, -Wmaybe-uninitialized, -Wmissing-field-initializers, -Wmissing-parameter-type (C/ObjC only), -Wold-style-declaration (C/ObjC only), -Woverride-init (C/ObjC only), -Wredundant-move (C++ and Objective-C++ only), -Wshift-negative-value (in C++11 to C++17 and in C99 and newer), -Wsign-compare (C++ and Objective-C++ only), -Wsized-deallocation (C++ and Objective-C++ only), -Wstring-compare, -Wtype-limits, -Wuninitialized, -Wunused-parameter (only with -Wunused or -Wall), -Wunused-but-set-parameter (only with -Wunused or -Wall)

-Wextra also prints warning messages for these cases too ๐Ÿ‘€

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

  • -Wabi (C, Objective-C, C++ and Objective-C++ only) โ€” okay this one is about ABI drama ๐Ÿง It warns about code affected by ABI changes, which includes code that might not be compatible with the vendor-neutral C++ ABI, as well as the psABI for the particular target.

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

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

If an explicit version number is provided and -fabi-compat-version is not specified, the version number from this option gets used for compatibility aliases. If no explicit version number is given with this option, but -fabi-compat-version is specified, that version number is used for C++ ABI warnings ๐ŸŒˆ

Now, real talk no check is perfect ๐Ÿฅบ Although an effort has been made to warn about all such cases, there are probably some that go unwarned, even though G++ is generating incompatible code. There may also be cases where warnings fire 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, you should rewrite your code to avoid these warnings ๐Ÿซถ

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

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

This was fixed in -fabi-version=3.

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

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

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

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

  • Scoped enumerators passed as arguments to a variadic function get promoted like unscoped enumerators, causing va_arg to complain. On most targets this doesn't actually affect the parameter passing ABI, since there's no way to pass an argument smaller than int. The ABI also changed the mangling of template argument packs, const_cast, static_cast, prefix increment/decrement, and a class scope function used as a template argument.

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

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

These issues were corrected in -fabi-version=7. ๐Ÿ’–

  • When mangling a function type that has function-cv-qualifiers, the un-qualified function type was wrongly counted as a substitution candidate ๐Ÿ˜ญ. This was fixed in -fabi-version=8, the default for GCC 5.1 ๐Ÿ’….
  • decltype(nullptr) had an alignment of 1, which led to unaligned accesses ๐Ÿ™ˆ. It didn't change the ABI of a function with a nullptr_t parameter, since parameters already get a minimum alignment ๐Ÿซถ. This was fixed in -fabi-version=9, the default for GCC 5.2 ๐Ÿ”ฅ.
  • Target-specific attributes that change what a type is, like ia32 calling conventions on a function type (stdcall, regparm, etc.), weren't reflected in the mangled name ๐Ÿ’€. That caused name collisions whenever function pointers were used as template arguments. This was fixed in -fabi-version=10, the default for GCC 6.1 ๐Ÿ‘‘.
  • For SysV/x86-64, unions with long double members are passed in memory, as the psABI specifies ๐Ÿงš. Before GCC 4.4 that wasn't the case. For example:
union U {
  long double ld;
  int i;
};

union U is now always passed in memory ๐Ÿฆ‹.

  • -Wno-changes-meaning (C++ and Objective-C++ only) โ€” C++ wants unqualified uses of a name inside a class to mean the same thing across the whole class scope, so using a name first and declaring it later is ill-formed ๐Ÿ™…โ€โ™€๏ธ:
struct A;
struct B1 { A a; typedef A A; }; // warning, 'A' changes meaning
struct B2 { A a; struct A { }; }; // error, 'A' changes meaning

By default the B1 case is only a warning, because both declarations have the same type. The B2 case is an error. Both diagnostics can be turned off with -Wno-changes-meaning. If you'd rather the error be a warning, use -Wno-error=changes-meaning or -fpermissive โœจ. Both diagnostics are also suppressed by -fms-extensions ๐ŸŒธ.

  • -Wchar-subscripts โ€” warns if an array subscript has type char ๐Ÿ“. This is a super common mistake, since people forget that char is signed on some machines. This warning is enabled by -Wall ๐Ÿ’œ.
  • -Wno-coverage-mismatch โ€” warns if feedback profiles don't match when you use -fprofile-use ๐Ÿ”. If a source file changes between -fprofile-generate and -fprofile-use, the profile feedback files can stop matching the source, and GCC can't use the feedback info. By default this warning is on and treated as an error. Use -Wno-coverage-mismatch to silence the warning, or -Wno-error=coverage-mismatch to silence the error.
Turning off the error can lead to poorly optimized code. It's only really useful for very minor changes, like bug fixes in an existing code-base. Completely disabling the warning is not recommended ๐Ÿ™ƒ.
  • -Wno-coverage-too-many-conditions โ€” warns if -fcondition-coverage is used and an expression has too many terms, so GCC gives up on coverage ๐Ÿฅบ. Coverage is given up when the conditional has more terms than there are bits in a gcov_type_unsigned. This warning is enabled by default ๐ŸŒˆ.
  • -Wno-coverage-invalid-line-number โ€” warns if a function ends before it begins because of invalid linenum macros ๐Ÿคฏ. The warning is only emitted when --coverage is enabled.

By default this warning is enabled and treated as an error. -Wno-coverage-invalid-line-number disables the warning, and -Wno-error=coverage-invalid-line-number disables the error ๐Ÿซ .

  • -Wno-cpp (C, Objective-C, C++, Objective-C++ and Fortran only) โ€” silences the warnings that #warning directives spit out ๐Ÿคซ.
  • -Wdouble-promotion (C, C++, Objective-C and Objective-C++ only) โ€” warns when a float value gets implicitly promoted to double ๐Ÿ“ˆ. CPUs with a 32-bit single-precision floating-point unit do float in hardware but emulate double in software. So doing math with double on those machines is way more expensive because of the emulation overhead ๐Ÿข.

It's super easy to accidentally do math in double, because floating-point literals are implicitly double ๐Ÿ˜ฉ. For example:

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

The compiler does the whole computation in double, because the floating-point literal is a double ๐Ÿ’€.

  • -Wduplicate-decl-specifier (C and Objective-C only) โ€” warns if a declaration has a duplicate const, volatile, restrict or _Atomic specifier ๐Ÿง. This warning is enabled by -Wall ๐Ÿ’….
  • -Wformat, -Wformat=n โ€” checks calls to printf and scanf (and friends) ๐Ÿ–จ๏ธ. It makes sure the arguments match the types the format string expects, and that the conversions in the format string actually make sense ๐Ÿง. This covers standard functions plus anything else marked with format attributes, in the printf, scanf, strftime and strfmon families (strfmon is an X/Open extension and isn't in the C standard), or other target-specific families ๐ŸŒท. Which functions get checked without a format attribute depends on the standard version you picked. Those checks are turned off by -ffreestanding or -fno-builtin ๐Ÿšซ.

The formats are checked against the features in GNU libc version 2.2 โœจ. That includes all of ISO C90 and C99, plus stuff from the Single Unix Specification and some BSD and GNU extensions. Other library implementations might not support all of these, and GCC won't warn about features that go beyond a particular library's limits ๐Ÿซถ. But if you use -Wpedantic together with -Wformat, you'll get warnings about format features that aren't in the standard version you selected. That doesn't apply to strfmon formats, since those aren't in any version of the C standard ๐Ÿ™ˆ.

  • -Wformat=1, -Wformat โ€” -Wformat is the same as -Wformat=1, and -Wno-format is the same as -Wformat=0 ๐ŸŽ€. Since -Wformat also checks for null format arguments in several functions, it implies -Wnonnull too ๐Ÿ’–. Some parts of this level of checking can be turned off with -Wno-format-contains-nul, -Wno-format-extra-args, and -Wno-format-zero-length. -Wformat is enabled by -Wall ๐ŸŒธ.
  • -Wformat=2 โ€” turns on -Wformat plus extra format checks ๐Ÿ”ฅ. Right now it'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 passed to a printf or scanf format function ๐Ÿฆ‹. The C standard says those extra arguments are just ignored ๐Ÿซ .

If the unused arguments sit between used arguments that are given with $ operand number specifications, warnings still come out by default. That's because the compiler can't know what type to pass to va_arg to skip the unused ones ๐Ÿ˜ตโ€๐Ÿ’ซ. For scanf formats, though, this option does suppress the warning when all the unused arguments are pointers. The Single Unix Specification says those unused pointer arguments are allowed ๐Ÿงš.

  • -Wformat-overflow, -Wformat-overflow=level โ€” warns about calls to formatted output functions like sprintf and vsprintf that might overflow the destination buffer ๐Ÿ’ฅ. If the exact number of bytes a format directive writes can't be figured out at compile time, GCC estimates it with heuristics. Those depend on the level argument and on optimization. Turning on optimization usually makes the warning more accurate, but it can also cause false positives ๐Ÿ™ƒ.
    • -Wformat-overflow, -Wformat-overflow=1 โ€” level 1 is enabled by -Wformat and takes a conservative approach ๐Ÿงธ. It only warns about calls that will most likely overflow the buffer. At this level, numeric arguments with unknown values are assumed to be one, and strings of unknown length are assumed to be empty ๐ŸŒฑ. Numeric arguments known to be bounded to a subrange of their type, or string arguments whose output is bounded by the directive's precision or by a finite set of string literals, are assumed to take whatever value in their range produces the most bytes of output ๐Ÿ“. For example, this call to sprintf gets flagged. 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 calls that might overflow the destination buffer if an argument is long enough or large enough in magnitude ๐Ÿ“ฃ. At level 2, unknown numeric arguments are assumed to have the minimum representable value for signed types with a precision greater than 1, and the maximum representable value otherwise ๐Ÿ”ข. Unknown string arguments whose length can't be assumed bounded, either by the directive's precision, by a finite set of string literals they might evaluate to, or by the character array they may point to, are assumed to be 1 character long ๐Ÿงฉ.

Okay so we're picking up right where that sprintf example left off ๐Ÿ˜ญ๐ŸŽ€ At level 2, that same call gets flagged again, but this time it's because if a is equal to a 32-bit INT_MIN, the first %i directive will write some of its digits past the end of the destination buffer ๐Ÿ’€. To make the call safe no matter what the two variables hold, the destination buffer has to be at least 34 bytes. GCC even drops the minimum buffer size into an informational note right after the warning, so you don't have to do the math yourself ๐Ÿ’…

If resizing the buffer isn't your vibe, you can limit the range of the formatted values instead โœจ You can cap the maximum length of string arguments by putting a precision in the format directive. And if you can assume numeric arguments are bounded by less than the precision of their type, picking an appropriate length modifier for the format specifier will shrink the buffer you need. For example, if a and b in the example above are guaranteed to be within the precision of the short int type, then either using the %hi format directive or casting the argument to short drops the maximum required size of the buffer to 24 bytes ๐Ÿฆ‹

void f (int a, int b)
{
  char buf [23];
  sprintf (buf, "a = %hi, b = %i\n", a, (short)b);
}
  • -Wno-format-zero-length โ€” Okay, so if -Wformat is on, this tells GCC to chill and not warn about zero-length formats ๐ŸŒธ The C standard says zero-length formats are totally allowed, so no drama needed.
  • -Wformat-nonliteral โ€” If -Wformat is on, GCC will also warn when the format string isn't a string literal, since it can't check that kind of format ๐Ÿ‘€. The exception is when the format function takes its format arguments as a va_list.
  • -Wformat-security โ€” If -Wformat is on, this one also flags format function calls that could be a security problem ๐Ÿ”ฅ. Right now it warns about printf and scanf calls where the format string isn't a string literal and there are no format arguments, like printf (foo);. That's a potential security hole if the format string came from untrusted input and contains %n. (This is currently a subset of what -Wformat-nonliteral warns about, but future warnings may be added to -Wformat-security that aren't included in -Wformat-nonliteral.)
  • -Wformat-signedness โ€” If -Wformat is on, this warns when the format string wants an unsigned argument but you pass a signed one, and vice versa ๐ŸŒˆ
  • -Wformat-truncation, -Wformat-truncation=level โ€” Okay this one is giving output truncation drama ๐Ÿ’… It warns about calls to formatted input/output functions like snprintf and vsnprintf that might cut off the output. When GCC can't figure out the exact number of bytes a format directive writes at compile time, it guesses using heuristics that depend on the level argument and on optimization. Turning on optimization usually makes the warning more accurate, but it can also cause false positives โš ๏ธ. Unless noted otherwise, this option uses the same logic as -Wformat-overflow.
    • -Wformat-truncation or -Wformat-truncation=1 โ€” Level 1 is enabled by -Wformat and is the conservative option ๐Ÿง. It only warns about calls to bounded functions whose return value is unused and that will most likely truncate the output.
    • -Wformat-truncation=2 โ€” Level 2 is spicier and also warns about bounded functions whose return value is used, if they might truncate given an argument of big enough length or magnitude ๐Ÿ”ฅ.
  • -Wformat-y2k โ€” If -Wformat is on, this warns about strftime formats that might only give you a two-digit year ๐Ÿ“…
  • -Wnonnull โ€” Warns when you pass a null pointer to an argument that the nonnull function attribute says must be non-null ๐Ÿšซ. -Wnonnull is included in -Wall and -Wformat, and you can turn it off with -Wno-nonnull.
  • -Wnonnull-compare โ€” Warns when you compare an argument marked with the nonnull function attribute against null inside the function ๐Ÿ™ˆ. It's included in -Wall, and you can disable it with -Wno-nonnull-compare.
  • -Wnull-dereference โ€” Warns if the compiler finds paths that trigger erroneous or undefined behavior from dereferencing a null pointer ๐Ÿ’€. This only works when -fdelete-null-pointer-checks is active, which optimizations enable on most targets. How precise the warnings are depends on the optimization options you use.
  • -Wnrvo (C++ and Objective-C++ only) โ€” Warns if the compiler doesn't elide the copy from a local variable to the return value, even though [class.copy.elision] allows it ๐Ÿ’–. This is commonly called the Named Return Value Optimization. In the example below, the compiler can't elide copies from both v1 and v2, so it doesn't elide either one.
std::vector<int> f()
{
  std::vector<int> v1, v2;
  // ...
  if (cond) return v1;
  else return v2; // warning: not eliding copy
}
  • -Winfinite-recursion โ€” Warns about infinitely recursive calls ๐Ÿ”. It works at all optimization levels, but you need optimization to catch infinite recursion across two or more functions. It's included in -Wall.

Compare this with -Wanalyzer-infinite-recursion, which gives a similar diagnostic but is implemented differently (as part of -fanalyzer).

  • -Winit-self (C, C++, Objective-C and Objective-C++ only) โ€” Warns about uninitialized variables that get initialized with themselves ๐Ÿชž. This option can only be used together with -Wuninitialized.

In the following snippet, GCC warns about i being uninitialized only when -Winit-self is specified:

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

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

  • -Wno-implicit-int (C and Objective-C only) โ€” This controls warnings when a declaration doesn't specify a type ๐Ÿค”. It's enabled by default as an error in C99 and later C dialects, and also by -Wall. You can downgrade the error to a warning with -fpermissive (along with certain other errors), or for this error alone with -Wno-error=implicit-int.

This warning gets upgraded to an error by -pedantic-errors.

  • -Wno-implicit-function-declaration (C and Objective-C only) โ€” This controls warnings when a function is used before it's declared ๐Ÿ“ฃ. It's enabled by default as an error in C99 and later C dialects, and also by -Wall. You can downgrade the error to a warning with -fpermissive (along with certain other errors), or for this error alone with -Wno-error=implicit-function-declaration.

This warning gets upgraded to an error by -pedantic-errors.

  • -Wimplicit (C and Objective-C only) โ€” Same as -Wimplicit-int and -Wimplicit-function-declaration combined ๐Ÿงฉ. This warning is enabled by -Wall.
  • -Whardened โ€” Warns when -fhardened didn't enable an option from its set (see -fhardened for the full list) ๐Ÿ›ก๏ธ. For instance, if you use -fhardened and -fstack-protector at the same time on the command line, -Whardened warns because -fstack-protector-strong isn't enabled by -fhardened.

This warning is enabled by default and only has an effect when -fhardened is enabled.

  • -Wimplicit-fallthrough โ€” This is the same as -Wimplicit-fallthrough=3, and -Wno-implicit-fallthrough is the same as -Wimplicit-fallthrough=0 ๐Ÿ˜Œ.
  • -Wimplicit-fallthrough=n โ€” Warns when a switch case falls through ๐Ÿ“. For example:
switch (cond)
  {
  case 1:
    a = 1;
    break;
  case 2:
    a = 2;
  case 3:
    a = 3;
    break;
  }

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

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

Sometimes a fallthrough is exactly what you want, so GCC gives you an attribute, __attribute__ ((fallthrough)), to use along with a null statement to suppress the warning that would otherwise show up ๐Ÿงš:

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

C++17 has a standard way to suppress -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. Instead of these attributes, you can also add a fallthrough comment to silence the warning ๐Ÿ’ฌ. The whole body of the C or C++ style comment has to match the regular expressions listed below. The option argument n decides what kinds of comments are accepted:

  • -Wimplicit-fallthrough=0 disables the warning altogether ๐Ÿšซ.
  • -Wimplicit-fallthrough=1 matches the ".*" regular expression, so any comment counts as a fallthrough comment ๐Ÿซถ.
  • -Wimplicit-fallthrough=2 case insensitively matches the ".*falls?[ \t-]*thr(ough|u).*" regular expression ๐ŸŒธ.
  • -Wimplicit-fallthrough=3 case sensitively matches one of the following regular expressions:

okay so -Wimplicit-fallthrough=3 is the pickiest level ๐Ÿ’… the comment has to match one of these patterns, and GCC checks them exactly like this ๐Ÿ”

*<"-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 is a bit more chill ๐ŸŒธ it matches case sensitively against this shorter list:

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

-Wimplicit-fallthrough=5 doesn't recognize any comments as fallthrough comments at all ๐Ÿ’€ only attributes can turn the warning off, so no comment-based escape hatch for you, bestie ๐Ÿ™ˆ

The comment also needs to sit right before case or default, with only whitespace and other comments in between, or before a user label that comes right before a case or default label โœจ like this:

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

The -Wimplicit-fallthrough=3 warning is turned on by -Wextra ๐Ÿ”ฅ

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

This one controls whether warnings triggered by the warn_if_not_aligned attribute get issued ๐Ÿฆ‹ they're on by default, so you have to actively turn them off with -Wno-if-not-aligned if you don't want them.

๐ŸŒˆ -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, since the returned value isn't an lvalue, so it's giving "pointless" ๐Ÿ˜ญ For 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, no cap.

This warning is also turned on by -Wextra.

๐Ÿ’œ -Wno-ignored-attributes (C and C++ only)

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

๐Ÿ‘‘ -Wmain

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

โš ๏ธ -pedantic-errors upgrades this warning into an error, so it stops being just a warning, bestie ๐Ÿ˜ฑ

๐Ÿงš -Wmisleading-indentation (C and C++ only)

Warns when the indentation doesn't match the real block structure ๐Ÿ™ˆ specifically, it fires for if, else, while, and for clauses that have a guarded statement without braces, followed by an unguarded statement at the same indentation level. Gotcha energy ๐Ÿ’€

In this example, bar is misleadingly indented like it's guarded by the if, 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 the statements actually line up, and it defaults to 8 ๐Ÿ“

It won't warn about code with multiline preprocessor logic like this one ๐ŸŒธ

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

It also skips anything after a #line directive ๐Ÿงš that usually means the code was autogenerated, and nobody can assume anything about the file layout that the directive points to.

This warning is turned on 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 ๐Ÿ” this matters because leaving them out can hurt correctness or efficiency of the generated code. For example, it fires for declarations of aliases that use attributes to set less restrictive requirements than their targets. That usually means a potential optimization opportunity ๐Ÿ’–

The option -Wattribute-alias=2 is kind of the opposite ๐Ÿ™ƒ it warns when an alias is more restrictive than its target, which could lead to incorrect code generation. The attributes considered here include "alloc_align", "alloc_size", "cold", "const", "hot", "leaf", "malloc", "nonnull", "noreturn", "nothrow", "pure", "returns_nonnull", and "returns_twice".

In C++, the warning fires when an explicit specialization of a primary template is declared without an attribute that the primary template has. The attributes that count are "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 works on declarations of functions, variables, or types.

-Wmissing-attributes is turned on by -Wall ๐Ÿ”ฅ

For example, the primary function template below uses both "malloc" and "alloc_size", so the explicit specialization gets flagged because it's missing one of them ๐Ÿ‘€

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

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

๐ŸŒธ -Wmissing-braces

Warns if an aggregate or union initializer isn't fully bracketed ๐Ÿ’… in this example, the initializer for a isn't fully bracketed, but the one for b is.

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

This warning is turned on by -Wall โœจ

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

Warns if a user-supplied include directory doesn't exist ๐Ÿ“‚ this option is disabled by default for C, C++, Objective-C, and Objective-C++. For Fortran, it's partially on by default, but only for -I and -J ๐Ÿ’–

๐Ÿซง -Wno-missing-profile

This controls warnings about missing feedback profiles when you use -fprofile-use ๐Ÿ“Š it catches cases where a new function or a new file got added between compiling with -fprofile-generate and -fprofile-use, without regenerating the profiles. In those cases, the profile feedback data files don't have any info for the new function or file, bestie.

Also, if profile count data (.gcda) files get removed, GCC can't use any profile feedback information at all ๐Ÿ˜ญ in every one of these cases, you get warnings reminding you that a profile generation step is due. Ignoring them can give you poorly optimized code, so be careful ๐Ÿ™ˆ

-Wno-missing-profile turns the warning off, but it's not recommended ๐Ÿšซ only do it when the missing profile data is actually justified.

๐Ÿ’€ -Wmismatched-dealloc

Warns about calls to deallocation functions with pointer arguments that came from allocation functions the deallocator doesn't match ๐Ÿง  you can pair up matching allocators and deallocators with the malloc attribute. Unless -fno-builtin turns it off, the standard functions "calloc", "malloc", "realloc", and "free", plus the C++ "operator new" and "operator delete" forms, are implicitly matched up already โœจ

In this example, mydealloc is the deallocator for pointers returned by myalloc ๐Ÿ“

void mydealloc (void*);

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

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

In C++, the related option -Wmismatched-new-delete catches mismatches involving either "operator new" or "operator delete" ๐Ÿ’œ

-Wmismatched-dealloc is included in -Wall ๐Ÿ‘‘

๐ŸŒˆ -Wmultistatement-macros

Warns about unsafe multi-statement macros that look guarded by a clause like if, else, for, switch, or while ๐Ÿ˜ฌ the problem is that after the macro expands, only the first statement is actually guarded.

For example:

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

This increments y unconditionally, not just when c holds ๐Ÿ’€ It 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 turned on by -Wall in C and C++ ๐Ÿซถ

๐Ÿง  -Wparentheses

Warns when parentheses are left out in certain spots ๐Ÿ” like when there's an assignment where a truth value is expected, or when nested operators have precedence that people often mix up.

It also warns if a comparison like x<=y<=z shows up ๐Ÿ‘€ that's equivalent to (x<=y ? 1 : 0) <= z, which is a different reading from ordinary math notation, so it's giving confusing ๐Ÿ˜ญ

It also warns about dangerous uses of the GNU extension to ?: with the middle operand omitted ๐Ÿ™ˆ 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.

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

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

This warning is turned on by -Wall ๐ŸŽ€

  • -Wno-self-move (C++ and Objective-C++ only) โ€” okay bestie ๐Ÿซถ this one screams when you std::move a value into itself. That usually does absolutely nothing, so it's lowkey a red flag ๐Ÿšฉ. Here's the sus code:
struct T {
...
};
void fn()
{
  T t;
  ...
  t = std::move (t);
}

This warning is enabled by -Wall ๐Ÿ’…

  • -Wsequence-point โ€” ohhh this one is the drama queen ๐Ÿ‘‘ It warns about code that might have undefined semantics because it breaks the sequence point rules in the C and C++ standards. Sequence points are like little checkpoints where the program has finished certain stuff. They happen after a full expression finishes (one that isn't part of a bigger expression), after the first operand of &&, ||, ? : or , (comma) operator gets evaluated, before a function is called (but after its arguments and the expression naming the called function are evaluated), and in a few other spots. Outside those checkpoints, the order that subexpressions get evaluated is not specified ๐Ÿคทโ€โ™€๏ธ The rules only give a partial order, not a total one. For example, if two functions get called in one expression with no sequence point between them, the order they run in is not specified. The standards committee did rule that function calls don't overlap though ๐ŸŒธ

It's also not specified when, between sequence points, changes to object values take effect. Programs that depend on that have undefined behavior. The standards basically say that between two sequence points, an object can only have its stored value changed once, and the old value can only be read to figure out the new value being stored.

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

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

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

The standard is worded confusingly, so there's some debate over the precise meaning of the sequence point rules in subtle cases. Links to discussions of the problem, including proposed formal definitions, can be found on the GCC readings page at <https://gcc.gnu.org/readings.html> ๐Ÿ“š

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


  • -Wno-return-local-addr โ€” bestie, this one turns off the warning for returning a pointer (or a reference, in C++) to a variable that goes out of scope once the function returns ๐Ÿฆ‹
  • -Wreturn-mismatch โ€” this one checks your return statements ๐Ÿง It warns about return statements without an expression in functions that don't return void. It also warns about a return with an expression in a void function, unless the expression's type is also void. As a GNU extension, that last case is accepted without a warning unless -Wpedantic is used.
โš ๏ธ Trying to use the return value of a non-void function other than main that flows off the end by reaching the closing curly brace that ends the function is undefined. Yikes ๐Ÿ˜ญ

This warning is specific to C and enabled by default. In C99 and later dialects it's treated as an error ๐Ÿ’€ If you want to downgrade it to a warning, you can use -fpermissive (which also downgrades other warnings), or just this one with -Wno-error=return-mismatch ๐ŸŒˆ

  • -Wreturn-type โ€” warns whenever a function is defined with a return type that defaults to int (unless -Wimplicit-int is active, which takes precedence). It also warns if execution may reach the end of the function body, or if the function doesn't contain any return statement at all ๐Ÿ‘€
โš ๏ธ Trying to use the return value of a non-void function other than main that flows off the end by reaching the closing curly brace that ends the function is undefined.

Unlike in C, in C++, flowing off the end of a non-void function other than main results in undefined behavior even when the value of the function isn't used. Scary stuff ๐Ÿ˜ฑ

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

  • -Wno-shift-count-negative โ€” controls warnings if a shift count is negative. This warning is enabled by default ๐Ÿซถ
  • -Wno-shift-count-overflow โ€” controls warnings if a shift count is greater than or equal to the bit width of the type. This warning is enabled by default ๐Ÿ’–
  • -Wshift-negative-value โ€” warns if you left shift a negative value. This warning is enabled by -Wextra in C99 (and newer) and C++11 to C++17 modes ๐Ÿ“
  • -Wno-shift-overflow, -Wshift-overflow=n โ€” these options control warnings about left shift overflows ๐ŸŒŠ
    • -Wshift-overflow=1 โ€” this is the warning level of -Wshift-overflow and is enabled by default in C99 and C++11 modes (and newer). This level does not warn about left-shifting 1 into the sign bit. (However, in C, such an overflow is still rejected in contexts where an integer constant expression is required.) No warning is emitted in C++20 mode (and newer), since signed left shifts always wrap ๐Ÿงš
    • -Wshift-overflow=2 โ€” this warning level also warns about left-shifting 1 into the sign bit, unless C++14 mode (or newer) is active ๐Ÿ”ฅ
  • -Wswitch โ€” warns whenever a switch statement has an index of enumerated type and lacks a case for one or more of the named codes of that enumeration. (Having a default label prevents this warning.) case labels outside the enumeration range also trigger warnings when this option is used, even if there's a default label. This warning is enabled by -Wall ๐ŸŽ€
  • -Wswitch-default โ€” warns whenever a switch statement doesn't have a default case ๐ŸŒธ
  • -Wswitch-enum โ€” the same vibe as -Wswitch, with case labels outside the enumeration range also provoking warnings. The only real difference is that this one warns about an omitted enumeration code even when there's a default label ๐Ÿ’…
  • -Wno-switch-bool โ€” don't warn when a switch statement has an index of boolean type and the case values are outside the range of a boolean type. You can suppress this warning by casting the controlling expression to a type other than bool. For example:
switch ((int) (a == 4))
  {
  ...
  }

This warning is enabled by default for C and C++ programs ๐Ÿฆ‹

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

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

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

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

  • -Wsync-nand (C and C++ only) โ€” warns when the __sync_fetch_and_nand and __sync_nand_and_fetch built-in functions are used. These functions changed semantics in GCC 4.4 โญ
  • -Wtrivial-auto-var-init โ€” warns when -ftrivial-auto-var-init can't initialize an automatic variable. A common situation is an automatic variable declared between the controlling expression and the first case label of a switch statement ๐Ÿง

  • -Wunused-but-set-parameter โ€” warns whenever a function parameter is assigned to but otherwise unused (aside from its declaration). To suppress this warning, use the unused attribute. This warning is also enabled by -Wunused together with -Wextra ๐ŸŒท
  • -Wunused-but-set-variable โ€” warns whenever a local variable is assigned to but otherwise unused (aside from its declaration). This warning is enabled by -Wall. To suppress it, use the unused attribute. It's also enabled by -Wunused, which is enabled by -Wall ๐Ÿ’œ
  • -Wunused-function โ€” warns whenever a static function is declared but not defined, or when a non-inline static function is unused. This warning is enabled by -Wall ๐ŸŒธ
  • -Wunused-label โ€” warns whenever a label is declared but not used. This warning is enabled by -Wall. To suppress it, use the unused attribute ๐Ÿ“
  • -Wunused-local-typedefs (C, Objective-C, C++ and Objective-C++ only) โ€” warns when a typedef locally defined in a function is not used. This warning is enabled by -Wall ๐Ÿซถ
  • -Wunused-parameter โ€” warns whenever a function parameter is unused aside from its declaration. This option is not enabled by -Wunused unless -Wextra is also specified. To suppress this warning, use the unused attribute โœจ
  • -Wno-unused-result โ€” don't warn if a caller of a function marked with the attribute warn_unused_result doesn't use its return value. The default is -Wunused-result ๐Ÿ‘‘
  • -Wunused-variable โ€” okay bestie, this one sounds the alarm whenever a local or static variable is just sitting there doing nothing except its declaration ๐Ÿ’€. This option implies -Wunused-const-variable=1 for C, but not for C++ ๐Ÿ™…โ€โ™€๏ธ. It's enabled by -Wall โœจ. To shush this warning, slap the "unused" attribute on it ๐Ÿ’….
  • -Wunused-const-variable, -Wunused-const-variable=n โ€” the sequel ๐ŸŽฌ. This warns whenever a constant static variable is unused aside from its declaration ๐ŸŒธ. To suppress it, use the "unused" attribute ๐Ÿซถ.
    • -Wunused-const-variable=1 โ€” warns about unused static const variables defined in the main compilation unit, but NOT about static const variables declared in any header that gets included ๐Ÿงš. It's enabled by either -Wunused-variable or -Wunused for C, but not for C++. In C this declares variable storage, but in C++ it isn't an error, since const variables take the place of "#define"s ๐Ÿคทโ€โ™€๏ธ.
    • -Wunused-const-variable=2 โ€” this level also warns about unused constant static variables in headers (excluding system headers) ๐Ÿ“š. It's equivalent to the short form -Wunused-const-variable. You have to explicitly request this level in both C and C++, because it might be hard to clean up all the headers you've included ๐Ÿ˜ญ.
  • -Wunused-value โ€” warns whenever a statement computes a result that's explicitly not used ๐Ÿง. To suppress it, cast the unused expression to "void" ๐Ÿซถ. It catches an expression-statement, or the left-hand side of a comma expression, that contains no side effects. For example, an expression such as x[i,j] causes a warning, while x[(void)i,j] does not ๐Ÿ‘€. This warning is enabled by -Wall ๐ŸŒˆ.
  • -Wunused โ€” the combo meal ๐ŸŸ. It's all the above -Wunused options combined, except the ones documented as needing to be specified explicitly ๐Ÿ“. If you want a warning about an unused function parameter, you must either specify -Wextra -Wunused (note that -Wall implies -Wunused), or separately specify -Wunused-parameter and/or -Wunused-but-set-parameter ๐ŸŽ€. -Wunused enables only -Wunused-const-variable=1 rather than -Wunused-const-variable, and only for C, not C++ ๐Ÿ™…โ€โ™€๏ธ.
  • -Wuse-after-free, -Wuse-after-free=n โ€” only for C, Objective-C, C++ and Objective-C++ ๐Ÿฆ‹. This one warns about uses of pointers to dynamically allocated objects that have been made indeterminate by a call to a deallocation function ๐Ÿ’€. It's enabled at all optimization levels, but it may give different results with optimization than without โš ๏ธ.
    • -Wuse-after-free=1 โ€” at level 1, the warning only tries to diagnose unconditional uses of pointers made indeterminate by a deallocation call or a successful call to "realloc", regardless of whether that call actually resulted in a reallocation of memory ๐Ÿง . This includes double-"free" calls, as well as uses in arithmetic and relational expressions. Although undefined, uses of indeterminate pointers in equality (or inequality) expressions are not diagnosed at this level ๐Ÿ™ˆ.
    • -Wuse-after-free=2 โ€” at level 2, on top of unconditional uses, the warning also diagnoses conditional uses of pointers made indeterminate by a deallocation call. As at level 2, uses in equality (or inequality) expressions are not diagnosed. For example, the second call to "free" in the following function is diagnosed at this level ๐Ÿ‘‘:
struct A { int refcount; void *data; };

void release (struct A *p)
{
  int refcount = --p->refcount;
  free (p);
  if (refcount == 0)
    free (p->data);   // warning: p may be used after free
}
  • -Wuse-after-free=3 โ€” at level 3, the warning also diagnoses uses of indeterminate pointers in equality expressions ๐Ÿ”ฅ. All uses of indeterminate pointers are undefined, but equality tests sometimes show up after calls to "realloc" as an attempt to figure out whether the call relocated the object to a different address ๐Ÿค”. They get their own level so legacy code can gradually transition to safe alternatives ๐ŸŒฑ. For example, the equality test in the function below is diagnosed at this level:
void adjust_pointers (int**, int);

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

To avoid the warning at this level, store offsets into allocated memory instead of pointers ๐Ÿงšโ€โ™€๏ธ. That obviates needing to adjust the stored pointers after reallocation โœจ. -Wuse-after-free=2 is included in -Wall ๐Ÿ’….

  • -Wuseless-cast โ€” only for C, Objective-C, C++ and Objective-C++ ๐Ÿ™„. It warns when an expression is cast to its own type. It does not occur when a class object is converted to a non-reference type, because that's a way to create a temporary ๐Ÿงƒ:
struct S { };
void g (S&&);
void f (S&& arg)
{
  g (S(arg)); // make arg prvalue so that it can bind to S&&
}
  • -Wuninitialized โ€” warns if an object with automatic or allocated storage duration is used without having been initialized ๐Ÿ˜ญ. In C++, it also warns if a non-static reference or non-static "const" member appears in a class without constructors ๐Ÿซ .

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

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

These warnings occur for individual uninitialized elements of structure, union or array variables, as well as for variables that are uninitialized as a whole ๐Ÿงฉ. They do not occur for variables or elements declared "volatile" ๐Ÿšซ. Because these warnings depend on optimization, the exact variables or elements that get warned about depend on the precise optimization options and 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 itself is never used, because such computations may be deleted by data flow analysis before the warnings are printed ๐Ÿ—‘๏ธ.

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

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

-Winvalid-memory-model is enabled by default ๐Ÿ’œ.

  • -Wmaybe-uninitialized โ€” for an object with automatic or allocated storage duration, if there's a path from the function entry to a use of the object that is initialized, but some other paths where it isn't, the compiler emits a warning if it can't prove the uninitialized paths aren't executed at run time ๐ŸŒ€. In addition, passing a pointer (or in C++, a reference) to an uninitialized object into a "const"-qualified function argument is also diagnosed by this warning ๐Ÿ”Ž. (-Wuninitialized is issued for built-in functions known to read the object.) Annotating the function with attribute "access (none)" indicates that the argument isn't used to access the object, and avoids the warning ๐Ÿซถ.

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

These warnings are made optional because GCC may not be able to determine when the code is correct in spite of appearing to have an error ๐Ÿ™ƒ. Here is one example of how this can happen:

{
  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 this ๐Ÿคทโ€โ™€๏ธ. To suppress the warning, you need to provide a default case with assert(0) or similar code ๐Ÿ’….

This option also warns when a non-volatile automatic variable might be changed by a call to "longjmp". The compiler sees only the calls to "setjmp". It cannot know where "longjmp" will be called; in fact, a signal handler could call it at any point in the code ๐Ÿ˜ฑ. As a result, you may get a warning even when there is in fact no problem, because "longjmp" cannot actually be called at the place that would cause a problem ๐Ÿ™ˆ.

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 is encountered that GCC doesn't understand ๐Ÿคจ. If this command-line option is used, warnings are even issued for unknown pragmas in system header files ๐Ÿ“‚. That is not the case if the warnings are only enabled by the -Wall command-line option ๐Ÿ™…โ€โ™€๏ธ.
  • -Wno-pragmas โ€” do not warn about misuses of pragmas, such as incorrect parameters, invalid syntax, or conflicts between pragmas ๐Ÿซก. See also -Wunknown-pragmas ๐ŸŽ€.
  • -Wno-prio-ctor-dtor: okay so this is a don't yell at me switch ๐Ÿ’… GCC won't warn if you give a constructor or destructor a priority from 0 to 100. The constructor and destructor attributes let you set a priority to control when they run, either before main is called or after it returns ๐Ÿงš But the compiler keeps 0โ€“100 for itself, so your priority values have to be greater than 100 โœจ
  • -Wstrict-aliasing: this one only works when -fstrict-aliasing is turned on ๐Ÿ‘‘ It warns about code that might break the strict aliasing rules the compiler uses for optimization. It doesn't catch every case, but it goes after the more common pitfalls ๐Ÿซถ It's included in -Wall, and it's equivalent to -Wstrict-aliasing=3 ๐Ÿฆ‹
  • -Wstrict-aliasing=n: also only active when -fstrict-aliasing is on โœจ It warns about the same kind of sketchy code, and higher levels are more accurate (fewer false positives) but take more effort, kinda like how -O works ๐Ÿ”ฅ -Wstrict-aliasing is equivalent to -Wstrict-aliasing=3.
    • Level 1: most aggressive, quick, and least accurate ๐Ÿ’€ It's possibly useful when the higher levels don't warn but -fstrict-aliasing still breaks your code, since it has very few false negatives. The tradeoff is 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 (possibly more than level 1). Unlike level 1, it only warns when an address is taken. It warns about incomplete types, and it runs in the front end only.
    • Level 3 (default for -Wstrict-aliasing): this is the one that should have very few false positives and few false negatives ๐Ÿ’– It's slightly slower than levels 1 or 2 when optimization is enabled. It takes care of the common pun+dereference pattern in the front end, like *(int*)&some_float. If optimization is enabled, it also runs in the back end, where it handles multiple statement cases using flow-sensitive points-to information. It only warns when the converted pointer is dereferenced, and it does not warn about incomplete types.
  • -Wstrict-overflow, -Wstrict-overflow=n: this is only active when signed overflow is undefined ๐ŸŒˆ It warns about cases where the compiler optimizes based on the assumption that signed overflow never happens. It doesn't warn about every spot where the code might overflow, just the spots where the compiler actually does an optimization, so this warning depends on your optimization level ๐Ÿค“

An optimization that assumes no signed overflow is perfectly safe if the variables involved never actually overflow, so this warning can easily give a false positive (a warning about code that isn't really a problem) ๐Ÿฅบ To help you focus on the important stuff, there are several warning levels. No warnings get issued for undefined signed overflow when estimating how many iterations a loop needs, especially when figuring out whether a loop runs at all.

  • -Wstrict-overflow=1: warns about cases that are both questionable and easy to avoid, like the compiler simplifying x + 1 > x to 1. This level is enabled by -Wall. Higher levels aren't, so you have to request them explicitly ๐ŸŽ€
  • -Wstrict-overflow=2: also warns about other cases where a comparison gets simplified to a constant, like abs (x) >= 0. That can only be simplified when signed integer overflow is undefined, because abs (INT_MIN) overflows to INT_MIN, which is less than zero ๐Ÿง  -Wstrict-overflow with no level is the same as -Wstrict-overflow=2.
  • -Wstrict-overflow=3: also warns about other cases where a comparison is simplified, like x + 1 > 1 getting simplified to x > 0 ๐Ÿ“
  • -Wstrict-overflow=4: also warns about other simplifications not covered above, like (x * 10) / 5 getting simplified to x * 2 โœจ
  • -Wstrict-overflow=5: also warns when the compiler reduces the magnitude of a constant involved in a comparison, like x + 2 > y getting simplified to x + 1 >= y. This only shows up at the highest warning level because the simplification applies to so many comparisons that this level gives a very large number of false positives ๐Ÿ’€
  • -Wstring-compare: warns for calls to strcmp and strncmp whose result is determined to be always zero or always non-zero in equality tests, because one argument is longer than the array the other argument is stored in (or the bound, for strncmp) ๐Ÿซง Calls like that could be mistakes. In the example below, the strcmp call gets flagged because its result is necessarily non-zero no matter what's in the array a. This one is enabled by -Wextra ๐Ÿ’…
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");
}
  • -Wno-stringop-overflow, -Wstringop-overflow, -Wstringop-overflow=type: warns for calls to string manipulation functions like memcpy and strcpy that are determined to overflow the destination buffer ๐Ÿšจ The optional argument is one greater than the type of Object Size Checking used to figure out the size of the destination ๐Ÿฆ‹ It only matters for functions that operate on character arrays, not raw memory functions like memcpy, which always use Object Size type-0. This 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 enabled, but it can detect a small subset of simple buffer overflows even without optimization in calls to GCC built-in functions like __builtin_memcpy that correspond to the standard functions. Either way, it only warns about a subset of the buffer overflows that the matching overflow checking built-ins would catch. In the example below, the strcpy call gets a warning 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
}
  • -Wstringop-overflow, -Wstringop-overflow=1: this uses type-zero Object Size Checking to figure out the sizes of destination objects ๐ŸŒˆ 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 as when the _FORTIFY_SOURCE macro is defined to a non-zero value ๐Ÿงš
  • -Wstringop-overflow=2: this uses type-one Object Size Checking to figure out the sizes of destination objects ๐ŸŽ€ At this setting, it warns about overflows when writing to members of the largest complete objects whose exact size is known. It does not warn for excessive writes to the same members of unknown objects referenced by pointers, since they might point to arrays with an unknown number of elements. This is the default setting for the option ๐Ÿ’–
  • -Wstringop-overflow=3: this uses type-two Object Size Checking to figure out the sizes of destination objects ๐Ÿ“ At this setting, it warns about overflowing the smallest object or data member. It's the most restrictive setting that can still give warnings for safe code ๐Ÿ˜ฌ
  • -Wstringop-overflow=4: this uses type-three Object Size Checking to figure out the sizes of destination objects ๐Ÿ”ฅ At this setting, it 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-overread: warns for calls to string manipulation functions like memchr or strcpy that are determined to read past the end of the source sequence ๐Ÿ‘€ -Wstringop-overread is enabled by default, so this is the switch to flip if you want it quiet ๐Ÿซถ
  • -Wno-stringop-truncation: don't 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 example below, the strncat call sets a bound that's less than the length of the source string. That means the copy gets truncated, so the call is flagged. To avoid the warning, use bufsize - strlen (buf) - 1) as the bound โœจ
void append (char *buf, size_t bufsize)
{
  strncat (buf, ".txt", 3);
}

Okay, so bestie, this next example is a whole vibe ๐Ÿ’… The strncpy call below copies only the characters before the terminating NUL into d, and it does not tack the NUL onto the end. Assuming strncpy always gives you a NUL-terminated string is a super common mistake ๐Ÿ˜ญ, so GCC calls it out. If you don't need the result to be NUL-terminated, use memcpy instead ๐ŸŽ€

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

Next up, the strncpy call here uses the size of the destination buffer as its bound. If the source string is equal to or longer than that size, the copy won't be NUL-terminated, so this one gets flagged too ๐Ÿ™ˆ To dodge the warning, pass sizeof buf - 1 as the bound and set the last element of the buffer to NUL. Main character energy ๐Ÿ‘‘

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

If a character array is meant to hold a sequence of bytes with no terminating NUL, you can annotate it with the attribute nonstring so GCC stops yelling about it ๐Ÿฆ‹ Just know these arrays aren't suitable for functions that expect NUL-terminated strings ๐Ÿ’€ To help catch accidental misuse, GCC warns unless it can prove the use is safe.

  • -Wstrict-flex-arrays (C and C++ only) โ€” Okay, this one checks for improper usage of flexible array members. The level comes from the strict_flex_array (level) attribute on the trailing array field of a struct if it's available, otherwise from the -fstrict-flex-arrays=level option. -Wstrict-flex-arrays is only effective when level is greater than 0 ๐ŸŒธ

The levels stack up like this:

  • level=1: warnings are issued for a trailing array reference of a structure that has 2 or more elements, if that trailing array is referenced as a flexible array member.
  • level=2: in addition to level=1, extra warnings are issued for a trailing one-element array reference of a structure if the array is referenced as a flexible array member.
  • level=3: in addition to level=2, extra warnings are issued for a trailing zero-length array reference of a structure if the array is referenced as a flexible array member.

This option hits harder when -ftree-vrp is active (the default for -O2 and above), but some warnings can show up even without optimization โœจ

  • -Wsuggest-attribute=[pure|const|noreturn|format|cold|malloc]returns_nonnull| โ€” Warns when adding an attribute might be a good idea ๐Ÿงš The attributes this covers are listed below:
-Wsuggest-attribute=pure
-Wsuggest-attribute=const
-Wsuggest-attribute=noreturn
-Wmissing-noreturn
-Wsuggest-attribute=malloc
-Wsuggest-attribute=returns_nonnull
-Wno-suggest-attribute=returns_nonnull

These flag functions that could be candidates for the pure, const, noreturn, malloc or returns_nonnull attributes. GCC only warns for functions visible in other compilation units, or (for pure and const) if it can't prove the function returns normally. A function returns normally if it doesn't contain an infinite loop or return abnormally by throwing, calling abort or trapping. This analysis needs -fipa-pure-const, which is on 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 used in assignment, initialization, parameter passing or return statements should have a matching format attribute in the resulting type. In other words, the left-hand side of the assignment or initialization, the type of the parameter variable, or the return type of the containing function should also have a format attribute to avoid the warning.

GCC also warns about function definitions that might be candidates for format attributes. Again, these are only possible candidates ๐Ÿซถ GCC guesses that format attributes might fit any function that calls something like vprintf or vscanf, but that's not always the case, and some functions where format attributes are appropriate might not get detected.

  • -Wsuggest-attribute=cold โ€” Warns about functions that might be candidates for the cold attribute ๐ŸงŠ This is based on static detection and usually only warns about functions that always lead to a call to another cold function, like wrappers of C++ throw or fatal error reporting functions that end up at abort.
  • -Walloc-size โ€” Warns about calls to allocation functions decorated with the alloc_size attribute that specify an insufficient size for the target type of the pointer the result gets assigned to. This includes the built-in forms of aligned_alloc, alloca, calloc, malloc, and realloc ๐Ÿ’–
  • -Walloc-zero โ€” Warns about calls to allocation functions decorated with alloc_size that specify zero bytes, including the built-in forms of aligned_alloc, alloca, calloc, malloc, and realloc ๐Ÿ˜ญ The behavior of these functions with a zero size differs between implementations (and for realloc it's been deprecated), so relying on it can cause subtle portability bugs. Please avoid it ๐Ÿ™…
  • -Wcalloc-transposed-args โ€” A coding style warning ๐Ÿ’… It flags calls to allocation functions decorated with alloc_size that have two arguments, use sizeof as the earlier size argument, and don't use it as the later one. The first argument to calloc is documented as the number of elements in the array, and the second is the size of each element, so calloc (n, sizeof (int)) is preferred over calloc (sizeof (int), n). If sizeof in the earlier argument (and not the latter) is intentional, you can suppress the warning with calloc (sizeof (struct S) + 0, n) or calloc (1 * sizeof (struct S), 4), or by using sizeof in the later argument as well โœจ
  • -Walloc-size-larger-than=byte-size โ€” Warns about calls to functions decorated with alloc_size that try to allocate objects larger than the specified number of bytes. It also fires when the size computation, done in an integer type with infinite precision, would exceed the value of PTRDIFF_MAX on the target. -Walloc-size-larger-than=PTRDIFF_MAX is on by default ๐ŸŒˆ You can turn off these warnings either by specifying a byte-size of SIZE_MAX or more, or with -Wno-alloc-size-larger-than.
  • -Wno-alloc-size-larger-than โ€” Disables the -Walloc-size-larger-than= warnings ๐Ÿ™ˆ It's the same as -Walloc-size-larger-than=SIZE_MAX or larger.
  • -Walloca โ€” Warns on all uses of alloca in the source ๐Ÿ˜ฌ
  • -Walloca-larger-than=byte-size โ€” This one warns on calls to alloca where the integer argument is either zero, or isn't bounded by a controlling predicate that limits its value to at most byte-size. It also warns for calls to alloca where the bound value is unknown. Arguments of non-integer types count as unbounded, even if they look like they're constrained to the expected range ๐Ÿ’€

A bounded use 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);
}

Passing -Walloca-larger-than=1000 won't warn here, because the call to alloca is known to be at most 1000 bytes. But if -Walloca-larger-than=500 were passed, the compiler would emit a warning ๐Ÿฆ‹

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

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

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

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 the above 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 (the default for -O2 and above). See also -Wvla-larger-than=byte-size.

  • -Wno-alloca-larger-than โ€” Disables the -Walloca-larger-than= warnings ๐ŸŒธ It's equivalent to -Walloca-larger-than=SIZE_MAX or larger.
  • -Warith-conversion โ€” Do warn about implicit conversions from arithmetic operations, even when converting the operands to the same type can't change their values ๐Ÿง  This affects warnings from -Wconversion, -Wfloat-conversion, and -Wsign-conversion.
void f (char c, int i)
{
  c = c + i; // warns with -Wconversion
  c = c + 1; // only warns with -Warith-conversion
}
  • -Warray-bounds, -Warray-bounds=n โ€” Warns about out-of-bounds subscripts or offsets into arrays ๐Ÿ“ This warning is enabled by -Wall. It's more effective when -ftree-vrp is active (the default for -O2 and above), but a subset of instances are issued even without optimization ๐Ÿ’œ

By default, bestie, the trailing array of a structure gets treated as a flexible array member by -Warray-bounds or -Warray-bounds=n if it's declared as any of these: a flexible array member per the C99 standard onwards ([]), a GCC zero-length array extension ([0]), or a one-element array ([1]). ๐Ÿ’… So out of bounds subscripts or offsets into zero-length arrays or one-element arrays are not warned about by default ๐Ÿ™ˆ

You can add -fstrict-flex-arrays or -fstrict-flex-arrays=level to control how this option treats the trailing array of a structure as a flexible array member. โœจ Here's the tea:

  • when level<=1, nothing changes from the default behavior ๐ŸŒธ
  • when level=2, you get additional warnings for out of bounds subscripts or offsets into one-element arrays ๐Ÿฆ‹
  • when level=3, you get everything from level=2 plus additional warnings for out of bounds subscripts or offsets into zero-length arrays ๐Ÿ‘‘
  • -Warray-bounds=1 โ€” This is the default warning level of -Warray-bounds, and it's enabled by -Wall. The higher levels aren't, so you've gotta ask for them explicitly ๐Ÿ’–
  • -Warray-bounds=2 โ€” This level also warns about the intermediate results of pointer arithmetic that may yield out of bounds values. Expect a bigger pile of false positives here, and it's deactivated by default ๐Ÿฅฒ

๐ŸŽ€ -Warray-compare

Warn about equality and relational comparisons between two operands of array type. Bestie, this comparison was deprecated in C++20 ๐Ÿฅ€ For example:

int arr1[5];
int arr2[5];
bool same = arr1 == arr2;

-Warray-compare is enabled by -Wall โœจ

๐ŸŒˆ -Warray-parameter, -Warray-parameter=n

Warn about redeclarations of functions involving parameters of array or pointer types of inconsistent kinds or forms, and enable the detection of out-of-bounds accesses to such parameters by warnings such as -Warray-bounds ๐Ÿ”ฅ

If the first function declaration uses the array form for a parameter declaration, the bound specified in the array is assumed to be the minimum number of elements expected to be provided in calls to the function and the maximum number of elements accessed by it. Failing to provide arguments of sufficient size, or accessing more than the maximum number of elements, may be diagnosed by warnings such as -Warray-bounds or -Wstringop-overflow. At level 1, the warning diagnoses inconsistencies involving array parameters declared using the "T[static N]" form ๐Ÿงš

For example, the warning triggers for the second declaration of f, because the first one with the keyword static specifies that the array argument must have at least four elements, while the second allows an array of any size to be passed to f ๐Ÿ’€

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

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

At level 2, the warning also triggers for redeclarations involving any other inconsistency in array or pointer argument forms denoting array sizes. Pointers and arrays of unspecified bound are considered equivalent and do not trigger a warning, so no drama there ๐Ÿซถ

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

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

The short form of the option, -Warray-parameter, is equivalent to -Warray-parameter=2. The negative form, -Wno-array-parameter, is equivalent to -Warray-parameter=0 ๐Ÿ’œ

๐Ÿฆ‹ -Wattribute-alias=n, -Wno-attribute-alias

Warn 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 of the -Wattribute-alias option. It diagnoses incompatibilities between the type of the alias declaration and that of its target. Such incompatibilities are typically indicative of bugs ๐Ÿ›
  • -Wattribute-alias=2 โ€” At this level, -Wattribute-alias also diagnoses cases where the attributes of the alias declaration are more restrictive than the attributes applied to its target. These mismatches can potentially result in incorrect code generation. In other cases they may be benign and could be resolved simply by adding the missing attribute to the target. For comparison, see the -Wmissing-attributes option, which controls diagnostics when the alias declaration is less restrictive than the target, rather than more restrictive ๐Ÿ”

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. This is the default. You can disable these warnings with either -Wno-attribute-alias or -Wattribute-alias=0 ๐Ÿ™…โ€โ™€๏ธ

๐ŸŒธ -Wbidi-chars=[none|unpaired|any|ucn]

Warn about possibly misleading UTF-8 bidirectional control characters in comments, string literals, character constants, and identifiers. Bestie, these characters are sneaky ๐Ÿ˜ญ They can change left-to-right writing direction into right-to-left (and vice versa), which can cause confusion between the logical order and the visual order. This may be dangerous. For instance, it may seem that a piece of code is not commented out, whereas it in fact is ๐Ÿ’€

There are three levels of warning supported by GCC. The default is -Wbidi-chars=unpaired, which warns about improperly terminated bidi contexts. -Wbidi-chars=none turns the warning off. -Wbidi-chars=any warns about any use of bidirectional control characters โœจ

By default, this warning does not warn about UCNs. It is, however, possible to turn on such checking by using -Wbidi-chars=unpaired,ucn or -Wbidi-chars=any,ucn. Using -Wbidi-chars=ucn is valid, and is equivalent to -Wbidi-chars=unpaired,ucn, if no previous -Wbidi-chars=any was specified ๐Ÿฆ‹

๐Ÿ’… -Wbool-compare

Warn about a boolean expression compared with an integer value different from "true"/"false". For instance, the following comparison is always false ๐Ÿ™ƒ

int n = 5;
...
if ((n > 1) == 2) { ... }

This warning is enabled by -Wall ๐ŸŒˆ

๐Ÿงš -Wbool-operation

Warn about suspicious operations on expressions of a boolean type. For instance, bitwise negation of a boolean is very likely a bug in the program ๐Ÿ› For C, this warning also warns about incrementing or decrementing a boolean, which rarely makes sense. (In C++, decrementing a boolean is always invalid. Incrementing a boolean is invalid in C++17, and deprecated otherwise.) ๐Ÿซ 

This warning is enabled by -Wall ๐Ÿ’–

๐Ÿ“ -Wduplicated-branches

Warn when an if-else has identical branches. This warning detects cases like this:

if (p != NULL)
  return 0;
else
  return 0;

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

int i = x ? *p : *p;

๐Ÿซง -Wduplicated-cond

Warn about duplicated conditions in an if-else-if chain. For instance, warn for the following code:

if (p->q != NULL) { ... }
else if (p->q != NULL) { ... }

๐Ÿ‘‘ -Wframe-address

Warn 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 ๐Ÿ˜ฑ The warning is included in -Wall ๐Ÿ”ฅ

๐ŸŒท -Wno-discarded-qualifiers (C and Objective-C only)

Do not warn if type qualifiers on pointers are being discarded. Typically, the compiler warns if a const char * variable is passed to a function that takes a char * parameter. This option can be used to suppress such a warning ๐Ÿคซ

๐ŸŒท -Wno-discarded-array-qualifiers (C and Objective-C only)

Do not warn if type qualifiers on arrays which are pointer targets are being discarded. Typically, the compiler warns if a const int (*)[] variable is passed to a function that takes an int (*)[] parameter. This option can be used to suppress such a warning ๐ŸŽ€

๐ŸŒบ -Wno-incompatible-pointer-types (C and Objective-C only)

Do not warn when there is a conversion between pointers that have incompatible types. This warning is for cases not covered by -Wno-pointer-sign, which warns for pointer argument passing or assignment with different signedness ๐Ÿฆ„

By default, in C99 and later dialects of C, GCC treats this issue as an error. The error can be downgraded to a warning using -fpermissive (along with certain other errors), or for this error alone, with -Wno-error=incompatible-pointer-types ๐Ÿซถ

This warning is upgraded to an error by -pedantic-errors ๐Ÿšจ

๐Ÿซ  -Wno-int-conversion (C and Objective-C only)

Do not warn about incompatible integer to pointer and pointer to integer conversions. This warning is about implicit conversions. For explicit conversions, the warnings -Wno-int-to-pointer-cast and -Wno-pointer-to-int-cast may be used ๐Ÿ’

By default, in C99 and later dialects of C, GCC treats this issue as an error. The error can be downgraded to a warning using -fpermissive (along with certain other errors), or for this error alone, with -Wno-error=int-conversion ๐ŸŒธ

This warning is upgraded to an error by -pedantic-errors โญ

๐Ÿ•ณ๏ธ -Wzero-length-bounds

Warn 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. Undefined behavior, bestie, so please don't ๐Ÿ™…โ€โ™€๏ธ

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

Okay so -Wzero-length-bounds is automatically switched on whenever you enable -Warray-bounds ๐Ÿ’…โœจ

  • -Wno-div-by-zero โ€” bestie, this one's a vibe ๐Ÿ™„ GCC stops yelling about compile-time integer division by zero. Floating-point division by zero never gets flagged, since it can be a totally legit way to get infinities and NaNs ๐ŸŒˆ
  • -Wsystem-headers โ€” normally GCC keeps quiet about warnings in system header files, since those usually aren't real problems and would just make the output messier ๐Ÿ™ˆ This flag tells GCC to treat those headers like your own code and print their warnings. Heads up though: -Wall combined with this flag still won't warn about unknown pragmas in system headers ๐Ÿ’€ For that, you also need -Wunknown-pragmas.
  • -Wtautological-compare โ€” no cap, this catches sneaky mistakes ๐Ÿ” It warns if a self-comparison always evaluates to true or false, like this:
int i = 1;
...
if (i > i) { ... }

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

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

That one is always false, so ๐Ÿ˜ญ This warning is enabled by -Wall.

  • -Wtrampolines โ€” warns about trampolines generated for pointers to nested functions ๐Ÿฆ‹ A trampoline is a small piece of data or code created at run time on the stack when the address of a nested function is taken, and it's used to call that nested function indirectly. On some targets it's only data, so it needs no special treatment. But on most targets it's 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 ๐Ÿงš Sometimes it's convenient to treat floats as approximations of infinitely precise real numbers, and if you're doing that, you need to figure out (by analyzing the code, or some other way) the maximum or likely maximum error the computation introduces, then allow for it in your comparisons (and when producing output, but that's a different problem). Instead of testing for equality, check whether the two values have overlapping ranges. That's done with relational operators, so equality comparisons are probably mistaken ๐Ÿ™…โ€โ™€๏ธ
  • -Wtraditional (C and Objective-C only) โ€” this one is the ultimate throwback check ๐Ÿ•ฐ๏ธ It warns about constructs that behave differently in traditional and ISO C. It also flags ISO C constructs with no traditional C equivalent, and/or problematic constructs you should avoid. Here's what it's watching for:
    • Macro parameters that appear within string literals in the macro body. Traditional C does macro replacement inside string literals, but ISO C does not.
    • Some preprocessor directives didn't exist in traditional C. Traditional preprocessors only considered a line a directive if the # appeared in column 1, so -Wtraditional warns about directives that traditional C understands but ignores because the # isn't the first character on the line. It also suggests hiding directives like #pragma, which traditional C doesn't understand, by indenting them. Some traditional implementations don't recognize #elif, so this option suggests avoiding it altogether.
    • A function-like macro that appears without arguments.
    • The unary plus operator.
    • The U integer constant suffix, or the F or L floating-point constant suffixes. (Traditional C does support the L suffix on integer constants.) These suffixes show up in macros defined in the system headers of most modern systems, e.g. the _MIN/_MAX macros in <limits.h>. Using these 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 the block.
    • A switch statement with an operand of type long.
    • A non-static function declaration that follows a static one. Some traditional C compilers don't accept this.
    • The ISO type of an integer constant has a different width or signedness from its traditional type. This warning is only issued if the base of the constant is ten, so hexadecimal or octal values, which typically represent bit patterns, aren't warned about.
    • Use of ISO string concatenation.
    • 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 is conditioned on something like __STDC__ to avoid missing-initializer warnings, and that it relies on default initialization to zero in the traditional C case.
    • Conversions by prototypes between fixed 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 is intentionally not issued for prototype declarations or variadic functions, because those ISO C features appear in your code when you use libiberty's traditional C compatibility macros, PARAMS and VPARAMS. It's also bypassed for nested functions, because that feature is already a GCC extension and isn't relevant to traditional C compatibility.
  • -Wtraditional-conversion (C and Objective-C only) โ€” warns if a prototype causes a type conversion that's different from what would happen to the same argument in the absence of a prototype ๐Ÿ”„ That includes conversions between fixed-point and floating-point values and vice versa, plus conversions that change the width or signedness of a fixed-point argument, except when it matches the default promotion.
  • -Wdeclaration-after-statement (C and Objective-C only) โ€” warns when a declaration is found after a statement in a block ๐Ÿ“ This construct comes from C++, was introduced with ISO C99, and is allowed by default in GCC. It's not supported by ISO C90. This warning is upgraded to an error by -pedantic-errors.
  • -Wshadow โ€” main character energy, but make it a warning ๐Ÿ‘‘ It warns whenever a local variable or type declaration shadows another variable, parameter, type, class member (in C++), or instance variable (in Objective-C), or whenever a built-in function is shadowed. In C++, the compiler warns if a local variable shadows an explicit typedef, but not if it shadows a struct/class/enum. If this warning is enabled, it also includes all instances of local shadowing. That means -Wno-shadow=local and -Wno-shadow=compatible-local 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 that of the shadowing variable. In C++, type compatibility here means the shadowing variable's type can be converted to the shadowed variable's type. The creation of this flag (in addition to -Wshadow=local) is based on the idea that when a local variable shadows another one of incompatible type, it's most likely intentional, not a bug or typo. Check out this example:
for (SomeIterator i = SomeObj.begin(); i != SomeObj.end(); ++i)
{
  for (int i = 0; i < N; ++i)
  {
    ...
  }
  ...
}

Since the two i variables above have incompatible types, enabling only -Wshadow=compatible-local does not emit a warning. Because their types are incompatible, if a programmer accidentally uses one in place of the other, type checking is expected to catch that and emit an error or warning. Using this flag instead of -Wshadow=local can possibly 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. Also warns for calls to bounded functions such as memchr or strnlen that specify a bound greater than the largest possible object, which is PTRDIFF_MAX bytes by default. These warnings can only be disabled by -Wno-larger-than ๐Ÿงš
  • -Wno-larger-than โ€” disables -Wlarger-than= warnings ๐Ÿ’– It's equivalent to -Wlarger-than=SIZE_MAX or larger.
  • -Wframe-larger-than=byte-size โ€” okay so this one warns you if a function's stack frame gets bigger than byte-size ๐Ÿ“๐Ÿ”ฅ. The compiler's guess at the frame size is approximate and not conservative ๐Ÿ™ˆ, so the real needs might be somewhat bigger than byte-size even when you get no warning at all. Also, space from alloca, variable-length arrays, or related constructs doesn't get counted when the compiler decides whether to warn ๐Ÿ’€. -Wframe-larger-than=PTRDIFF_MAX is on by default โœจ. You can switch these warnings off by giving a byte-size of SIZE_MAX or more, or by using -Wno-frame-larger-than ๐Ÿฆ‹.
  • -Wno-frame-larger-than โ€” bye bye, -Wframe-larger-than= warnings ๐Ÿ‘‹๐ŸŒธ. It works the same as -Wframe-larger-than=SIZE_MAX or anything bigger.
  • -Wfree-nonheap-object โ€” this one catches you trying to free something that was never on the heap, or freeing a pointer that didn't come straight from the matching allocation function ๐Ÿงš. Like, stpcpy hands back a pointer to the terminating nul character instead of the start of your object, so the free below gets flagged ๐Ÿ˜ญ. -Wfree-nonheap-object is part of -Wall ๐Ÿ’œ.
void f (char *p)
{
  p = stpcpy (p, "abc");
  // ...
  free (p);   // warning
}
  • -Wstack-usage=byte-size โ€” warns if a function's stack usage might go over byte-size ๐Ÿฅž. This math is conservative, so any space from alloca, variable-length arrays, or related constructs gets counted ๐Ÿซถ. The message matches what -fstack-usage prints ๐Ÿ’…. Here's what you'll see:
    • If the stack usage is fully static but goes over the limit, it says: warning: stack usage is 1120 bytes
    • If the stack usage is partly dynamic but bounded, it says: warning: stack usage might be 1648 bytes
    • If the stack usage is partly dynamic and not bounded, it says: warning: stack usage might be unbounded

-Wstack-usage=PTRDIFF_MAX is on by default ๐ŸŒˆ. You can turn these warnings off by giving a byte-size of SIZE_MAX or more, or by using -Wno-stack-usage ๐ŸŽ€.

  • -Wno-stack-usage โ€” no more -Wstack-usage= warnings, periodt ๐Ÿ™…โ€โ™€๏ธ. Same as -Wstack-usage=SIZE_MAX or bigger.
  • -Wunsafe-loop-optimizations โ€” warns when a loop can't be optimized because the compiler can't assume anything about its index bounds ๐ŸŒ€. Pair it with -funsafe-loop-optimizations and it'll warn you whenever the compiler does make those assumptions ๐Ÿ‘€.
  • -Wno-pedantic-ms-format (MinGW targets only) โ€” when you use it together with -Wformat and -pedantic (without GNU extensions), it silences the warnings about the non-ISO printf / scanf width specifiers I32, I64, and I on Windows targets ๐ŸชŸโœจ. Those depend on the MS runtime, so they're not standard, but if that's what you're going for, you can chill ๐ŸงŠ.
  • -Wpointer-arith โ€” heads up for anything that depends on the "size of" a function type or of void ๐Ÿ“. GNU C gives those types a size of 1, which is handy for math with void * pointers and pointers to functions ๐Ÿ“. In C++, it also warns when an arithmetic operation involves NULL ๐Ÿ’–. This warning is also turned on by -Wpedantic ๐Ÿ”ฅ. It gets upgraded to an error by -pedantic-errors ๐Ÿšจ.
  • -Wno-pointer-compare โ€” don't warn when a pointer gets compared with a zero character constant ๐Ÿ™ƒ. That usually means the pointer was meant to be dereferenced, so the warning is usually helpful ๐Ÿคทโ€โ™€๏ธ. Here's an example:
const char *p = foo ();
if (p == '\0')
  return 42;

Just so you know, the code above is invalid in C++11 ๐Ÿ’€. This warning is enabled by default โœ….

  • -Wno-tsan โ€” shuts up the warnings about unsupported features in ThreadSanitizer ๐Ÿงต. Real talk, ThreadSanitizer doesn't support std::atomic_thread_fence and can report false positives ๐Ÿ™ˆ.
  • -Wtype-limits โ€” warns if a comparison is always true or always false because of the limited range of the data type ๐Ÿ“. Constant expressions don't get the warning, though ๐Ÿ’…. For example, it warns if an unsigned variable gets compared against zero with < or >= ๐Ÿ‘‘. This warning is also enabled by -Wextra โœจ.
  • -Wabsolute-value (C and Objective-C only) โ€” warns when you call a standard function that computes an absolute value when there's a better standard function for the job ๐Ÿงฎ. For example, abs(3.14) triggers it because fabs is the right call for a double ๐Ÿ’–. It also warns if the argument to one of those functions has an unsigned type ๐Ÿ™ˆ. You can suppress it with an explicit type cast, and it's also enabled by -Wextra ๐Ÿซถ.
  • -Wcomment, -Wcomments โ€” warns whenever a comment-start sequence /* shows up inside a /* comment, or whenever a backslash-newline shows up in a // comment ๐Ÿง. This warning is enabled by -Wall ๐ŸŒธ.
  • -Wtrigraphs โ€” warns if any trigraphs get encountered that might change what your 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, this option is still on unless trigraphs are enabled ๐ŸŒˆ. Want trigraph conversion with no warnings but still get the other -Wall warnings? Use -trigraphs -Wall -Wno-trigraphs ๐Ÿ“.
  • -Wundef โ€” warns if an undefined identifier gets evaluated in an #if directive ๐Ÿ•ต๏ธโ€โ™€๏ธ. Those identifiers get replaced with zero, which can be sneaky ๐Ÿ˜ญ.
  • -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 gets expanded or tested for existence at least once ๐Ÿ‘€. The preprocessor also warns if the macro hasn't been used by the time it gets redefined or undefined โœจ.

Built-in macros, macros defined on the command line, and macros defined in include files don't get warned about ๐Ÿ™Œ.

Heads up: if a macro is actually used, but only inside skipped conditional blocks, the preprocessor still reports it as unused ๐Ÿ™ˆ. To dodge the warning in that case, 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 with something like this:

#if defined the_macro_causing_the_warning
#endif
  • -Wno-endif-labels โ€” don't warn when an #else or an #endif gets followed by text ๐ŸŽ€. This happens sometimes in older programs with code that looks like this:
#if FOO
...
#else FOO
...
#endif FOO

The second and third FOO are supposed to be in comments ๐Ÿ˜ญ. 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 are in ISO C99 but not in ISO C90 ๐Ÿ•ฐ๏ธ. Examples include variable length arrays, the long long type, the bool type, compound literals, designated initializers, and so on ๐Ÿงธ. This option doesn't depend on the standards mode ๐ŸŒˆ. Warnings are disabled in the expression that follows __extension__ ๐Ÿซถ.
  • -Wc99-c11-compat (C and Objective-C only) โ€” warns about features that are in ISO C11 but not in ISO C99 โœจ. Think anonymous structures and unions, the _Atomic type qualifier, the _Thread_local storage-class specifier, the _Alignas specifier, the Alignof operator, the _Generic keyword, and so on ๐Ÿ’…. This option doesn't depend on the standards mode ๐Ÿ‘‘. Warnings are disabled in the expression that follows __extension__ ๐ŸŒธ.
  • -Wc11-c23-compat, -Wc11-c2x-compat (C and Objective-C only) โ€” warns about features that are in ISO C23 but not in ISO C11 ๐Ÿ”ฎ. Examples are omitting the string in _Static_assert, using [[]] attribute syntax, using decimal floating-point types, and so on ๐Ÿง. This option doesn't depend on the standards mode ๐ŸŒˆ. Warnings are disabled in the expression that follows __extension__ ๐Ÿซถ. The name -Wc11-c2x-compat is deprecated, so use -Wc11-c23-compat instead ๐Ÿฅน.

When you're not compiling in C23 mode, these warnings get upgraded to errors by -pedantic-errors ๐Ÿšจ.

  • -Wc++-compat (C and Objective-C only) โ€” warns about ISO C constructs that sit outside the common subset of ISO C and ISO C++ ๐Ÿงฉ. One example is asking for an implicit conversion from void * to a pointer to a non-void type ๐Ÿ’œ.
  • -Wc++11-compat (C++ and Objective-C++ only) โ€” warns about C++ constructs whose meaning changed between ISO C++ 1998 and ISO C++ 2011 ๐Ÿ•ฐ๏ธ. For example, identifiers that were fine in ISO C++ 1998 but are keywords in ISO C++ 2011 ๐Ÿ’€. This warning turns on -Wnarrowing and is enabled by -Wall ๐ŸŒŸ.
  • -Wc++14-compat (C++ and Objective-C++ only) โ€” warns about C++ constructs whose meaning changed 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 changed 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 changed between ISO C++ 2017 and ISO C++ 2020 ๐ŸŒˆ. This warning is enabled by -Wall โœ….
  • -Wno-c++11-extensions (C++ and Objective-C++ only) โ€” don't warn about C++11 constructs when you're compiling with an older C++ standard ๐Ÿ™Œ. Even without this option, some C++11 constructs only get flagged if you use -Wpedantic ๐Ÿง.
  • -Wno-c++14-extensions (C++ and Objective-C++ only) โ€” don't warn about C++14 constructs when you're compiling with an older C++ standard ๐ŸŒธ. Even without this option, some C++14 constructs only get flagged if you use -Wpedantic ๐Ÿง.
  • -Wno-c++17-extensions (C++ and Objective-C++ only) โ€” don't warn about C++17 constructs when you're compiling with an older C++ standard โœจ. Even without this option, some C++17 constructs only get flagged if you use -Wpedantic ๐Ÿง.
  • -Wno-c++20-extensions (C++ and Objective-C++ only) โ€” okay bestie, this one tells the compiler to chill about C++20 stuff when your code is written for an older C++ standard ๐Ÿ™ˆ Even without it, some C++20 constructs only get flagged if you turn on -Wpedantic.
  • -Wno-c++23-extensions (C++ and Objective-C++ only) โ€” same energy, but for C++23 โœจ It stops the warnings about C++23 constructs when you're compiling with an older C++ standard. Some C++23 constructs still only get called out with -Wpedantic.
  • -Wno-c++26-extensions (C++ and Objective-C++ only) โ€” and yes, C++26 gets the same treatment ๐Ÿ’… No warnings about C++26 constructs in code built with an older C++ standard. Some C++26 constructs will only be diagnosed if -Wpedantic is used.
  • -Wcast-qual โ€” this one catches you when a pointer gets cast so it drops a type qualifier from the target type. For example, it warns if a const char * gets cast to a plain char * ๐Ÿ‘€

It also warns when a cast adds a type qualifier in an unsafe way. Casting char ** to const char ** is the classic example, and it's a whole mess:

/* 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 cast increases the alignment the target needs. 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 โ€” the no-excuses version of the one above ๐Ÿ˜ค It warns whenever a pointer cast increases the required alignment, no matter the target machine. So a char * cast to an int * gets flagged everywhere.
  • -Wcast-function-type โ€” warns when a function pointer gets cast to an incompatible function pointer type. A few vibes to know about:
    • With function types that take 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 get 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, it warns whenever the cast changes the pointer to member type.

This warning is enabled by -Wextra.

  • -Wwrite-strings โ€” in C, string constants get the type const char[length], so copying one's address into a non-const char * pointer gives a warning. These help you find, at compile time, code that might try to write into a string constant. The catch is they only work well if you've been super careful with const in your declarations and prototypes. Otherwise they're just annoying ๐Ÿ™„ That's why -Wall doesn't ask for them.

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

Heads up: in C++11 mode or later, this warning gets upgraded to an error by -pedantic-errors.

  • -Wclobbered โ€” warns about variables that might get changed by longjmp or vfork ๐ŸงŸ This warning is also enabled by -Wextra.
  • -Wno-complain-wrong-lang โ€” by default, language front ends complain when a command-line option is valid but doesn't apply to that front end. This flag shuts that down. It's mostly useful when you're invoking one compiler driver for multiple source files written in different languages, like this:
$ g++ -fno-rtti a.cc b.f90

The g++ driver uses the C++ front end to compile a.cc and the Fortran front end to compile b.f90. The Fortran front end then complains with this message:

f951: Warning: command-line option '-fno-rtti' is valid for C++/D/ObjC++ but not for Fortran, which may be disabled with -Wno-complain-wrong-lang.
  • -Wcompare-distinct-pointer-types (C and Objective-C only) โ€” warns if pointers of distinct types get compared without a cast. This warning is enabled by default ๐Ÿ’–
  • -Wconversion โ€” warns about implicit conversions that might change a value ๐Ÿ‘€ That includes:
    • conversions between real and integer, like abs (x) when x is a double;
    • conversions between signed and unsigned, like unsigned ui = -1;
    • conversions to smaller types, like sqrtf (M_PI).

It doesn't warn about explicit casts like abs ((int) x) and ui = (unsigned) -1, or about conversions that don't change the value, like abs (2.0). If you want to silence warnings about signed and unsigned integer conversions, use -Wno-sign-conversion.

In C++, it also warns about confusing overload resolution for user-defined conversions. It also covers conversions that never use a type conversion operator: conversions to void, to the same type, to a base class, or to a reference to them. In C++, warnings about signed and unsigned integer conversions are disabled by default unless you explicitly enable -Wsign-conversion.

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

  • -Wdangling-else โ€” warns about constructions where it's unclear which if statement an else branch belongs to ๐Ÿซ  Here's a sneaky example:
{
  if (a)
    if (b)
      foo ();
  else
    bar ();
}

In C and C++, every else branch belongs to the innermost possible if statement, which here is if (b). That's often not what the programmer meant, and the indentation in the example above shows exactly that trap. When there's potential for this confusion, GCC issues a warning if this flag is specified. To get rid of the warning, add explicit braces around the innermost if statement, so the else can't possibly belong to the enclosing if. The fixed code looks like this:

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

This warning is enabled by -Wparentheses.

  • -Wdangling-pointer, -Wdangling-pointer=n โ€” โœจ these warn about uses of pointers (or C++ references) to objects with automatic storage duration after their lifetime has ended. That includes local variables declared in nested blocks, compound literals, and other unnamed temporary objects. It also warns about storing the address of such objects in escaped pointers ๐Ÿงš This warning is enabled at all optimization levels, but it may give different results with optimization than without.
    • -Wdangling-pointer=1 โ€” at level 1, the warning only diagnoses unconditional uses of dangling pointers.
    • -Wdangling-pointer=2 โ€” at level 2, the warning also diagnoses conditional uses of dangling pointers, on top of the unconditional ones.

The short form -Wdangling-pointer is the same as -Wdangling-pointer=2. Meanwhile, -Wno-dangling-pointer and -Wdangling-pointer=0 both turn the warnings off. -Wdangling-pointer=2 is included in -Wall.

This example triggers the warning at level 1, because the address of the unnamed temporary is unconditionally referenced outside of its scope:

char f (char c1, char c2, char c3)
{
  char *p;
  {
    p = (char[]) { c1, c2, c3 };
  }
  // warning: using dangling pointer 'p' to an unnamed temporary
  return *p;
}

In the next function, storing the address of the local variable x into the escaped pointer *p triggers the warning at level 1 ๐Ÿ’…

void g (int **p)
{
  int x = 7;
  // warning: storing the address of local variable 'x' in '*p'
  *p = &x;
}

In this one, the array a is out of scope by the time the pointer s gets used. Since the code that sets s is conditional, the warning triggers at level 2:

extern void frob (const char *);
void h (char *s)
{
  if (!s)
    {
      char a[12] = "tmpname";
      s = a;
    }
  // warning: dangling pointer 's' to 'a' may be used
  frob (s);
}
  • -Wdate-time โ€” warns when the macros __TIME__, __DATE__ or __TIMESTAMP__ show up, since they might stop your builds from being bit-wise-identical and reproducible โฐ
  • -Wempty-body โ€” warns if an empty body shows up in an if, else or do while statement. This warning is also enabled by -Wextra ๐Ÿซถ
  • -Wno-endif-labels โ€” stops the warnings about stray tokens after #else and #endif ๐Ÿ™ˆ
  • -Wenum-compare โ€” warns about a comparison between values of different enumerated types. In C++, enumerated type mismatches in conditional expressions also get diagnosed, and this warning is enabled by default there. In C, it's enabled by -Wall ๐Ÿ”ฅ
  • -Wenum-conversion โ€” warns when a value of enumerated type gets implicitly converted to a different enumerated type. In C, this warning is enabled by -Wextra ๐ŸŒˆ
  • -Wenum-int-mismatch (C and Objective-C only) โ€” warns about mismatches between an enumerated type and an integer type in declarations. For example:
enum E { l = -1, z = 0, g = 1 };
int foo(void);
enum E foo(void);

In C, an enumerated type is compatible with char, a signed integer type, or an unsigned integer type. But since the choice of the underlying type of an enumerated type is implementation-defined, these mismatches can cause portability issues. In C++, such mismatches are an error. In C, this warning is enabled by -Wall and -Wc++-compat ๐Ÿ‘‘

okay so this one is about jumping over variables ๐Ÿฆ‹

  • -Wjump-misses-init (C, Objective-C only) โ€” this warns if a goto or a switch hops forward past the initialization of a variable, or jumps backward to a label after that variable has already been set up. It only cares about variables that get initialized right where they're declared. This one is only for C and Objective-C, because in C++ this kind of jump is already an error anyway ๐Ÿ’…
  • -Wjump-misses-init is part of -Wc++-compat ๐Ÿซถ and you can switch it off with the -Wno-jump-misses-init option ๐ŸŒธ
  • -Wsign-compare โ€” compare vibes check ๐Ÿ‘‘ this warns when you compare signed and unsigned values and the result could be wrong because the signed one gets converted to unsigned. In C++ it's also turned on by -Wall, and in C it's turned on by -Wextra โœจ
  • -Wsign-conversion โ€” this one catches implicit conversions that might flip the sign of an integer, like shoving a signed integer expression into an unsigned integer variable ๐Ÿ™ˆ An explicit cast will shut it up. In C, -Wconversion also turns this on ๐ŸŽ€
  • -Wflex-array-member-not-at-end (C and C++ only) โ€” not it ๐Ÿ’€ this warns when a struct with a C99 flexible array member as its last field ends up sitting in the middle of another struct. Here's the kind of thing it's talking about:
struct flex  { int length; char data[]; };
struct mid_flex { int m; struct flex flex_data; int n; };
  • -Wfloat-conversion โ€” warns about implicit conversions that lower the precision of a real value. That covers real to integer, and higher precision real to lower precision real ๐Ÿงš This one is also enabled by -Wconversion ๐Ÿ“
  • -Wno-scalar-storage-order โ€” bye bye suspicious stuff ๐ŸŒˆ this stops the warnings about questionable constructs involving reverse scalar storage order โœจ
  • -Wsizeof-array-div โ€” warns when you divide two sizeof operators and the first one is applied to an array, but the divisor isn't the size of an array element. The math won't give you the number of elements, which is almost definitely not what you meant ๐Ÿ˜ญ Here's an example it would flag:
int fn ()
{
  int arr[10];
  return sizeof (arr) / sizeof (short);
}

This warning is enabled by -Wall ๐Ÿ’–

  • -Wsizeof-pointer-div โ€” this flags suspicious divisions of two sizeof expressions that divide the pointer size by the element size. That's the usual trick for getting an array's length, but it totally falls apart with pointers ๐Ÿ’€ It warns about "sizeof (ptr) / sizeof (ptr[0])" when "ptr" is a pointer and not an array. This warning is enabled by -Wall ๐Ÿ”ฅ
  • -Wsizeof-pointer-memaccess โ€” warns about sketchy length arguments to certain string and memory built-in functions when the argument uses sizeof. It goes off for things like memset (ptr, 0, sizeof (ptr)); when ptr is really a pointer, and it even suggests a possible fix. It also catches memcpy (&foo, ptr, sizeof (&foo)); ๐Ÿ™ˆ This option also warns about bounded string copy functions like strncat or strncpy when the bound is a sizeof on the source array. Check out this one:
void make_file (const char *name)
{
  char path[PATH_MAX];
  strncpy (path, name, sizeof path - 1);
  strncat (path, ".text", sizeof ".text");
  ...
}
In that function, the strncat call uses the size of the source string as its bound. That's almost certainly a mistake, so it gets diagnosed ๐Ÿšจ

This option is enabled by -Wall ๐ŸŽ€

  • -Wno-sizeof-array-argument โ€” chill, it's fine ๐ŸŒธ this turns off the warning for when sizeof is applied to a parameter that's declared as an array in a function definition. This warning is on by default for C and C++ programs ๐Ÿซถ
  • -Wmemset-elt-size โ€” warns about shady memset built-in calls where the first argument points to an array, and the third argument is a number equal to the element count but not equal to the array's full size in memory. That usually means you forgot to multiply by the element size ๐Ÿ’… This one is enabled by -Wall โœจ
  • -Wmemset-transposed-args โ€” warns about suspicious memset built-in calls where the second argument isn't zero and the third argument is zero. For example, memset (buf, sizeof buf, 0) gets flagged, because memset (buf, 0, sizeof buf) was what you meant ๐Ÿ‘‘ The diagnostic only shows up if the third argument is a literal zero. If it's an expression that folds down to zero, or a cast of zero to some type, the arguments are way less likely to be transposed by mistake, so no warning is emitted ๐Ÿฆ‹ This warning is enabled by -Wall ๐Ÿ“
  • -Waddress โ€” suspicious address alert ๐Ÿšจ this warns about dodgy address expressions. That includes comparing the address of a function or a declared object to a null pointer constant, like this:
void f (void);
void g (void)
{
  if (!f)   // warning: expression evaluates to false
    abort ();
}

It also includes comparing a pointer to a string literal:

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

And testing the result of pointer addition or subtraction for equality to null:

void f (const int *p, int i)
{
  return p + i == NULL;
}
These uses usually point to a programmer error. The address of most functions and objects always evaluates to true (weak symbols are the exception), so using them in a conditional might mean you're missing parentheses in a function call or a dereference in an array expression ๐Ÿ˜ญ

The part about object pointers can be silenced by casting the pointer operand to an integer type like intptr_t or uintptr_t ๐Ÿซถ Comparing against string literals leads to unspecified behavior and isn't portable, and it suggests you probably meant to call strcmp ๐Ÿ’œ The warning is also suppressed if the suspicious expression came from macro expansion. The -Waddress warning is enabled by -Wall ๐ŸŒˆ

  • -Wno-address-of-packed-member โ€” don't warn about this one ๐Ÿงš this stops the warning for when the address of a packed member of a struct or union gets taken, which usually ends up as an unaligned pointer value. This is enabled by default ๐Ÿ“
  • -Wlogical-op โ€” warns about suspicious uses of logical operators in expressions, including places where a bitwise operator was probably what you wanted ๐Ÿค” It also warns when both operands of a logical operator are the same:
extern int a;
if (a < 0 && a < 0) { ... }
  • -Wlogical-not-parentheses โ€” warns when a logical not is used on the left-hand side of a comparison. It won't warn if the right operand is a boolean expression. The whole point is catching sus code like this ๐Ÿ™ˆ
int a;
...
if (!a > 1) { ... }

You can make the warning go away by wrapping the left-hand side in parentheses:

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

This warning is enabled by -Wall ๐Ÿ’…

  • -Waggregate-return โ€” warns if any functions that return structs or unions are defined or called ๐Ÿ’– (In languages where you can return an array, this also triggers a warning.)
  • -Wno-aggressive-loop-optimizations โ€” this one is about loops ๐Ÿ” it warns if, in a loop with a constant number of iterations, the compiler detects undefined behavior in some statement during one or more of the iterations โœจ
  • -Wno-attributes โ€” attribute drama ๐Ÿ’œ this stops the warning when an unexpected __attribute__ shows up, like unrecognized attributes, function attributes slapped onto variables, and so on. It doesn't stop errors for incorrectly using attributes that are supported ๐Ÿซถ
Warnings about ill-formed uses of standard attributes get upgraded to errors by -pedantic-errors ๐Ÿ˜ญ

You can also use -Wno-attributes= to suppress warnings about unknown scoped attributes (in C++11 and C23) ๐Ÿงš For example, -Wno-attributes=vendor::attr disables the warning for this declaration:

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

Or you can disable warnings about all attributes in a namespace with -Wno-attributes=vendor::, which covers both of these declarations:

[[vendor::safe]] void f();
[[vendor::unsafe]] void f2();

Just remember that -Wno-attributes= does not imply -Wno-attributes ๐Ÿ’€

  • -Wno-builtin-declaration-mismatch โ€” built-in beef ๐Ÿ‹ this warns if a built-in function is declared with an incompatible signature, or as something that isn't a function. It also fires when a built-in function declared without a prototype gets called with arguments whose promoted types don't match what the function expects. With -Wextra, it also warns when a built-in that takes arguments is declared without a prototype. The -Wbuiltin-declaration-mismatch warning is on by default ๐ŸŒธ To dodge it, include the right header so the built-in prototypes are in scope โœจ

In this example, the memset call gets flagged because the function expects a size_t argument, but 32 is an int. With -Wextra, the declaration of the function gets flagged too ๐Ÿ‘‘

extern void* memset ();
void f (void *d)
{
  memset (d, '\0', 32);
}
  • -Wno-builtin-macro-redefined โ€” stops warnings when certain built-in macros get redefined ๐Ÿฆ‹ This silences redefinitions of __TIMESTAMP__, __TIME__, __DATE__, __FILE__, and __BASE_FILE__ ๐Ÿ’œ
  • -Wstrict-prototypes (C and Objective-C only) โ€” warns if a function is declared or defined without specifying its argument types ๐ŸŽ€ An old-style function definition is fine without a warning, as long as it's preceded by a declaration that does specify the argument types ๐Ÿ’…
  • -Wold-style-declaration (C and Objective-C only) โ€” this one goes after old C habits ๐Ÿ•ฐ๏ธ It warns about declarations the C Standard calls obsolescent, like a storage-class specifier such as static showing up somewhere other than the very front of the declaration. It's also turned on by -Wextra โœจ
  • -Wold-style-definition (C and Objective-C only) โ€” warns whenever you write an old-style function definition, and it still speaks up even if you already gave that function a prototype ๐Ÿ™„ Quick heads up: a definition using () isn't treated as old-style in C23 mode, since it means the same thing as (void) there. For older standards, though, it does count as old-style. ๐Ÿ’…
  • -Wmissing-parameter-type (C and Objective-C only) โ€” catches K&R-style functions where a parameter is declared without a type specifier, like this:
void foo(bar) { }

This warning is also enabled by -Wextra ๐ŸŽ€

  • -Wno-declaration-missing-parameter-type (C and Objective-C only) โ€” the "don't yell at me" flag for function declarations that have a parameter name but no type. Those declarations don't give you a function prototype, so they block most type checking in function calls, which is literally chaos ๐Ÿ’€

This warning is enabled by default. In C99 and later dialects of C, it's treated as an error ๐Ÿšจ You can downgrade it to a warning with -fpermissive (along with certain other errors), or downgrade this one error alone with -Wno-error=declaration-missing-parameter-type.

This warning gets upgraded to an error by -pedantic-errors ๐Ÿ˜ญ

  • -Wmissing-prototypes (C and Objective-C only) โ€” warns if a global function is defined without a previous prototype declaration. It still warns even when the definition itself has a prototype, so it's a great way to catch global functions that don't have a matching prototype in a header file ๐Ÿฆ‹

This option isn't valid for C++, because all function declarations there provide prototypes, and a non-matching declaration just declares an overload instead of conflicting with an earlier one. For missing declarations in C++, use -Wmissing-declarations instead ๐Ÿงš

  • -Wmissing-variable-declarations (C and Objective-C only) โ€” warns if a global variable is defined without a previous declaration. Use it to catch global variables that don't have a matching extern declaration in a header file ๐ŸŒธ
  • -Wmissing-declarations โ€” warns if a global function is defined without a previous declaration, and does so 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 to catch missing prototypes there. 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 triggers the warning:
struct s { int f, g, h; };
struct s x = { 3, 4 };

In C, this option doesn't warn about designated initializers, so this modification doesn't trigger a warning:

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

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

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

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

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

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


  • -Wno-missing-requires โ€” by default, the compiler warns about a concept-id showing up as a C++20 simple-requirement, like this:
bool satisfied = requires { C<T> };

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

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

That way, satisfied is only true if concept C is satisfied for type T ๐Ÿ‘‘

This warning can be disabled with -Wno-missing-requires.

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

In rare cases, you can get false positives. To silence that, wrap the expression in parentheses. For example, the following is treated as a template, even where m and N are integers:

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

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

This warning can be disabled with -Wno-missing-template-keyword ๐Ÿ™ˆ

  • -Wno-multichar โ€” don't warn if a multicharacter constant ('FOOF') is used. These usually signal a typo in your code, since they have implementation-defined values and shouldn't be used in portable code ๐Ÿ“
  • -Wnormalized=[none|id|nfc|nfkc] โ€” okay, this one is a whole mood ๐ŸŒˆ In ISO C and ISO C++, two identifiers are different if they're different sequences of characters. But sometimes, when characters outside basic ASCII are used, you can get two different character sequences that look exactly the same. To avoid that confusion, the ISO 10646 standard sets 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. 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.

Unfortunately, some characters that ISO C and ISO C++ allow in identifiers stop being allowed once they're turned into NFC. So there's no way to use those symbols in portable ISO C or C++ and still have all your identifiers in NFC. -Wnormalized=id suppresses the warning for those characters. The hope is that future versions of the standards will fix this, which is why this 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"), because otherwise you can easily create bugs that are literally impossible to see ๐Ÿ‘€

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

  • -Wno-attribute-warning โ€” don't warn about usage of functions declared with the "warning" attribute. This warning is enabled by default. Use -Wno-attribute-warning to disable the warning, or -Wno-error=attribute-warning to disable the error when compiled with the -Werror flag ๐Ÿซง
  • -Wno-deprecated โ€” don't warn about usage of deprecated features ๐Ÿฆ‹
  • -Wno-deprecated-declarations โ€” don't warn about uses of functions, variables, and types marked as deprecated with the "deprecated" attribute ๐ŸŒท
  • -Wno-overflow โ€” don't warn about compile-time overflow in constant expressions ๐Ÿ”ข
  • -Wno-odr โ€” warns about One Definition Rule violations during link-time optimization. It's enabled by default โญ
  • -Wopenacc-parallelism โ€” warns about potentially suboptimal choices related to OpenACC parallelism ๐Ÿš€
  • -Wno-openmp โ€” warns about suspicious OpenMP code ๐Ÿง
  • -Wopenmp-simd โ€” warns if the vectorizer cost model overrides the OpenMP simd directive you set. The -fsimd-cost-model=unlimited option can be used to relax the cost model ๐ŸŒˆ
  • -Woverride-init (C and Objective-C only) โ€” warns if an initialized field without side effects gets overridden when you're using designated initializers ๐Ÿ’œ

This warning is included in -Wextra. To get the other -Wextra warnings without this one, use -Wextra -Wno-override-init ๐ŸŽ€

  • -Wno-override-init-side-effects (C and Objective-C only) โ€” don't warn if an initialized field with side effects gets overridden when you're using designated initializers. This warning is enabled by default ๐Ÿญ
  • -Wpacked โ€” warns if a structure is given the packed attribute, but that attribute has no effect on the layout or size of the structure. Those structures may end up misaligned for little benefit ๐Ÿ˜ฌ Here, the variable f.x in struct bar is misaligned, even though struct bar doesn't have the packed attribute itself:
struct foo {
  int x;
  char a, b, c, d;
} __attribute__((packed));
struct bar {
  char z;
  struct foo f;
};
  • -Wnopacked-bitfield-compat โ€” the 4.1, 4.2 and 4.3 series of GCC ignore the packed attribute on bit-fields of type char. That got fixed in GCC 4.4, but the change can lead to differences in structure layout. GCC tells you when the offset of such a field has changed in GCC 4.4. For example, in this structure there's no longer a 4-bit padding between field a and b:
struct foo
{
  char a:4;
  char b:8;
} __attribute__ ((packed));

This one's on by default, bestie ๐Ÿ’– but if it's being extra, you can mute it with -Wno-packed-bitfield-compat ๐Ÿ™ˆ

  • -Wpacked-not-aligned โ€” C, C++, Objective-C and Objective-C++ only ๐Ÿ’… Warns if a field with an explicitly set alignment, sitting inside a packed struct or union, ends up misaligned. In this code you'll get "warning: alignment 1 of 'struct S' is less than 8", so watch out ๐Ÿ‘€
struct __attribute__ ((aligned (8))) S8 { char a[8]; };
struct __attribute__ ((packed)) S {
  struct S8 s8;
};

This one is enabled by -Wall โœจ

  • -Wpadded โ€” Flags any padding the compiler sneaks into a struct, whether it's lining up one element or the whole struct. Sometimes you can shuffle the fields around to cut the padding and make the struct smaller ๐Ÿฆ‹
  • -Wredundant-decls โ€” Warns if something gets declared more than once in the same scope, even when that's legal and changes nothing ๐Ÿ™„
  • -Wrestrict โ€” Warns when an object referenced by a restrict-qualified parameter (or a __restrict-qualified one in C++) gets aliased by another argument, or when copies between those objects overlap. In the example below, strcpy is trying to chop off the front of the string by copying the last four characters over the first ones. But the call also writes the terminating NUL into a[4], so the copies overlap and GCC catches it ๐Ÿšจ
void foo (void)
{
  char a[] = "abcd1234";
  strcpy (a, a + 4);
  ...
}

-Wrestrict can catch some simple overlaps even without optimization, but it works best at -O2 and above. It's included in -Wall ๐Ÿ’œ

  • -Wnested-externs โ€” C and Objective-C only ๐ŸŒธ Warns if an extern declaration shows up inside a function
  • -Winline โ€” Warns if a function declared inline can't actually be inlined. Even with this on, GCC won't warn about failures to inline functions declared in system headers ๐Ÿ™ƒ

GCC uses a whole bag of heuristics to decide whether to inline something. It looks at things like how big the function being inlined is, and how much inlining has already happened in the current function. So even seemingly tiny edits to your source can make -Winline warnings appear or disappear ๐ŸŒ€

  • -Winterference-size โ€” Warns about using C++17's std::hardware_destructive_interference_size without setting its value with --param destructive-interference-size. It also warns about questionable values for that option ๐Ÿง

This is meant for class layout, so concurrent code doesn't suffer from false sharing ๐Ÿซถ

struct independent_fields {
  alignas(std::hardware_destructive_interference_size)
    std::atomic<int> one;
  alignas(std::hardware_destructive_interference_size)
    std::atomic<int> two;
};

The whole idea is that one and two are far enough apart that a store to one won't force a reload of the cache line two lives on ๐Ÿ’…

By default, --param destructive-interference-size and --param constructive-interference-size are set based on the current -mtune option. That's typically the L1 cache line size for the particular target CPU, though sometimes it's a range if you're tuning for a generic target.

So every translation unit that depends on ABI compatibility for these variables must be compiled with the same -mtune (or -mcpu). โš ๏ธ

If ABI stability matters, like if you're using this in a header for a library, you should probably not use the hardware interference size variables at all. Alternatively, you can force a particular value with --param ๐ŸŽ€

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

  • -Wint-in-bool-context โ€” Warns about sus integer usage 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++);. The same goes for all kinds of multiplications, no matter the data type. Enabled by -Wall ๐Ÿ”ฅ
  • -Wno-int-to-pointer-cast โ€” Suppresses warnings about casts to a pointer type from an integer of a different size.
In C++, casting to a pointer type of smaller size is an error. ๐Ÿ’€

-Wint-to-pointer-cast is enabled by default ๐Ÿ“

  • -Wno-pointer-to-int-cast โ€” C and Objective-C only ๐ŸŒˆ Suppresses warnings about casts from a pointer to an integer type of a different size
  • -Winvalid-pch โ€” Warns if a precompiled header is found in the search path but can't be used ๐Ÿฅฒ
  • -Winvalid-utf8 โ€” Warns if an invalid UTF-8 character is found. This one's on by default for C++23 when -finput-charset=UTF-8 is used, and it gets turned into an error with -pedantic-errors ๐ŸŒธ
  • -Wno-unicode โ€” Stops GCC from diagnosing invalid forms of delimited or named escape sequences that get treated as separate tokens. -Wunicode is enabled by default โœจ
  • -Wlong-long โ€” Warns if the long long type is used. This is enabled by either -Wpedantic or -Wtraditional in ISO C90 and C++98 modes. To inhibit the messages, use -Wno-long-long ๐Ÿ“

This warning gets upgraded to an error by -pedantic-errors ๐Ÿšซ

  • -Wvariadic-macros โ€” Warns if variadic macros are used in ISO C90 mode, or if the GNU alternate syntax is used in ISO C99 mode. This is enabled by either -Wpedantic or -Wtraditional. To inhibit the warning messages, use -Wno-variadic-macros ๐Ÿงฉ
  • -Wno-varargs โ€” Stops warnings about questionable usage of the macros that handle variable arguments, like va_start. These warnings are enabled by default ๐Ÿ™…
  • -Wvector-operation-performance โ€” Warns if a vector operation isn't implemented via the SIMD capabilities of the architecture. It's mainly useful for performance tuning ๐ŸŽ๏ธ A vector operation can be implemented "piecewise", meaning the scalar operation runs on every vector element. It can be implemented "in parallel", meaning it uses scalars of a wider type, which is normally more performance efficient. Or it can be implemented "as a single scalar", meaning the vector fits into a scalar type.
  • -Wvla โ€” Warns if a variable-length array is used in the code. -Wno-vla prevents the -Wpedantic warning about variable-length arrays. This warning is upgraded to an error by -pedantic-errors ๐Ÿšซ
  • -Wvla-larger-than=byte-size โ€” If you use this, the compiler warns for declarations of variable-length arrays whose size is either unbounded, or bounded by an argument that lets the array size exceed byte-size bytes. It's kind of like how -Walloca-larger-than=byte-size works, but for VLAs ๐Ÿ“

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

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

See also -Walloca-larger-than=byte-size ๐Ÿ‘€

  • -Wno-vla-larger-than โ€” Disables -Wvla-larger-than= warnings. The option is equivalent to -Wvla-larger-than=SIZE_MAX or larger ๐Ÿ›‘
  • -Wvla-parameter โ€” Warns about redeclarations of functions involving arguments of Variable Length Array types with inconsistent kinds or forms. It also enables detection of out-of-bounds accesses to those parameters by warnings like -Warray-bounds ๐Ÿงฎ If the first function declaration uses the VLA form, the bound in the array is assumed to be the minimum number of elements expected in calls to the function, and the maximum number of elements it accesses. Passing arguments that are too small, or accessing more than that maximum, may be diagnosed.

For example, the warning triggers for these redeclarations. The first one allows an array of any size to be passed to f, while the second one says the array argument must have at least n elements. Calling f with the associated VLA bound parameter in excess of the actual VLA bound triggers a warning as well ๐Ÿซ 

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

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

-Wvla-parameter is included in -Wall. -Warray-parameter triggers warnings for similar problems involving ordinary array arguments ๐ŸŒˆ

  • -Wvolatile-register-var โ€” Warns if a register variable is declared volatile. Heads up, the volatile modifier doesn't inhibit all optimizations that may eliminate reads and/or writes to register variables. This warning is enabled by -Wall ๐Ÿ’…
  • -Wno-xor-used-as-pow โ€” C, C++, Objective-C and Objective-C++ only ๐Ÿค” Disables warnings about uses of ^, the exclusive or operator, where it looks like you meant exponentiation. Specifically, the warning happens when the left-hand side is the decimal constant 2 or 10 and the right-hand side is also a decimal constant.

In C and C++, ^ means exclusive or, whereas in some other languages (like TeX and some versions of BASIC) it means exponentiation โœจ

This warning can be silenced by converting one of the operands to hexadecimal, as well as by compiling with -Wno-xor-used-as-pow ๐Ÿซถ

  • -Wdisabled-optimization โ€” Warns if a requested optimization pass is disabled. This doesn't generally mean anything is wrong with your code. It just means GCC's optimizers can't handle the code effectively ๐Ÿข Often the problem is that your code is too big or too complex, since GCC refuses to optimize programs when the optimization itself would likely take inordinate amounts of time.
  • -Wpointer-sign (C and Objective-C only) โ€” okay bestie, this one yells when a pointer gets passed or assigned with a different signedness ๐Ÿ’…
    • This only works for C and Objective-C ๐ŸŽ€
    • It's already switched on by -Wall and -Wpedantic, and you can turn it off with -Wno-pointer-sign ๐Ÿ™ˆ
    • -pedantic-errors upgrades it into an error ๐Ÿ’€
  • -Wstack-protector โ€” this one is only active when -fstack-protector is on ๐Ÿ›ก๏ธ It warns about functions that aren't protected against stack smashing ๐Ÿ˜ญ
  • -Woverlength-strings โ€” this one warns about string constants that go past the "minimum maximum" length from the C standard โœจ
    • Modern compilers are super chill and let strings get way longer than that minimum, but very portable programs should avoid longer strings ๐Ÿงš
    • The limit applies after string concatenation, and it doesn't count the trailing NUL. In C90 the limit was 509 characters, and in C99 it got raised to 4095 ๐Ÿ“
    • C++98 doesn't set a normative minimum maximum, so GCC doesn't diagnose overlength strings in C++ ๐ŸŒˆ
    • -Wpedantic implies it, and you can disable it with -Wno-overlength-strings ๐Ÿซถ
  • -Wunsuffixed-float-constants (C and Objective-C only) โ€” this warns for any floating constant that doesn't have a suffix ๐Ÿฆ‹
    • Add -Wsystem-headers and it'll also warn about those constants in system header files ๐Ÿ‘€
    • It's giving prep work for the "FLOAT_CONST_DECIMAL64" pragma from the decimal floating-point extension to C99 ๐Ÿ’œ
  • -Wno-lto-type-mismatch โ€” during link-time optimization, this stops GCC from warning about type mismatches in global declarations across different compilation units ๐ŸŒธ It needs -flto to be enabled, and it's enabled by default โœจ
  • -Wno-designated-init (C and Objective-C only) โ€” this suppresses warnings when a positional initializer is used on a structure marked with the "designated_init" attribute ๐ŸŽ€

๐Ÿ” Options That Control Static Analysis

  • -fanalyzer โ€” okay this one is the big boss ๐Ÿ‘‘ It enables a static analysis of program flow that hunts for "interesting" interprocedural paths through the code, and it warns you about problems it finds on them ๐Ÿ”ฅ
    • It's way more expensive than other GCC warnings, so be patient bestie โณ
    • In technical terms, it does coverage-guided symbolic execution of the code being compiled ๐Ÿค“
    • It is neither sound nor complete, so it can have false positives and false negatives ๐Ÿ™ˆ It's a bug-finding tool, not a tool for proving program correctness ๐Ÿ’…
    • In this release, the analyzer is only suitable for use on C code ๐ŸŒธ
    • Turning this on effectively enables these warnings:
-Wanalyzer-allocation-size -Wanalyzer-deref-before-check
-Wanalyzer-double-fclose -Wanalyzer-double-free
-Wanalyzer-exposure-through-output-file
-Wanalyzer-exposure-through-uninit-copy
-Wanalyzer-fd-access-mode-mismatch -Wanalyzer-fd-double-close
-Wanalyzer-fd-leak -Wanalyzer-fd-phase-mismatch
-Wanalyzer-fd-type-mismatch -Wanalyzer-fd-use-after-close
-Wanalyzer-fd-use-without-check -Wanalyzer-file-leak
-Wanalyzer-free-of-non-heap -Wanalyzer-imprecise-fp-arithmetic
-Wanalyzer-infinite-loop -Wanalyzer-infinite-recursion
-Wanalyzer-jump-through-null -Wanalyzer-malloc-leak
-Wanalyzer-mismatching-deallocation -Wanalyzer-null-argument
-Wanalyzer-null-dereference -Wanalyzer-out-of-bounds
-Wanalyzer-overlapping-buffers -Wanalyzer-possible-null-argument
-Wanalyzer-possible-null-dereference -Wanalyzer-putenv-of-auto-var
-Wanalyzer-shift-count-negative -Wanalyzer-shift-count-overflow
-Wanalyzer-stale-setjmp-buffer -Wanalyzer-tainted-allocation-size
-Wanalyzer-tainted-array-index -Wanalyzer-tainted-assertion
-Wanalyzer-tainted-divisor -Wanalyzer-tainted-offset
-Wanalyzer-tainted-size -Wanalyzer-undefined-behavior-strtok
-Wanalyzer-unsafe-call-within-signal-handler
-Wanalyzer-use-after-free
-Wanalyzer-use-of-pointer-in-stale-stack-frame
-Wanalyzer-use-of-uninitialized-value
-Wanalyzer-va-arg-type-mismatch -Wanalyzer-va-list-exhausted
-Wanalyzer-va-list-leak -Wanalyzer-va-list-use-after-va-end
-Wanalyzer-write-to-const -Wanalyzer-write-to-string-literal
  • This only works if GCC was configured with analyzer support enabled ๐Ÿ”ง
  • -Wanalyzer-symbol-too-complex โ€” the analyzer uses heuristics to track the state of memory, but sufficiently complicated code can totally defeat them ๐Ÿ˜ตโ€๐Ÿ’ซ
    • By default, if an expression goes past the threshold set by --param analyzer-max-svalue-depth=value, the analysis quietly stops tracking its values and falls back to an imprecise representation ๐Ÿซ 
    • This option warns you when that happens ๐Ÿšจ
  • -Wanalyzer-too-complex โ€” the analyzer tries to explore control flow and data flow, but again, sufficiently complicated code can defeat it ๐ŸŒ€
    • By default the analysis silently stops if the code is too complicated and it hits an internal limit ๐Ÿค
    • This option warns you when that happens ๐Ÿ“ฃ
  • -Wno-analyzer-allocation-size โ€” this warning needs -fanalyzer to be enabled, and you can switch it off with -Wno-analyzer-allocation-size ๐Ÿ™…โ€โ™€๏ธ
    • It warns for paths through the code where a pointer to a buffer gets assigned to point at a buffer whose size isn't a multiple of sizeof (*pointer) ๐Ÿ“
    • See CWE-131: Incorrect Calculation of Buffer Size, "https://cwe.mitre.org/data/definitions/131.html" ๐Ÿ”—
  • -Wno-analyzer-deref-before-check โ€” this one needs -fanalyzer too, and you disable it with -Wno-analyzer-deref-before-check ๐Ÿ™ƒ
    • It warns for paths where a pointer gets checked for NULL after it's already been dereferenced, which suggests the pointer could've been NULL all along ๐Ÿ˜ณ Either the check is redundant, or it needs to move to before the dereference ๐Ÿ’โ€โ™€๏ธ
    • It also treats values passed to a function argument marked with __attribute__((nonnull)) as needing to be non-NULL, so it'll complain if those values get checked for NULL after the function call returns ๐Ÿง
    • > This one is unlikely to show up when any level of optimization is on, because GCC's optimizer usually sees those NULL checks as redundant and deletes them before the analyzer gets a look ๐Ÿ™ˆ So turn optimization off if you're trying to trigger it ๐Ÿ’€
  • -Wno-analyzer-double-fclose โ€” needs -fanalyzer, and you can disable it with -Wno-analyzer-double-fclose ๐ŸŽ€
  • -Wno-analyzer-double-free โ€” needs -fanalyzer, and use -Wno-analyzer-double-free to disable it ๐Ÿงน
    • It warns for paths where a pointer can have a deallocator called on it more than once, either free, or a deallocator referenced by attribute malloc ๐Ÿ—‘๏ธ
    • See CWE-415: Double Free, "https://cwe.mitre.org/data/definitions/415.html" ๐Ÿ”—
  • -Wno-analyzer-exposure-through-output-file โ€” needs -fanalyzer, and you turn it off with -Wno-analyzer-exposure-through-output-file ๐Ÿคซ
    • It warns for paths where a security-sensitive value gets written to an output file, like writing a password to a log file ๐Ÿ”
    • See CWE-532: Information Exposure Through Log Files, "https://cwe.mitre.org/data/definitions/532.html" ๐Ÿ”—
  • -Wanalyzer-exposure-through-uninit-copy โ€” this one needs both -fanalyzer and a plugin that specifies a function copying across a "trust boundary" ๐Ÿงฉ Use -Wno-analyzer-exposure-through-uninit-copy to disable it ๐Ÿ™…โ€โ™€๏ธ
    • It warns about "infoleaks", which are paths where uninitialized values get copied across a security boundary, like code inside an OS kernel copying a partially-initialized struct from the stack over to user space ๐Ÿ˜ฑ
    • See CWE-200: Exposure of Sensitive Information to an Unauthorized Actor, "https://cwe.mitre.org/data/definitions/200.html" ๐Ÿ”—
  • -Wno-analyzer-fd-access-mode-mismatch โ€” needs -fanalyzer, and you can disable it with -Wno-analyzer-fd-access-mode-mismatch ๐Ÿ“‚
    • It warns for paths where a "read" is attempted on a write-only file descriptor, or the other way around ๐Ÿ”„
    • It also warns for code paths where a function with attribute fd_arg_read (N) is called with a file descriptor opened with O_WRONLY at referenced argument N, or where a function with attribute fd_arg_write (N) is called with a file descriptor opened with O_RDONLY at referenced argument N ๐Ÿงพ
  • -Wno-analyzer-fd-double-close โ€” needs -fanalyzer, and you disable it with -Wno-analyzer-fd-double-close โœŒ๏ธ
  • -Wno-analyzer-fd-leak โ€” needs -fanalyzer, and use -Wno-analyzer-fd-leak to disable it ๐Ÿ’ง
  • -Wno-analyzer-fd-phase-mismatch โ€” needs -fanalyzer, and you disable it with -Wno-analyzer-fd-phase-mismatch โฐ
    • It warns for paths where an operation gets attempted in the wrong phase of a file descriptor's lifetime ๐Ÿ•ฐ๏ธ For example, it'll warn if you try to call accept on a stream socket that hasn't had listen successfully called on it yet ๐Ÿงฆ
    • See CWE-666: Operation on Resource in Wrong Phase of Lifetime, "https://cwe.mitre.org/data/definitions/666.html" ๐Ÿ”—

-Wno-analyzer-fd-type-mismatch ๐Ÿฆ‹

Okay so this one needs -fanalyzer to be switched on, which turns it on for you. To silence it, use -Wno-analyzer-fd-type-mismatch. ๐Ÿ’…

It catches paths through your code where an operation gets run on the wrong type of file descriptor. Like trying socket operations on an fd you got from open, or doing a stream socket operation on a datagram socket. Not it. ๐Ÿ™…โ€โ™€๏ธ

-Wno-analyzer-fd-use-after-close ๐ŸŒธ

Also needs -fanalyzer to be enabled. Use -Wno-analyzer-fd-use-after-close to turn it off. ๐Ÿซถ

This one flags paths where a read or write gets called on a file descriptor that's already been closed. ๐Ÿ’€ It also catches functions with the attribute fd_arg (N), fd_arg_read (N), or fd_arg_write (N) getting called with a closed fd at the referenced argument N. Main character energy, but make it a closed file descriptor and it's a whole mess. ๐Ÿ˜ญ

-Wno-analyzer-fd-use-without-check ๐Ÿงš

Needs -fanalyzer, obviously. Disable it with -Wno-analyzer-fd-use-without-check. โœจ

This warns on paths where a file descriptor gets used without anyone checking whether it's valid first. ๐Ÿ™ˆ It also warns when a function marked with fd_arg (N), fd_arg_read (N), or fd_arg_write (N) gets handed a file descriptor at referenced argument N without a validity check. Always check your fds, bestie. ๐Ÿ”ฅ

-Wno-analyzer-file-leak ๐Ÿ“

Requires -fanalyzer. Use -Wno-analyzer-file-leak to turn it off. ๐ŸŽ€

This one lights up paths through the code where a FILE * stream object from <stdio.h> gets leaked. Like, you opened it and just... never let it go. ๐Ÿ˜ค

Go peep CWE-775: Missing Release of File Descriptor or Handle after Effective Lifetime, which is at https://cwe.mitre.org/data/definitions/775.html. ๐Ÿ’œ

-Wno-analyzer-free-of-non-heap ๐Ÿ’–

Needs -fanalyzer to run. Silence it with -Wno-analyzer-free-of-non-heap. ๐Ÿฆ‹

It warns on paths where free gets called on a pointer that isn't on the heap. Think an on-stack buffer, or a global. You can't free something that was never heap-allocated, sweetie. ๐Ÿ’€

See CWE-590: Free of Memory not on the Heap at https://cwe.mitre.org/data/definitions/590.html. ๐ŸŒˆ

-Wno-analyzer-imprecise-fp-arithmetic โญ

Requires -fanalyzer. Turn it off with -Wno-analyzer-imprecise-fp-arithmetic. ๐ŸŒธ

This one catches paths where floating-point arithmetic shows up in places that really need precise computation. ๐Ÿง Right now, it only warns about floating-point operands used inside the calculation of an allocation size. That's the whole vibe for now. โœจ

-Wno-analyzer-infinite-loop ๐Ÿ”ฅ

Needs -fanalyzer. Disable it with -Wno-analyzer-infinite-loop. ๐Ÿ’…

This diagnostic warns on paths that seem to lead into an infinite loop. ๐ŸŒ€

Specifically, the analyzer will throw this warning when it notices a loop where all of these are true:

  • nothing externally visible can actually get done inside the loop
  • there's no way to escape from the loop
  • the analyzer is confident enough about the program state throughout the loop to know both of the above are true

One way this shows up is when there's a path through a loop where taking it on one iteration means the same path gets taken on every iteration after that. Honestly iconic, but also a trap. ๐Ÿชค

Here's an example:

while (1)
  {
    char opcode = *cpu_state.pc;
    switch (opcode)
     {
     case OPCODE_FOO:
       handle_opcode_foo (&cpu_state);
       break;
     case OPCODE_BAR:
       handle_opcode_bar (&cpu_state);
       break;
     }
  }

The analyzer will absolutely side-eye this one. If opcode ever matches none of the cases, the switch falls through to its implicit default case. That makes the loop body a no-op, cpu_state.pc never changes, and opcode stays the same on every iteration after. Now you're stuck in an infinite loop forever. ๐Ÿ˜ญ

See CWE-835: Loop with Unreachable Exit Condition ('Infinite Loop') at https://cwe.mitre.org/data/definitions/835.html. ๐Ÿซถ

-Wno-analyzer-infinite-recursion ๐ŸŒ€

Needs -fanalyzer. Use -Wno-analyzer-infinite-recursion to turn it off. ๐ŸŽ€

This one flags paths that look like they're headed for infinite recursion. ๐Ÿ” Here's how it works: whenever the analyzer sees a recursive call, it compares the state of memory at the entry of the new frame with the state at the entry of the previous frame for that same function on the stack. If nothing in memory seems to be changing, it warns. But if it spots any changes to parameters or globals, it assumes the recursion will eventually end and keeps quiet. ๐Ÿคซ

Heads up: this diagnostic is likely to miss infinite recursion that the optimizer turns into iteration before the analyzer gets a look. So if you're trying to trigger this one on purpose, disable optimization first. ๐Ÿ™ƒ

Compare this with -Winfinite-recursion, which gives you a similar diagnostic but is implemented in a totally different way. ๐Ÿ’œ

See CWE-674: Uncontrolled Recursion at https://cwe.mitre.org/data/definitions/674.html. ๐ŸŒธ

-Wno-analyzer-jump-through-null ๐Ÿฆ‹

Requires -fanalyzer. Disable it with -Wno-analyzer-jump-through-null. ๐Ÿ’…

This warns on paths where a NULL function pointer gets called. Calling nothing is not a vibe. ๐Ÿ™…โ€โ™€๏ธ

-Wno-analyzer-malloc-leak ๐Ÿ“

Needs -fanalyzer. Use -Wno-analyzer-malloc-leak to silence it. โœจ

It warns on paths where a pointer allocated through an allocator gets leaked. The allocator can be malloc, or any function marked with the attribute malloc. ๐Ÿ’€

See CWE-401: Missing Release of Memory after Effective Lifetime at https://cwe.mitre.org/data/definitions/401.html. ๐Ÿซถ

-Wno-analyzer-mismatching-deallocation ๐Ÿงš

Requires -fanalyzer. Turn it off with -Wno-analyzer-mismatching-deallocation. ๐ŸŒˆ

This one warns on paths where the wrong deallocation function gets called on a pointer, based on which function originally allocated it. ๐Ÿ™ƒ It will warn about mismatches between free, scalar delete, and vector delete[]. It also covers anything marked as an allocator/deallocator pair using the attribute malloc. Pair your allocs and deallocs properly, bestie. ๐Ÿซถ

See CWE-762: Mismatched Memory Management Routines at https://cwe.mitre.org/data/definitions/762.html. ๐Ÿ’–

-Wno-analyzer-out-of-bounds ๐Ÿ”ฅ

Needs -fanalyzer. Disable it with -Wno-analyzer-out-of-bounds. ๐Ÿ’…

This diagnostic warns on paths where a buffer is definitely read or written out-of-bounds. It applies when the analyzer can work out a constant offset, and for accesses past the end of a buffer with a constant capacity. It also does some limited checking for accesses past the end when both the offset and the capacity are symbolic. ๐Ÿง 

See CWE-119: Improper Restriction of Operations within the Bounds of a Memory Buffer at https://cwe.mitre.org/data/definitions/119.html. ๐ŸŒธ

When the analyzer can manage it, it'll even draw you a text art diagram of the memory involved. ๐ŸŽจ It shows how the region the analyzer thinks gets accessed compares to the range that's actually valid: whether they overlap, touch, or sit far apart, which one comes first in memory, the relative sizes, whether it's a read or a write, and sometimes the data values involved. Lowkey the coolest part. โœจ You can hide the diagram with -fdiagnostics-text-art-charset=none. ๐Ÿ™ˆ

-Wno-analyzer-overlapping-buffers ๐ŸŒˆ

Needs -fanalyzer. Use -Wno-analyzer-overlapping-buffers to turn it off. ๐Ÿฆ‹

This one warns on paths where overlapping buffers get passed to an API that has undefined behaviour for that kind of input. ๐Ÿ˜ฌ Specifically, it fires on calls to these functions:

  • memcpy
  • strcat
  • strcpy

...but only when the buffers are known to overlap. ๐Ÿซถ

-Wno-analyzer-possible-null-argument ๐Ÿ“

Requires -fanalyzer. Disable it with -Wno-analyzer-possible-null-argument. ๐ŸŽ€

This warns on paths where a value that might be NULL gets passed to a function argument marked with __attribute__((nonnull)), which says it needs a non-NULL value. ๐Ÿค”

See CWE-690: Unchecked Return Value to NULL Pointer Dereference at https://cwe.mitre.org/data/definitions/690.html. ๐Ÿ’œ

-Wno-analyzer-possible-null-dereference ๐ŸŒธ

Needs -fanalyzer. Silence it with -Wno-analyzer-possible-null-dereference. โœจ

This one warns on paths where a value that might be NULL gets dereferenced. ๐Ÿ˜ฌ

See CWE-690: Unchecked Return Value to NULL Pointer Dereference at https://cwe.mitre.org/data/definitions/690.html. ๐Ÿซถ

-Wno-analyzer-null-argument ๐Ÿฆ‹

Requires -fanalyzer. Use -Wno-analyzer-null-argument to turn it off. ๐Ÿ’…

This warns on paths where a value the analyzer knows is NULL gets passed to a function argument marked with __attribute__((nonnull)). ๐Ÿšซ

See CWE-476: NULL Pointer Dereference at https://cwe.mitre.org/data/definitions/476.html. ๐Ÿ”ฅ

-Wno-analyzer-null-dereference ๐Ÿ’–

Needs -fanalyzer. Disable it with -Wno-analyzer-null-dereference. ๐ŸŒˆ

This one warns on paths where a value known to be NULL gets dereferenced. Big yikes. ๐Ÿ’€

See CWE-476: NULL Pointer Dereference at https://cwe.mitre.org/data/definitions/476.html. ๐Ÿงš

-Wno-analyzer-putenv-of-auto-var โญ

This warning requires -fanalyzer, which enables it; use -Wno-analyzer-putenv-of-auto-var to disable it. ๐ŸŒธ

Okay so this bit is all about putenv ๐ŸŒธ It warns about paths through the code where a call to putenv gets handed a pointer to an automatic variable or an on-stack buffer. Big nope, bestie ๐Ÿ™…โ€โ™€๏ธ

See POS34-C. The rule is "Do not call putenv() with a pointer to an automatic variable as the argument" ๐Ÿ’… (https://wiki.sei.cmu.edu/confluence/x/6NYxBQ).

  • -Wno-analyzer-shift-count-negative โ€” ๐Ÿ”ฅ This one needs -fanalyzer to turn it on, and you can switch it off with -Wno-analyzer-shift-count-negative. It flags paths where a shift is attempted with a negative count. It's the sibling of the -Wshift-count-negative warning from the C/C++ front ends, except it works by analyzing interprocedural paths instead of just reading the syntax tree. Lowkey, the analyzer doesn't prioritise finding these, so false negatives are more likely than with other warnings ๐Ÿ™ˆ
  • -Wno-analyzer-shift-count-overflow โ€” โœจ Also requires -fanalyzer, which enables it, and you disable it with -Wno-analyzer-shift-count-overflow. This one catches paths where a shift count is greater than or equal to the precision of the operand's type. It's the analyzer's take on -Wshift-count-overflow from the C/C++ front ends, again built on interprocedural paths rather than the syntax tree. Same deal as before: the analyzer doesn't prioritise these, so false negatives are more likely compared to other warnings ๐Ÿ’€
  • -Wno-analyzer-stale-setjmp-buffer โ€” ๐Ÿฆ‹ Needs -fanalyzer, which enables it, and -Wno-analyzer-stale-setjmp-buffer turns it off. It warns for paths where longjmp is called to rewind to a jmp_buf tied to a setjmp call in a function that has already returned. When setjmp records a rewind location on a jmp_buf, it records the stack frame, and that frame becomes invalid once the function containing the setjmp call returns. Trying to rewind to it with longjmp means referencing a stack frame that doesn't exist anymore, which will likely lead to a crash (or worse) ๐Ÿ˜ญ
  • -Wno-analyzer-tainted-allocation-size โ€” ๐Ÿงš Requires -fanalyzer, which enables it, and you can silence it with -Wno-analyzer-tainted-allocation-size. It warns for paths where a value an attacker could control gets used as the size of an allocation without being sanitised, so an attacker could inject a massively huge allocation and cause a denial of service attack. See CWE-789: Memory Allocation with Excessive Size Value (https://cwe.mitre.org/data/definitions/789.html) ๐Ÿซถ
  • -Wno-analyzer-tainted-assertion โ€” ๐Ÿ‘‘ This one also needs -fanalyzer, and -Wno-analyzer-tainted-assertion is how you disable it. It warns for paths where an attacker-controllable value gets used as part of a condition without being sanitised first, and that condition guards a call to a function marked with the noreturn attribute (like __builtin_unreachable). Those functions usually mean the program is terminating abnormally, like assertion failure handlers. For example:
assert (some_tainted_value < SOME_LIMIT);

In such cases:

  • when assertion-checking is enabled: an attacker could trigger a denial of service by injecting an assertion failure
  • when assertion-checking is disabled, such as by defining NDEBUG, an attacker could inject data that subverts the process, since it presumably violates a precondition that is being assumed by the code.

Note that when assertion-checking is disabled, the assertions are typically removed by the preprocessor before the analyzer has a chance to "see" them, so this diagnostic can only generate warnings on builds in which assertion-checking is enabled ๐ŸŽ€

For the purpose of this warning, any function marked with the noreturn attribute counts as a possible assertion failure handler, including __builtin_unreachable. These functions are sometimes removed by the optimizer before the analyzer "sees" them, so optimization should be disabled when you're trying to trigger this diagnostic.

See CWE-617: Reachable Assertion (https://cwe.mitre.org/data/definitions/617.html).

The warning can also report problematic constructions such as:

switch (some_tainted_value) {
case 0:
  /* [...etc; various valid cases omitted...] */
  break;

default:
  __builtin_unreachable (); /* BUG: attacker can trigger this  */
}

despite the above not being an assertion failure, strictly speaking ๐Ÿ™ƒ

  • -Wno-analyzer-tainted-array-index โ€” ๐ŸŒˆ Needs -fanalyzer, which enables it, and -Wno-analyzer-tainted-array-index switches it off. It warns for paths where an attacker-controllable value is used as the index of an array access without being sanitised, so an attacker could inject an out-of-bounds access. See CWE-129: Improper Validation of Array Index (https://cwe.mitre.org/data/definitions/129.html) ๐Ÿ’–
  • -Wno-analyzer-tainted-divisor โ€” โญ Requires -fanalyzer, which enables it, and you disable it with -Wno-analyzer-tainted-divisor. It warns for paths where an attacker-controllable value is used as the divisor in a division or modulus operation without being sanitised, so an attacker could inject a division-by-zero. See CWE-369: Divide By Zero (https://cwe.mitre.org/data/definitions/369.html) ๐Ÿ“
  • -Wno-analyzer-tainted-offset โ€” ๐ŸŒธ Needs -fanalyzer, which enables it, and -Wno-analyzer-tainted-offset turns it off. It warns for paths where an attacker-controllable value is used as a pointer offset without being sanitised, so an attacker could inject an out-of-bounds access. See CWE-823: Use of Out-of-range Pointer Offset (https://cwe.mitre.org/data/definitions/823.html) โœจ
  • -Wno-analyzer-tainted-size โ€” ๐Ÿ’œ Requires -fanalyzer, which enables it, and you can silence it with -Wno-analyzer-tainted-size. It warns for paths where an attacker-controllable value is used as the size of an operation such as memset without being sanitised, so an attacker could inject an out-of-bounds access. See CWE-129: Improper Validation of Array Index (https://cwe.mitre.org/data/definitions/129.html) ๐Ÿซถ
  • -Wno-analyzer-undefined-behavior-strtok โ€” ๐Ÿ”ฅ Needs -fanalyzer, which enables it, and -Wno-analyzer-undefined-behavior-strtok disables it. It warns for paths where a call is made to strtok that has undefined behavior. Specifically, passing NULL as the first parameter for the initial call to strtok within a process is undefined behavior, so watch out ๐Ÿ‘€
  • -Wno-analyzer-unsafe-call-within-signal-handler โ€” ๐Ÿฆ‹ Requires -fanalyzer, which enables it, and you turn it off with -Wno-analyzer-unsafe-call-within-signal-handler. It warns for paths where a function known to be async-signal-unsafe (like fprintf) gets called from a signal handler. See CWE-479: Signal Handler Use of a Non-reentrant Function (https://cwe.mitre.org/data/definitions/479.html) ๐Ÿงš
  • -Wno-analyzer-use-after-free โ€” ๐ŸŒˆ Needs -fanalyzer, which enables it, and -Wno-analyzer-use-after-free is your off switch. It warns for paths where a pointer is used after a deallocator has been called on it, either free or a deallocator referenced by the malloc attribute. See CWE-416: Use After Free (https://cwe.mitre.org/data/definitions/416.html) ๐Ÿ’€
  • -Wno-analyzer-use-of-pointer-in-stale-stack-frame โ€” ๐Ÿ™ˆ Requires -fanalyzer, which enables it, and you disable it with -Wno-analyzer-use-of-pointer-in-stale-stack-frame. It warns for paths where a pointer is dereferenced that points to a variable in a stale stack frame.
  • -Wno-analyzer-va-arg-type-mismatch โ€” ๐Ÿ‘‘ Needs -fanalyzer, which enables it, and -Wno-analyzer-va-arg-type-mismatch turns it off. It warns for interprocedural paths where the analyzer detects an attempt to use va_arg to extract a value passed to a variadic call, but the type used doesn't match the type of the expression passed to the call. See CWE-686: Function Call With Incorrect Argument Type (https://cwe.mitre.org/data/definitions/686.html) ๐Ÿ’…
  • -Wno-analyzer-va-list-exhausted โ€” ๐Ÿ“ Requires -fanalyzer, which enables it, and you can silence it with -Wno-analyzer-va-list-exhausted. It warns for interprocedural paths where the analyzer detects an attempt to use va_arg to access the next value passed to a variadic call, but every value in the va_list has already been consumed. See CWE-685: Function Call With Incorrect Number of Arguments (https://cwe.mitre.org/data/definitions/685.html) ๐ŸŒธ
  • -Wno-analyzer-va-list-leak โ€” โœจ Needs -fanalyzer, which enables it, and -Wno-analyzer-va-list-leak disables it. It warns for interprocedural paths where the analyzer detects that va_start or va_copy has been called on a va_list without a corresponding call to va_end.
  • -Wno-analyzer-va-list-use-after-va-end โ€” ๐Ÿงš Requires -fanalyzer, which enables it, and you turn it off with -Wno-analyzer-va-list-use-after-va-end. It warns for interprocedural paths where the analyzer detects an attempt to use a va_list after va_end has been called on it. va_list.
  • -Wno-analyzer-write-to-const โ€” ๐Ÿ’œ This warning requires -fanalyzer, which enables it; use -Wno-analyzer-write-to-const to disable it.

Okay bestie, this one's the analyzer side-eyeing your writes ๐Ÿ‘€. It warns about paths where it spots an attempt to write through a pointer to a const object ๐ŸŽ€ The catch is that the analyzer doesn't prioritize hunting these down, so false negatives (missed issues) are more likely than with other warnings ๐Ÿ’€

  • -Wno-analyzer-write-to-string-literal ๐ŸŒธ This one needs -fanalyzer to be on, since that's what turns it on. Use -Wno-analyzer-write-to-string-literal to switch it off. It warns about paths where the analyzer sees a write through a pointer to a string literal. Same deal as before: it doesn't prioritize these paths, so false negatives are more likely than with other warnings.
  • -Wno-analyzer-use-of-uninitialized-value ๐Ÿฆ‹ Also requires -fanalyzer (which enables it), and you can disable it with -Wno-analyzer-use-of-uninitialized-value. It warns about paths where an uninitialized value gets used.

See CWE-457: Use of Uninitialized Variable (https://cwe.mitre.org/data/definitions/457.html).


The analyzer already has hardcoded knowledge about how these memory-management functions behave ๐Ÿง โœจ

  • alloca
  • The built-in functions __builtin_alloc, __builtin_alloc_with_align, __builtin_calloc, __builtin_free, __builtin_malloc, __builtin_memcpy, __builtin_memcpy_chk, __builtin_memset, __builtin_memset_chk, __builtin_realloc, __builtin_stack_restore, and __builtin_stack_save
  • calloc
  • free
  • malloc
  • memset
  • operator delete
  • operator delete []
  • operator new
  • operator new []
  • realloc
  • strdup
  • strndup

It also knows about these file descriptor functions ๐Ÿซถ

  • open
  • close
  • creat
  • dup, dup2 and dup3
  • isatty
  • pipe, and pipe2
  • read
  • write
  • socket, bind, listen, accept, and connect

And these <stdio.h> stream functions ๐ŸŒˆ

  • The built-in functions __builtin_fprintf, __builtin_fprintf_unlocked, __builtin_fputc, __builtin_fputc_unlocked, __builtin_fputs, __builtin_fputs_unlocked, __builtin_fwrite, __builtin_fwrite_unlocked, __builtin_printf, __builtin_printf_unlocked, __builtin_putc, __builtin_putchar, __builtin_putchar_unlocked, __builtin_putc_unlocked, __builtin_puts, __builtin_puts_unlocked, __builtin_vfprintf, and __builtin_vprintf
  • fopen
  • fclose
  • ferror
  • fgets
  • fgets_unlocked
  • fileno
  • fread
  • getc
  • getchar
  • fprintf
  • printf
  • fwrite

And finally, a grab bag of other functions ๐Ÿ’…

  • The built-in functions __builtin_expect, __builtin_expect_with_probability, __builtin_strchr, __builtin_strcpy, __builtin_strcpy_chk, __builtin_strlen, __builtin_va_copy, and __builtin_va_start
  • The GNU extensions error and error_at_line
  • getpass
  • longjmp
  • putenv
  • setjmp
  • siglongjmp
  • signal
  • sigsetjmp
  • strcat
  • strchr
  • strlen

Also, various functions with an __analyzer_ prefix have special meaning to the analyzer. Those are described in the GCC Internals manual ๐Ÿ“–๐Ÿ”ฅ

Pertinent parameters for controlling the exploration (aka how far the analyzer digs) are:

  • --param analyzer-bb-explosion-factor=value
  • --param analyzer-max-enodes-per-program-point=value
  • --param analyzer-max-recursion-depth=value
  • --param analyzer-min-snodes-for-call-summary=value

The following options control the analyzer, so let's get into it ๐Ÿ“

  • -fanalyzer-call-summaries โ€” This simplifies interprocedural analysis (checking across function calls) 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 running just the named checker, and enables it ๐ŸŽฏ
  • -fanalyzer-debug-text-art-headings โ€” This one's for analyzer developers ๐Ÿ› ๏ธ When enabled, the analyzer adds extra annotations to any diagrams it generates.
  • -fno-analyzer-feasibility โ€” Also for analyzer developers. By default the analyzer checks that there's a feasible control flow path for each diagnostic it emits, meaning the conditions that hold aren't mutually exclusive. Diagnostics where no feasible path can be found get rejected. This filtering can be suppressed with -fno-analyzer-feasibility, which is handy for debugging issues in this code ๐Ÿ™ˆ
  • -fanalyzer-fine-grained โ€” Developer-only again ๐Ÿ’œ Internally the analyzer builds an "exploded graph" that combines control flow graphs with data flow information. By default, an edge in this graph can contain the effects of a run of multiple statements within a basic block. With -fanalyzer-fine-grained, each statement gets its own edge.
  • -fanalyzer-show-duplicate-count โ€” For analyzer developers: if multiple diagnostics have been detected as duplicates of each other, it emits a note when reporting the best diagnostic. That note gives the number of additional diagnostics the deduplication logic suppressed โœจ
  • -fanalyzer-show-events-in-system-headers โ€” By default the analyzer emits simplified diagnostic paths by hiding events fully located within a system header. With -fanalyzer-show-events-in-system-headers, those events are no longer 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, that merging gets suppressed, which is useful 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. For example, that's the values of locals that aren't accessed later in the function and aren't relevant to leak analysis. With -fno-analyzer-state-purge, that purging gets suppressed, for debugging state-handling issues.
  • -fno-analyzer-suppress-followups โ€” Developer-only ๐Ÿงช By default the analyzer stops exploring an execution path after hitting certain diagnostics, so it doesn't spam a cascade of follow-up diagnostics. The diagnostics that end analysis along a path are:
    • -Wanalyzer-null-argument
    • -Wanalyzer-null-dereference
    • -Wanalyzer-use-after-free
    • -Wanalyzer-use-of-pointer-in-stale-stack-frame
    • -Wanalyzer-use-of-uninitialized-value

With -fno-analyzer-suppress-followups, the analyzer keeps exploring those paths even after such diagnostics. That can help with debugging the analyzer, or with microbenchmarks for detecting undefined behavior.

  • -fanalyzer-transitivity โ€” Turns on transitivity of constraints within the analyzer ๐Ÿ”—
  • -fno-analyzer-undo-inlining โ€” Developer-only ๐Ÿงฉ -fanalyzer runs relatively late compared to other code analysis tools, and some optimizations may have already been applied. In particular, function inlining may have happened, which can leave the interprocedural execution paths with function frames that don't match the original source code. By default the analyzer tries to reconstruct the original function frames and emits events showing the inlined calls. With -fno-analyzer-undo-inlining, that attempt to reconstruct the original frame information gets disabled, which can help when debugging analyzer issues.
  • -fanalyzer-verbose-edges โ€” For analyzer developers. It enables more verbose, lower-level detail in the descriptions of control flow within diagnostic paths ๐ŸŒ€
  • -fanalyzer-verbose-state-changes โ€” Also for analyzer developers. It enables more verbose, lower-level detail in the descriptions of state machine events within diagnostic paths ๐ŸŒ™
  • -fanalyzer-verbosity=level โ€” This controls how complex the control flow paths emitted for analyzer diagnostics are. The level can be one of:
    • 0 โ€” At this level, interprocedural call and return events are 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 previous level, but it also shows events for the entry to each function.
    • 2 โ€” Same as the previous level, but it also shows control flow events that are significant to triggering the issue (e.g. "true path taken" at a conditional). This level is the default. ๐Ÿ’–
    • 3 โ€” Same as the previous level, but shows all control flow events, not just significant ones.
    • 4 โ€” For analyzer developers. It adds various other events intended for debugging the analyzer ๐Ÿงฏ
  • -fdump-analyzer โ€” Dumps internal details about what the analyzer is doing to file.analyzer.txt. -fdump-analyzer-stderr overrides this option.
  • -fdump-analyzer-stderr โ€” Dumps internal details about what the analyzer is doing to stderr. This option overrides -fdump-analyzer.
  • -fdump-analyzer-callgraph โ€” Dumps a representation of the call graph that's suitable for viewing with GraphViz to file.callgraph.dot ๐Ÿ—บ๏ธ
  • -fdump-analyzer-exploded-graph โ€” Dumps a representation of the "exploded graph" 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 โ€” okay so this one dumps a textual version of the "exploded graph" with one dump file per node, named file.eg-id.txt ๐Ÿ“‚. Heads up bestie, that's usually a huge pile of files ๐Ÿ˜ญ๐Ÿ’€.
  • -fdump-analyzer-exploded-paths โ€” dumps a textual "exploded path" for every diagnostic, into file.idx.kind.epath.txt โœจ.
  • -fdump-analyzer-feasibility โ€” this spills the tea on the analyzer's search for feasible paths ๐Ÿ”. It's written so you can view it with GraphViz, into file.*.fg.dot, file.*.tg.dot, and file.*.fpath.txt ๐Ÿฆ‹.
  • -fdump-analyzer-infinite-loop โ€” internal details about the analyzer's hunt for infinite loops ๐ŸŒ€. Also GraphViz-friendly, saved as file.*.infinite-loop.dot ๐Ÿ’œ.
  • -fdump-analyzer-json โ€” a compressed JSON version of analyzer internals, saved to file.analyzer.json.gz ๐ŸŽ€. The precise format is subject to change, so don't build your whole life on it ๐Ÿ’….
  • -fdump-analyzer-state-purge โ€” same vibe as -fdump-analyzer-supergraph, a GraphViz-ready supergraph ๐Ÿงš, but this one is annotated with what state gets purged at each node ๐Ÿซถ. It's written to file.state-purge.dot.
  • -fdump-analyzer-supergraph โ€” gives you GraphViz dumps of the "supergraph" in file.supergraph.dot and file.supergraph-eg.dot ๐ŸŒˆ. These show every control flow graph in the program, with interprocedural edges for calls and returns ๐Ÿ‘‘. The second dump also has annotations showing nodes in the "exploded graph" and the diagnostics attached to them โœจ.
  • -fdump-analyzer-untracked โ€” emits custom warnings packed with internal details, made for analyzer developers only ๐Ÿ™ˆ.

โœจ Options for Debugging Your Program โœจ

Okay so if you want GCC to hand your debugger all the info, bestie, you really only need to add -g to your other options ๐Ÿ’–. Some debug formats can hang out together (like DWARF with CTF) as long as you turn each one on explicitly with its own command line option ๐ŸŒธ.

You're allowed to use -g with -O, and it's honestly kinda iconic ๐Ÿ’…. Optimized code gets a little sneaky though ๐Ÿ‘ป: some variables you declared may not exist at all, flow of control might briefly jump somewhere you didn't expect ๐Ÿ˜ญ, some statements won't run because they compute constant results or their values are already at hand ๐Ÿ’€, and some statements may run in different places since they got moved out of loops ๐ŸŒ€. Still, you can debug optimized output, which makes the optimizer totally reasonable for programs that might have bugs ๐Ÿ”ฅ.

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

  • -g โ€” this makes debugging info in the operating system's native format (stabs, COFF, XCOFF, or DWARF), and GDB can work with it ๐Ÿ’œ.
    • On most systems that use stabs, -g turns on extra info that only GDB can use ๐Ÿ™ˆ. That makes debugging way better in GDB, but other debuggers might crash or refuse to read the program ๐Ÿ˜ญ. If you want to be 100% certain whether the extra info gets generated, use -gvms (see below).
  • -ggdb โ€” debugging info made for GDB ๐ŸŒˆ. It uses the most expressive format available (DWARF, stabs, or the native format if neither of those are supported), and it includes GDB extensions if at all possible โœจ.
  • -gdwarf, -gdwarf-version โ€” debugging info in DWARF format, if that's supported ๐Ÿฆ‹. The version can be 2, 3, 4 or 5. The default is 5 for most targets, except VxWorks, TPF and Darwin / macOS (which default to version 2) and AIX (which defaults to version 4) ๐Ÿ“.
    • With DWARF Version 2, some ports require and always use some non-conflicting DWARF 3 extensions in the unwind tables ๐Ÿงš.
    • Version 4 may require GDB 7.0 and -fvar-tracking-assignments to get the maximum benefit ๐Ÿ’…. Version 5 requires GDB 8.0 or higher ๐Ÿ”ฅ.
    • GCC no longer supports DWARF Version 1, which is substantially different from Version 2 and later ๐Ÿ’€. For historical reasons, some other DWARF-related options such as -fno-dwarf2-cfi-asm) still have a reference to DWARF Version 2 in their names, but they apply to all currently-supported versions of DWARF ๐Ÿซถ.
  • -gbtf โ€” requests BTF debug info ๐ŸŽ€. BTF is the default debugging format for the eBPF target ๐Ÿ‘‘. On other targets, like x86, BTF debug info can be generated along with DWARF debug info when both formats are enabled explicitly through their respective command line options ๐Ÿ’–.
  • -gctf, -gctflevel โ€” requests CTF debug info, and the level decides how much CTF info you get ๐ŸŒธ. If you use -gctf without a value for level, the default level is 2 โœจ.
    • CTF debug info can be generated along with DWARF debug info when both formats are enabled explicitly through their respective command line options ๐Ÿฆ‹.
    • Level 0 produces no CTF debug info at all, so -gctf0 negates -gctf ๐Ÿ’€.
    • Level 1 produces CTF info for tracebacks only. That includes callsite info, but not type info ๐Ÿงš.
    • Level 2 produces type info for entities (functions, data objects etc.) at file-scope or global-scope only ๐ŸŒˆ.
  • -gvms โ€” produces debugging info in the Alpha/VMS debug format (if that's supported) ๐Ÿ“. It's the format used by DEBUG on Alpha/VMS systems ๐Ÿ’œ.
  • -gcodeview โ€” produces debugging info in the CodeView debug format (if that's supported) ๐ŸชŸ. It's the format Microsoft Visual C++ uses on Windows ๐Ÿ‘‘.
  • -glevel, -ggdblevel, -gvmslevel โ€” requests debugging info and uses level to decide how much info you get ๐Ÿซถ. The default level is 2 ๐Ÿ’….
    • Level 0 produces no debug info at all, so -g0 negates -g ๐Ÿ’€.
    • Level 1 produces minimal info, enough for making backtraces in parts of the program you don't plan to debug ๐Ÿ”. That includes descriptions of functions and external variables, plus line number tables, but no info about local variables ๐Ÿ™ˆ.
    • Level 3 includes extra info, such as all the macro definitions present in the program ๐ŸŽ€. Some debuggers support macro expansion when you use -g3 โœจ.
    • If you use multiple -g options, with or without level numbers, the last one is the one that takes effect โญ.
    • -gdwarf does not accept a concatenated debug level, to avoid confusion with -gdwarf-level. Instead, use an additional -glevel option to change the debug level for DWARF ๐Ÿฆ‹.
  • -fno-eliminate-unused-debug-symbols โ€” by default, no debug info is produced for symbols that aren't actually used ๐Ÿงน. Use this if you want debug info for all symbols ๐ŸŒธ.
  • -femit-class-debug-always โ€” instead of emitting debugging info for a C++ class in only one object file, this emits it in all object files that use the class ๐Ÿ’œ. Only use this with debuggers that can't handle the way GCC normally emits class debug info, because it increases the size of debugging info by as much as a factor of two ๐Ÿ˜ญ.
  • -fno-merge-debug-strings โ€” tells the linker not to merge together strings in the debugging info that are identical across different object files ๐Ÿงต. Merging isn't supported by all assemblers or linkers ๐Ÿ’€. It decreases the size of the debug info in the output file, at the cost of longer link processing time ๐Ÿข. Merging is enabled by default โœจ.
  • -fdebug-prefix-map=old=new โ€” when compiling files in directory old, debugging info describes them as if they lived in directory new instead ๐Ÿ—บ๏ธ. This is handy for swapping a build-time path for an install-time path in the debug info ๐Ÿซถ. You can also turn an absolute path into a relative one by using . for new ๐Ÿฆ‹. This can give you more reproducible builds, which are location independent, but you might need an extra command to tell GDB where to find the source files ๐Ÿ”. See also -ffile-prefix-map and -fcanon-prefix-map ๐Ÿ’–.
  • -fvar-tracking โ€” runs the variable tracking pass, which computes where variables are stored at each position in the code ๐Ÿง . Better debug info gets generated afterwards (if the debugging info format supports it) ๐Ÿ‘‘.
    • It's enabled by default when compiling with optimization (-Os, -O, -O2, ...), debugging info (-g), and a debug info format that supports it ๐ŸŒˆ.
  • -fvar-tracking-assignments โ€” annotates assignments to user variables early in compilation and tries to carry those annotations all the way to the end, to improve debug info while optimizing ๐Ÿช„. Using -gdwarf-4 is recommended alongside it ๐Ÿ’….
    • It can be enabled even if var-tracking is disabled. In that case the annotations are created and maintained, but discarded at the end ๐Ÿงน.
    • By default, this flag is enabled together with -fvar-tracking, except when selective scheduling is enabled ๐Ÿ™ˆ.
  • -gsplit-dwarf โ€” if DWARF debug info is enabled, this separates as much of it as possible into a separate output file with the .dwo extension ๐Ÿ“ฆ. This lets the build system avoid linking files with debug info ๐Ÿงต. To be useful, it requires a debugger that can read .dwo files ๐Ÿ”.
  • -gdwarf32, -gdwarf64 โ€” if DWARF debug info is enabled, -gdwarf32 selects the 32-bit DWARF format and -gdwarf64 selects the 64-bit one ๐ŸŒธ. The default is target specific, but on most targets it's -gdwarf32 ๐Ÿ’œ.
    • The 32-bit format is smaller, but it can't support more than 2GiB of debug info in any of the DWARF debug info sections ๐Ÿ˜ญ.
    • The 64-bit format allows larger debug info, but it might not be well supported by all consumers yet ๐Ÿข.
  • -gdescribe-dies โ€” adds description attributes to some DWARF DIEs that have no name attribute ๐Ÿงš. Examples are artificial variables, external references and call site parameter DIEs โœจ.
  • -gpubnames โ€” generates the DWARF ".debug_pubnames" and ".debug_pubtypes" sections ๐ŸŽ€.
  • -ggnu-pubnames โ€” okay bestie, this one makes the .debug_pubnames and .debug_pubtypes sections in a format that can get turned into a GDB index ๐Ÿงš. Heads up though, it's only useful if your linker can produce GDB index version 7 ๐Ÿ’…
  • -fdebug-types-section โ€” when you're on DWARF Version 4 or higher, type DIEs can get their own .debug_types section instead of living in .debug_info ๐Ÿฆ‹ It's more efficient to stick them in a separate comdat section, since the linker can then remove duplicates โœจ But not every DWARF consumer supports .debug_types yet, and on some objects it makes the debugging 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 debugging info ๐ŸŽ€ They're joined with spaces, separating them from each other and from the compiler version. It's on by default! Also see -frecord-gcc-switches if you want another way to store compiler options in the object file ๐ŸŒธ
  • -gstrict-dwarf โ€” no extensions from a later DWARF standard version than the one you picked with -gdwarf-version ๐Ÿ™…โ€โ™€๏ธ On most targets, using non-conflicting extensions from later standard versions is totally allowed.
  • -gno-strict-dwarf โ€” the opposite energy: you are allowed to use extensions from a later DWARF standard version than the one picked with -gdwarf-version ๐ŸŒˆ
  • -gas-loc-support โ€” tells the compiler that your assembler supports .loc directives, so it can use them to generate DWARF2+ line number tables ๐Ÿงš This is usually the move, because assembler-generated line-number tables are way more compact than the ones the compiler makes itself ๐Ÿ’– It's enabled by default if the assembler was found to support these directives when GCC was configured โœจ
  • -gno-as-loc-support โ€” forces GCC to generate DWARF2+ line number tables internally, if they're going to be generated at all ๐Ÿ™ˆ
  • -gas-locview-support โ€” tells the compiler your assembler supports "view" assignment and reset assertion checking in .loc directives ๐Ÿฆ‹ It's enabled by default if the assembler was found to support them at configure time ๐Ÿ’…
  • -gno-as-locview-support โ€” forces GCC to assign view numbers internally, if you've explicitly asked for -gvariable-location-views ๐Ÿซถ
  • -gcolumn-info, -gno-column-info โ€” puts location column information into your DWARF debugging info, not just file and line ๐Ÿ“ It's on by default, bestie ๐Ÿ“
  • -gstatement-frontiers, -gno-statement-frontiers โ€” GCC drops markers in its internal representation at the start of statements and keeps them roughly in place through the whole compile ๐Ÿงš It uses them to guide where the is_stmt markers show up in the line number table. This is enabled by default when you compile with optimization (-Os, -O1, -O2, ...) and output DWARF 2 debug info at the normal level ๐Ÿ‘‘
  • -gvariable-location-views, -gvariable-location-views=incompat5, -gno-variable-location-views โ€” augments variable location lists with progressive view numbers implied by the line number table ๐Ÿ”ฅ This lets debug info consumers inspect state at certain points in the program, even when no instructions tied to those source locations exist there ๐Ÿ‘€ If the assembler can't handle view numbers in line number tables, the compiler has to emit the line number table itself, which makes things a little less compact ๐Ÿ˜ญ The augmented tables and location lists are fully backward-compatible, so older consumers can read them, but they also won't get any benefit from them ๐Ÿซ 

This is enabled by default at the normal level of DWARF 2 debug output, as long as the assembler supports it, -fvar-tracking-assignments is enabled, and -gstrict-dwarf isn't. If the assembler doesn't support it, the option can still be on, but it forces GCC to output internal line number tables. And if -ginternal-reset-location-views isn't enabled too, that will most certainly lead to silently mismatching location views ๐Ÿšจ

There's also a proposed representation for view numbers that isn't backward compatible with the location list format introduced in DWARF 5. You can turn it on with -gvariable-location-views=incompat5 ๐Ÿงช This option may be removed in the future, and it's only a reference implementation of the proposed representation. Debug info consumers aren't expected to support this extended format, so they'd be unable to decode location lists that use it ๐Ÿ’€

  • -ginternal-reset-location-views, -gno-internal-reset-location-views โ€” this one tries to figure out which location views can be dropped from the location view lists โœ‚๏ธ It needs the compiler to have very accurate insn length estimates, which isn't always the case. It may silently generate incorrect view lists when you're using an assembler that doesn't support location view lists. The GNU assembler will flag any such error as a "view number mismatch" ๐Ÿ™ƒ It's only enabled on ports that define a reliable estimation function ๐Ÿ”’
  • -ginline-points, -gno-inline-points โ€” generates extended debug info for inlined functions ๐Ÿงš Location view tracking markers get inserted at inlined entry points, so address and view numbers can be computed and output in the debug info. This can be turned on independently of location views, in which case the view numbers won't be output. It can only be enabled along with statement frontiers, and it's only enabled by default if location views are enabled ๐Ÿ’œ
  • -gz[=type] โ€” 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) or zlib (use zlib compression in ELF gABI format). If the linker can't write compressed debug sections, the option gets rejected. Otherwise, if the assembler doesn't support them, -gz is silently ignored when producing object files ๐Ÿซง
  • -femit-struct-debug-baseonly โ€” only emits debug info for struct-like types when the base name of the compilation source file matches the base name of the file where the struct is defined ๐ŸŽฏ This drastically shrinks your debug info, but there can be a big loss in the type info the debugger gets ๐Ÿ˜ฌ For a less aggressive option, check out -femit-struct-debug-reduced, and for more detailed control, see -femit-struct-debug-detailed. This option only works with DWARF debug output ๐ŸŒธ
  • -femit-struct-debug-reduced โ€” only emits debug info for struct-like types when the base name of the compilation source file matches the base name of the file where the type is defined. The exception is if the struct is a template or is defined in a system header ๐Ÿงธ This significantly shrinks your debug info, with some potential loss in type info. For a more aggressive option, see -femit-struct-debug-baseonly, and for more detailed control, see -femit-struct-debug-detailed. Only works with DWARF debug output ๐Ÿ’–
  • -femit-struct-debug-detailed[=spec-list] โ€” lets you pick which struct-like types the compiler generates debug info for โœจ The goal is to cut down on duplicate struct debug info across 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 uses this 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 is used directly when it's the type of a variable or a member. Indirect uses come through pointers to structs. In other words, when using an incomplete struct is valid, the use is indirect. For example: struct one direct; struct two * indirect;

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

The third word says which source files the structs should get debug info for. none and any have their normal meanings. base means the base of the name of the file where the type declaration appears has to match the base of the name of the main compilation file. In practice, that means when you compile foo.c, debug info gets generated for types declared in that file and in foo.h, but not in other header files ๐Ÿ“„ sys means those types that satisfy base, or that are declared in system or compiler headers, count too.

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 the GAS .cfi_* directives ๐Ÿงš
  • -fno-eliminate-unused-debug-types โ€” okay so, normally when producing DWARF output, GCC skips debug symbol output for types that are nowhere used in the source file being compiled ๐Ÿ™…โ€โ™€๏ธ Sometimes you actually want debug info for every type declared in the compilation unit, even unused ones. For example, if you want to cast a value to a type in the debugger that's declared but never used in your program ๐Ÿ”ฎ More often, though, this just wastes a ton of space ๐Ÿ’€

โœจ Options That Control Optimization โœจ

These options control various sorts of optimizations ๐Ÿ”ฅ They're the glow-up knobs, bestie ๐Ÿ’…

๐ŸŒธ The Vibe Without Any -O Flag ๐ŸŒธ

Okay so, bestie, if you don't pass any optimization flag at all, the compiler's whole thing is keeping compilation cheap and making debugging act the way you expect ๐ŸŽ€. Statements are basically their own little islands ๐Ÿ๏ธ. Stop at a breakpoint between statements and you can change a variable's value or move the program counter to any other statement in the function, and you'll get exactly what the source code promised โœจ.

Turning on optimization flags is a total glow-up ๐Ÿ’…. The compiler tries to boost performance and/or shrink the code size, but the tradeoff is longer compile times and maybe a harder time debugging ๐Ÿ˜ญ.

The compiler optimizes based on what it knows about your program ๐Ÿง . If you compile multiple files at once into a single output file, it can use info from all of those files when it works on each one ๐Ÿซถ.

Not every optimization has its own flag ๐Ÿ™ˆ. This section only covers the ones that do.

Most optimizations are completely switched off at -O0, or whenever no -O level is set on the command line, even if you add individual optimization flags yourself ๐Ÿ’€. And -Og skips plenty of optimization passes too ๐Ÿฆ‹.

Depending on the target and how GCC was configured, the set of optimizations enabled at each -O level might be a little different from what's listed here ๐ŸŒˆ. If you want the exact lineup for your setup, invoke GCC with -Q --help=optimizers and it'll spill every enabled optimization at each level ๐Ÿ‘‘.


๐Ÿ“ -O and -O1 ๐Ÿ“

  • -O, -O1 โ€” Optimize! This one takes a bit more time to compile, and a lot more memory for a big function ๐Ÿง .

With -O, the compiler tries to shrink the code and speed up execution ๐Ÿƒโ€โ™€๏ธ, but it skips any optimization that would take forever to compile โœจ.

-O turns on the following optimization flags:

-fauto-inc-dec -fbranch-count-reg -fcombine-stack-adjustments
-fcompare-elim -fcprop-registers -fdce -fdefer-pop -fdelayed-branch
-fdse -fforward-propagate -fguess-branch-probability -fif-conversion
-fif-conversion2 -finline-functions-called-once -fipa-modref
-fipa-profile -fipa-pure-const -fipa-reference
-fipa-reference-addressable -fmerge-constants -fmove-loop-invariants
-fmove-loop-stores -fomit-frame-pointer -freorder-blocks
-fshrink-wrap -fshrink-wrap-separate -fsplit-wide-types
-fssa-backprop -fssa-phiopt -ftree-bit-ccp -ftree-ccp -ftree-ch
-ftree-coalesce-vars -ftree-copy-prop -ftree-dce
-ftree-dominator-opts -ftree-dse -ftree-forwprop -ftree-fre
-ftree-phiprop -ftree-pta -ftree-scev-cprop -ftree-sink -ftree-slsr
-ftree-sra -ftree-ter -funit-at-a-time

๐Ÿ’– -O2 ๐Ÿ’–

  • -O2 โ€” Optimize even more! GCC does nearly every supported optimization that doesn't involve a space-speed tradeoff ๐Ÿ”ฅ. Compared to -O, it makes compilation slower but gives you faster generated code ๐Ÿš€.

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

-falign-functions  -falign-jumps -falign-labels  -falign-loops
-fcaller-saves -fcode-hoisting -fcrossjumping -fcse-follow-jumps
-fcse-skip-blocks -fdelete-null-pointer-checks -fdevirtualize
-fdevirtualize-speculatively -fexpensive-optimizations
-ffinite-loops -fgcse  -fgcse-lm -fhoist-adjacent-loads
-finline-functions -finline-small-functions -findirect-inlining
-fipa-bit-cp  -fipa-cp  -fipa-icf -fipa-ra  -fipa-sra  -fipa-vrp
-fisolate-erroneous-paths-dereference -flra-remat
-foptimize-sibling-calls -foptimize-strlen -fpartial-inlining
-fpeephole2 -freorder-blocks-algorithm=stc
-freorder-blocks-and-partition  -freorder-functions
-frerun-cse-after-loop -fschedule-insns  -fschedule-insns2
-fsched-interblock  -fsched-spec -fstore-merging -fstrict-aliasing
-fthread-jumps -ftree-builtin-call-dce -ftree-loop-vectorize
-ftree-pre -ftree-slp-vectorize -ftree-switch-conversion
-ftree-tail-merge -ftree-vrp -fvect-cost-model=very-cheap
Heads up, bestie ๐Ÿซฃ: please read the warning under -fgcse about turning on -O2 for programs that use computed gotos. It's important!
NOTE ๐Ÿ’…: On Ubuntu 8.10 and later, -D_FORTIFY_SOURCE=2 is set by default. On Ubuntu 24.04 and later, -D_FORTIFY_SOURCE=3 is set by default instead. Either one kicks in when -O is set to 2 or higher and adds extra compile-time and run-time checks for several libc functions ๐Ÿ›ก๏ธ. Want it gone? Specify either -U_FORTIFY_SOURCE or -D_FORTIFY_SOURCE=0 ๐Ÿ™…โ€โ™€๏ธ.
NOTE ๐ŸŒˆ: On Debian 13 and Ubuntu 24.04 and later, -D_TIME_BITS=64 together with -D_FILE_OFFSET_BITS=64 is set by default on the 32bit architectures armel, armhf, hppa, m68k, mips, mipsel, powerpc and sh4 ๐Ÿงš.

๐Ÿ”ฅ -O3 ๐Ÿ”ฅ

  • -O3 โ€” Optimize yet more! -O3 turns on everything -O2 does, plus the following optimization flags ๐Ÿ‘‘:
-fgcse-after-reload -fipa-cp-clone -floop-interchange
-floop-unroll-and-jam -fpeel-loops -fpredictive-commoning
-fsplit-loops -fsplit-paths -ftree-loop-distribution
-ftree-partial-pre -funswitch-loops -fvect-cost-model=dynamic
-fversion-loops-for-strides

๐ŸŽ€ -O0 ๐ŸŽ€

  • -O0 โ€” Reduce compilation time and make debugging produce the expected results โœจ. This is the default! ๐Ÿ’–

๐Ÿงš -Os ๐Ÿงš

  • -Os โ€” Optimize for size ๐Ÿฆ‹. -Os enables all -O2 optimizations except the ones that often make code bigger ๐Ÿ™ˆ:
-falign-functions  -falign-jumps -falign-labels  -falign-loops
-fprefetch-loop-arrays  -freorder-blocks-algorithm=stc

It also enables -finline-functions, tells the compiler to tune for code size instead of execution speed, and runs extra optimizations designed to shrink the code ๐ŸŒธ.


๐ŸŒˆ -Ofast ๐ŸŒˆ

  • -Ofast โ€” Disregard strict standards compliance ๐Ÿ˜ค. -Ofast enables all -O3 optimizations, plus optimizations that aren't valid for every standard-compliant program ๐Ÿ’€. It turns on -ffast-math, -fallow-store-data-races and the Fortran-specific -fstack-arrays (unless -fmax-stack-var-size is specified), and -fno-protect-parens. It turns off -fsemantic-interposition ๐Ÿ™ƒ.

๐Ÿฆ‹ -Og ๐Ÿฆ‹

  • -Og โ€” Optimize the debugging experience ๐Ÿ”. -Og should be your go-to level for the standard edit-compile-debug cycle ๐Ÿ’–. You get a reasonable amount of optimization while keeping compilation fast and debugging 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 number of optimization passes, so the individual options that control them do nothing. Otherwise, -Og enables all -O1 optimization flags except the ones that might get in the way of debugging ๐Ÿง:

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

๐Ÿซง -Oz ๐Ÿซง

  • -Oz โ€” Optimize aggressively for size rather than speed ๐Ÿฐ. This may increase the number of instructions executed if those instructions take fewer bytes to encode. -Oz behaves similarly to -Os, including turning on most -O2 optimizations โœจ.

If you use multiple -O options, with or without level numbers, the last one is the one that counts ๐Ÿ‘‘. Periodt ๐Ÿ’….


๐Ÿ’œ -f Flags ๐Ÿ’œ

Options of the form -fflag are machine-independent flags ๐Ÿซถ. Most flags have both a positive and a negative form, and the negative form of -ffoo is -fno-foo ๐Ÿ”„. The table below only lists the form you'll typically use, but you can figure out the other one by either removing no- or adding it ๐Ÿ™Œ.

The following options control specific optimizations. They're either turned on by -O options or related to ones that are. You only need these in the rare cases where you want to "fine-tune" which optimizations get performed ๐ŸŽ€.

  • -fno-defer-pop โ€” For machines that have to pop arguments after a function call, this always pops the arguments as soon as each function returns ๐Ÿงน. At -O1 and higher, -fdefer-pop is the default, which lets the compiler let arguments pile up on the stack across several function calls and pop them all at once ๐Ÿ“š.
  • -fforward-propagate โ€” Performs a forward propagation pass on RTL ๐Ÿ”. The pass tries to combine two instructions and checks whether the result can be simplified โœจ. If loop unrolling is active, two passes run, and the second one is scheduled after loop unrolling ๐ŸŒ€.

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

  • -ffp-contract=style โ€” -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 contraction if the language standard allows it ๐Ÿ™†โ€โ™€๏ธ. This is implemented for C and C++, where it allows contraction within one expression, but not across different statements ๐Ÿง .

The default is -ffp-contract=off for C in a standards-compliant mode (-std=c11 or similar), and -ffp-contract=fast otherwise ๐ŸŒˆ.

  • -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 ๐Ÿ™ƒ.

Heads up: -fno-omit-frame-pointer doesn't guarantee the frame pointer gets used in every function. Several targets always omit it in leaf functions ๐Ÿ‘€.

Enabled by default at -O1 and higher ๐Ÿ’–.

  • -foptimize-sibling-calls โ€” Optimizes sibling and tail recursive calls ๐Ÿ”. Enabled at levels -O2, -O3, -Os โœจ.
  • -foptimize-strlen โ€” 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 ๐Ÿ’….
  • -finline-stringops[=fn] โ€” Expands memory and string operations inline (for now, only "memset"), even when the length is variable or big enough to need looping ๐Ÿงต. This is most useful along with -ffreestanding and -fno-builtin ๐ŸŽ€.

In some circumstances it lets the compiler generate code that takes advantage of known alignment and length multipliers. But even then, it may be less efficient than optimized runtime implementations, and it can grow the code so much that a less performant but shared implementation runs faster thanks to better use of code caches ๐Ÿ˜ญ. This option is disabled by default ๐Ÿ™ˆ.

  • -fno-inline โ€” โœจ Okay bestie, this one says don't inline anything unless it's marked with the always_inline attribute ๐Ÿ™…โ€โ™€๏ธ. It's the default when you're not optimizing ๐Ÿ’…. If you want one specific function to sit out, tag it with the noinline attribute ๐Ÿซถ.
  • -finline-small-functions โ€” ๐Ÿฆ‹ The compiler copies a function into its callers when the body is smaller than the code it'd take to call it, so the whole program actually gets smaller ๐Ÿ’–. The compiler makes this call heuristically ๐Ÿง , and it applies to every function, even the ones that aren't declared inline. Enabled at levels -O2, -O3, -Os ๐Ÿ”ฅ.
  • -findirect-inlining โ€” ๐Ÿ‘‘ This one inlines indirect calls that become known at compile time because of earlier inlining. It only does anything when inlining is already switched on by -finline-functions or -finline-small-functions ๐Ÿ™ˆ. Enabled at levels -O2, -O3, -Os โœจ.
  • -finline-functions โ€” ๐ŸŒˆ Every function is up for inlining, even the ones not declared inline ๐Ÿ’…. The compiler heuristically picks which ones are worth it. If every call to a given function gets inlined and that function is static, it normally won't be emitted as its own assembler code ๐Ÿงš. Enabled at levels -O2, -O3, -Os, and also turned on by -fprofile-use and -fauto-profile ๐Ÿ’œ.
  • -finline-functions-called-once โ€” ๐Ÿ“ Any static function that's called exactly once gets inlined into its caller, even if it isn't marked inline ๐Ÿซถ. Once that call is inlined, the function isn't output as assembler code on its own ๐Ÿ’€. Enabled at levels -O1, -O2, -O3, and -Os, but not -Og ๐Ÿ™…โ€โ™€๏ธ.
  • -fearly-inlining โ€” โญ Functions marked always_inline, plus functions whose body looks smaller than the call overhead, get inlined early, before -fprofile-generate instrumentation and the real inlining pass ๐ŸŒธ. That makes profiling way cheaper and usually makes inlining faster for programs with big chains of nested wrapper functions ๐Ÿ˜ญ. Enabled by default ๐Ÿ’–.
  • -fipa-sra โ€” ๐Ÿ”ฅ Interprocedural scalar replacement of aggregates ๐Ÿง, removal of unused parameters ๐Ÿ—‘๏ธ, and swapping parameters passed by reference for parameters passed by value ๐Ÿ”. Enabled at levels -O2, -O3, -Os โœจ.
  • -finline-limit=n โ€” ๐ŸŽ€ This gives you a coarse dial for how big a function can be and still get inlined. n is the size measured in pseudo instructions ๐Ÿ“. Inlining is really controlled by a bunch of parameters you can set one at a time with --param name=value. The -finline-limit=n option sets a couple of them for you:
    • max-inline-insns-single is set to n/2.
    • max-inline-insns-auto is set to n/2.

Check out the individual inlining parameters below for their docs and defaults ๐Ÿ“š.

Heads up: there may be no value of -finline-limit that gives you the default behavior ๐Ÿ™ˆ.
Also, a "pseudo instruction" is just an abstract measure of how big a function is ๐Ÿงšโ€โ™€๏ธ. It has nothing to do with counting assembly instructions, so what it means can change from one release to another ๐Ÿ’€.
  • -fno-keep-inline-dllexport โ€” ๐Ÿฆ‹ This is the more fine-grained cousin of -fkeep-inline-functions. It only touches functions declared with the dllexport attribute or declspec ๐Ÿ’….
  • -fkeep-inline-functions โ€” ๐Ÿ’œ In C, static functions declared inline still get emitted into the object file, even if they were inlined into every single caller ๐Ÿ“ฆ. This doesn't change 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 nothing ever uses them ๐Ÿงน.
  • -fkeep-static-consts โ€” โœจ Emits variables declared static const when optimization is off, even if nothing references them ๐ŸŽ€. GCC turns this on by default ๐Ÿ’–. If you want the compiler to check whether a variable is referenced no matter what optimization level you're on, use -fno-keep-static-consts ๐Ÿ”.
  • -fmerge-constants โ€” ๐ŸŒธ Tries to merge identical constants (string constants and floating-point constants) across compilation units ๐Ÿงฉ. This is the default for optimized builds if the assembler and linker support it ๐Ÿ‘‘. To stop it, use -fno-merge-constants ๐Ÿ™…โ€โ™€๏ธ. Enabled at levels -O1, -O2, -O3, -Os โœจ.
  • -fmerge-all-constants โ€” ๐Ÿ˜ญ Tries to merge identical constants and identical variables ๐Ÿงจ. It implies -fmerge-constants, and on top of that it looks at things like constant initialized arrays and initialized constant variables with integral or floating-point types ๐Ÿงฑ.
Danger zone ๐Ÿ’€: C and C++ require each variable to have its own distinct location, including multiple instances of the same variable in recursive calls. Using this option results in non-conforming behavior, so it's not a vibe ๐Ÿ™ˆ.
  • -fmodulo-sched โ€” ๐Ÿ” Runs swing modulo scheduling right before the first scheduling pass ๐ŸŽข. It looks at the innermost loops and reorders their instructions by overlapping different iterations ๐Ÿ’ซ.
  • -fmodulo-sched-allow-regmoves โ€” ๐Ÿš€ This goes harder with SMS-based modulo scheduling and lets register moves happen ๐Ÿ’…. Turning it on deletes certain anti-dependence edges, which triggers reg-move generation based on life-range analysis ๐Ÿง . It only works if -fmodulo-sched is also on ๐Ÿซถ.
  • -fno-branch-count-reg โ€” ๐Ÿ™…โ€โ™€๏ธ Turns off the pass that hunts for chances to use "decrement and branch" instructions on a count register ๐Ÿ”ข. Those replace the usual sequence of decrementing a register, comparing it to zero, then branching on the result ๐ŸŒ€. This only matters on architectures that have those instructions, like x86, PowerPC, IA-64, and S/390 ๐Ÿ–ฅ๏ธ. Heads up: -fno-branch-count-reg doesn't remove decrement and branch instructions that other optimization passes already put into the stream ๐Ÿ’โ€โ™€๏ธ. The default is -fbranch-count-reg at -O1 and higher, except for -Og โœจ.
  • -fno-function-cse โ€” ๐ŸงŠ Don't stash function addresses in registers. Instead, every instruction that calls a constant function spells out the function's address explicitly ๐Ÿ“. This makes the code less efficient ๐Ÿ˜ฉ, but some strange hacks that mess with 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 zero-initialized variables in there, which can save space ๐Ÿ“ฆ. This option turns that off ๐Ÿšซ. Why? Some programs explicitly count on variables landing in the data section ๐Ÿซฃ, like when the executable needs to find the start of that section or makes assumptions based on it ๐Ÿ—บ๏ธ. The default is -fzero-initialized-in-bss ๐Ÿ’–.
  • -fthread-jumps โ€” ๐Ÿงต Checks whether a jump lands on a spot where another comparison that the first one already covers shows up ๐Ÿ‘€. If it does, the first branch gets redirected to the second branch's destination or to the spot right after it ๐Ÿƒโ€โ™€๏ธ. Which one depends on whether the condition is known to be true or false ๐ŸŽฏ. Enabled at levels -O1, -O2, -O3, -Os โœจ.
  • -fsplit-wide-types โ€” ๐Ÿงฉ When a type takes up multiple registers, like long long on a 32-bit system, this splits those registers apart and allocates them independently ๐Ÿฐ. That usually makes better code for those types ๐Ÿš€, but debugging can get harder ๐Ÿ˜ตโ€๐Ÿ’ซ. Enabled at levels -O1, -O2, -O3, -Os ๐Ÿ’….
  • -fsplit-wide-types-early โ€” โฐ Fully splits wide types early instead of waiting until very late ๐ŸŒ…. It does nothing unless -fsplit-wide-types is on ๐Ÿ™…โ€โ™€๏ธ. This one is the default on some targets ๐Ÿ‘‘.
  • -fcse-follow-jumps โ€” ๐Ÿฆ‹ During common subexpression elimination (CSE), this scans through jump instructions when nothing else reaches the jump's target ๐Ÿ”. Like, when CSE hits an if with an else clause, it follows the jump when the tested condition is false ๐Ÿช„. Enabled at levels -O2, -O3, -Os โœจ.
  • -fcse-skip-blocks โ€” ๐ŸŒท Kind of like -fcse-follow-jumps, but this one follows jumps that conditionally skip over blocks ๐Ÿ™ƒ. When CSE sees a simple if with no else clause, it follows the jump around the body of the if ๐ŸŽ€. Enabled at levels -O2, -O3, -Os ๐Ÿ”ฅ.
  • -frerun-cse-after-loop โ€” ๐Ÿ”„ Re-runs common subexpression elimination after loop optimizations are done ๐ŸŽข. Enabled at levels -O2, -O3, -Os ๐Ÿ’–.
  • -fgcse โ€” ๐ŸŒ Performs a global common subexpression elimination pass ๐Ÿง . This pass also does global constant and copy propagation ๐Ÿ“‹.
Note ๐Ÿ’…: If your program uses computed gotos (a GCC extension), you might get better run-time performance by disabling the global CSE pass with -fno-gcse on the command line ๐ŸŽ๏ธ.

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

  • -fgcse-lm โ€” ๐ŸŒ™ When this is on, global CSE tries to move loads that only get killed by stores into themselves ๐Ÿงฒ. That lets a loop with a load/store sequence turn into a load outside the loop and a copy/store inside it ๐Ÿซถ. Enabled by default whenever -fgcse is on ๐Ÿ’œ.
  • -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, loops with 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 ๐Ÿงผ. That covers both partial and full redundancies ๐Ÿ’ฏ. Not enabled at any optimization level ๐Ÿ’€.
  • -fgcse-after-reload โ€” okay so when this is turned on, a redundant load elimination pass runs after reload ๐Ÿ’…. Its whole job is cleaning up redundant spilling โœจ
    • Enabled by -O3, -fprofile-use and -fauto-profile ๐ŸŽ€
  • -faggressive-loop-optimizations โ€” the loop optimizer gets bold and uses language constraints to figure out bounds for how many times a loop runs ๐Ÿ”ฅ Those bounds steer loop unrolling, peeling and loop exit test optimizations
    • It assumes your loop code never triggers undefined behavior, like signed integer overflows or out-of-bound array accesses ๐Ÿ™ˆ
    • This option is enabled by default ๐Ÿ’œ
  • -funconstrained-commons โ€” tells the compiler that variables in common blocks (e.g. Fortran) might get overridden later with longer trailing arrays ๐Ÿฆ‹ Because of that, certain optimizations that rely on knowing the array bounds get switched off
  • -fcrossjumping โ€” performs the cross-jumping transformation, which unifies equivalent code and saves code size ๐ŸŒธ Heads up, bestie: the result may or may not run better 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 -O1 and higher on architectures that support this ๐Ÿ‘‘
  • -fdce โ€” performs dead code elimination (DCE) on RTL ๐Ÿงน
    • Enabled by default at -O1 and higher
  • -fdse โ€” performs dead store elimination (DSE) on RTL ๐Ÿ’–
    • Enabled by default at -O1 and higher
  • -fif-conversion โ€” attempts to turn conditional jumps into branch-less equivalents ๐Ÿฆ‹ That includes conditional moves, min, max, set flags and abs instructions, plus some tricks you can pull off with standard arithmetic ๐Ÿงš Whether conditional execution gets used on chips that have it is controlled by -fif-conversion2
    • Enabled at levels -O1, -O2, -O3, -Os, but not with -Og ๐Ÿ™…โ€โ™€๏ธ
  • -fif-conversion2 โ€” uses conditional execution (where available) to turn conditional jumps into branch-less equivalents ๐Ÿซถ
    • Enabled at levels -O1, -O2, -O3, -Os, but not with -Og
  • -fdeclone-ctor-dtor โ€” 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, meaning two copies of the function. With this option, those base and complete variants become thunks that call a common implementation ๐ŸŽ€
    • Enabled by -Os
  • -fdelete-null-pointer-checks โ€” assumes programs can't safely dereference null pointers, and that no code or data element lives at address zero ๐Ÿ’… This option turns on simple constant folding optimizations at all optimization levels. On top of that, other optimization passes in GCC use this flag to control global dataflow analyses that axe useless null pointer checks ๐Ÿ”ช Those analyses assume a memory access to address zero always results in a trap, so if a pointer gets checked after it's already been dereferenced, it can't be null
    • > ๐Ÿ’€ Note however that in some environments this assumption is not true. Use -fno-delete-null-pointer-checks to disable this optimization for programs that depend on that behavior.
    • This option is enabled by default on most targets. On Nios II ELF, it defaults to off. On AVR and MSP430, this option is completely disabled ๐Ÿ™ˆ
    • Passes that use the dataflow information are enabled independently at different optimization levels ๐ŸŒˆ
  • -fdevirtualize โ€” attempts to convert calls to virtual functions into direct calls ๐Ÿฆ‹ This happens both within a procedure and interprocedurally, as part of indirect inlining (-findirect-inlining) and interprocedural constant propagation (-fipa-cp)
    • Enabled at levels -O2, -O3, -Os
  • -fdevirtualize-speculatively โ€” attempts to convert calls to virtual functions into speculative direct calls ๐Ÿง  Based on analysis of the type inheritance graph, GCC figures out the set of likely targets for a given call. If the set is small, preferably of size 1, the call gets changed into a conditional that decides between a direct and an indirect call ๐Ÿ“ Speculative calls unlock more optimizations, like inlining. If they seem useless after further optimization, they get converted back into their original form
  • -fdevirtualize-at-ltrans โ€” streams extra information needed for aggressive devirtualization when the link-time optimizer runs in local transformation mode ๐ŸŒธ This gives you more devirtualization, but it significantly increases the size of the streamed data ๐Ÿ˜ค For that reason it's disabled by default
  • -fexpensive-optimizations โ€” performs a bunch of minor optimizations that are relatively expensive ๐Ÿ’ธ
    • Enabled at levels -O2, -O3, -Os
  • -free โ€” attempts to remove redundant extension instructions ๐Ÿงผ This is especially helpful for the x86-64 architecture, which implicitly zero-extends in 64-bit registers after writing to their lower 32-bit half ๐Ÿ’œ
    • Enabled for Alpha, AArch64, LoongArch, PowerPC, RISC-V, SPARC, h83000 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. If your code relies on the value of the object storage sticking around beyond the object's lifetime, use this flag to turn that optimization off ๐Ÿ™…โ€โ™€๏ธ
    • To keep stores made before the constructor starts (e.g. because your operator new clears the object storage) but still treat the object as dead after the destructor, 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-size register sets ๐ŸŽ๏ธ
  • -fira-algorithm=algorithm โ€” picks the coloring algorithm for the integrated register allocator ๐ŸŽจ The algorithm argument can be priority, which means Chow's priority coloring, or CB, which means Chaitin-Briggs coloring
    • Chaitin-Briggs coloring isn't implemented for every architecture, but for targets that do support it, it's the default because it generates better code ๐Ÿ‘‘
  • -fira-region=region โ€” picks the regions used by the integrated register allocator ๐Ÿ—บ๏ธ The region argument should be one of the following:
    • all โ€” uses all loops as register allocation regions ๐Ÿ’… This can give the best results for machines with a small and/or irregular register set
    • mixed โ€” uses all loops except loops with small register pressure as the regions โœจ This usually gives the best results in most cases and for most architectures, and it's enabled by default when compiling with optimization for speed (-O, -O2, ...) ๐Ÿ”ฅ
    • one โ€” uses all functions as a single region ๐Ÿฐ This typically results in the smallest code size, and it's enabled by default for -Os or -O0
  • -fira-hoist-pressure โ€” uses IRA to evaluate register pressure in the code hoisting pass when deciding whether to hoist expressions ๐Ÿงบ This usually results in smaller code, but it can slow the compiler down ๐Ÿข
    • This option is enabled at level -Os for all targets
  • -fira-loop-pressure โ€” uses IRA to evaluate register pressure in loops when deciding whether to move loop invariants ๐Ÿš€ This usually results in faster and smaller code on machines with large register files (>= 32 registers), but it can slow the compiler down ๐ŸŒ
    • This option is enabled at level -O3 for some targets
  • -fno-ira-share-save-slots โ€” disables 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 โ€” disables sharing of stack slots allocated for pseudo-registers ๐Ÿ™…โ€โ™€๏ธ Each pseudo-register that doesn't get a hard register gets its own stack slot, so function stack frames end up larger ๐Ÿ“ฆ
  • -flra-remat โ€” enables CFG-sensitive rematerialization in LRA ๐ŸŒ€ Instead of loading the values of spilled pseudos, LRA tries to rematerialize (recalculate) values when that's profitable
    • Enabled at levels -O2, -O3, -Os
  • -fdelayed-branch โ€” if the target machine supports it, GCC tries to reorder instructions to take advantage of instruction slots available after delayed branch instructions ๐Ÿงฉ
    • Enabled at levels -O1, -O2, -O3, -Os, but not at -Og
  • -fschedule-insns โ€” if the target machine supports it, GCC tries to reorder instructions to eliminate execution stalls caused by required data being unavailable ๐Ÿฅฑ This helps machines with slow floating point or memory load instructions, by letting other instructions issue until the result of the load or floating-point instruction is actually needed ๐Ÿ’ซ
    • Enabled at levels -O2, -O3
  • -fschedule-insns2 โ€” similar to -fschedule-insns, but it requests an additional pass 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 โ€” disables instruction scheduling across basic blocks ๐Ÿšซ This is normally enabled when scheduling happens before register allocation, i.e. with -fschedule-insns or at -O2 or higher ๐Ÿซ 
  • -fno-sched-spec โ€” disables speculative motion of non-load instructions ๐Ÿ™…โ€โ™€๏ธ This is normally enabled when scheduling happens before register allocation, i.e. with -fschedule-insns or at -O2 or higher โœจ
  • -fsched-pressure โ€” okay bestie, this one turns on register-pressure-aware scheduling ๐Ÿ’… before register allocation even starts ๐ŸŒธ. It only slaps when scheduling before register allocation is on, so think -fschedule-insns or -O2 or higher. The payoff is that your code can get better and smaller ๐Ÿฆ‹ because it stops register pressure from climbing past the number of available hard registers, which means fewer annoying spills during register allocation ๐Ÿฅน.
  • -fsched-spec-load โ€” lowkey a spicy one โœจ. It lets some load instructions get speculatively moved around. Same rule as before: this only makes sense when scheduling happens before register allocation, so -fschedule-insns or -O2 or higher ๐Ÿซถ.
  • -fsched-spec-load-dangerous โ€” the more chaotic sibling ๐Ÿ’€. This one allows speculative motion of more load instructions. Same vibe check applies, though: it only makes sense when scheduling before register allocation, aka -fschedule-insns or -O2 or higher ๐Ÿ”ฅ.
  • -fsched-stalled-insns, -fsched-stalled-insns=n โ€” this one controls how many stalled instructions can be yeeted early from the stalled queue into the ready list during the second scheduling pass ๐ŸŽ€. -fno-sched-stalled-insns means no instructions get moved early at all ๐Ÿ™…โ€โ™€๏ธ. -fsched-stalled-insns=0 means there's no limit on how many queued instructions can jump the line โœจ. And if you just write -fsched-stalled-insns with no value, it's the same as -fsched-stalled-insns=1 ๐Ÿ’–.
  • -fsched-stalled-insns-dep, -fsched-stalled-insns-dep=n โ€” this one decides how many instruction groups (cycles) get checked for a dependency on a stalled instruction that's a candidate for early removal from the queue ๐Ÿงš. It only matters during the second scheduling pass, and only if -fsched-stalled-insns is being used ๐ŸŒˆ. -fno-sched-stalled-insns-dep is the same as -fsched-stalled-insns-dep=0 ๐Ÿ™ˆ. Writing -fsched-stalled-insns-dep with no value is the same as -fsched-stalled-insns-dep=1 ๐Ÿ“.
  • -fsched2-use-superblocks โ€” when scheduling after register allocation, this one uses superblock scheduling ๐Ÿฆ‹. The glow-up is that instructions can move across basic block boundaries, which gives you faster schedules โœจ. BUT it's experimental ๐Ÿ’€, because not every machine description GCC uses models the CPU closely enough to avoid unreliable results. This only makes sense when scheduling after register allocation, so -fschedule-insns2 or -O2 or higher.
โš ๏ธ bestie, read that experimental part twice. Some machine descriptions don't model the CPU closely enough, so results can be unreliable. Proceed with caution ๐Ÿ˜ญ.
  • -fsched-group-heuristic โ€” turns on the group heuristic in the scheduler ๐ŸŒธ. It favors the instruction that belongs to a schedule group. This one is on by default whenever scheduling is enabled, so -fschedule-insns, -fschedule-insns2, or -O2 or higher ๐Ÿ‘‘.
  • -fsched-critical-path-heuristic โ€” enables the critical-path heuristic, which favors instructions sitting on the critical path ๐Ÿ›ฃ๏ธ. Also on by default whenever scheduling is enabled, aka -fschedule-insns, -fschedule-insns2, or -O2 or higher ๐Ÿ’œ.
  • -fsched-spec-insn-heuristic โ€” enables the speculative instruction heuristic, which favors speculative instructions with greater dependency weakness ๐Ÿง . Enabled by default when scheduling is enabled, i.e. with -fschedule-insns or -fschedule-insns2 or at -O2 or higher ๐ŸŽ€.
  • -fsched-rank-heuristic โ€” enables the rank heuristic, which favors instructions belonging to a basic block with greater size or frequency ๐Ÿ“Š. On by default whenever scheduling is enabled, i.e. with -fschedule-insns or -fschedule-insns2 or at -O2 or higher ๐ŸŒˆ.
  • -fsched-last-insn-heuristic โ€” enables the last-instruction heuristic ๐Ÿซง. It favors the instruction that's less dependent on the last instruction scheduled. It's on by default when scheduling is enabled, i.e. with -fschedule-insns or -fschedule-insns2 or at -O2 or higher ๐Ÿ“.
  • -fsched-dep-count-heuristic โ€” enables the dependent-count heuristic, which favors the instruction that has more instructions depending on it ๐Ÿงšโ€โ™€๏ธ. Enabled by default when scheduling is enabled, i.e. with -fschedule-insns or -fschedule-insns2 or at -O2 or higher ๐Ÿ’–.
  • -freschedule-modulo-scheduled-loops โ€” here's the tea โ˜•: modulo scheduling happens before traditional scheduling ๐Ÿซ–. If a loop gets modulo scheduled, later scheduling passes might change its schedule ๐Ÿ™ˆ. Use this option to control that behavior ๐Ÿ’….
  • -fselective-scheduling โ€” schedules instructions using the selective scheduling algorithm ๐Ÿฆ‹. It runs instead of the first scheduler pass โœจ.
  • -fselective-scheduling2 โ€” same energy, but this one schedules instructions with the selective scheduling algorithm and runs instead of the second scheduler pass ๐ŸŒŸ.
  • -fsel-sched-pipelining โ€” turns on software pipelining of innermost loops during selective scheduling ๐Ÿ”. Heads up, though: it does absolutely nothing unless -fselective-scheduling or -fselective-scheduling2 is on ๐Ÿ™ƒ.
  • -fsel-sched-pipelining-outer-loops โ€” when pipelining loops during selective scheduling, this one also pipelines the outer loops ๐Ÿช†. It has no effect unless -fsel-sched-pipelining is turned on ๐Ÿฅฒ.
  • -fsemantic-interposition โ€” okay, this one is a lot, so get comfy ๐Ÿงธ. Some object formats, like ELF, let the dynamic linker interpose symbols. So for symbols exported from the DSO, the compiler can't do interprocedural propagation, inlining, or other optimizations, because the function or variable might get swapped out later ๐Ÿ˜ฉ. That's actually useful, like if you want to swap in a debugging version of a memory allocation function ๐Ÿ› ๏ธ, but it's expensive when it comes to code quality ๐Ÿ’ธ.

With -fno-semantic-interposition, the compiler assumes that if interposition happens for functions, the overwriting function will have precisely the same semantics (and side effects) ๐Ÿซถ. Same deal 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 โœจ, and it also does nothing for symbols explicitly declared weak ๐Ÿ™…โ€โ™€๏ธ.

  • -fshrink-wrap โ€” emits function prologues only before the parts of the function that actually need them, instead of at the very top ๐ŸŽ€. It's enabled by default at -O and higher ๐Ÿ”ฅ.
  • -fshrink-wrap-separate โ€” shrink-wraps the prologue and epilogue parts separately, so those parts only run when they're needed ๐ŸŒ™. It's on by default, but it does nothing unless -fshrink-wrap is also on and the target supports this ๐Ÿซ .
  • -fcaller-saves โ€” this one lets values live in registers that get clobbered by function calls ๐Ÿงบ. To make that work, it emits extra instructions to save and restore those registers around the calls ๐Ÿ’…. The allocation only happens when it seems to result in better code โœจ. It's always on by default on certain machines, usually the ones that don't have call-preserved registers to use instead ๐Ÿฆ‹. Enabled at levels -O2, -O3, -Os ๐Ÿ‘‘.
  • -fcombine-stack-adjustments โ€” tracks stack adjustments (pushes and pops) and stack memory references, then tries to find ways to combine them ๐Ÿงฉ. Enabled by default at -O1 and higher ๐ŸŒˆ.
  • -fipa-ra โ€” uses caller-save registers for allocation if those registers aren't used by any called function ๐Ÿง . The payoff is that they don't have to be saved and restored around calls ๐Ÿ™Œ. This is only possible if the called functions are part of the same compilation unit as the current function and they're compiled before it ๐Ÿ“ฆ. It's enabled at -O2, -O3, -Os, however 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 โ€” tries to minimize stack usage, even if that makes the program slower ๐Ÿข. This one implies setting the large-stack-frame parameter to 100 and the large-stack-frame-growth parameter to 400 ๐Ÿงฎ.
  • -ftree-reassoc โ€” performs reassociation on trees ๐ŸŒณ. Enabled by default at -O1 and higher ๐Ÿ’–.
  • -fcode-hoisting โ€” performs code hoisting ๐Ÿช. It tries to move the evaluation of expressions that get executed 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 -O1 and higher ๐Ÿฆ‹.
  • -ftree-fre โ€” performs full redundancy elimination (FRE) on trees ๐Ÿงฝ. Here's the difference between FRE and PRE ๐Ÿค“: FRE only considers expressions computed on all paths leading to the redundant computation. That makes it faster than PRE, though it exposes fewer redundancies ๐Ÿ‡. Enabled by default at -O1 and higher ๐ŸŒธ.
  • -ftree-phiprop โ€” performs hoisting of loads from conditional pointers on trees ๐Ÿช„. This pass is enabled by default at -O1 and higher โœจ.
  • -fhoist-adjacent-loads โ€” speculatively hoists loads from both branches of an if-then-else, but only if the loads are 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 ๐Ÿ“‹. This pass gets rid of unnecessary copy operations, which is so iconic ๐Ÿ‘‘. Enabled by default at -O1 and higher ๐Ÿซถ.
  • -fipa-pure-const โ€” discovers which functions are pure or constant ๐Ÿ”. Enabled by default at -O1 and higher ๐ŸŒˆ.
  • -fipa-reference โ€” discovers which static variables do not escape the compilation unit ๐Ÿšช. Enabled by default at -O1 and higher ๐Ÿฆ‹.
  • -fipa-reference-addressable โ€” discovers read-only, write-only, and non-addressable static variables ๐Ÿ•ต๏ธโ€โ™€๏ธ. Enabled by default at -O1 and higher ๐Ÿ’œ.
  • -fipa-stack-alignment โ€” reduces stack alignment on call sites if possible ๐Ÿ“. Enabled by default ๐ŸŒŸ.
  • -fipa-pta โ€” performs interprocedural pointer analysis, plus interprocedural modification and reference analysis ๐Ÿ”ฌ. Fair warning, though ๐Ÿšจ: this can cause excessive memory and compile-time usage on large compilation units. It is not enabled by default at any optimization level ๐Ÿ™ˆ.
๐Ÿšจ bestie, -fipa-pta can absolutely eat your memory and your compile time on big compilation units. It's off by default at every optimization level, so you have to ask for it on purpose ๐Ÿ˜ญ๐Ÿ’€.
  • -fipa-profile โ€” okay so this one does interprocedural profile propagation ๐Ÿ”ฎโœจ Functions that are only called 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 loop-less parts of run-once functions get optimized for size ๐Ÿ“. It's enabled by default at -O1 and higher ๐Ÿ’….
  • -fipa-modref โ€” this is giving interprocedural mod/ref analysis ๐Ÿ•ต๏ธโ€โ™€๏ธ It looks at the side effects of functions (the memory locations they modify or reference) so the compiler can optimize better across the function call boundary ๐Ÿฆ‹. Enabled by default at -O1 and higher ๐ŸŒธ.
  • -fipa-cp โ€” interprocedural constant propagation ๐Ÿ’– The compiler checks when the values passed into functions are constants and optimizes around that ๐Ÿง . This can seriously boost performance if your app is passing constants into functions ๐Ÿ”ฅ. Enabled by default at -O2, -Os and -O3, and also turned on by -fprofile-use and -fauto-profile ๐Ÿ’œ.
  • -fipa-cp-clone โ€” function cloning to make interprocedural constant propagation even stronger ๐Ÿ‘ฏโ€โ™€๏ธ When it's on, the compiler clones externally visible functions that can be called with constant arguments ๐Ÿงฌ. Because it can make multiple copies of functions, it may significantly increase code size (see --param ipa-cp-unit-growth=value) ๐Ÿ“ฆ. Enabled by default at -O3, and also by -fprofile-use and -fauto-profile ๐ŸŒˆ.
  • -fipa-bit-cp โ€” when enabled, you get 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, the compiler does interprocedural propagation of value ranges ๐Ÿ“ Enabled by default at -O2 ๐Ÿ’…. It requires that -fipa-cp is enabled ๐Ÿซถ.
  • -fipa-icf โ€” Identical Code Folding for functions and read-only variables ๐Ÿงน It reduces code size, but it can disturb unwind stacks because it swaps a function out for an equivalent one with a different name ๐Ÿ˜ฌ. It works better with link-time optimization turned on ๐Ÿ”—.

Okay so this is similar to the Gold Linker's ICF optimization, but GCC's ICF works on different levels, so the optimizations aren't the same. There are equivalences only GCC finds and equivalences only Gold finds ๐Ÿค“.

Enabled by default at -O2 and -Os ๐Ÿ’–.

  • -flive-patching=level โ€” tells GCC to control its optimizations so the output is suitable for live-patching ๐Ÿฉนโœจ

If an optimization uses a function's body (or info pulled from that body) to change another function, that other function is called an impacted function of the first one. If a function gets patched, its impacted functions should get patched too ๐Ÿšจ. Which functions count as impacted is decided by the interprocedural optimizations. For example, a caller is impacted when a function gets inlined into it, when a function gets cloned and its caller is changed to call the clone, or when a function's pureness/constness info is used to optimize its direct or indirect callers, and so on ๐Ÿงฉ.

Usually, the more IPA optimizations you have on, the more impacted functions each function has. To keep that number under control and make the list easier to compute, IPA optimizations can be partially enabled at two different levels ๐ŸŽš๏ธ.

The level argument should be one of the following:

  • inline-clone โ€” only inlining and cloning optimizations are enabled, which covers inlining, cloning, interprocedural scalar replacement of aggregates and partial inlining ๐ŸŒท. So when you patch a function, all its callers and its clones' callers are impacted and need patching too ๐Ÿ“Œ.
โš ๏ธ -flive-patching=inline-clone disables these optimization flags: -fwhole-program -fipa-pta -fipa-reference -fipa-ra -fipa-icf -fipa-icf-functions -fipa-icf-variables -fipa-bit-cp -fipa-vrp -fipa-pure-const -fipa-reference-addressable -fipa-stack-alignment -fipa-modref
  • inline-only-static โ€” only inlining of static functions is enabled ๐Ÿงš. So when you patch a static function, all its callers are impacted and need patching 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 ๐Ÿฅ€.

๐Ÿšซ -flive-patching is not supported with link-time optimization (-flto). Do not mix these two, bestie ๐Ÿ’€.
  • -fisolate-erroneous-paths-dereference โ€” this one detects paths that trigger erroneous or undefined behavior by 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 โ€” similar vibe, but this one detects paths where a null value gets used in a way forbidden by a "returns_nonnull" or "nonnull" attribute ๐Ÿ™…. It isolates those paths 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 -O1 and higher ๐Ÿ’–.
  • -ftree-bit-ccp โ€” sparse conditional bit constant propagation on trees, plus it propagates pointer alignment information ๐Ÿ“. This pass only operates on local scalar variables ๐Ÿ”. It's enabled by default at -O1 and higher, except for -Og ๐Ÿ™ƒ. It requires that -ftree-ccp is enabled ๐Ÿซถ.
  • -ftree-ccp โ€” sparse conditional constant propagation (CCP) on trees ๐ŸŒŸ. It only operates on local scalar variables and is enabled by default at -O1 and higher ๐Ÿ’….
  • -fssa-backprop โ€” propagates info about how a value gets used back up the definition chain so the definitions can be simplified ๐Ÿช„. For example, this pass strips sign operations if the sign of a value never matters ๐Ÿงฝ. Enabled by default at -O1 and higher ๐ŸŒธ.
  • -fssa-phiopt โ€” pattern matching on SSA PHI nodes to optimize conditional code ๐Ÿงฉ. It's enabled by default at -O1 and higher, except for -Og ๐Ÿ™ˆ.
  • -ftree-switch-conversion โ€” turns simple initializations in a switch into initializations from a scalar array ๐ŸŽฒ. Enabled by default at -O2 and higher ๐Ÿ’œ.
  • -ftree-tail-merge โ€” looks for identical code sequences, and when it finds them it replaces one with a jump to the other ๐Ÿฆ˜. This is known as tail merging or cross jumping ๐Ÿซถ. Enabled by default at -O2 and higher ๐ŸŒˆ. The compilation time in this pass can be limited with the max-tail-merge-comparisons parameter and the max-tail-merge-iterations parameter โฑ๏ธ.
  • -ftree-dce โ€” dead code elimination (DCE) on trees ๐Ÿ—‘๏ธ Enabled by default at -O1 and higher โœจ.
  • -ftree-builtin-call-dce โ€” conditional dead code elimination (DCE) for calls to built-in functions that may set "errno" but are otherwise free of side effects ๐Ÿงน. Enabled by default at -O2 and higher, if -Os is not also specified ๐Ÿซ .
  • -ffinite-loops โ€” the compiler assumes that a loop with an exit will eventually take the exit and won't loop forever ๐Ÿ”โœ…. This lets it remove loops that otherwise have no side effects, without treating eventual endless looping as a side effect ๐Ÿ—‘๏ธ.

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

  • -ftree-dominator-opts โ€” a bunch of simple scalar cleanups (constant/copy propagation, redundancy elimination, range propagation and expression simplification) based on a dominator tree traversal ๐ŸŒณ. It also does jump threading (to reduce jumps to jumps) ๐Ÿฆ‹. Enabled by default at -O1 and higher ๐ŸŒธ.
  • -ftree-dse โ€” 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, so the earlier store can be deleted ๐Ÿ—‘๏ธ. Enabled by default at -O1 and higher ๐Ÿ’–.
  • -ftree-ch โ€” loop header copying on trees ๐Ÿ”„. This is great because it increases the effectiveness of code motion optimizations, and it also saves one jump ๐Ÿซถ. Enabled by default at -O1 and higher. It's not enabled for -Os, since it usually increases code size ๐Ÿ“ˆ.
  • -ftree-loop-optimize โ€” loop optimizations on trees ๐Ÿ” Enabled by default at -O1 and higher ๐Ÿ’….
  • -ftree-loop-linear, -floop-strip-mine, -floop-block โ€” loop nest optimizations ๐Ÿช†. These are the same as -floop-nest-optimize. To use this code transformation, GCC has to be configured with --with-isl to enable the Graphite loop transformation infrastructure ๐Ÿ› ๏ธ.
  • -fgraphite-identity โ€” enables the identity transformation for Graphite ๐Ÿชž. For every SCoP, it generates the polyhedral representation and transforms it back to GIMPLE ๐Ÿ”„. You can use -fgraphite-identity to check the costs or benefits of the GIMPLE -> GRAPHITE -> GIMPLE transformation ๐Ÿง. Some minimal optimizations are also performed by the isl code generator, 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 ๐Ÿงช.
  • -floop-parallelize-all โ€” uses the Graphite data dependence analysis to find loops that can be parallelized ๐Ÿงต. It parallelizes all the loops that can be analyzed to not contain loop carried dependences, without checking whether parallelizing them is profitable ๐Ÿซฃ. Yikes, bestie, that's a bold move ๐Ÿ’….
  • -ftree-coalesce-vars โ€” okay so when GCC is turning the program out of SSA form, it tries to cut down on copying by merging versions of different user-defined variables, not just compiler temporaries ๐Ÿงš. Heads up though, this can seriously limit your ability to debug an optimized program compiled with -fno-var-tracking-assignments ๐Ÿ˜ญ. In the negated form, this flag stops SSA coalescing of user variables. It's enabled by default if optimization is on, and it does very little otherwise ๐Ÿ’….
  • -ftree-loop-if-convert โ€” this one tries to turn conditional jumps in the innermost loops into branch-less equivalents ๐Ÿฆ‹. The whole point is to strip control flow out of those loops so the vectorization pass can handle them better โœจ. It's enabled by default if vectorization is enabled.
  • -ftree-loop-distribution โ€” loop distribution, bestie ๐ŸŒธ. It can improve cache performance on big loop bodies and open the door for more loop optimizations, like parallelization or vectorization, to take place ๐Ÿ”ฅ. This flag is enabled by default at -O3, and also by -fprofile-use and -fauto-profile. Here's the glow-up:
DO I = 1, N
  A(I) = B(I) + C
  D(I) = E(I) * F
ENDDO

becomes

DO I = 1, N
   A(I) = B(I) + C
ENDDO
DO I = 1, N
   D(I) = E(I) * F
ENDDO
  • -ftree-loop-distribute-patterns โ€” this one distributes loops 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 splits up the initialization loops and generates a call to memset zero ๐Ÿงธ. Check out the vibe:
DO I = 1, N
  A(I) = 0
  B(I) = A(I) + I
ENDDO

becomes

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

The initialization loop gets transformed into a call to memset zero. This flag is enabled by default at -O3. It is also enabled by -fprofile-use and -fauto-profile โœจ.

  • -floop-interchange โ€” loop interchange outside of graphite, and it's giving performance ๐Ÿ”ฅ. It can improve cache performance on loop nests and let further loop optimizations, like vectorization, take place ๐ŸŒˆ. Look at this swap:
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 is also enabled by -fprofile-use and -fauto-profile ๐Ÿ‘‘.

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

  • -ftrivial-auto-var-init=choice โ€” okay this one is a whole security glow-up ๐Ÿ›ก๏ธ๐Ÿ’…. It initializes automatic variables with either a pattern or zeroes, so your program is more secure and predictable by preventing uninitialized memory from being disclosed and used ๐Ÿ˜ญ. GCC still considers an automatic variable without an explicit initializer to be uninitialized, and -Wuninitialized and -Wanalyzer-use-of-uninitialized-value will still report warnings on those variables. The compiler will also still optimize as if the variable were uninitialized ๐Ÿ™ˆ. With this option, GCC will also initialize any padding of automatic variables that have structure or union types to zeroes โœจ. However, the current implementation cannot initialize automatic variables declared between the controlling expression and the first case of a "switch" statement, so use -Wtrivial-auto-var-init to report all such cases ๐Ÿ’€.

The three values of choice are:

  • uninitialized doesn't initialize any automatic variables. This is C and C++'s default ๐Ÿฅฑ.
  • pattern initializes automatic variables with values that will likely turn logic bugs into crashes down the line ๐Ÿ’ฅ. They're easy to spot in a crash dump and aren't values programmers can rely on for useful program semantics ๐Ÿ”. The current value is a byte-repeatable pattern with byte 0xFE. The values used for pattern initialization might be changed in the future ๐ŸŒ€.
  • zero initializes automatic variables with zeroes ๐Ÿซง.

The default is uninitialized.

Note that the initializer values, whether zero or pattern, refer to data representation (in memory or machine registers), rather than to their interpretation as numerical values. This distinction may be important in languages that support types with biases or implicit multipliers, and with extensions such as hardbool. For example, a variable that uses 8 bits to represent (biased) quantities in the range 160..400 will be initialized with the bit patterns 0x00 or 0xFE, depending on choice. That's true whether or not these representations stand for values in that range. And even if they do, the interpretation of the value held by the variable will depend on the bias ๐Ÿงฎ. A hardbool variable that uses, say, 0X5A and 0xA5 for "false" and "true", respectively, will trap with either choice of trivial initializer. In other words, zero initialization will not convert to the representation for "false", even if it would for a static variable of the same type ๐Ÿšจ. This means the initializer pattern doesn't generally depend on the type of the initialized variable. One notable exception is that (non-hardened) boolean variables that fit in registers are initialized with "false" (zero), even when pattern is requested ๐Ÿซถ.

You can control this behavior for a specific variable by using the variable attribute uninitialized ๐Ÿ’œ.

  • -fvect-cost-model=model โ€” okay bestie, this one lets you tweak the cost model the vectorizer uses ๐Ÿฆ‹ The model argument has to be unlimited, dynamic, cheap or very-cheap. With unlimited, the vectorized code path is just assumed to be profitable, no questions asked ๐Ÿ’… With dynamic, a runtime check guards the vectorized path so it only switches on for iteration counts that will likely run faster than the original scalar loop โœจ

The cheap model is the cautious one ๐Ÿงธ It turns off vectorization for loops where it would be cost prohibitive, like when it needs runtime checks for data dependence or alignment, but otherwise it's exactly the same as dynamic. Then there's very-cheap, the most picky of the bunch ๐Ÿ™ˆ It only allows vectorization if the vector code would entirely replace the scalar code being vectorized. For example, if each iteration of a vectorized loop can only handle exactly four iterations of the scalar loop, very-cheap only says yes if the scalar iteration count is known to be a multiple of four.

The default cost model depends on your other optimization flags and is either dynamic or cheap ๐ŸŒธ

  • -fsimd-cost-model=model โ€” same vibe, but for loops marked with the OpenMP simd directive ๐Ÿ’œ The model argument should be unlimited, dynamic or cheap (no very-cheap here, sorry bestie ๐Ÿซถ). All of them mean the same thing as in -fvect-cost-model, and by default, the cost model you set with -fvect-cost-model is the one that gets used ๐ŸŽ€
  • -ftree-vrp โ€” this one does Value Range Propagation on trees ๐ŸŒˆ It's kinda like constant propagation, except instead of tracking single values, it tracks ranges of values. That lets the optimizers delete stuff like array bound checks and null pointer checks when they're unnecessary ๐Ÿ˜ญ It's on by default at -O2 and higher. Heads up, though: null pointer check elimination only happens if -fdelete-null-pointer-checks is turned on ๐Ÿ’…
  • -fsplit-paths โ€” splits paths that lead to loop backedges โœ‚๏ธ This can level up your dead code elimination and common subexpression elimination. It's enabled by default at -O3 and above ๐Ÿ‘‘
  • -fsplit-ivs-in-unroller โ€” when a loop gets unrolled, this lets the compiler express the values of induction variables in later iterations using the value from the first iteration ๐Ÿงš That breaks up long dependency chains, which helps the scheduling passes run more efficiently.

A combo of -fweb and CSE is often enough to get the same effect. Still, it's not reliable when the loop body is more complicated than a single basic block ๐Ÿ™ˆ And on some architectures, it doesn't work at all because of restrictions in the CSE pass.

This optimization is enabled by default โœจ

  • -fvariable-expansion-in-unroller โ€” with this one, the compiler makes multiple copies of some local variables when it unrolls a loop, which can give you superior code ๐Ÿ“

It's enabled by default for PowerPC targets, but disabled by default everywhere else ๐Ÿ’€

  • -fpartial-inlining โ€” inlines parts of functions ๐Ÿฆ‹ This only does anything if inlining itself is turned on with -finline-functions or -finline-small-functions.

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

  • -fpredictive-commoning โ€” performs predictive commoning, which means reusing computations (especially memory loads and stores) that were done in previous iterations of loops ๐Ÿ’–

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

  • -fprefetch-loop-arrays โ€” if the target machine supports it, this generates instructions to prefetch memory, which can improve loops that access large arrays ๐Ÿ”ฅ

Fair warning: this may generate better or worse code, because the results are highly dependent on how the loops are structured in your source code ๐Ÿ™ˆ

Disabled at level -Os ๐Ÿ’…

  • -fno-printf-return-value โ€” do not substitute constants for the known return value of formatted output functions like "sprintf", "snprintf", "vsprintf" and "vsnprintf" (but not "printf" or "fprintf") ๐Ÿง This substitution lets GCC optimize or even eliminate branches based on the known return value of these functions, as long as the arguments are either constant or have values known to be in a range that makes the exact return value possible.

For example, when -fprintf-return-value is in effect, both the branch and the body of the if statement (but not the call to snprint) can be optimized away when i is a 32-bit or smaller integer, because the return value is guaranteed to be at most 8 โœจ

char buf[9];
if (snprintf (buf, "%08x", i) >= sizeof buf)
  ...

The -fprintf-return-value option relies on other optimizations and gives the best results with -O2 and above ๐Ÿ‘‘ It works in tandem with the -Wformat-overflow and -Wformat-truncation options. The -fprintf-return-value option is enabled by default ๐Ÿ’–

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

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

  • -fno-guess-branch-probability โ€” do not guess branch probabilities using heuristics ๐Ÿ™ƒ

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

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

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

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

Enabled at levels -O1, -O2, -O3, -Os ๐Ÿ’…

  • -freorder-blocks-algorithm=algorithm โ€” picks the algorithm used for basic block reordering ๐Ÿ“ The algorithm argument can be simple, which doesn't increase code size (except sometimes because of secondary effects like alignment), or stc, the "software trace cache" algorithm. stc tries to put all the often executed code together, which minimizes the number of branches executed, but it does this by making extra copies of code ๐Ÿ”ฅ

The default is simple at levels -O1, -Os, and stc at levels -O2, -O3 โœจ

  • -freorder-blocks-and-partition โ€” on top of reordering basic blocks, this one partitions hot and cold basic blocks into separate sections of the assembly and .o files, to improve paging and cache locality performance ๐ŸงŠ

This optimization gets turned off automatically in a few situations: when there's exception handling or unwind tables (on targets using setjump/longjump or a target specific scheme), for linkonce sections, for functions with a user-defined section attribute, and on any architecture that doesn't support named sections ๐Ÿ˜ญ When -fsplit-stack is used, this option isn't enabled by default (to avoid linker errors), but you can still enable it explicitly if you're using a working linker ๐Ÿซถ

Enabled for x86 at levels -O2, -O3, -Os ๐Ÿ‘‘

  • -freorder-functions โ€” reorders functions in the object file to improve code locality ๐Ÿ’œ It's done using special subsections: ".text.hot" for the most frequently executed functions, and ".text.unlikely" for the unlikely executed ones. The linker does the reordering, so the object file format must support named sections and the linker has to place them in a reasonable way ๐Ÿงš

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

Enabled at levels -O2, -O3, -Os ๐ŸŒธ

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

Pay special attention to code like this ๐Ÿ‘€

union a_union {
  int i;
  double d;
};

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

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

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

Similarly, accessing something by taking its address, casting the resulting pointer and dereferencing the result has undefined behavior, even if the cast uses a union type ๐Ÿšจ For example:

int f() {
  double d = 3.0;
  return ((union a_union *) &d)->i;
}

The -fstrict-aliasing option is enabled at levels -O2, -O3, -Os ๐ŸŒˆ

  • -fipa-strict-aliasing โ€” controls whether the rules of -fstrict-aliasing are applied across function boundaries ๐Ÿง Keep in mind that if multiple functions get inlined into a single function, the memory accesses are no longer considered to be crossing a function boundary ๐Ÿ’–

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

  • -falign-functions, -falign-functions=n, -falign-functions=n:m, -falign-functions=n:m:n2, -falign-functions=n:m:n2:m2 โ€” okay bestie, this one lines up the start of your functions ๐Ÿ’… It nudges them to the next power-of-two boundary that's greater than or equal to n, skipping up to m-1 bytes ๐Ÿฆ‹ The goal is that at least the first m bytes of the function can be fetched by the CPU without crossing an n-byte alignment boundary ๐Ÿงš It's a code performance optimization โœจ and alignment gets ignored for functions considered cold ๐ŸงŠ If you need alignment on every function, reach for -fmin-function-alignment instead ๐Ÿ‘‘
    • If m isn't specified, it defaults to n ๐Ÿ“
    • Examples ๐ŸŒธ:
      • -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
      • -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 n2:m2 pair gives you a secondary alignment ๐ŸŽ€ -falign-functions=64:7:32:3 aligns to the next 64-byte boundary if that can be done by skipping 6 bytes or less, otherwise it aligns to the next 32-byte boundary if that can be done by skipping 2 bytes or less
    • If m2 isn't specified, it defaults to n2 ๐Ÿ’œ
    • Some assemblers only support this flag when n is a power of two. In that case, the value gets rounded up ๐Ÿ™ˆ
    • -fno-align-functions and -falign-functions=1 are equivalent and mean functions are not aligned ๐Ÿ’€
    • If n isn't specified or is zero, the compiler uses a machine-dependent default ๐Ÿค– The max allowed n value is 65536
    • Enabled at levels -O2, -O3 โœจ
  • -flimit-function-alignment โ€” if this one's on, the compiler tries not to overalign functions when it doesn't need to ๐Ÿ™…โ€โ™€๏ธ It asks the assembler to align by the amount set with -falign-functions, but it won't skip more bytes than the size of the function itself ๐ŸŒˆ
  • -falign-labels, -falign-labels=n, -falign-labels=n:m, -falign-labels=n:m:n2, -falign-labels=n:m:n2:m2 โ€” aligns all branch targets to a power-of-two boundary ๐ŸŽฏ The parameters work just like the ones for -falign-functions ๐Ÿ’– -fno-align-labels and -falign-labels=1 are equivalent and mean labels aren't aligned ๐Ÿซถ
    • If -falign-loops or -falign-jumps apply and are greater than this value, their values get used instead ๐Ÿ‘‘
    • If n isn't specified or is zero, a machine-dependent default is used. That default is very likely 1, which means no alignment ๐Ÿ’… The max allowed n value is 65536
    • Enabled at levels -O2, -O3 ๐Ÿ”ฅ
  • -falign-loops, -falign-loops=n, -falign-loops=n:m, -falign-loops=n:m:n2, -falign-loops=n:m:n2:m2 โ€” aligns loops to a power-of-two boundary ๐Ÿ” If the loops run many times, this makes up for the cost of the dummy padding instructions ๐Ÿ˜ญ It's a code performance optimization, and alignment is ignored for loops considered cold ๐ŸงŠ
    • If -falign-labels is greater than this value, its value is used instead ๐ŸŽ€
    • The parameters are analogous to the -falign-functions option ๐Ÿ’œ -fno-align-loops and -falign-loops=1 are equivalent and mean loops are not aligned ๐Ÿ’€ The max allowed n value is 65536
    • If n isn't specified or is zero, a machine-dependent default is used ๐Ÿค–
    • Enabled at levels -O2, -O3 โœจ
  • -falign-jumps, -falign-jumps=n, -falign-jumps=n:m, -falign-jumps=n:m:n2, -falign-jumps=n:m:n2:m2 โ€” aligns branch targets to a power-of-two boundary, but only for branch targets that can only be reached by jumping ๐Ÿฆ˜ In that case, no dummy operations need to be executed ๐Ÿ™Œ It's a code performance optimization, and alignment is ignored for jumps considered cold ๐ŸงŠ
    • If -falign-labels is greater than this value, its value is used instead ๐ŸŽ€
    • The parameters are analogous to the -falign-functions option ๐Ÿ’– -fno-align-jumps and -falign-jumps=1 are equivalent and mean that loops are not aligned ๐Ÿ™ˆ
    • If n isn't specified or is zero, a machine-dependent default is used. The max allowed n value is 65536
    • Enabled at levels -O2, -O3 ๐ŸŒธ
  • -fmin-function-alignment โ€” sets the minimal alignment of functions to the next power-of-two boundary greater than or equal to n ๐Ÿ“ Unlike -falign-functions, this applies to all functions, even the cold ones ๐Ÿฅถ It also isn't affected by -flimit-function-alignment ๐Ÿ™Œ
  • -fno-allocation-dce โ€” don't remove unused C++ allocations during dead code elimination ๐Ÿ—‘๏ธ
  • -fallow-store-data-races โ€” lets the compiler do optimizations that might introduce new data races on stores, without proving the variable can't be accessed by other threads at the same time ๐Ÿงต It doesn't affect optimization of local data ๐Ÿ  It's only safe to use if you know global data won't be accessed by multiple threads ๐Ÿ˜ฌ
    • Examples include hoisting, or if-conversions that might cause a value already in memory to be written back with that same value. That rewriting is safe in a single-threaded context but may be unsafe in a multi-threaded one ๐Ÿง 
    • Note that on some processors, if-conversions may be required to enable vectorization โšก
    • Enabled at level -Ofast ๐Ÿ”ฅ
  • -funit-at-a-time โ€” only here for compatibility reasons ๐Ÿ•ฐ๏ธ It has no effect. -fno-unit-at-a-time, on the other hand, implies -fno-toplevel-reorder and -fno-section-anchors ๐Ÿ‘€ Enabled by default ๐Ÿ’…
  • -fno-toplevel-reorder โ€” don't reorder top-level functions, variables, and "asm" statements. Output them in the same order they appear in the input file ๐Ÿ“œ When this is used, unreferenced static variables are not removed ๐Ÿ™…โ€โ™€๏ธ It's meant to support existing code that relies on a particular ordering. For new code, attributes are the better move when possible ๐Ÿ’ก
    • -ftoplevel-reorder is the default at -O1 and higher, and also at -O0 if -fsection-anchors is explicitly requested โœจ
    • -fno-toplevel-reorder also implies -fno-section-anchors ๐Ÿซถ
  • -funreachable-traps โ€” turns calls to "__builtin_unreachable" into traps, instead of using them for optimization ๐Ÿšจ This also affects any such calls the compiler generates implicitly ๐Ÿ™ˆ It has the same effect as -fsanitize=unreachable -fsanitize-trap=unreachable, but it doesn't change the values of those options. If -fsanitize=unreachable is enabled, that option takes priority over this one ๐Ÿ‘‘ Enabled by default at -O0 and -Og ๐ŸŒˆ
  • -fweb โ€” constructs webs, the way they're commonly used for register allocation, and gives each web its own pseudo register ๐Ÿ•ธ๏ธ That lets the register allocation pass work on pseudos directly, and it also strengthens several other passes like CSE, the loop optimizer, and the trivial dead code remover ๐Ÿ’ช The catch: it can make debugging impossible, since variables no longer stay in a "home register" ๐Ÿ˜ญ Enabled by default with -funroll-loops ๐ŸŽ€
  • -fwhole-program โ€” 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 means the interprocedural optimizers can go harder on them โšก
    • With -flto, this option has limited use ๐Ÿฅฑ In most cases, the precise list of symbols used or exported from the binary is already known from the resolution info the linker plugin passes to the link-time optimizer ๐Ÿงฉ
    • It's still useful if no linker plugin is used, or during the incremental link step when the final code is produced (with -flto -flinker-output=nolto-rel) ๐Ÿฆ‹
  • -flto[=n] โ€” runs the standard link-time optimizer ๐Ÿง  When it's invoked with source code, it generates GIMPLE (one of GCC's internal representations) and writes it into special ELF sections in the object file โœจ When the object files get linked together, all the function bodies are read back from those ELF sections and instantiated as if they had been part of the same translation unit ๐Ÿฆ‹

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

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

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

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

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

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

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

Okay so bestie, whole program optimization is a total main character move, but it needs some big assumptions ๐Ÿ’…. The compiler has to know which functions and variables outside the link-time optimized unit can reach them, like libraries and runtime stuff. When your linker supports it, the linker plugin (see -fuse-linker-plugin) hands the compiler a list of used and externally visible symbols, which is so helpful ๐Ÿซถ. If there's no linker plugin, use -fwhole-program so the compiler can make those assumptions and go way more aggressive with its optimization choices ๐Ÿ”ฅ.

When you compile with -flto and skip -fuse-linker-plugin, the object file ends up bigger than a regular one ๐Ÿ“. That's because it has GIMPLE bytecodes and the usual final code (see -ffat-lto-objects). The upside is that these LTO-aware objects can still be linked like normal objects. Just know that if you pass -fno-lto to the linker, no interprocedural optimizations happen at all ๐Ÿ’€. Also, if -fno-fat-lto-objects is on, the compile stage is faster, but you can't do a regular, non-LTO link with those files.

When GCC builds the final binary, it only runs link-time optimizations on the files that have bytecode in them โœจ. So you can totally mix and match object files and libraries, with GIMPLE bytecode and final object code living side by side. GCC figures out on its own which files get the LTO treatment and which ones just link straight through ๐Ÿงš.

Generally, options you give at link time beat the ones you gave at compile time ๐Ÿ‘‘. Sometimes though, GCC tries to guess link-time options from the settings used to compile the input files, so it's giving detective energy ๐Ÿ™ˆ.

If you don't pass an optimization level -O at link time, GCC uses the highest level that was used when compiling the object files ๐Ÿฆ‹. Heads up, though: it's pretty ineffective to set an optimization level only at link time and not at compile time. There are two reasons for this. First, compiling without optimization skips the compiler passes that collect the info needed for good link-time optimization. Second, some early optimization passes can only run at compile time, not at link time ๐Ÿ˜ญ.

GCC keeps some code generation flags around inside the bytecode, because they're needed during the final link ๐Ÿ’œ. Right now, these are taken from the first object file that explicitly sets them: -fcommon, -fexceptions, -fnon-call-exceptions, -fgnu-tm and all the -m target flags.

The PIC and PIE flags (-fPIC, -fpic, -fpie and -fPIE) get combined using this scheme, and it's kind of a vibe ๐ŸŒˆ:

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

Some ABI-changing flags have to match across all compilation units. If you try to override them at link time with a conflicting value, it gets ignored ๐Ÿ™…โ€โ™€๏ธ. This includes stuff 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 when translation units conflict ๐ŸŒธ. Specifically, -fno-strict-overflow, -fwrapv and -fno-trapv take precedence. For example, -ffp-contract=off beats -ffp-contract=fast. You can still override these at link time if you need to.

Diagnostic options like -Wstringop-overflow also 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 end up turning warnings on or off for regions when the code doesn't match the compile-time setting, so keep an eye on that ๐Ÿ‘€.

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

To get debug info, you need to supply -g at compile time ๐Ÿ”. If any input file at link time was built with debug info, the link turns debug info generation on too. Fancy debug info settings, like the DWARF level -gdwarf-5, need to be repeated explicitly on the linker command line. Mixing different settings across translation units is discouraged, so don't do it, bestie ๐Ÿ™…โ€โ™€๏ธ.

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

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

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

Notice the final link is done with g++ to pull in the C++ runtime libraries, and -lgfortran is added to get the Fortran runtime libraries ๐Ÿฆ‹. In general, when you mix languages in LTO mode, use the same link command options you'd use when mixing languages in a regular, non-LTO compilation.

If object files 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 you're using a linker with plugin support ๐Ÿซถ. To make static libraries that work with LTO, use gcc-ar and gcc-ranlib instead of ar and ranlib. To 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, use -fuse-linker-plugin so the library joins the LTO optimization process โœจ:

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

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

If you aren't using a linker with plugin support, and/or you don't enable the linker plugin, the objects inside libfoo.a get extracted and linked as usual. They just won't take part in the LTO optimization process ๐Ÿ˜ญ. To make a static library that works for both LTO optimization and usual linkage, compile its object files with -flto -ffat-lto-objects ๐Ÿ’–.

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

The current LTO implementation doesn't try to make bytecode that's portable between different host types ๐Ÿ™ˆ. The bytecode files are versioned with a strict version check, so bytecode generated by one GCC version won't work with an older or newer GCC version. Not a vibe!

Link-time optimization doesn't work super well with debug info generation on systems other than the ones using ELF and DWARF together ๐Ÿ’€.

If you specify the optional n, the optimization and code generation done at link time runs in parallel using n jobs, by using an installed make program ๐Ÿงš. You can use the environment variable MAKE to override which program gets used.

You can also use -flto=jobserver to let GNU make's job server mode decide how many parallel jobs to run ๐Ÿ‘‘. This is clutch 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. This option likely only works if MAKE is GNU make. Even without the option value, GCC tries to automatically detect a running GNU make's job server โœจ.

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

  • -flto-partition=alg โ€” Okay, this one picks the partitioning algorithm the link-time optimizer uses ๐ŸŽ€. Your choices are 1to1, which mirrors the original source files, balanced, which splits things into equally sized chunks whenever that's possible, or max, which makes a new partition for every symbol where possible. Picking none turns partitioning and streaming off completely ๐Ÿ’…. The default is balanced. 1to1 can be used as a workaround for various code ordering issues, but max partitioning is only meant for internal testing, so don't go there ๐Ÿ™ˆ. The value one means exactly one partition gets used, while none skips partitioning and runs the link-time optimization step straight from the WPA phase ๐ŸŒธ.
  • -flto-compression-level=n โ€” This one controls how much the intermediate language written to LTO object files gets compressed ๐Ÿ“. It only matters when you're in LTO mode (-flto). GCC currently supports two LTO compression algorithms. For zstd, valid values are 0 (no compression) up to 19 (maximum compression), and zlib supports values from 0 to 9. Values outside the range get clamped to the minimum or maximum of whatever's supported. If you don't give the option, a default balanced compression setting gets used ๐Ÿ’–.
  • -fuse-linker-plugin โ€” This turns on a linker plugin during link-time optimization ๐Ÿ”Œ. It relies on plugin support in the linker, which is available in gold or in GNU ld 2.21 or newer โœจ.

The -fuse-linker-plugin deal is that GCC can dig into library archives and pull out the object files carrying GIMPLE bytecode ๐Ÿงš. That gives the link-time optimizer way more code to work with, so the results are glow-up levels โœจ. The info also says which symbols can be accessed from outside, by non-LTO object files or during dynamic linking ๐Ÿฆ‹. Binaries (and shared libraries that use hidden visibility) get code quality improvements that are similar to -fwhole-program ๐Ÿ”ฅ. Check -flto for the full tea on what this flag does and how to use it ๐Ÿซถ.

This option is on by default when LTO support is enabled in GCC and GCC was set up for a linker that supports plugins (GNU ld 2.21 or newer, or gold) ๐Ÿ’–.

  • -ffat-lto-objects โ€” okay so fat LTO objects are object files that hold both the intermediate language and the object code ๐Ÿ“. That makes them usable for LTO linking and normal linking, which is so iconic. This only matters when you're compiling with -flto, and it gets ignored at link time ๐Ÿ’€.

-fno-fat-lto-objects improves compilation time over plain LTO, but the complete toolchain has to be aware of LTO for it to work ๐Ÿง. It needs a linker with linker plugin support for basic functionality. nm, ar and ranlib also need to support linker plugins if you want a full-featured build environment (one that can build static libraries etc). GCC gives you the gcc-ar, gcc-nm, gcc-ranlib wrappers to pass the right options to these tools. With non fat LTO, makefiles need to be modified to use them.

Modern binutils has a plugin auto-load mechanism, so installing the linker plugin into $libdir/bfd-plugins has the same effect as using the command wrappers (gcc-ar, gcc-nm and gcc-ranlib) ๐ŸŒˆ.

The default is -fno-fat-lto-objects on targets with linker plugin support.

  • -fcompare-elim โ€” after register allocation and post-register allocation instruction splitting, GCC hunts down arithmetic instructions that compute processor flags in a way that looks like a comparison based on that arithmetic ๐Ÿ”. If possible, it eliminates the explicit comparison operation ๐Ÿ’….

This pass only applies to certain targets that can't explicitly represent the comparison operation before register allocation is complete.

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

  • -ffold-mem-offsets, -fno-fold-mem-offsets โ€” tries to eliminate add instructions by folding them into memory loads and stores ๐Ÿงš.

Enabled at levels -O2, -O3.

  • -fcprop-registers โ€” after register allocation and post-register allocation instruction splitting, GCC runs a copy-propagation pass to try to reduce scheduling dependencies and occasionally eliminate the copy ๐ŸŒธ.

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

  • -fprofile-correction โ€” profiles collected from an instrumented binary for multi-threaded programs can be inconsistent because of missed counter updates ๐Ÿ™ˆ. 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 portions of the program that weren't executed during the train run get optimized aggressively for size rather than speed ๐Ÿ“. Sometimes it's not practical to train every possible hot path. For example, a program may contain functions specific to certain hardware, and training may not cover every hardware configuration the program runs on ๐Ÿ–ฅ๏ธ. With "-fprofile-partial-training", profile feedback is ignored for all functions not executed during the train run, so they're optimized as if they were compiled without profile feedback. This leads to better performance when the train run isn't representative, but it also leads to significantly bigger code ๐Ÿ“ฆ.
  • -fprofile-use, -fprofile-use=path โ€” turns on profile feedback-directed optimizations, plus the following optimizations, many of which are usually only worth it when profile feedback is available ๐Ÿ‘‘:
-fbranch-probabilities  -fprofile-values -funroll-loops
-fpeel-loops  -ftracer  -fvpt -finline-functions  -fipa-cp
-fipa-cp-clone  -fipa-bit-cp -fpredictive-commoning  -fsplit-loops
-funswitch-loops -fgcse-after-reload  -ftree-loop-vectorize
-ftree-slp-vectorize -fvect-cost-model=dynamic
-ftree-loop-distribute-patterns -fprofile-reorder-functions

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

By default, GCC emits an error message if the feedback profiles don't match the source code. You can turn that error into a warning with -Wno-error=coverage-mismatch.

Note this may result in poorly optimized code ๐Ÿ˜ฌ.

Also by default, GCC emits a warning message if the feedback profiles don't exist (see -Wmissing-profile).

If path is specified, GCC looks there for the profile feedback data files. See -fprofile-dir.

  • -fauto-profile, -fauto-profile=path โ€” turns on sampling-based feedback-directed optimizations, plus the following optimizations, many of which are usually only worth it when profile feedback is available โœจ:
-fbranch-probabilities  -fprofile-values -funroll-loops
-fpeel-loops  -ftracer  -fvpt -finline-functions  -fipa-cp
-fipa-cp-clone  -fipa-bit-cp -fpredictive-commoning  -fsplit-loops
-funswitch-loops -fgcse-after-reload  -ftree-loop-vectorize
-ftree-slp-vectorize -fvect-cost-model=dynamic
-ftree-loop-distribute-patterns -fprofile-correction

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

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

E.g.

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

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

E.g.

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

The following options control compiler behavior around floating-point arithmetic ๐Ÿงฎ. They trade off speed against correctness, and you have to turn every single one of them on yourself ๐ŸŽ€.

  • -ffloat-store โ€” do not store floating-point variables in registers, and stop other options that might change whether a floating-point value is pulled from a register or from memory ๐ŸงŠ.

This option prevents the undesirable excess precision you get on machines like the 68000, where the floating registers (of the 68881) keep more precision than a "double" is supposed to have ๐Ÿ˜ญ. The same goes for the x86 architecture. For most programs the excess precision only does good, but a few programs rely on the precise definition of IEEE floating point. For those, use -ffloat-store after modifying them to store all pertinent intermediate computations into variables.

  • -fexcess-precision=style โ€” this gives you more control over excess precision on machines where floating-point operations happen in a format with more precision or range than the IEEE standard and interchange floating-point types ๐Ÿง . By default, -fexcess-precision=fast is in effect, which means operations may be carried out in a wider precision than the types in the source if that makes the code faster, and it's unpredictable when rounding to the source types takes place.

When compiling C or C++, if -fexcess-precision=standard is specified, excess precision follows the rules of ISO C99 or C++. In particular, both casts and assignments cause values to be rounded to their semantic types (whereas -ffloat-store only affects assignments). This option is enabled by default for C or C++ if a strict conformance option such as -std=c99 or -std=c++17 is used. -ffast-math enables -fexcess-precision=fast by default regardless of whether a strict conformance option is used. If -fexcess-precision=16 is specified, constants and the results of expressions with types "_Float16" and "__bf16" are computed without excess precision.

-fexcess-precision=standard isn't implemented for languages other than C or C++. On x86, it has no effect if -mfpmath=sse or -mfpmath=sse+387 is specified. In the former case, IEEE semantics apply without excess precision, and in the latter, rounding is unpredictable.

  • -ffast-math โ€” sets -fno-math-errno, -funsafe-math-optimizations, -ffinite-math-only, -fno-rounding-math, -fno-signaling-nans, -fcx-limited-range and -fexcess-precision=fast ๐Ÿš€.

This option causes the preprocessor macro "__FAST_MATH__" to be defined.

This option is not turned on by any -O option besides -Ofast, since it can result in incorrect output for programs that depend on an exact implementation of IEEE or ISO rules/specifications for math functions. It may, however, yield faster code for programs that don't need the guarantees of those specifications ๐Ÿ’€.
  • -fno-math-errno โ€” do not set errno after calling math functions that are executed with a single instruction, e.g., sqrt. A program that relies on IEEE exceptions for math error handling may want this flag for speed while keeping IEEE arithmetic compatibility ๐ŸŽ๏ธ.

This option is not turned on by any -O option, since it can result in incorrect output for programs that depend on an exact implementation of IEEE or ISO rules/specifications for math functions. It may, however, yield faster code for programs that don't need the guarantees of those specifications.

The default is -fmath-errno.

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

  • -funsafe-math-optimizations โ€” allows optimizations for floating-point arithmetic that (a) assume arguments and results are valid and (b) may violate IEEE or ANSI standards.
Be careful with this one ๐Ÿ˜ฑ. When used at link time, it may include libraries or startup files that change the default FPU control word or other similar optimizations.

This one's the "not turned on by any -O option" energy again, bestie ๐Ÿ™ˆ -funsafe-math-optimizations is never switched on by an -O flag because it can give you wrong output for programs that depend on the exact IEEE or ISO math rules ๐Ÿ’€ It might make faster code for programs that don't need those guarantees though โœจ and it turns on -fno-signed-zeros, -fno-trapping-math, -fassociative-math and -freciprocal-math all at once ๐Ÿซถ

The default is -fno-unsafe-math-optimizations ๐Ÿ’–

  • -fassociative-math โ€” okay so this lets the compiler regroup operands in a chain of floating-point operations ๐Ÿฆ‹ It breaks the ISO C and C++ standard because the result can change ngl ๐Ÿ˜ญ
    • NOTE: reordering can flip the sign of zero, ignore NaNs, and cause or hide underflow and overflow ๐Ÿ’€ So it's a no-go for code that relies on rounding tricks like (x + 2**52) - 2**52. It can also reorder floating-point comparisons, so don't use it where ordered comparisons are required ๐Ÿ™…โ€โ™€๏ธ
    • It requires both -fno-signed-zeros and -fno-trapping-math to be in effect, and it doesn't really make sense with -frounding-math ๐ŸŒธ
    • For Fortran, it gets switched on automatically when both -fno-signed-zeros and -fno-trapping-math are in effect โœจ
    • The default is -fno-associative-math.
  • -freciprocal-math โ€” this one lets the compiler use the reciprocal of a value instead of dividing, if that unlocks some optimizations ๐Ÿงš So x / y can become x * (1/y), which is super handy when (1/y) can be pulled out as a common subexpression ๐Ÿ’… The catch is that it loses precision and adds more flops on the value ๐Ÿ˜ฌ
    • The default is -fno-reciprocal-math.
  • -ffinite-math-only โ€” allows optimizations that assume arguments and results are never NaNs or +-Infs ๐ŸŒˆ
    • It's not turned on by any -O option, same as before, because it can give wrong output for programs that need the exact IEEE or ISO math rules ๐Ÿ’€ It might still give faster code for programs that don't need those guarantees ๐Ÿฆ‹
    • The default is -fno-finite-math-only.
  • -fno-signed-zeros โ€” allows optimizations that don't care about whether zero is signed ๐Ÿซง IEEE says distinct +0.0 and -0.0 have their own behaviour, which stops the compiler from simplifying things like x+0.0 or 0.0*x (even with -ffinite-math-only) ๐Ÿ™ˆ This option basically says the sign of a zero result doesn't matter ๐Ÿ’–
    • The default is -fsigned-zeros.
  • -fno-trapping-math โ€” tells the compiler to assume floating-point operations can't cause user-visible traps ๐ŸŽ€ Those traps are division by zero, overflow, underflow, inexact result and invalid operation ๐Ÿ˜ฑ It requires -fno-signaling-nans to be in effect, and it can make faster code if you rely on "non-stop" IEEE arithmetic ๐ŸŽ๏ธ
    • > Warning: this should never be turned on by any -O option, because it can give wrong output for programs that depend on the exact IEEE or ISO math rules ๐Ÿ’€
    • The default is -ftrapping-math.
    • Future GCC versions might give finer control over this using C99's FENV_ACCESS pragma ๐Ÿ”ฎ This flag will then be used along with -frounding-math to set the default state for FENV_ACCESS โœจ
  • -frounding-math โ€” disables transformations and optimizations that assume the default floating-point rounding behaviour ๐ŸŒธ That default is round-to-zero for all floating-point to integer conversions, and round-to-nearest for all other arithmetic truncations ๐Ÿ“ Use this if your program changes the FP rounding mode dynamically, or might run with a non-default rounding mode ๐Ÿซถ
    • It turns off compile-time constant folding of floating-point expressions (since rounding mode can change those), plus arithmetic transformations that are unsafe with sign-dependent rounding modes ๐Ÿ™…โ€โ™€๏ธ
    • The default is -fno-rounding-math.
    • > Experimental: this doesn't currently guarantee to disable every GCC optimization affected by rounding mode ๐Ÿฅบ
    • Future versions might give finer control using C99's FENV_ACCESS pragma ๐Ÿ”ฎ This flag will be used along with -ftrapping-math to set the default state for FENV_ACCESS โœจ
  • -fsignaling-nans โ€” compiles assuming IEEE signaling NaNs may cause user-visible traps during floating-point operations ๐Ÿ’ฅ Turning it on disables optimizations that might change how many exceptions are visible with signaling NaNs ๐Ÿ‘€ It implies -ftrapping-math, and it defines the preprocessor macro __SUPPORT_SNAN__ ๐Ÿงš
    • The default is -fno-signaling-nans.
    • > Experimental: this doesn't currently guarantee to disable every GCC optimization that affects signaling NaN behaviour ๐Ÿ™ˆ
  • -fno-fp-int-builtin-inexact โ€” stops the built-in functions ceil, floor, round and trunc (plus their float and long double variants) from generating code that raises the inexact floating-point exception for non-integer arguments ๐Ÿช„ ISO C99 and C11 let these raise inexact, but ISO/IEC TS 18661-1:2014 (the C bindings to IEEE 754-2008, now part of ISO C23) doesn't ๐Ÿ™…โ€โ™€๏ธ
    • The default is -ffp-int-builtin-inexact, which lets the exception be raised, unless C23 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 may still be raised if that library doesn't follow TS 18661 ๐Ÿ˜ญ
  • -fsingle-precision-constant โ€” treats floating-point constants as single precision, instead of quietly converting them to double-precision constants ๐Ÿฆ‹
  • -fcx-limited-range โ€” when this is on, the compiler is told that a range reduction step isn't needed for complex division ๐ŸŒˆ It also skips checking whether the result of a complex multiplication or division is NaN + I*NaN and trying to rescue it ๐Ÿซง
    • The default is -fno-cx-limited-range, but -ffast-math turns it on โœจ
    • This controls the default setting of the ISO C99 CX_LIMITED_RANGE pragma ๐Ÿ’– It applies to all languages, though ๐ŸŒ
  • -fcx-fortran-rules โ€” complex multiplication and division follow Fortran rules ๐Ÿงš Range reduction happens as part of complex division, but there's still no checking for a NaN + I*NaN result or any attempt to rescue it ๐Ÿ™ˆ
    • The default is -fno-cx-fortran-rules.

The following options control optimizations that may improve performance, but none of them are enabled by any -O option ๐Ÿ“ This section also includes experimental options that may produce broken code, so be careful bestie โš ๏ธ

  • -fbranch-probabilities โ€” okay this one is a whole glow-up ๐ŸŒŸ First you run a program compiled with -fprofile-arcs, then you compile it a second time with -fbranch-probabilities so the optimizations can use how many times each branch was taken ๐Ÿ“Š When the -fprofile-arcs program exits, it saves arc execution counts to a file called sourcename.gcda for each source file ๐Ÿ’พ That data is super dependent on the structure of the generated code, so you must use the same source code and the same optimization options for both compilations ๐Ÿซถ Check -fprofile-arcs for the details on file naming ๐Ÿ”
    • With -fbranch-probabilities, GCC puts a REG_BR_PROB note on each JUMP_INSN and CALL_INSN ๐Ÿง  These can be used to improve optimization ๐Ÿ“ˆ Right now they're only used in one place: in reorg.cc, where 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 โ€” if you combine it with -fprofile-arcs, it adds code that gathers some data about the values of expressions in the program ๐Ÿ“ฅ With -fbranch-probabilities, it reads that data back and uses it for optimizations ๐Ÿ”
    • Enabled by -fprofile-generate, -fprofile-use, and -fauto-profile.
  • -fprofile-reorder-functions โ€” function reordering based on profile instrumentation records the first time each function runs, then sorts those functions in ascending order ๐Ÿ—‚๏ธ
    • Enabled with -fprofile-use.
  • -fvpt โ€” with -fprofile-arcs, this tells the compiler to add code that gathers information about expression values ๐Ÿ•ต๏ธโ€โ™€๏ธ With -fbranch-probabilities, it reads that data back and actually performs optimizations based on it ๐ŸŽ€ Right now those optimizations include specialising division operations using what it knows about the denominator's value ๐Ÿ’…
    • 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 ๐ŸŒˆ It mostly helps processors with loads of registers ๐Ÿ’ช Heads up though: depending on the debug information format the target uses, it can make debugging impossible, because variables no longer stay in a "home register" ๐Ÿ˜ญ
    • Enabled by default with -funroll-loops.
  • -fschedule-fusion โ€” runs a target-dependent pass over the instruction stream to group instructions of the same type together ๐Ÿงฉ The target machine can run them more efficiently when they're next to each other in the flow ๐Ÿƒโ€โ™€๏ธ
    • Enabled at levels -O2, -O3, -Os.
  • -ftracer โ€” performs tail duplication to enlarge the superblock size ๐Ÿฐ This simplifies the function's control flow, so other optimizations can do a better job ๐Ÿ‘‘
    • Enabled by -fprofile-use and -fauto-profile.
  • -funroll-loops โ€” okay bestie, this one unrolls loops whose number of iterations is known at compile time or when the loop gets entered ๐Ÿ’– It also implies -frerun-cse-after-loop, -fweb and -frename-registers, so it brings its whole squad โœจ It also switches on complete loop peeling, which fully removes loops that only run a small constant number of times. > Heads up: this makes your code bigger, and it may or may not make it run faster ๐Ÿ’€ It's enabled by -fprofile-use and -fauto-profile.
  • -funroll-all-loops โ€” the no-chill version ๐Ÿ’… This unrolls every loop, even when the iteration count is still a mystery when the loop starts. > This usually makes programs run more slowly ๐Ÿ˜ญ It implies the same options as -funroll-loops.
  • -fpeel-loops โ€” this peels loops that don't roll much, going off profile feedback or static analysis ๐ŸŒธ It also turns on complete loop peeling, meaning loops with a small constant number of iterations get fully removed. It's enabled by -O3, -fprofile-use, and -fauto-profile.
  • -fmove-loop-invariants โ€” turns on the loop invariant motion pass in the RTL loop optimizer ๐Ÿงš It's enabled at level -O1 and higher, except for -Og.
  • -fmove-loop-stores โ€” enables the loop store motion pass in the GIMPLE loop optimizer ๐Ÿฆ‹ It moves invariant stores to after the end of the loop, trading that for keeping the stored value in a register across each iteration. Note that for this to actually do anything, -ftree-loop-im has to be enabled too. It's enabled at level -O1 and higher, except for -Og.
  • -fsplit-loops โ€” if a loop has a condition that's always true on one side of the iteration space and always false on the other, this splits the loop into two โœ‚๏ธ It's enabled by -fprofile-use and -fauto-profile.
  • -funswitch-loops โ€” this yanks branches with loop invariant conditions out of the loop ๐Ÿซถ You get duplicates of the loop on both branches, each tweaked to match what the condition came out to be. It's enabled by -fprofile-use and -fauto-profile.
  • -fversion-loops-for-strides โ€” if a loop walks an array with a variable stride, GCC makes a second copy of the loop that assumes the stride is always one ๐Ÿ‘‘ Here's the vibe:
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 iconic for Fortran's assumed-shape arrays, since it lets the compiler vectorize better when it can assume contiguous access ๐ŸŒˆ It's enabled by default at -O3, and it's also enabled by -fprofile-use and -fauto-profile.

  • -ffunction-sections, -fdata-sections โ€” these put each function or data item into its own section in the output file, but only if the target supports arbitrary sections ๐Ÿงฉ The function or data item's name decides the section name.
    • Use these where the linker can optimize for locality of reference in the instruction space. Most ELF object format systems have linkers that can do this. On AIX, the linker rearranges sections (CSECTs) based on the call graph, and the performance impact varies ๐Ÿ”ฅ
    • Paired with linker garbage collection (the linker --gc-sections option), these can lead to smaller statically-linked executables (after stripping) ๐Ÿ’–
    • On ELF/DWARF systems, these don't make the debug info worse. Other object file or debug info formats might have issues ๐Ÿ™ˆ
    • > Only use these when there are significant benefits, bestie ๐Ÿซถ They make the assembler and linker produce larger object and executable files, and they're also slower. They also affect code generation: they stop the compiler and assembler from using relative locations inside a translation unit, since those aren't known until link time. One example of an optimization that gets blocked is relaxing calls to short call instructions.
  • -fstdarg-opt โ€” optimizes the prologue of variadic argument functions based on how those arguments are actually used โœจ
  • -fsection-anchors โ€” this tries to cut down on symbolic address calculations by using shared "anchor" symbols to reach nearby objects ๐Ÿฆ‹ It can reduce GOT entries and GOT accesses on some targets. Say you have this function "foo":
static int a, b, c;
int foo (void) { return a + b + c; }

Normally it calculates the addresses of all three variables, but with -fsection-anchors it reads them from one common anchor point instead. The effect is similar to this pseudocode (which isn't valid C, so don't try it ๐Ÿ™ˆ):

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

Not every target supports this one, so check before you get too attached ๐Ÿ’…

  • -fzero-call-used-regs=choice โ€” zeroes the call-used registers when a function returns, which boosts program security ๐Ÿ” It either helps mitigate Return-Oriented Programming (ROP) attacks or stops information from leaking out through registers. The possible values of choice are the same as for the zero_call_used_regs attribute, and the default is skip. You can control this per function with the function attribute zero_call_used_regs ๐Ÿ’œ
  • --param name=value โ€” GCC uses a bunch of internal constants to decide how much optimization to do. For example, it won't inline functions that have more than a certain number of instructions ๐Ÿ‘€ You can tweak some of these from the command line with --param. Heads up: the names and meanings are tied to compiler internals and can change without notice in future releases ๐Ÿ˜ญ To see the minimal, maximal, and default value of a parameter, use --help=param -Q. The value is always an integer, and these names are recognized for all targets:
    • predictable-branch-outcome โ€” if a branch is predicted to be taken with a probability lower than this threshold (in percent), it counts as well predictable ๐ŸŽฏ
    • max-rtl-if-conversion-insns โ€” RTL if-conversion tries to get rid of conditional branches around a block by swapping them for conditionally executed instructions. This sets the max number of instructions in a block that get considered for if-conversion. The compiler also uses other heuristics to decide whether it's actually worth it โœจ
    • max-rtl-if-conversion-predictable-cost โ€” RTL if-conversion will try to remove conditional branches around a block the same way. These parameters cap the cost of the sequence it would generate, depending on whether the branch is statically determined to be predictable or not. The units match GCC's internal seq_cost metric. The compiler tries to pick a reasonable default for this 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 edges coming into each block ๐Ÿซ  Bigger values mean more aggressive optimization, with compile time going up for probably a small size win.
    • min-crossjump-insns โ€” the min number of instructions that must match at the end of two blocks before cross-jumping happens on them. This 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. To avoid O(N^2) behavior in several passes, GCC factors computed gotos early and unfactors them as late as possible. Only computed jumps at the end of a basic block with no more than max-goto-duplication-insns instructions get unfactored ๐Ÿฆ‹
    • max-delay-slot-insn-search โ€” the max number of instructions to check when hunting for something to fill a delay slot. If you search past this arbitrary number, the time saved by filling the slot is tiny, so GCC just stops searching ๐Ÿ›‘ Bigger values mean more aggressive optimization, with compile time going up for probably a small execution time win.
    • max-delay-slot-live-search โ€” when filling delay slots, the max number of instructions to check while looking for a block with valid live register information. Raising this arbitrarily chosen value means more aggressive optimization but longer compile times. This parameter should get removed once the delay slot code is rewritten to maintain the control-flow graph ๐Ÿงน
    • max-gcse-memory โ€” the approximate max amount of memory in kB that can be allocated for global common subexpression elimination. If the optimization needs more memory than this, it just doesn't happen ๐Ÿง 
    • max-gcse-insertion-ratio โ€” if the ratio of expression insertions to deletions is bigger than this value for any expression, RTL PRE inserts or removes that expression, which leaves partially redundant computations sitting in the instruction stream ๐Ÿ‘€
  • max-pending-list-length โ€” bestie, this is the cap on how many pending dependencies scheduling is allowed to hold ๐Ÿ’… Once it hits the limit, it flushes the current state and starts over. Huge functions with barely any branches or calls can build up massive lists that waste memory and resources for no reason ๐Ÿ˜ญ
  • max-modulo-backtrack-attempts โ€” the max number of backtrack attempts the scheduler will make while modulo scheduling a loop ๐Ÿ” Go too high and your compile time can blow up exponentially ๐Ÿ’€
  • max-inline-functions-called-once-loop-depth โ€” the maximal loop depth of a call that the inline heuristics will consider when they're trying to inline every function that's called once ๐Ÿงš
  • max-inline-functions-called-once-insns โ€” the maximal estimated size of functions that come out of inlining the functions called once ๐ŸŒธ
  • max-inline-insns-single โ€” okay so the tree inliner has a whole squad of parameters ๐Ÿ‘‘ This one sets the max number of instructions (counted in GCC's internal representation) in a single function that the tree inliner will even look at for inlining. It only affects functions declared inline and methods implemented right inside a class declaration (C++) ๐ŸŽ€
  • max-inline-insns-auto โ€” when you turn on -finline-functions (which comes with -O3), a whole bunch of functions that the compiler wouldn't normally think about inlining suddenly get checked ๐Ÿ‘€ For those, a different, more restrictive limit applies than for functions declared inline (--param max-inline-insns-auto) ๐Ÿฆ‹
  • max-inline-insns-small โ€” the bound that applies to calls considered relevant when you use -finline-small-functions ๐Ÿ“
  • max-inline-insns-size โ€” the bound that applies to calls being optimized for size ๐Ÿ“ A little bit of growth can actually be a good thing here, since it can open up optimization opportunities that inlining exposes โœจ
  • uninlined-function-insns โ€” the number of instructions the inliner counts as overhead for a function, like its prologue and epilogue ๐Ÿซถ
  • uninlined-function-time โ€” the extra time the inliner counts as overhead for a function, like the time it takes to run that 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 enable later optimizations ๐Ÿ”ฅ
  • uninlined-thunk-insns, uninlined-thunk-time โ€” same deal as --param uninlined-function-insns and --param uninlined-function-time, except these are applied to function thunks ๐Ÿงต
  • inline-min-speedup โ€” if the estimated performance improvement of caller + 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 ๐Ÿš€ Main character move, honestly ๐Ÿ‘‘
  • large-function-insns โ€” the limit that defines a really large function ๐Ÿ˜ For functions bigger than this after inlining, inlining gets constrained by --param large-function-growth. This one is mostly there to stop 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 might be too tight ๐Ÿ˜ฌ Say you've got a unit with function A (inline) and function B that just calls A three times. If B is small compared to A, the unit's growth is 300%, and honestly that kind of inlining is totally sane ๐Ÿ™Œ But for huge units full of tiny inlineable functions, the overall unit growth limit is what stops an exponential explosion of code size ๐Ÿ’€ So for smaller units, the size gets bumped up to --param large-unit-insns before the --param inline-unit-growth limit gets applied ๐Ÿง 
  • lazy-modules โ€” the max number of C++ module files that can be open at the same time when lazy loading ๐ŸŒˆ
  • inline-unit-growth โ€” the max overall growth of the compilation unit caused by inlining ๐ŸŒฑ For example, a value of 20 limits unit growth to 1.2 times the original size. Cold functions (either marked cold with an attribute or flagged by profile feedback) don't count toward the unit size ๐ŸงŠ
  • ipa-cp-unit-growth โ€” the max overall growth of the compilation unit caused by interprocedural constant propagation ๐Ÿ’œ For example, a value of 10 limits unit growth to 1.1 times the original size โœจ
  • ipa-cp-large-unit-insns โ€” the size at which the IPA-CP pass considers a translation unit to be large ๐Ÿ”
  • large-stack-frame โ€” the limit that defines large stack frames ๐Ÿฅž While it's inlining, the algorithm tries really hard not to grow past this limit 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, max-inline-insns-recursive-auto โ€” the max number of instructions an out-of-line copy of a self-recursive inline function is allowed to grow into by doing recursive inlining ๐Ÿ”„ --param max-inline-insns-recursive applies to functions declared inline. For functions not declared inline, recursive inlining only happens when -finline-functions (included in -O3) is enabled, and then --param max-inline-insns-recursive-auto is the one that applies instead ๐ŸŽ€
  • max-inline-recursive-depth, max-inline-recursive-depth-auto โ€” the max recursion depth used for recursive inlining ๐Ÿชž --param max-inline-recursive-depth applies to functions declared inline. For functions not declared inline, recursive inlining only happens when -finline-functions (included in -O3) is enabled, and --param max-inline-recursive-depth-auto applies instead ๐Ÿ’…
  • min-inline-recursive-probability โ€” recursive inlining is only worth it for functions that recurse deeply on average ๐ŸŒ€ For functions with a shallow recursion depth it can actually hurt, because it bumps up the prologue size or makes the function body more complicated for other optimizers ๐Ÿ˜ต When profile feedback is available (see -fprofile-generate), the real recursion depth can be guessed from how likely a function is to recurse through a given call expression ๐Ÿ”ฎ This parameter limits inlining to only those call expressions whose probability goes over the threshold (in percent) ๐ŸŽฏ
  • early-inlining-insns โ€” how much growth the early inliner is allowed to make ๐ŸŒท Basically, it ramps up the amount of inlining for code that has a large abstraction penalty ๐Ÿ—๏ธ
  • max-early-inliner-iterations โ€” the limit on how many iterations the early inliner runs ๐Ÿ” This basically caps how many nested indirect calls the early inliner can resolve ๐Ÿงฉ Deeper chains still get handled later, by late inlining ๐Ÿฆ‹
  • comdat-sharing-probability โ€” the probability (in percent) that C++ inline functions with comdat visibility get shared across multiple compilation units ๐Ÿค
  • modref-max-bases, modref-max-refs, modref-max-accesses โ€” the max number of base pointers, references, and accesses stored for a single function by mod/ref analysis ๐Ÿ—‚๏ธ
  • modref-max-tests โ€” the max number of tests the alias oracle can run to tell memory locations apart using the mod/ref info ๐Ÿ•ต๏ธโ€โ™€๏ธ This one ought to be bigger than --param modref-max-bases and --param modref-max-refs, so keep that in mind ๐Ÿซถ
  • modref-max-depth โ€” the max depth of the DFS walk used by modref escape analysis ๐ŸŒŠ Setting it to 0 disables the analysis completely ๐Ÿšซ
  • modref-max-escape-points โ€” the max number of escape points tracked by modref per SSA-name ๐Ÿ“
  • modref-max-adjustments โ€” the max amount the access range gets enlarged during modref dataflow analysis ๐Ÿ“
  • profile-func-internal-id โ€” controls whether the function's internal id gets used in the profile database lookup ๐Ÿ—ƒ๏ธ If the value is 0, the compiler uses an id based on the function's assembler name and filename instead ๐Ÿง  That makes old profile data way more forgiving of source changes, like function reordering and stuff ๐Ÿซ 
  • min-vect-loop-bound โ€” the min number of iterations below which loops don't get vectorized when -ftree-vectorize is in use ๐ŸŽถ The iteration count after vectorization has to be greater than this value for vectorization to happen ๐Ÿ’ช
  • gcse-cost-distance-ratio โ€” a scaling factor used when calculating how far an expression can get moved by GCSE optimizations ๐Ÿšš It's only supported in the code hoisting pass for now ๐Ÿช The bigger the ratio, the more aggressively code gets hoisted for simple expressions (ones that cost less than gcse-unrestricted-cost) ๐Ÿ”ฅ Setting it to 0 disables hoisting of simple expressions completely ๐Ÿ™…โ€โ™€๏ธ
  • gcse-unrestricted-cost โ€” the cost, roughly measured as the cost of a single typical machine instruction, at which GCSE optimizations stop constraining how far an expression can travel ๐ŸŒ Also only supported in the code hoisting pass ๐Ÿช„ The lower the cost, the more aggressive the hoisting gets ๐Ÿ“‰ Setting it to 0 lets every expression travel an unrestricted distance ๐Ÿฆ…
  • max-hoist-depth โ€” the depth of the search in the dominator tree for expressions to hoist ๐ŸŒณ It's there to avoid quadratic behavior in the hoisting algorithm ๐Ÿงฎ A value of 0 doesn't limit the search at all, but it might slow down compilation of huge functions ๐Ÿข
  • max-tail-merge-comparisons โ€” the max number of similar basic blocks to compare any one basic block against ๐Ÿง It's used to avoid quadratic behavior in tree tail merging ๐Ÿ’–
  • max-tail-merge-iterations โ€” the cap on how many passes over the function the tree tail merging can make ๐Ÿ” It's basically a compile-time leash so this doesn't go on forever โฑ๏ธ
  • store-merging-allow-unaligned โ€” lets the store merging pass create unaligned stores, but only when that's legal ๐Ÿงฉ
  • max-stores-to-merge โ€” how many stores the store merging pass will try to squish together into wider stores ๐Ÿซถ
  • max-store-chains-to-track โ€” how many store chains the store merging pass can track at once while trying to merge them into wider stores ๐Ÿ”—
  • max-stores-to-track โ€” how many stores get tracked at the same time while the store merging pass tries to merge them into wider stores ๐Ÿ‘€
  • max-unrolled-insns โ€” the most instructions a loop can have and still get unrolled ๐Ÿ” If the loop does get unrolled, this same number also decides how many times the loop body is copied ๐ŸŽ€
  • max-average-unrolled-insns โ€” like the one above, but counts instructions weighted by how likely they are to run ๐Ÿ“Š Again, if a loop gets unrolled, this value also sets how many times the loop code is unrolled ๐ŸŒธ
  • max-unroll-times โ€” the max number of times a single loop can be unrolled ๐Ÿฆ‹
  • max-peeled-insns โ€” the most instructions a loop can have and still get peeled ๐Ÿ“ If it does get peeled, this also decides how many times the loop code is peeled ๐Ÿงš
  • max-peel-times โ€” the max number of times a single loop can be peeled ๐Ÿซง
  • max-peel-branches โ€” the max number of branches allowed on the hot path through the peeled sequence ๐ŸŒˆ
  • max-completely-peeled-insns โ€” the max number of instructions a completely peeled loop can have ๐Ÿ’œ
  • max-completely-peel-times โ€” the max number of iterations a loop can have and still be a good candidate for complete peeling โญ
  • max-completely-peel-loop-nest-depth โ€” the deepest a loop nest can be and still be suitable for complete peeling ๐Ÿช†
  • max-unswitch-insns โ€” the max number of instructions an unswitched loop can have ๐Ÿ”€
  • max-unswitch-depth โ€” the deepest a loop nest can be and still get unswitched ๐ŸŒŠ
  • 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 a semi-invariant condition statement needs before it triggers a loop split โœ‚๏ธ
  • iv-consider-all-candidates-bound โ€” if there are this many induction variable candidates or fewer, every candidate gets considered for each use in the induction variable optimizations ๐Ÿง  If there are more than that, only the most relevant ones get looked at, so the time complexity doesn't go quadratic ๐Ÿ˜ญ
  • iv-max-considered-uses โ€” the induction variable optimizations just give up on any loop that has more induction variable uses than this ๐Ÿณ๏ธ
  • iv-always-prune-cand-set-bound โ€” if the candidate set is smaller than this value, the compiler always tries to clear out unnecessary ivs from the set whenever it adds a new one ๐Ÿงน
  • avg-loop-niter โ€” the average number of iterations a loop is expected to run ๐Ÿ”ข
  • dse-max-object-size โ€” the biggest object (in bytes) that dead store elimination will track byte by byte ๐Ÿ“ฆ Bigger values can mean bigger compilation times, so keep that in mind ๐Ÿข
  • dse-max-alias-queries-per-store โ€” the max number of queries sent to the alias oracle for each store ๐Ÿ” Larger values can take longer to compile but may remove more dead stores ๐Ÿ’€
  • scev-max-expr-size โ€” the upper bound on how big expressions can be in the scalar evolutions analyzer ๐Ÿ“ Big expressions slow the analyzer down ๐ŸŒ
  • scev-max-expr-complexity โ€” the upper bound on how complex expressions can be in the scalar evolutions analyzer ๐Ÿงถ Complicated expressions slow the analyzer down too ๐Ÿ˜ฉ
  • max-tree-if-conversion-phi-args โ€” the max number of arguments a PHI can have and still be supported by TREE if conversion, unless the loop is marked with a simd pragma ๐ŸŽ€
  • vect-max-layout-candidates โ€” the max number of possible vector layouts, such as permutations, that get considered when optimizing code that's about to be vectorized ๐ŸŽจ
  • vect-max-version-for-alignment-checks โ€” the max number of run-time checks allowed when the vectorizer does loop versioning for alignment ๐Ÿ› ๏ธ
  • vect-max-version-for-alias-checks โ€” the max number of run-time checks allowed when the vectorizer does loop versioning for alias ๐Ÿ•ต๏ธ
  • vect-max-peeling-for-alignment โ€” the max number of loop peels the vectorizer can do to improve access alignment ๐Ÿซง A value of -1 means there's no limit ๐Ÿ”“
  • max-iterations-to-track โ€” the max number of iterations of a loop that the brute-force algorithm for figuring out a loop's iteration count will try to evaluate ๐Ÿงฎ
  • hot-bb-count-fraction โ€” the n in the fraction 1/n of the maximal execution count of a basic block in the whole program. A basic block has to hit at least that to count as hot ๐Ÿ”ฅ The default is 10000, which means a basic block is hot if its execution count is greater than 1/10000 of the maximal execution count ๐Ÿ’– A value of 0 means it's never considered hot ๐Ÿฅถ This one is used in non-LTO mode ๐Ÿงƒ
  • hot-bb-count-ws-permille โ€” how many of the most-executed permilles, from 0 to 1000, of the profiled execution of the whole program a basic block's execution count has to be part of to count as hot ๐ŸŒก๏ธ The default is 990, which means a basic block is hot if its count contributes to the upper 990 permilles, or 99.0%, of the profiled execution of the whole program โœจ A value of 0 means it's never hot ๐Ÿšซ This one is used in LTO mode ๐ŸŒ
  • hot-bb-frequency-fraction โ€” the n in the fraction 1/n of the entry block's execution frequency in a function that a basic block in that function has to reach to be hot ๐ŸŒŸ The default is 1000, which means a basic block is hot in a function if it runs more often than 1/1000 of the entry block's frequency ๐Ÿ’… A value of 0 means it's never hot ๐Ÿ™…โ€โ™€๏ธ
  • unlikely-bb-count-fraction โ€” the n in the fraction 1/n of the number of profiled runs of the whole program. If a basic block's execution count is below that, it counts as unlikely to run ๐Ÿ˜ด The default is 20, meaning a basic block is unlikely if it runs in fewer than 1/20, or 5%, of the program's runs ๐ŸŒ A value of 0 means it's always considered unlikely ๐Ÿซ 
  • max-predicted-iterations โ€” the max number of loop iterations the compiler predicts statically ๐Ÿ”ฎ This comes in clutch when a function has one loop with a known bound and another with an unknown bound ๐Ÿซถ The known count gets predicted correctly, but the unknown one averages out to roughly 10, so the unbounded loop looks artificially cold next to the other one ๐Ÿฅถ
  • builtin-expect-probability โ€” controls how likely it is that an expression has the specified value ๐ŸŽฏ This takes a percentage, from 0 to 100 ๐Ÿ’ฏ
  • builtin-string-cmp-inline-length โ€” the max length of a constant string for a builtin string cmp call that's eligible for inlining ๐Ÿงต
  • align-threshold โ€” picks a fraction of the maximal execution frequency of a basic block in a function to decide whether that block gets aligned ๐Ÿ“
  • align-loop-iterations โ€” any loop expected to iterate at least this many times gets aligned ๐Ÿช„
  • tracer-dynamic-coverage, tracer-dynamic-coverage-feedback โ€” these limit superblock formation once the given percentage of executed instructions is covered ๐Ÿงƒ That keeps the code from ballooning in size for no reason ๐ŸŽˆ

The tracer-dynamic-coverage-feedback parameter only gets used when profile feedback is available ๐Ÿ“ˆ Real profiles, unlike statically estimated ones, are much less balanced, so the threshold can be set to a larger value ๐Ÿ’ช

  • tracer-max-code-growth โ€” stops tail duplication once code growth reaches the given percentage ๐ŸŒฑ It's a pretty artificial limit, since most of the duplicates get cleaned up later in cross jumping, so it can be set way higher than the code growth you actually want ๐Ÿ™ƒ
  • tracer-min-branch-ratio โ€” stops reverse growth when the reverse probability of the best edge drops below this threshold, given as a percent ๐Ÿ“‰
  • tracer-min-branch-probability, tracer-min-branch-probability-feedback โ€” stops forward growth if the best edge has a probability lower than this threshold ๐Ÿšฆ

Like tracer-dynamic-coverage, there are two versions of this one. tracer-min-branch-probability-feedback is for compiling with profile feedback, and tracer-min-branch-probability is for compiling without it ๐Ÿง  The feedback value needs to be more conservative, meaning higher, so the tracer actually works well ๐Ÿ’œ

  • stack-clash-protection-guard-size โ€” the size of the operating system's stack guard, written as 2 raised to num bytes ๐Ÿ›ก๏ธ Higher values can reduce the number of explicit probes โœจ
โš ๏ธ If this value is larger than the operating system's guard, the code is left vulnerable to stack clash style attacks. Not it! ๐Ÿ™…โ€โ™€๏ธ
  • stack-clash-protection-probe-interval โ€” stack clash protection probes the stack space as it gets allocated ๐Ÿ”Ž This sets the max distance between probes into the stack, written as 2 raised to num bytes ๐Ÿ“ Higher values can reduce the number of explicit probes ๐ŸŒท
โš ๏ธ If this value is larger than the operating system's guard, the code is left vulnerable to stack clash style attacks. Bestie, don't let that happen ๐Ÿ˜ญ
  • max-cse-path-length โ€” โœจ okay so this is the max number of basic blocks on a path that CSE is allowed to look at ๐Ÿงš
  • max-cse-insns โ€” ๐Ÿ’… the max number of instructions CSE chews through before it flushes everything and starts fresh ๐Ÿซง
  • ggc-min-expand โ€” ๐Ÿง  GCC runs its own garbage collector to handle its memory, and this one sets the minimum percentage the GC heap can grow by between collections. Tuning it might speed up compilation, but it has zero effect on code generation, so no cap ๐Ÿ’–
    • Default: 30% + 70% * (RAM/1GB), with an upper bound of 100% when RAM >= 1GB. If getrlimit is available, "RAM" means the smallest of actual RAM and RLIMIT_DATA or RLIMIT_AS. If GCC can't work out RAM on a platform, the 30% lower bound kicks in.
    • Setting this and ggc-min-heapsize to zero forces a full collection at every opportunity. That's extremely slow ๐Ÿ’€ but it can be useful for debugging ๐Ÿ”
  • ggc-min-heapsize โ€” ๐ŸŒธ the minimum size the GC heap has to reach before it even starts bothering to collect garbage. The first collection happens once the heap grows by ggc-min-expand% beyond ggc-min-heapsize. Again, tuning this may speed up compilation and has no effect on code generation ๐Ÿฆ‹
    • Default: 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 will look backward through to find an equivalent register. Higher numbers 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 will take into account. Higher values mean more aggressive optimization, which bumps up compile time for probably slightly better performance โœจ
  • max-sched-ready-insns โ€” ๐Ÿ“ the max number of instructions that are ready to be issued that the scheduler will consider at any given moment during the first scheduling pass. Higher values mean more thorough searches, so compile time climbs with probably little benefit ๐Ÿฅฑ
  • max-sched-region-blocks โ€” ๐Ÿ—บ๏ธ the max number of blocks in a region that gets considered for interblock scheduling ๐Ÿฉท
  • max-pipeline-region-blocks โ€” ๐Ÿšฐ the max number of blocks in a region that gets considered for pipelining in the selective scheduler ๐Ÿ’œ
  • max-sched-region-insns โ€” ๐ŸŽฏ the max number of insns in a region that gets considered for interblock scheduling ๐ŸŒˆ
  • max-pipeline-region-insns โ€” ๐Ÿ› ๏ธ the max number of insns in a region that gets 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 when extending regions. Setting this to 0 disables region extensions completely ๐Ÿšซ
  • max-sched-insn-conflict-delay โ€” โณ the max conflict delay an insn can have and still be considered for speculative motion ๐ŸŒท
  • sched-spec-prob-cutoff โ€” โœ‚๏ธ the minimal probability of speculation success (in percents) needed before speculative insns actually get scheduled ๐Ÿฆ„
  • sched-state-edge-prob-cutoff โ€” ๐ŸŒŠ the minimum probability an edge has 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 that target the same memory locations ๐Ÿ’พ
  • selsched-max-lookahead โ€” ๐Ÿ‘€ the max size of the lookahead window for selective scheduling. Basically, it's how deep the search for available instructions goes ๐Ÿ•ต๏ธโ€โ™€๏ธ
  • selsched-max-sched-times โ€” ๐Ÿ”‚ the max number of times an instruction gets scheduled during selective scheduling. This is the cap on how many iterations an 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, counted as the number of RTLs, that the combiner can record in an expression for a pseudo register as that register's last known value ๐Ÿงถ
  • max-combine-insns โ€” ๐Ÿงƒ the max number of instructions the RTL combiner tries to combine together ๐Ÿน
  • integer-share-limit โ€” ๐Ÿค small integer constants can use a shared data structure, which saves the compiler memory and makes it faster. This sets the max value of a shared integer constant ๐Ÿ”ข
  • ssp-buffer-size โ€” ๐Ÿ›ก๏ธ the minimum size of buffers (aka arrays) that get stack smashing protection when -fstack-protector is used
    • Before Ubuntu 10.10 the default was "8". Right now it's "4", so more functions get protected ๐Ÿฅน
  • min-size-for-stack-sharing โ€” ๐Ÿฅž the minimum size of variables that take part in stack slot sharing when you're not optimizing ๐Ÿ™ƒ
  • max-jump-thread-duplication-stmts โ€” ๐Ÿงต the max number of statements a block can have and still be allowed to get duplicated when threading jumps ๐Ÿชก
  • max-jump-thread-paths โ€” ๐Ÿ›ค๏ธ the max number of paths to consider when hunting for jump threading opportunities. When the compiler arrives at a block, it only considers incoming edges if (paths searched so far) ร— (number of incoming edges) doesn't blow past this max ๐Ÿšฆ
  • max-fields-for-field-sensitive โ€” ๐Ÿท๏ธ the max number of fields in a structure that gets treated in a field-sensitive way 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 number. 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 โ€” ๐ŸŒ€ whether the loop array prefetch pass should issue software prefetch hints for strides that aren't constant. Sometimes that's a win, but a non-constant stride can make it hard to tell when the hints will actually help ๐Ÿค”
    • Set to 1 if prefetch hints should be issued for non-constant strides.
    • Set to 0 if prefetch hints should only be issued for strides that are known to be constant and below prefetch-minimum-stride.
  • prefetch-minimum-stride โ€” ๐Ÿ›ฃ๏ธ the minimum constant stride, in bytes, before prefetch hints start getting used. If the stride is under this threshold, no prefetch hints get issued ๐Ÿšง
    • This one's super useful for processors with hardware prefetchers, since the hardware and software prefetchers can clash. If the hardware prefetchers have a max stride they can handle, put that number here so the software prefetchers get used better ๐Ÿค
    • A value of -1 means there's no threshold, so prefetch hints can go out for any constant stride โœจ
    • This only matters for strides that are known and constant.
  • destructive-interference-size, constructive-interference-size โ€” ๐Ÿงฒ these are the values behind the C++17 variables std::hardware_destructive_interference_size and std::hardware_constructive_interference_size. The destructive interference size is the minimum recommended offset between two independent objects that are accessed concurrently. The constructive interference size is the maximum recommended size of contiguous memory that gets accessed together. Usually both match the size of an L1 cache line for the target, in bytes. For a generic target that covers a range of L1 cache line sizes, the constructive size is the small end of the range and the destructive size is the large end ๐ŸŒˆ
    • The destructive interference size is meant for layout, so it has ABI impact. Its default isn't expected to be stable, and on some targets it changes with -mtune. So using it somewhere ABI stability really matters, like a library's public interface, is strongly discouraged ๐Ÿ˜ญ If you do use it there, you can lock the value in place with this option.
    • The constructive interference size is way less sensitive. It's usually only used in a static_assert to make sure a type fits inside a cache line ๐Ÿ’…
    • See also -Winterference-size.
  • loop-interchange-max-num-stmts โ€” ๐Ÿ”„ the max number of statements in a loop that can be interchanged ๐Ÿงฎ
  • loop-interchange-stride-ratio โ€” โš–๏ธ the minimum ratio between the strides of two loops for an interchange to be profitable ๐Ÿ“ˆ
  • min-insn-to-prefetch-ratio โ€” ๐Ÿงฎ the minimum ratio between the number of instructions and the number of prefetches needed to enable prefetching in a loop ๐ŸŽฏ
  • prefetch-min-insn-to-mem-ratio โ€” ๐Ÿง  the minimum ratio between the number of instructions and the number of memory references needed to enable prefetching in a loop ๐Ÿ’–
  • use-canonical-types โ€” okay so this one is a toggle for whether the compiler uses the "canonical" type system ๐Ÿ’… It should always be 1, because that's the more efficient internal way of comparing types in C++ and Objective-C++ โœจ But if bugs in the canonical type system are causing compilation failures, set it to 0 to turn canonical types off ๐Ÿ™ˆ
  • switch-conversion-max-branch-ratio โ€” switch initialization conversion won't create arrays bigger than switch-conversion-max-branch-ratio times the number of branches in the switch ๐ŸŽ€
  • max-partial-antic-length โ€” caps the length of the partial antic set built during tree partial redundancy elimination (-ftree-pre) when you're optimizing at -O3 and up ๐Ÿ”ฅ Some code makes this optimization run totally wild and eat all the memory on the host machine ๐Ÿ’€ This limit stops that runaway behavior. Setting it to 0 means the set length is unlimited ๐Ÿฆ‹
  • rpo-vn-max-loop-depth โ€” the maximum loop depth that gets value-numbered optimistically ๐ŸŒˆ When the limit is hit, the innermost rpo-vn-max-loop-depth loops and the outermost loop in the loop nest get value-numbered optimistically, and the remaining ones don't
  • sccvn-max-alias-queries-per-access โ€” the max number of alias-oracle queries allowed while hunting for redundancies in loads and stores ๐Ÿงš If the limit is hit, the search is aborted and that load or store isn't considered redundant. The number of queries is algorithmically capped at the number of stores on all paths from the load to the function entry
  • ira-max-loops-num โ€” IRA uses regional register allocation by default โœจ If a function has more loops than this number, only that many of the most frequently executed loops form regions for regional register allocation
  • ira-max-conflict-table-size โ€” IRA is super smart about compressing its conflict table, but huge functions can still eat way too much memory ๐Ÿ˜ญ If the conflict table for a function could be bigger than this many MB, the register allocator switches to a faster, simpler, lower-quality algorithm that doesn't build a pseudo-register conflict table
  • ira-loop-reserved-regs โ€” IRA can estimate more accurate register pressure in loops, which helps it decide when to move loop invariants (see -O3) ๐Ÿ’œ This sets how many available registers are reserved for other purposes. The default is the best value found from numerous experiments
  • ira-consider-dup-in-all-alts โ€” makes IRA take matching constraints (duplicated operand numbers) seriously across all available alternatives for the preferred register class ๐Ÿ‘‘ When set to zero, IRA only respects the matching constraint when it's the only available alternative with an appropriate register class. Otherwise, IRA checks every available alternative for the preferred register class, even after it has found a qualified choice, and respects that qualified matching constraint
  • ira-simple-lra-insn-threshold โ€” the approximate number of function insns, counted in 1K units, that triggers simple local RA ๐ŸŒธ
  • lra-inheritance-ebb-probability-cutoff โ€” LRA tries to reuse values that were reloaded into registers in later insns, and this trick is called inheritance ๐Ÿซถ EBB is the region used for this optimization. This parameter sets the minimum fall-through edge probability, as a percentage, needed to add a BB to an inheritance EBB in LRA. The default was picked from numerous SPEC2000 runs on x86-64
  • loop-invariant-max-bbs-in-loop โ€” loop invariant motion can get really expensive for very large loops, both in compile time and in compile-time memory ๐Ÿ’€ Loops with more basic blocks than this parameter won't get loop invariant motion performed on them
  • loop-max-datarefs-for-datadeps โ€” building data dependencies is expensive for huge loops ๐Ÿ™ˆ This caps the number of data references in loops that get considered for data dependence analysis. Those big loops aren't handled by the optimizations that use loop data dependencies
  • max-vartrack-size โ€” the max number of hash table slots allowed while variable tracking dataflow analysis runs on any function ๐Ÿง  If this limit gets exceeded with variable tracking at assignments enabled, the analysis for that function is retried without it, after removing all debug insns from the function. If the limit is still exceeded without debug insns, var tracking analysis is completely disabled for that function. Setting it to zero makes it unlimited
  • max-vartrack-expr-depth โ€” the max number of recursion levels when mapping variable names or debug temporaries to value expressions ๐Ÿฆ‹ This trades compile time for more complete debug information. If it's set too low, value expressions that are available and could go in the debug info might not get used. Setting it higher may let the compiler find more complex debug expressions, but compile time and memory use may grow
  • max-debug-marker-count โ€” a threshold on the number of debug markers (like begin stmt markers) so things don't blow up at inlining or RTL expansion ๐Ÿ’… If a function has more of these gimple stmts than the limit, they get dropped from the inlined copy of the function, and from its RTL expansion
  • min-nondebug-insn-uid โ€” uids start at this value for nondebug insns โœจ The range below it is reserved exclusively for debug insns created by -fvar-tracking-assignments. Debug insns can still get (non-overlapping) uids above it if that reserved range runs out
  • ipa-sra-deref-prob-threshold โ€” IPA-SRA swaps a pointer that's known not to be NULL for one or more new parameters only when the probability of it being dereferenced (in percent, relative to function entry) is higher than this parameter ๐Ÿ”ฅ
  • ipa-sra-ptr-growth-factor โ€” IPA-SRA swaps a pointer to an aggregate for one or more new parameters only 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-ptrwrap-growth-factor โ€” the extra maximum growth allowed in the total size of new parameters that ipa-sra swaps a pointer to an aggregate for ๐ŸŽ€ This applies when the pointer points to a local variable that the caller only writes to and passes along as an argument to other functions
  • ipa-sra-max-replacements โ€” the max number of pieces of an aggregate that IPA-SRA tracks ๐Ÿงš That also makes it the max number of replacements for a formal parameter
  • sra-max-scalarization-size-Ospeed, sra-max-scalarization-size-Osize โ€” the two Scalar Reduction of Aggregates passes (SRA and IPA-SRA) try to swap scalar parts of aggregates for uses of independent scalar variables ๐Ÿซถ These parameters set the max size, in storage units, of an aggregate considered for replacement when compiling for speed (sra-max-scalarization-size-Ospeed) or for size (sra-max-scalarization-size-Osize), respectively
  • sra-max-propagations โ€” the max number of artificial accesses that Scalar Replacement of Aggregates (SRA) tracks per local variable, so copy propagation can happen ๐Ÿ’–
  • tm-max-aggregate-size โ€” when making copies of thread-local variables inside a transaction, this is the size in bytes after which variables get saved with the logging functions instead of save/restore code sequence pairs ๐Ÿ”ฅ This only applies when using -fgnu-tm
  • graphite-max-nb-scop-params โ€” to avoid exponential effects in the Graphite loop transforms, the number of parameters in a Static Control Part (SCoP) is capped ๐Ÿฆ‹ A value of zero lifts the cap. A variable whose value is unknown at compile time and is defined outside a SCoP counts as a parameter of the SCoP
  • hardcfr-max-blocks โ€” disables -fharden-control-flow-redundancy for functions with more blocks than this value ๐Ÿ™ˆ Zero removes any limit
  • hardcfr-max-inline-blocks โ€” forces -fharden-control-flow-redundancy to use out-of-line checking for functions with more basic blocks than this value ๐Ÿ‘‘
  • loop-block-tile-size โ€” loop blocking or strip mining (turned on with -floop-block or -floop-strip-mine) strip mines each loop in the loop nest by a given number of iterations ๐ŸŒธ You can change that strip length with this parameter
  • ipa-jump-function-lookups โ€” the number of statements visited during jump function offset discovery ๐Ÿงš
  • ipa-cp-value-list-size โ€” IPA-CP tries to track every possible value and type passed to a function's parameter so it can propagate them and do devirtualization ๐Ÿ’œ This is the max number of values and types it stores for each formal parameter of a function
  • ipa-cp-eval-threshold โ€” IPA-CP calculates its own score for cloning profitability, and it goes ahead with the cloning opportunities whose scores exceed ipa-cp-eval-threshold ๐Ÿ”ฅ
  • ipa-cp-max-recursive-depth โ€” the max depth of recursive cloning for a self-recursive function ๐ŸŒˆ
  • ipa-cp-min-recursive-probability โ€” recursive cloning only happens when the probability of the call being executed is higher than this parameter ๐Ÿ’…
  • ipa-cp-profile-count-base โ€” okay bestie, ๐Ÿ’– when you compile with -fprofile-use, IPA-CP looks at the measured execution count of a call graph edge at this percentage spot in its histogram and uses that as the basis for its heuristics ๐Ÿ“Šโœจ
  • ipa-cp-recursive-freq-factor โ€” the number of times interprocedural copy propagation expects recursive functions to call themselves ๐Ÿ”๐ŸŒธ
  • ipa-cp-recursion-penalty โ€” the percentage penalty recursive functions take when they're being evaluated for cloning ๐Ÿ“‰๐Ÿฆ‹
  • ipa-cp-single-call-penalty โ€” the percentage penalty that functions containing a single call to another function get when they're evaluated for cloning ๐Ÿ“‰๐ŸŽ€
  • ipa-max-agg-items โ€” IPA-CP can also propagate a bunch of scalar values passed inside an aggregate ๐Ÿงบ, and this one caps how many of those values you get per parameter ๐Ÿ™ˆ
  • ipa-cp-loop-hint-bonus โ€” when IPA-CP realizes a cloning candidate would make a loop's number of iterations known, it adds this bonus to the candidate's profitability score โญ๐Ÿ”ฅ
  • ipa-max-loop-predicates โ€” the max number of different predicates IPA uses to describe when loops in a function have known properties ๐Ÿง ๐Ÿ’œ
  • ipa-max-aa-steps โ€” while IPA-CP analyzes function bodies, it uses alias analysis to track values pointed to by function parameters ๐Ÿ‘€. To avoid spending forever on huge functions, it gives up after examining this many statements that modify memory and just treats all memory as clobbered ๐Ÿ’€
  • ipa-max-switch-predicate-bounds โ€” the max number of boundary endpoints of case ranges in a switch statement ๐Ÿ“. If a switch goes over this limit, IPA-CP won't build the cloning cost predicate for its default case ๐Ÿ™…โ€โ™€๏ธ
  • ipa-max-param-expr-ops โ€” IPA-CP looks at conditional statements that reference a function parameter to estimate the benefit of cloning for a certain constant value ๐Ÿ”. But if a parameter expression has more operations than this, it's considered too complicated and IPA analysis skips it ๐Ÿšซ

  • lto-partitions โ€” the desired number of partitions made during WHOPR compilation ๐Ÿงฉ. It should be bigger than the number of CPUs you're compiling with ๐Ÿ’ป
  • lto-min-partition โ€” the minimum size of a WHOPR partition, measured in estimated instructions ๐Ÿ“. This stops tiny programs from getting chopped into way too many pieces ๐Ÿ™ƒ
  • lto-max-partition โ€” the max size of a WHOPR partition, in estimated instructions ๐Ÿ“. It's basically an upper bound for how big any single partition can get ๐Ÿซถ. It's only meant to be used with balanced partitioning โš–๏ธ
  • lto-max-streaming-parallelism โ€” the max number of parallel processes used for LTO streaming ๐ŸŒŠโœจ
  • cxx-max-namespaces-for-diagnostic-help โ€” when C++ name lookup fails for an identifier, this is the max number of namespaces the compiler will check for suggestions ๐Ÿ”Ž๐Ÿ’…

  • sink-frequency-threshold โ€” the max relative execution frequency (in percent) of the target block compared to a statement's original block, which decides whether a statement can get sunk ๐Ÿ›. Bigger numbers mean more aggressive sinking ๐Ÿ”ฅ. Statements with memory operands get a small positive adjustment, since sinking them is even more profitable ๐Ÿ’œ
  • max-stores-to-sink โ€” the max number of conditional store pairs that can be sunk ๐Ÿ•ณ๏ธ. It's set 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 is the better move over a tree of conditional branches ๐ŸŒณ. If it's 0, the compiler uses the default for the machine ๐Ÿ–ฅ๏ธ
  • jump-table-max-growth-ratio-for-size โ€” the max code size growth ratio (in percent) when expanding into a jump table ๐Ÿ“ฆ. This one is used when you're optimizing for size ๐Ÿค
  • jump-table-max-growth-ratio-for-speed โ€” same deal as above: the max code size growth ratio (in percent) when expanding into a jump table ๐Ÿ“ˆ. This one is used when you're optimizing for speed ๐ŸŽ๏ธ
  • tree-reassoc-width โ€” sets the max number of instructions executed in parallel in a reassociated tree ๐Ÿงต. If it has a non-zero value, it overrides the target-dependent heuristics that would normally be used ๐Ÿ‘‘
  • sched-pressure-algorithm โ€” picks between the two available implementations of -fsched-pressure ๐Ÿง . Algorithm 1 is the original one, and it's the more likely of the two to stop instructions from getting reordered ๐Ÿ™…. Algorithm 2 was designed as a compromise between algorithm 1's pretty conservative approach and the rather aggressive approach of the default scheduler ๐ŸŽข. It leans harder on having a regular register file and accurate register pressure classes ๐Ÿ“š. For more details, check out haifa-sched.cc in the GCC sources ๐Ÿ—‚๏ธ

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

  • max-slsr-cand-scan โ€” the max number of existing candidates considered when hunting for a basis for a new straight-line strength reduction candidate ๐Ÿ”โœจ

  • asan-globals โ€” 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 ๐Ÿฅž. This is on by default when using -fsanitize=address. To turn off stack protection, use --param asan-stack=0 ๐Ÿšซ
  • asan-instrument-reads โ€” turns on buffer overflow detection for memory reads ๐Ÿ‘€. It's on by default when using -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 turn off memory writes protection, use --param asan-instrument-writes=0 ๐Ÿซ 
  • asan-memintrin โ€” turns on detection for built-in functions ๐Ÿงฐ. It's on by default when using -fsanitize=address. To turn off built-in functions protection, use --param asan-memintrin=0 โŒ
  • asan-use-after-return โ€” turns on detection of use-after-return ๐Ÿ”™. This is on by default when you use the -fsanitize=address option. To turn it off, use --param asan-use-after-return=0 ๐Ÿ’…
Heads up: this check is disabled at run time by default ๐Ÿ˜ญ. To enable it, add "detect_stack_use_after_return=1" to the ASAN_OPTIONS environment variable ๐ŸŒธ.
  • asan-instrumentation-with-call-threshold โ€” if a function being instrumented has at least this many memory accesses, the compiler uses callbacks instead of inline checks ๐Ÿ“ž. For example, to disable inline code, use --param asan-instrumentation-with-call-threshold=0 ๐Ÿงš
  • asan-kernel-mem-intrinsic-prefix โ€” if it's nonzero, calls to "memcpy", "memset" and "memmove" get prefixed with __asan_ or __hwasan_ for -fsanitize=kernel-address or -fsanitize=kernel-hwaddress, respectively ๐Ÿงฉ

  • hwasan-instrument-stack โ€” turns on hwasan instrumentation for statically sized stack-allocated variables ๐Ÿฅž. This is enabled by default with -fsanitize=hwaddress and disabled by default with -fsanitize=kernel-hwaddress ๐Ÿ”„. To turn stack instrumentation off, use --param hwasan-instrument-stack=0, and to turn it on, use --param hwasan-instrument-stack=1 ๐Ÿ’–
  • hwasan-random-frame-tag โ€” when stack instrumentation is on, tags for stack variables come from a deterministic sequence that starts at a random tag for each frame ๐ŸŽฒ. If this parameter isn't set, the tags use the same sequence but start from 1 1๏ธโƒฃ. It's enabled by default for -fsanitize=hwaddress and unavailable for -fsanitize=kernel-hwaddress ๐Ÿ™…. To turn it off, use --param hwasan-random-frame-tag=0 ๐Ÿซถ
  • hwasan-instrument-allocas โ€” turns on hwasan instrumentation for dynamically sized stack-allocated variables ๐ŸŒ€. Like the stack one, it's enabled by default with -fsanitize=hwaddress and disabled by default with -fsanitize=kernel-hwaddress ๐Ÿ”. To turn it off, use --param hwasan-instrument-allocas=0, and to turn it on, use --param hwasan-instrument-allocas=1 ๐Ÿฆ‹
  • hwasan-instrument-reads โ€” turns on hwasan checks on memory reads ๐Ÿ‘๏ธ. Read instrumentation is enabled by default for both -fsanitize=hwaddress and -fsanitize=kernel-hwaddress โœจ. To stop checking memory reads, use --param hwasan-instrument-reads=0 ๐Ÿ™ˆ
  • hwasan-instrument-writes โ€” turns on hwasan checks on memory writes โœ๏ธ. Write instrumentation is enabled by default for both -fsanitize=hwaddress and -fsanitize=kernel-hwaddress ๐Ÿ’…. To stop checking memory writes, use --param hwasan-instrument-writes=0 ๐Ÿซ 
  • hwasan-instrument-mem-intrinsics โ€” turns on hwasan instrumentation for built-in functions ๐Ÿงฐ. This is enabled by default for both -fsanitize=hwaddress and -fsanitize=kernel-hwaddress ๐Ÿ’œ. To turn off instrumentation of built-in functions, use --param hwasan-instrument-mem-intrinsics=0 โŒ

  • use-after-scope-direct-emission-threshold โ€” if a local variable's size in bytes is less than or equal to this number, the shadow memory gets poisoned (or unpoisoned) directly ๐Ÿช„, instead of going through run-time callbacks ๐Ÿ“ž
  • tsan-distinguish-volatile โ€” emits special instrumentation for accesses to volatiles โšก๐ŸŒˆ
  • tsan-instrument-func-entry-exit โ€” emits instrumentation calls to __tsan_func_entry() and __tsan_func_exit() ๐Ÿฆ‹๐Ÿ”ฅ

๐ŸŽ€ Parloops, Vectorizer, and Friends ๐ŸŽ€

okay bestie, this next batch is all --param knobs, and they're giving tuning fork energy ๐ŸŽถ each one controls how a specific optimization pass behaves ๐Ÿ’…

  • max-fsm-thread-path-insns ๐Ÿฆ‹ โ€” the max number of instructions copied when duplicating blocks on a finite state automaton jump thread path.
  • threader-debug ๐Ÿ” โ€” threader-debug=[none|all] turns on verbose dumping for the threader solver. Super useful when you're trying to see what it's thinking ๐Ÿง 
  • parloops-chunk-size ๐Ÿงฉ โ€” the chunk size of the omp schedule for loops that parloops parallelizes.
  • parloops-schedule ๐Ÿ“… โ€” the schedule type of the omp schedule for those same parallelized loops. You can pick 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 beats the single-threaded one. Heads up: for a parallelized loop nest, the minimum iterations of the outermost loop per thread is two โœจ
  • max-ssa-name-query-depth ๐ŸŒ€ โ€” how deep the recursion can go when querying properties of SSA names in things like fold routines. One level of recursion means following a use-def chain ๐Ÿ”—
  • max-speculative-devirt-maydefs ๐Ÿ‘€ โ€” the max number of may-defs we analyze while hunting for a must-def that tells us the dynamic type of an object making a virtual call we might speculatively devirtualize. Big brain stuff ๐Ÿง ๐Ÿ’œ
  • ranger-debug ๐Ÿ–จ๏ธ โ€” picks the type of debug output printed for ranges.
  • unroll-jam-min-percent ๐Ÿ“‰ โ€” the minimum percentage of memory references that have to get optimized away for unroll-and-jam to count as 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 most expensive the sequence from the RTL if-conversion pass can be for a branch that's considered unpredictable.
  • max-variable-expansions-in-unroller ๐Ÿชž โ€” if -fvariable-expansion-in-unroller is on, this caps how many times one variable gets expanded during loop unrolling.
  • partial-inlining-entry-probability ๐ŸŽฏ โ€” the max probability of the entry BB of a split region (as a percent, relative to the function's entry BB) that still lets partial inlining happen.
  • max-tracked-strlens ๐Ÿ“ โ€” how many strings the strlen optimization pass will track lengths for.
  • gcse-after-reload-partial-fraction โš–๏ธ โ€” the threshold ratio for doing partial redundancy elimination after reload.
  • gcse-after-reload-critical-fraction ๐Ÿ›ค๏ธ โ€” the threshold ratio of critical edge execution count that lets redundancy elimination happen after reload.
  • max-loop-header-insns ๐Ÿงพ โ€” the max number of insns in a loop header that the copy loop headers pass will duplicate.
  • vect-epilogues-nomask ๐Ÿง โ€” turns on loop epilogue vectorization using a smaller vector size.
  • vect-partial-vector-usage ๐Ÿงฉ โ€” decides when the loop vectorizer will use partial vector loads and stores instead of falling back to scalar code:
    • 0 means the vectorizer never uses partial vector loads and stores ๐Ÿšซ
    • 1 allows them only if vectorizing removes the need for the code to iterate
    • 2 allows them in all loops

This only does something on targets that actually support partial vector loads and stores ๐ŸŽฏ

  • vect-inner-loop-cost-factor ๐Ÿงฎ โ€” the max factor the loop vectorizer applies to the cost of statements in an inner loop, compared to the loop being vectorized. The factor used is the max of the estimated inner loop iteration count and this parameter. The default value is 50 ๐Ÿ’ฏ
  • vect-induction-float ๐ŸŒŠ โ€” enables loop vectorization of floating point inductions.
  • vrp-sparse-threshold ๐Ÿ•ธ๏ธ โ€” the max number of basic blocks before VRP switches to a sparse bitmap cache.
  • vrp-switch-limit ๐Ÿ”€ โ€” the max number of outgoing edges in a switch before VRP just skips it.
  • vrp-vector-threshold ๐Ÿ“ฆ โ€” the max number of basic blocks for VRP to use a basic cache vector.
  • avoid-fma-max-bits ๐Ÿ™…โ€โ™€๏ธ โ€” the max number of bits for which we avoid creating FMAs.
  • fully-pipelined-fma ๐Ÿšฐ โ€” whether the target fully pipelines FMA instructions. If it's non-zero, reassociation weighs the benefit of parallelizing the FMUL part and the FADD part, assuming FMUL and FMA use the same units that can also do FADD ๐Ÿง 
  • sms-loop-average-count-threshold ๐Ÿ”ข โ€” a threshold on the average loop count the swing modulo scheduler considers.
  • sms-dfa-history ๐Ÿ•ฐ๏ธ โ€” how many cycles the swing modulo scheduler looks at when checking for conflicts using DFA.
  • graphite-allow-codegen-errors ๐Ÿšจ โ€” whether codegen errors should be ICEs when -fchecking is on.
  • sms-max-ii-factor ๐ŸŽš๏ธ โ€” a factor for tuning the upper bound the swing modulo scheduler uses when scheduling a loop.
  • lra-max-considered-reload-pseudos ๐Ÿ”Ž โ€” the max number of reload pseudos considered while spilling a non-reload pseudo.
  • max-pow-sqrt-depth ๐ŸŒณ โ€” the max depth of sqrt chains used when synthesizing exponentiation by a real constant.
  • max-dse-active-local-stores ๐Ÿ—ƒ๏ธ โ€” the max number of active local stores in RTL dead store elimination.
  • asan-instrument-allocas ๐Ÿ›ก๏ธ โ€” turns on asan protection for allocas and VLAs.
  • max-iterations-computation-cost ๐Ÿ’ฐ โ€” a bound on the cost of an expression used to compute the number of iterations.
  • max-isl-operations โ™พ๏ธ โ€” the max number of isl operations. 0 means unlimited.
  • graphite-max-arrays-per-scop ๐Ÿงบ โ€” the max number of arrays per scop.
  • max-vartrack-reverse-op-size ๐Ÿ“ โ€” the max size of a loc list for which reverse ops should be added.
  • fsm-scale-path-stmts โš–๏ธ โ€” a scale factor applied to the number of statements in a threading path that crosses a loop backedge, when comparing against --param=max-jump-thread-duplication-stmts.
  • uninit-control-dep-attempts ๐Ÿ” โ€” the max number of nested calls used to search for control dependencies during uninitialized variable analysis.
  • uninit-max-chain-len โ›“๏ธ โ€” the max number of predicates anded together for each predicate ored in the normalized predicate chain.
  • uninit-max-num-chains ๐Ÿ”— โ€” the max number of predicates ored together in the normalized predicate chain.
  • sched-autopref-queue-depth ๐Ÿงญ โ€” a control flag for the hardware autoprefetcher scheduler model. It's the number of lookahead cycles the model looks into. 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 this ๐Ÿ™Œ
  • 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 the iterations or recursive calls GCC makes when optimizing certain statements or checking whether they're valid before issuing diagnostics ๐Ÿง
  • store-merging-max-size ๐Ÿ“ฆ โ€” the max size of a single store merging region, in bytes.
  • hash-table-verification-limit โœ… โ€” the number of elements that get hash table verification for each searched element.
  • max-find-base-term-values ๐Ÿ” โ€” the max number of VALUEs handled during a single find_base_term call.
  • analyzer-max-enodes-per-program-point ๐ŸŒ โ€” the max number of exploded nodes per program point in the analyzer. Once it hits this, analysis of that point stops ๐Ÿ›‘
  • analyzer-max-constraints ๐Ÿงฑ โ€” the max number of constraints per state.
  • analyzer-min-snodes-for-call-summary ๐Ÿ“ โ€” the min number of supernodes inside a function before the analyzer considers summarizing its effects at call sites.
  • analyzer-max-enodes-for-full-dump ๐Ÿ—บ๏ธ โ€” the max depth of exploded nodes that should show up in a dot dump before it switches to a less verbose format.
  • analyzer-max-recursion-depth ๐ŸŒ€ โ€” the max number of times a callsite can appear in a call stack within the analyzer. Past that, analysis of a call that would recurse deeper gets terminated ๐Ÿ›‘
  • analyzer-max-svalue-depth ๐Ÿชœ โ€” the max depth of a symbolic value before the analyzer approximates it as unknown โ”
  • analyzer-max-infeasible-edges ๐Ÿšซ โ€” the max number of infeasible edges to put up with before a diagnostic gets declared infeasible.
  • gimple-fe-computed-hot-bb-threshold ๐Ÿ”ฅ โ€” the number of executions of a basic block that counts as hot. This parameter is only used in the GIMPLE FE ๐Ÿงช
  • analyzer-bb-explosion-factor ๐Ÿ’ฅ โ€” the max number of "after supernode" exploded nodes per supernode in the analyzer, before analysis gets terminated.
  • analyzer-text-art-string-ellipsis-threshold โœ‚๏ธ โ€” the number of bytes where string literals get ellipsized in analyzer text art diagrams.
  • analyzer-text-art-ideal-canvas-width ๐Ÿ–ผ๏ธ โ€” the ideal width, in characters, of text art diagrams the analyzer generates.
  • analyzer-text-art-string-ellipsis-head-len โช โ€” the number of literal bytes shown at the head of a string literal in text art when it gets ellipsized.
  • analyzer-text-art-string-ellipsis-tail-len โฉ โ€” the number of literal bytes shown at the tail of a string literal in text art when it gets ellipsized.
  • ranger-logical-depth ๐Ÿง  โ€” the max depth of logical expression evaluation that ranger looks through when evaluating outgoing edge ranges.
  • ranger-recompute-depth ๐Ÿ”„ โ€” the max depth of instruction chains considered for recomputation in the outgoing range calculator.
  • relation-block-limit ๐Ÿšง โ€” the max number of relations the oracle will register in a basic block.
  • min-pagesize โ€” the minimum page size, used for warning purposes ๐Ÿ“„โœจ
  • openacc-kernels โ€” this one decides how OpenACC kernels constructs get handled ๐ŸŒˆ
    • --param=openacc-kernels=decompose โ€” the kernels constructs get split into parts, a sequence of compute constructs, and each part is handled individually. This is work in progress ๐Ÿšง
    • --param=openacc-kernels=parloops โ€” the kernels constructs are handled by the parloops pass, en bloc. This is the current default ๐Ÿ‘‘
  • openacc-privatization โ€” controls whether -fopt-info-omp-note and applicable -fdump-tree-*-details options print OpenACC privatization diagnostics ๐Ÿ”
    • --param=openacc-privatization=quiet โ€” no diagnostics. This is the current default ๐Ÿคซ
    • --param=openacc-privatization=noisy โ€” yep, do diagnose ๐Ÿ“ข

The following choices of name are available on AArch64 targets ๐Ÿฆพ

  • aarch64-vect-compare-costs โ€” when vectorizing, GCC can try a bunch of different approaches and let the cost model pick the cheapest one ๐Ÿ’… That includes:
    • trying both SVE and Advanced SIMD, when SVE is available
    • trying to use 64-bit Advanced SIMD vectors for the smallest data elements, instead of using 128-bit vectors for everything
    • trying to use "unpacked" SVE vectors for smaller elements. This includes 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, and prefer Advanced SIMD when the costs are deemed equal
    • 4 โ€” use both Advanced SIMD and SVE, and prefer SVE when the costs are deemed equal

The default value is 0.

  • aarch64-ldp-policy โ€” the fine-grained policy for load pairs ๐Ÿ”—
    • --param=aarch64-ldp-policy=default โ€” use the policy of the tuning structure. This is the current default ๐Ÿ‘‘
    • --param=aarch64-ldp-policy=always โ€” emit ldp regardless of alignment
    • --param=aarch64-ldp-policy=never โ€” do not emit ldp
    • --param=aarch64-ldp-policy=aligned โ€” emit ldp only if the source pointer is aligned to at least double the alignment of the type
  • aarch64-stp-policy โ€” the fine-grained policy for store pairs ๐Ÿ’œ
    • --param=aarch64-stp-policy=default โ€” use the policy of the tuning structure. This is the current default ๐Ÿ‘‘
    • --param=aarch64-stp-policy=always โ€” emit stp regardless of alignment
    • --param=aarch64-stp-policy=never โ€” do not emit stp
    • --param=aarch64-stp-policy=aligned โ€” emit stp only if the source pointer is aligned to at least double the alignment of the type
  • aarch64-ldp-alias-check-limit โ€” the limit on the number of alias checks the AArch64 load/store pair fusion pass performs when it's trying to form an ldp/stp ๐Ÿง  Higher values make the pass more aggressive about re-ordering loads over stores, but at the cost of increased compile time โณ
  • aarch64-ldp-writeback โ€” controls which writeback opportunities get handled in the AArch64 load/store pair fusion pass ๐Ÿฆ‹
    • a value of 0 disables writeback handling
    • a value of 1 means it tries to form pairs involving one or more existing individual writeback accesses where possible
    • a value of 2 means it also tries to opportunistically form writeback opportunities by folding in trailing destructive updates of the base register used by a pair
  • aarch64-loop-vect-issue-rate-niters โ€” some AArch64 CPU tuning tries to weigh both latencies and issue rates when deciding whether a loop gets vectorized with SVE, vectorized with Advanced SIMD, or not vectorized at all ๐Ÿค” If this parameter is set to n, GCC will not use this heuristic for loops that are known to execute in fewer than n Advanced SIMD iterations
  • aarch64-vect-unroll-limit โ€” the vectorizer uses available tuning information to figure out whether it would be beneficial to unroll the main vectorized loop, and by how much. This param sets the upper bound on how much the vectorizer will unroll the main loop. The default value is four ๐ŸŒท

The following choices of name are available on GCN targets ๐ŸŽฎ

  • gcn-preferred-vectorization-factor โ€” the preferred vectorization factor: default, 32, or 64 ๐Ÿ”ฅ

The following choices of name are available on i386 and x86_64 targets ๐Ÿ’ป

  • x86-stlf-window-ninsns โ€” the number of instructions above which an STFL stall penalty can be compensated ๐Ÿซถ
  • x86-stv-max-visits โ€” the maximum number of use and def visits when discovering an STV chain. If that count gets hit before discovery finishes, the discovery is aborted ๐Ÿ›‘

โœจ Program Instrumentation Options โœจ

okay so GCC can add a whole bunch of run-time instrumentation to the code it normally generates ๐Ÿ•ต๏ธโ€โ™€๏ธ๐Ÿ’… One reason to do this is to collect profiling stats so you can find program hot spots, do code coverage analysis, or run profile-guided optimizations ๐Ÿ“Š Another kind is run-time checking, which catches programming errors like invalid pointer dereferences or out-of-bounds array accesses. It also helps against deliberately hostile attacks like stack smashing or C++ vtable hijacking ๐Ÿ›ก๏ธ And there's a general hook you can use to build other forms of tracing or function-level instrumentation for debugging or program analysis ๐Ÿงฉ

  • -p, -pg โ€” generates extra code to write profile information suitable for the analysis program prof (for -p) or gprof (for -pg) ๐Ÿ“ˆ You must use this option when compiling the source files you want data about, and you must also use it when linking
    • you can use the function attribute no_instrument_function to suppress profiling of individual functions when compiling with these options ๐Ÿ™ˆ
  • -fprofile-arcs โ€” adds code so that program flow arcs are instrumented ๐Ÿน
    • during execution, the program records how many times each branch and call is executed, and how many times it is taken or returns. On targets that support constructors with priority support, profiling properly handles constructors, destructors, and C++ constructors (and destructors) of classes that are used as the type of a global variable ๐Ÿงฑ
    • when the compiled program exits, it saves this data to a file called auxname.gcda for each source file. The data may 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 it's explicitly specified and it is not the final executable. Otherwise it's the basename of the source file. In both cases any suffix is removed. For example, foo.gcda for input file dir/foo.c, or dir/foo.gcda for output file specified as -o dir/foo.o ๐Ÿ“
    • note that if a command line directly links source files, the corresponding .gcda files will be prefixed with the unsuffixed name of the output file. E.g. gcc a.c b.c -o binary would generate binary-a.gcda and binary-b.gcda files ๐ŸŒˆ
  • -fcondition-coverage โ€” adds code so that program conditions are instrumented ๐Ÿงช During execution, the program records which terms in a conditional contribute to a decision. You can use this to verify that all terms in a Boolean function are tested and have an independent effect on the outcome of a decision. The result can be read with gcov --conditions ๐Ÿฆ‹
  • --coverage โ€” the option you use to compile and link code instrumented for coverage analysis ๐ŸŽ€ It's a synonym for -fprofile-arcs -ftest-coverage (when compiling) and -lgcov (when linking). See the documentation for those options for more details ๐Ÿ“š
    1. Compile the source files with -fprofile-arcs plus optimization and code generation options. For test coverage analysis, use the additional -ftest-coverage option. You don't need to profile every source file in a program ๐Ÿ’…
    2. Compile the source files additionally with -fprofile-abs-path to create absolute path names in the .gcno files. This lets gcov find the correct sources in projects where compilations happen with different working directories ๐Ÿ—บ๏ธ
    3. Link your object files with -lgcov or -fprofile-arcs (the latter implies the former) ๐Ÿ”—
    4. Run the program on a representative workload to generate the arc profile information. This may be repeated any number of times. You can run concurrent instances of your program, and provided that the file system supports locking, the data files will be correctly updated. Unless a strict ISO C dialect option is in effect, "fork" calls are detected and correctly handled without double counting ๐Ÿด

Moreover, an object file can be recompiled multiple times, and the corresponding .gcda file merges as long as the source file and the compiler options are unchanged ๐Ÿซถ

  1. For profile-directed optimizations, compile the source files again with the same optimization and code generation options plus -fbranch-probabilities ๐Ÿ‘‘
  2. For test coverage analysis, use gcov to produce human-readable information from the .gcno and .gcda files. Refer to the gcov documentation for further information ๐Ÿง

With -fprofile-arcs, GCC builds a program flow graph for every function in your program and then finds a spanning tree for it โœจ Only the arcs that aren't on that tree need instrumenting, so the compiler just adds code to count how many times those arcs get executed ๐Ÿงš If an arc is the only exit or only entrance to a block, the counting code can go right into that block. Otherwise GCC has to make a brand new basic block to hold it ๐Ÿซถ

And with -fcondition-coverage, GCC creates a bitset for each conditional in your program and records the exercised boolean values that have an independent effect on the outcome of that expression ๐Ÿฆ‹

  • -ftest-coverage โ€” okay bestie, this one makes a notes file that the gcov code-coverage utility can use to show your program coverage ๐Ÿ“Š Each source file's notes file is called auxname.gcno. Check the -fprofile-arcs entry above for what auxname means and how to generate test coverage data. Also, coverage data matches your source files way more closely if you don't optimize ๐Ÿ’…
  • -fprofile-abs-path โ€” this automatically turns relative source file names into absolute path names inside the .gcno files ๐Ÿ—บ๏ธ That way gcov can find the right sources even 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, and used by -fprofile-use and -fbranch-probabilities plus its 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 avoid file name clashes, if the object file name isn't an absolute path, GCC mangles the absolute path of the sourcename .gcda file and uses that as the name of the .gcda file. Peek -fprofile-arcs for the full file naming details. There's also a 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 โ€” the process ID ๐Ÿ†”
    • %q{VAR} โ€” the value of the environment variable VAR ๐ŸŒธ
  • -fprofile-generate, -fprofile-generate=path โ€” this turns on the options you usually want for instrumenting an app so it can produce a profile for later recompilation with profile feedback based optimization ๐Ÿ”ฅ You must use -fprofile-generate both when compiling and when linking your program ๐Ÿšจ It enables -fprofile-arcs, -fprofile-values, -finline-functions, and -fipa-bit-cp. If path is specified, GCC looks there for the profile feedback data files (see -fprofile-dir). To optimize the program based on the collected profile information, use -fprofile-use โœจ
  • -fprofile-info-section, -fprofile-info-section=name โ€” this registers the profile information in a specified section instead of using a constructor/destructor ๐Ÿงฉ The section name is name if you give one, otherwise it defaults to .gcov_info. A pointer to the profile information made by -fprofile-arcs gets placed in that section for each translation unit. This option turns off the profile information registration through a constructor, and it also turns off the profile information processing through a destructor. Heads up: this is not meant for hosted environments like GNU/Linux ๐Ÿ™…โ€โ™€๏ธ It targets freestanding environments (like embedded systems) with limited resources that don't support constructors/destructors or C library file I/O.

The linker could collect the input sections into one continuous memory block and define start and end symbols ๐Ÿง  Here's a GNU linker script example that defines a linker output section:

.gcov_info      :
{
  PROVIDE (__gcov_info_start = .);
  KEEP (*(.gcov_info))
  PROVIDE (__gcov_info_end = .);
}

The program could then dump the profiling information registered in this linker set. For example, like this ๐ŸŽ€

#include <gcov.h>
#include <stdio.h>
#include <stdlib.h>

extern const struct gcov_info *const __gcov_info_start[];
extern const struct gcov_info *const __gcov_info_end[];

static void
dump (const void *d, unsigned n, void *arg)
{
  const unsigned char *c = d;

  for (unsigned i = 0; i < n; ++i)
    printf ("%02x", c[i]);
}

static void
filename (const char *f, void *arg)
{
  __gcov_filename_to_gcfn (f, dump, arg );
}

static void *
allocate (unsigned length, void *arg)
{
  return malloc (length);
}

static void
dump_gcov_info (void)
{
  const struct gcov_info *const *info = __gcov_info_start;
  const struct gcov_info *const *end = __gcov_info_end;

  /* Obfuscate variable to prevent compiler optimizations.  */
  __asm__ ("" : "+r" (info));

  while (info != end)
  {
    void *arg = NULL;
    __gcov_info_to_gcda (*info, filename, dump, allocate, arg);
    putchar ('\n');
    ++info;
  }
}

int
main (void)
{
  dump_gcov_info ();
  return 0;
}

The merge-stream subcommand of gcov-tool can deserialize the data stream generated by the __gcov_filename_to_gcfn and __gcov_info_to_gcda functions, then merge the profile information into .gcda files on the host filesystem ๐Ÿ’œ

  • -fprofile-note=path โ€” if path is specified, GCC saves the .gcno file into that location ๐Ÿ“ Heads up: 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 will contain files with mangled absolute paths of all object files in the built project. That's not ideal when the directory used to build the instrumented binary is different from the one used to build the binary optimized with profile feedback, because the profile data won't be found during the optimized build ๐Ÿ’€ In setups like that, -fprofile-prefix-path=path, with path pointing to the base directory of the build, strips the irrelevant part of the path and keeps all file names relative to the main build directory โœจ
  • -fprofile-prefix-map=old=new โ€” when compiling files living in directory old, GCC records their profiling information (with --coverage) as if they lived in directory new instead ๐Ÿ—บ๏ธ See also -ffile-prefix-map and -fcanon-prefix-map.
  • -fprofile-update=method โ€” this changes the update method for an app instrumented for profile feedback based optimization ๐Ÿ”„ The method argument should be one of single, atomic, or prefer-atomic. The first one is good for single-threaded apps, and the second one prevents profile corruption by emitting thread-safe code ๐Ÿงต
Warning: When an application doesn't properly join all threads (or creates a detached thread), a profile file can still get corrupted ๐Ÿ˜ฑ

Using prefer-atomic gets transformed either into atomic (when the target supports it) or into single otherwise. The GCC driver automatically picks prefer-atomic when -pthread is in the command line. Otherwise the default method is single ๐ŸŽ€

If atomic is selected, the profile information is updated using atomic operations on a best-effort basis. Ideally, it's updated through atomic operations in hardware. If the target platform doesn't support the required atomic operations in hardware, but libatomic is available, the profile information gets updated through calls to libatomic. If the target platform supports neither the required hardware atomics nor libatomic, the profile information is not atomically updated and a warning is issued. In that case, the profiling information may be corrupt for multi-threaded applications ๐Ÿฅฒ

For performance reasons, if 64-bit counters are used for the profiling information and the target platform only supports 32-bit atomic operations in hardware, then the performance critical profiling updates are done using two 32-bit atomic operations for each counter update. If a signal interrupts these two operations while updating a counter, the profiling information may end up in an inconsistent state ๐Ÿ™ˆ

  • -fprofile-filter-files=regex โ€” instruments only the functions from files whose name matches any of the regular expressions (separated by semicolons) ๐Ÿ” 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 the functions from files whose name does not match any of the regular expressions (separated by semicolons) ๐Ÿšซ For example, -fprofile-exclude-files=/usr/.* will prevent instrumentation of all files located in the /usr/ folder ๐Ÿ™…โ€โ™€๏ธ
  • -fprofile-reproducible=[multithreaded|parallel-runs|serial] โ€” controls the level of reproducibility of the profile gathered by -fprofile-generate ๐Ÿง This makes it possible to rebuild a program with the same outcome, which is super useful for things like distribution packages ๐Ÿ“ฆ With -fprofile-reproducible=serial, the profile gathered by -fprofile-generate is reproducible, provided the trained program behaves the same at each invocation of the train run, it is not multi-threaded, and profile data streaming is always done in the same order ๐Ÿ’… Note that profile streaming happens at the end of the program run, but also before the fork function is invoked ๐Ÿซถ

Okay so bestie, here's the deal with reproducibility ๐Ÿงšโœจ: execution counts in some parts of a program can depend on stuff like how long temporary file names are, or on memory space randomization (which can shift the hash-table collision rate) ๐Ÿ™ˆ. That non-reproducible bit can be marked with the "no_instrument_function" function attribute ๐Ÿ’…. And if you want to check that your gathered data is actually reproducible, gcov-dump with -l can dump it out so you can see for yourself ๐Ÿ”.

With -fprofile-reproducible=parallel-runs, the collected profile stays reproducible no matter what order the data gets streamed into the gcda files ๐Ÿ’–. This is the move if you want to run multiple instances of your instrumented program in parallel, like with make -j ๐Ÿƒโ€โ™€๏ธ. Just know it's a trade-off: it reduces the quality of the gathered data, especially for indirect call profiling ๐Ÿ˜ญ.

  • -fsanitize=address โ€” Turns on AddressSanitizer ๐Ÿฆ‹, a super fast memory error detector. Memory access instructions get instrumented to catch out-of-bounds and use-after-free bugs, and it also enables -fsanitize-address-use-after-scope. More details live at https://github.com/google/sanitizers/wiki/AddressSanitizer. Run-time behavior can be tweaked with the ASAN_OPTIONS environment variable, and if you set it to "help=1", the available options get shown when your instrumented program starts. For the full list of supported options, peep https://github.com/google/sanitizers/wiki/AddressSanitizerFlags#run-time-flags. This one can't be combined with -fsanitize=thread or -fsanitize=hwaddress ๐Ÿ™…โ€โ™€๏ธ, and the only target -fsanitize=hwaddress is currently supported on is AArch64.

To get more accurate stack traces ๐Ÿ”ฅ, you can use options like -O0, -O1, or -Og (which, for instance, prevent most function inlining), -fno-optimize-sibling-calls (which stops sibling and tail recursive calls from getting optimized; this option is implicit for -O0, -O1, or -Og), or -fno-ipa-icf (which disables Identical Code Folding for functions). Since multiple runs of the program can give you backtraces with different addresses thanks to ASLR (Address Space Layout Randomization), it may be desirable to turn ASLR off ๐ŸŒˆ. On Linux, you can do that with:

setarch `uname -m` -R ./prog
  • -fsanitize=kernel-address โ€” Enables AddressSanitizer for the Linux kernel ๐Ÿง. Check out https://github.com/google/kernel-sanitizers for more details.
  • -fsanitize=hwaddress โ€” Hardware-assisted AddressSanitizer ๐Ÿ› ๏ธ uses a hardware ability to ignore the top byte of a pointer, so it can catch memory errors with a low memory overhead ๐Ÿ’œ. Memory access instructions get instrumented to detect out-of-bounds and use-after-free bugs. It enables -fsanitize-address-use-after-scope. See https://clang.llvm.org/docs/HardwareAssistedAddressSanitizerDesign.html for more details. Run-time behavior is influenced through the HWASAN_OPTIONS environment variable, and when it's set to "help=1", the available options show at startup of the instrumented program. It can't be combined with -fsanitize=thread or -fsanitize=address, and it's currently only available on AArch64 ๐Ÿ™ƒ.
  • -fsanitize=kernel-hwaddress โ€” Enables Hardware-assisted AddressSanitizer for compiling the Linux kernel ๐Ÿงโœจ. It's similar to -fsanitize=kernel-address but uses an alternate instrumentation method, and it's similar to -fsanitize=hwaddress but with the instrumentation differences the kernel needs. Those differences exist to avoid hwasan library initialization calls, and to account for the stack pointer having a different value in its top byte.
Note: This option has different defaults to -fsanitize=hwaddress. Instrumenting the stack and alloca calls is not on by default, but it's still possible by specifying the command-line options --param hwasan-instrument-stack=1 and --param hwasan-instrument-allocas=1 respectively. Using a random frame tag is not implemented for kernel instrumentation.
  • -fsanitize=pointer-compare โ€” Instruments comparison operations (<, <=, >, >=) with pointer operands ๐Ÿ”. It must be combined with either -fsanitize=kernel-address or -fsanitize=address, and it can't be combined with -fsanitize=thread. 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 operation when both pointers are non-null.
  • -fsanitize=pointer-subtract โ€” Instruments subtraction with pointer operands โž–. It must be combined with either -fsanitize=kernel-address or -fsanitize=address, and it can't be combined with -fsanitize=thread. Note: by default the check is disabled at run time ๐Ÿ˜ด. To enable it, add "detect_invalid_pointer_pairs=2" to the ASAN_OPTIONS environment variable. Using "detect_invalid_pointer_pairs=1" only detects invalid operation when both pointers are non-null.
  • -fsanitize=shadow-call-stack โ€” Enables ShadowCallStack ๐Ÿ›ก๏ธ, a security enhancement that protects programs against return address overwrites (like stack buffer overflows.) It works by saving a function's return address to a separately allocated shadow call stack in the function prologue, then restoring the return address from the shadow call stack in the function epilogue. Instrumentation only happens in functions that need to save the return address to the stack.

Heads up, this one's picky ๐Ÿ’…: it's currently only supported on the aarch64 platform. It's specifically designed for Linux kernels that enable the CONFIG_SHADOW_CALL_STACK option. For user space programs, runtime support isn't currently provided in libc and libgcc, so if you want this feature in user space, you need to provide your own runtime support. It should be noted that this may cause the ABI rules to be broken ๐Ÿšจ.

On aarch64, the instrumentation makes use of the platform register "x18" ๐Ÿง . That generally means any code that may run on the same thread as code compiled with ShadowCallStack must be compiled with the flag -ffixed-x18. Otherwise, functions compiled without -ffixed-x18 might clobber "x18" and corrupt the shadow stack pointer ๐Ÿ’€.

Also, because there's no userspace runtime support, code compiled with ShadowCallStack can't use exception handling. Use -fno-exceptions to turn off exceptions ๐Ÿ™…โ€โ™€๏ธ. See https://clang.llvm.org/docs/ShadowCallStack.html for more details.

Note that sanitized atomic builtins cannot throw exceptions when operating on invalid memory addresses with non-call exceptions (-fnon-call-exceptions).
  • -fsanitize=leak โ€” Enables LeakSanitizer ๐Ÿ’ง, a memory leak detector. This option only matters for linking executables. The executable gets linked against a library that overrides "malloc" and other allocator functions. See https://github.com/google/sanitizers/wiki/AddressSanitizerLeakSanitizer for more details. The run-time behavior can be influenced using the LSAN_OPTIONS environment variable. It can't 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 using the UBSAN_OPTIONS environment variable. These are the current suboptions:
    • -fsanitize=shift โ€” Checks that the result of a shift operation isn't undefined ๐Ÿซถ. What's considered undefined differs slightly between C and C++, as well as between ISO C90 and C99, etc. This option has two suboptions, -fsanitize=shift-base and -fsanitize=shift-exponent.
    • -fsanitize=shift-exponent โ€” Checks that the second argument of a shift operation isn't negative and is smaller than the precision of the promoted first argument.
    • -fsanitize=shift-base โ€” If the second argument of a shift operation is within range, checks that the result of the shift isn't undefined. What's considered undefined differs slightly between C and C++, as well as between ISO C90 and C99, etc.
    • -fsanitize=integer-divide-by-zero โ€” Detects integer division by zero โž—.
    • -fsanitize=unreachable โ€” The compiler turns the __builtin_unreachable call into a diagnostics message call instead. When you reach the __builtin_unreachable call, the behavior is undefined ๐Ÿ’€.
    • -fsanitize=vla-bound โ€” Tells the compiler to check that the size of a variable length array is positive ๐Ÿ“.
    • -fsanitize=null โ€” Enables pointer checking ๐Ÿ‘€. Apps built with this on will throw an error message 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 is invoked on an object pointed to by a NULL pointer.
    • -fsanitize=return โ€” Enables return statement checking ๐Ÿ”™. Programs built with this on will throw an error message when the end of a non-void function is reached without actually returning a value. This option works in C++ only.
    • -fsanitize=signed-integer-overflow โ€” Enables signed integer overflow checking โž•. It checks that the result of "+", "*", and both unary and binary "-" doesn't overflow in signed arithmetic. This also detects INT_MIN / -1 signed division. Heads up, integer promotion rules have to be taken into account, which means the following is not an overflow ๐Ÿ™ˆ:
signed char a = SCHAR_MAX;
a++;
  • -fsanitize=bounds โ€” okay so this one turns on array bounds instrumentation ๐ŸŽ€ and catches a bunch of out-of-bounds accesses ๐Ÿ’…. Flexible array members, flexible-array-member-like arrays, and initializers of variables with static storage are not instrumented, with one exception: flexible-array-member-like arrays that -fstrict-flex-arrays, -fstrict-flex-arrays=, or the strict_flex_array attribute say shouldn't be treated that way do get checked ๐Ÿฆ‹
  • -fsanitize=bounds-strict โ€” the stricter, no-excuses version ๐Ÿ”ฅ It catches most out-of-bounds accesses, including flexible-array-member-like arrays. Initializers of variables with static storage still aren't instrumented ๐Ÿ™ˆ
  • -fsanitize=alignment โ€” checks pointer alignment when a pointer gets dereferenced ๐ŸŒธ It also checks when a reference is bound to an insufficiently aligned target, and when a method or constructor gets called on an insufficiently aligned object โœจ
  • -fsanitize=object-size โ€” instruments memory references using the __builtin_dynamic_object_size function ๐Ÿงš It's how 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 dividing by zero in floating point can be a legit way to get infinities and NaNs ๐Ÿคทโ€โ™€๏ธ
  • -fsanitize=float-cast-overflow โ€” enables checking whenever a floating-point value gets converted to an integer ๐Ÿ’– It makes sure the result of that conversion doesn't overflow โœจ Also, this one is not turned on by -fsanitize=undefined, just like the other special ones ๐Ÿ“
Heads up bestie: this option does not work well with FE_INVALID exceptions enabled ๐Ÿ˜ญ
  • -fsanitize=nonnull-attribute โ€” instruments calls to check that null values aren't passed to arguments marked as requiring a non-null value by the nonnull function attribute ๐Ÿซถ
  • -fsanitize=returns-nonnull-attribute โ€” instruments return statements in functions marked with the returns_nonnull function attribute ๐Ÿฆ‹ It catches those functions returning null values, which is a big no-no ๐Ÿ’€
  • -fsanitize=bool โ€” instruments loads from bool ๐Ÿ’œ If a value other than 0/1 gets loaded, you get a run-time error ๐Ÿšจ
  • -fsanitize=enum โ€” instruments loads from an enum type ๐Ÿ“ If a value outside the enum's range of values gets loaded, a run-time error is issued ๐Ÿ’…
  • -fsanitize=vptr โ€” instruments C++ member function calls, member accesses, and some conversions between pointers to base and derived classes ๐Ÿ‘‘ It verifies the referenced object has the correct dynamic type, so nothing sneaky happens ๐Ÿงš
  • -fsanitize=pointer-overflow โ€” instruments pointer arithmetic ๐ŸŒธ If the pointer arithmetic overflows, a run-time error is issued ๐Ÿ”ฅ
  • -fsanitize=builtin โ€” instruments the 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 ๐Ÿ™ˆ

Quick vibe check on sanitizers in general: they tend to bring along extra false positive warnings, especially the ones around -Wmaybe-uninitialized ๐Ÿ˜ญ We recommend against combining -Werror and the use of sanitizers, so you don't get stuck on warnings that aren't even real ๐Ÿซถ

While -ftrapv causes traps for signed overflows to be emitted, -fsanitize=undefined gives a diagnostic message instead ๐Ÿ’– This currently works only for the C family of languages ๐ŸŒˆ

  • -fno-sanitize=all โ€” disables all the sanitizers you turned on before ๐Ÿงน Note that -fsanitize=all is not allowed, because some sanitizers can't be used together ๐Ÿ’€
  • -fasan-shadow-offset=number โ€” forces GCC to use a custom shadow offset in AddressSanitizer checks โœจ It's super useful for experimenting with different shadow memory layouts in Kernel AddressSanitizer ๐Ÿงช
  • -fsanitize-sections=s1,s2,... โ€” sanitizes global variables in selected user-defined sections ๐Ÿฆ‹ Each si may contain wildcards ๐ŸŒธ
  • -fsanitize-recover[=opts] โ€” okay this one controls the error recovery mode for the sanitizers in the comma-separated list of opts ๐Ÿ’… When recovery is enabled for a sanitizer, the program keeps running like no error happened ๐Ÿซ  That means multiple runtime errors can get reported in one run, and the exit code may say success even when errors were reported ๐Ÿ™ˆ

The -fno-sanitize-recover= option flips that around: only the first detected error gets reported, and then the program exits with a non-zero exit code ๐Ÿšซ

Right now this feature only works for -fsanitize=undefined (and its suboptions, except -fsanitize=unreachable and -fsanitize=return), -fsanitize=float-cast-overflow, -fsanitize=float-divide-by-zero, -fsanitize=bounds-strict, -fsanitize=kernel-address, and -fsanitize=address ๐ŸŒˆ For these sanitizers, error recovery is turned on by default, except for -fsanitize=address, where it's still experimental ๐Ÿงช

-fsanitize-recover=all and -fno-sanitize-recover=all are also accepted ๐Ÿ’œ The first enables recovery for all sanitizers that support it, and the second disables recovery for all sanitizers that support it โœจ

Even if recovery mode 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 value for AddressSanitizer is halt_on_error=1 ๐ŸŽ€ You can override this by setting the halt_on_error flag in the corresponding environment variable ๐ŸŒธ

Syntax without an explicit opts parameter is deprecated ๐Ÿ™…โ€โ™€๏ธ It's equivalent to specifying this opts list:

        undefined,float-cast-overflow,float-divide-by-zero,bounds-strict
  • -fsanitize-address-use-after-scope โ€” enables sanitization of local variables so you can catch use-after-scope bugs ๐Ÿ•ต๏ธโ€โ™€๏ธ This option sets -fstack-reuse to none ๐Ÿซถ
  • -fsanitize-trap[=opts] โ€” this one tells the compiler to report undefined behavior for the sanitizers in the comma-separated opts list using __builtin_trap instead of a libubsan library routine ๐Ÿชค If it's enabled for a sanitizer, it takes precedence over -fsanitizer-recover= for that sanitizer, so __builtin_trap gets emitted and it's fatal whether recovery is on or off ๐Ÿ’€
    • The big perk is that the libubsan library isn't needed and isn't linked in, so this works even in freestanding environments ๐Ÿงš
    • Right now it works with -fsanitize=undefined (and its suboptions, except -fsanitize=vptr), -fsanitize=float-cast-overflow, -fsanitize=float-divide-by-zero, and -fsanitize=bounds-strict ๐ŸŒˆ
    • -fsanitize-trap=all can also be specified, which enables it for the undefined suboptions, -fsanitize=float-cast-overflow, -fsanitize=float-divide-by-zero, and -fsanitize=bounds-strict ๐Ÿ’–
    • If -fsanitize-trap=undefined or -fsanitize-trap=all is used and -fsanitize=vptr is enabled on the command line, the instrumentation is silently ignored ๐Ÿค That's because the instrumentation always needs libubsan support ๐Ÿ“š
    • -fsanitize-trap=vptr is not allowed ๐Ÿšซ
  • -fsanitize-undefined-trap-on-error โ€” this one is deprecated, but it's an equivalent of -fsanitize-trap=all ๐Ÿฅ€
  • -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 ๐Ÿ” Here's who gets called when:
    • __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] โ€” enables code instrumentation of control-flow transfers to boost program security ๐Ÿ›ก๏ธ It checks that the 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 some unexpected target ๐Ÿ‘‘ This is meant to protect against threats like Return-oriented Programming (ROP), and similarly 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 is an alias for specifying both branch and return ๐Ÿ’œ
    • none turns off instrumentation ๐Ÿšซ
    • check is 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 ๐Ÿ™ƒ

To override -fcf-protection, you need to add -fcf-protection=none and then add -fcf-protection=xxx after it ๐Ÿ”

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

You can also use the nocf_check attribute to identify which functions and calls should be skipped from instrumentation ๐Ÿ™…โ€โ™€๏ธ

Currently, the x86 GNU/Linux target provides an implementation based on Intel Control-flow Enforcement Technology (CET), which works for i686 processors or newer ๐Ÿ’ป

NOTE: NOTE: In Ubuntu 19.10 and later versions, -fcf-protection gets turned on by default for C, C++, ObjC, and ObjC++ ๐ŸŒˆ, as long as neither -fno-cf-protection nor -fcf-protection=* shows up in your command ๐Ÿซถ.

๐ŸŽ€ -fharden-compares

okay so this one goes after every logical test that makes it through gimple optimizations and isn't the condition in a conditional branch ๐Ÿ‘€. Think conditional moves, or tests stored in boolean variables. GCC adds extra code that computes and verifies the reversed condition, and if the results don't match it calls __builtin_trap ๐Ÿ’€. Pair it with -fharden-conditional-branches to cover all the conditionals, bestie โœจ.

๐Ÿฆ‹ -fharden-conditional-branches

For every non-vectorized conditional branch that survives gimple optimizations, GCC adds extra code that computes and verifies the reversed condition ๐Ÿ”ฅ. If the result is unexpected, it calls __builtin_trap. Use it with -fharden-compares so nothing slips through ๐Ÿ’….

๐ŸŒธ -fharden-control-flow-redundancy

this one is giving main character energy ๐Ÿ‘‘. GCC emits extra code that sets booleans when it enters basic blocks, then at function exits it verifies them and traps if they don't form an execution path that matches the control flow graph ๐Ÿ˜ญ.

The verification happens before returns, and before mandatory tail calls (more on those below). It can also happen, if you ask for it, before escaping exceptions with -fhardcfr-check-exceptions, before returning calls with -fhardcfr-check-returning-calls, and before noreturn calls with -fhardcfr-check-noreturn-calls. There are tuning knobs too: --param hardcfr-max-blocks and --param hardcfr-max-inline-blocks โš™๏ธ.

Tail call optimization happens too late to mess with control flow redundancy ๐Ÿ™ˆ. Calls that language front-ends mark as mandatory tail calls, and any calls marked early enough as potential tail calls, would also get verification before the call. But honestly these cases are merely theoretical, since they can only come up when you're using custom compiler plugins ๐Ÿงš.

๐Ÿงš -fhardcfr-skip-leaf

Disables -fharden-control-flow-redundancy in leaf functions ๐ŸŒฟ.

๐Ÿ’œ -fhardcfr-check-exceptions

When -fharden-control-flow-redundancy is active, the recorded execution path gets checked against the control flow graph at exception escape points ๐Ÿฆ‹. It's like the function body is wrapped in a cleanup handler that does the check and then reraises. This one is enabled by default โœจ. If you want it gone, use -fno-hardcfr-check-exceptions.

๐Ÿ“ -fhardcfr-check-returning-calls

When -fharden-control-flow-redundancy is active, the recorded path gets checked before any function call that's immediately followed by a return of its result (if it has one) ๐Ÿ’…. This keeps tail-call optimization working, whether or not the call actually ends up optimized into a tail call.

This option is enabled by default whenever sibling call optimizations are on (see -foptimize-sibling-calls) ๐Ÿซถ. But you can flip it on or off explicitly with its negated form, no matter what the optimizations are doing.

๐ŸŒˆ -fhardcfr-check-noreturn-calls=[always|no-xthrow|nothrow|never]

When -fharden-control-flow-redundancy is active, the recorded path gets checked before noreturn calls. You get to pick which ones:

  • always โ€” checks before all of them ๐Ÿ”’
  • no-xthrow โ€” checks before those not expected to return control to the caller through an exception. This is the default ๐Ÿ’–
  • nothrow โ€” checks before those that may not return control to the caller through an exception either ๐ŸŒธ
  • never โ€” checks before none of them ๐Ÿ™…

Checking before a noreturn function that may return control through an exception can get you checked more than once, if the caller catches that exception with a handler or a cleanup ๐Ÿ˜ญ. When -fhardcfr-check-exceptions is also on, the compiler skips associating a noreturn call with the implicit cleanup handler, since it'd be redundant with the check before the call โœจ. Other handlers or cleanups in the function, if they're activated, will modify the recorded path and check it again when another checkpoint gets hit. That checkpoint could even be another noreturn call, so the checking may end up happening multiple times ๐Ÿ”.

Okay here's the tea โ˜•. Various optimizers may cause calls to be marked noreturn and/or nothrow even without the matching attributes, and that can shift where checks land before calls, as well as which implicit cleanup handlers get added ๐Ÿ™ˆ. That unpredictability, plus the fact that raising and reraising exceptions often amounts to implicitly calling noreturn functions, is why no-xthrow is the default. It excludes from the noreturn treatment only the internal functions used to (re)raise exceptions, which those optimizations don't touch ๐Ÿ’….

๐Ÿ‘‘ -fhardened

Enables a set of flags for C and C++ that boost the security of the generated code without messing with its ABI ๐Ÿ›ก๏ธ. The exact flags can change between major GCC releases, but right now they are:

-D_FORTIFY_SOURCE=3 -D_GLIBCXX_ASSERTIONS
-ftrivial-auto-var-init=zero -fPIE  -pie  -Wl,-z,relro,-z,now
-fstack-protector-strong -fstack-clash-protection
-fcf-protection=full (x86 GNU/Linux only)

You can see the whole list yourself with --help=hardened ๐Ÿ‘€.

If the system glibc is older than 2.35, -D_FORTIFY_SOURCE=2 gets used instead ๐Ÿงธ.

This option is meant for production builds, not just debug builds. It's not a debug-only vibe ๐Ÿ’€.

Right now -fhardened only works on GNU/Linux targets ๐Ÿง.

Also, -fhardened only turns on a particular option if you haven't already specified it somewhere on the command line ๐Ÿ™…. For example, -fhardened -fstack-protector will only enable -fstack-protector, but not -fstack-protector-strong โœจ.

๐Ÿ›ก๏ธ -fstack-protector

Emits extra code to check for buffer overflows, like stack smashing attacks ๐Ÿšจ. It works by adding a guard variable to functions with vulnerable objects. That includes functions that call alloca, and functions with buffers larger than or equal to 8 bytes. The guards get initialized when the 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. Optimized-away variables or variables living in registers don't ๐Ÿง .

๐Ÿ›ก๏ธ -fstack-protector-all

Like -fstack-protector, except all functions get protected ๐Ÿซก.

๐Ÿ›ก๏ธ -fstack-protector-strong

Like -fstack-protector, but it also protects extra functions: 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 or register variables don't.

NOTE: In Ubuntu 14.10 and later versions, -fstack-protector-strong is enabled by default for C, C++, ObjC, ObjC++, if none of -fno-stack-protector, -nostdlib, nor -ffreestanding are found ๐ŸŒธ.

๐Ÿ›ก๏ธ -fstack-protector-explicit

Like -fstack-protector, but it only protects functions that have the stack_protect attribute ๐ŸŽฏ.

๐Ÿงญ -fstack-check

Generates code to verify that you don't go past the boundary of the stack ๐Ÿงญ. You should specify this if you're running in an environment with multiple threads ๐Ÿงต. In a single-threaded environment you rarely need it, because stack overflow is automatically detected on nearly all systems if there's only one stack ๐Ÿ’….

Here's the tea: this switch doesn't actually do the checking ๐Ÿซ . The operating system or the language runtime has to do that. The switch just makes the code that ensures they see the stack being extended ๐Ÿ‘€.

You can also pass 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. It doesn't need any specific target support in the compiler, but it comes with some drawbacks ๐Ÿ˜ญ:

  1. Modified allocation strategy for large objects. They're always allocated dynamically if their size goes over 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's topped by a particular function, stack checking isn't reliable and the compiler issues a warning ๐Ÿšฉ.
  3. Inefficiency. Because of both the modified allocation strategy and the generic implementation, code performance takes a hit ๐ŸŒ.

Old-style stack checking is also the fallback for specific if the compiler has no target support added for it ๐Ÿ”.

-fstack-check= was 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 enough to protect against stack-clash attacks though. For that you want -fstack-clash-protection ๐Ÿซถ.

๐Ÿง— -fstack-clash-protection

Generates code to prevent stack clash style attacks ๐Ÿง—. When this is enabled, the compiler only allocates one page of stack space at a time, and each page gets accessed right after allocation. That way, allocations can't jump over any stack guard page the operating system provides ๐Ÿ›‘.

Most targets don't fully support stack clash protection ๐Ÿ™ˆ. On those that do, -fstack-clash-protection protects dynamic stack allocations. It may also give limited protection for static stack allocations if the target supports -fstack-check=specific ๐ŸŒˆ.

NOTE: In Ubuntu 19.10 and later versions, -fstack-clash-protection is enabled by default for C, C++, ObjC, and ObjC++, unless -fno-stack-clash-protection is found ๐Ÿ’….

๐Ÿšง -fstack-limit-register=reg ยท -fstack-limit-symbol=sym ยท -fno-stack-limit

Generates code to make sure the stack doesn't grow beyond a certain value, either the value of a register or the address of a symbol ๐Ÿšง. If a larger stack is needed, a signal gets raised at run time ๐Ÿ“ก. For most targets the signal is raised before the stack overruns the boundary, so you can catch it without taking any 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, so heads up, bestie.

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

  • -fsplit-stack โ€” Okay, this one is giving main character energy ๐Ÿ‘‘ It generates code that automatically splits the stack before it overflows. The result is a discontiguous stack that can only overflow if the program runs out of memory to allocate. It's most useful for threaded programs, because you no longer have to figure out a good stack size for each thread. ๐Ÿงต Right now it's only implemented for x86 targets running GNU/Linux, so keep that in mind ๐Ÿซถ

When code compiled with -fsplit-stack calls code compiled without -fsplit-stack, the latter code may not have much stack space to run in. ๐Ÿ˜ฌ If compiling all your code, library code included, with -fsplit-stack isn't an option, the linker can fix up those calls so the code compiled without -fsplit-stack always gets a large stack. ๐Ÿฆ‹ This is supported in the gold linker in GNU binutils release 2.21 and later.

  • -fstrub=disable โ€” Disable stack scrubbing entirely, ignoring any "strub" attributes. ๐Ÿงน See
  • -fstrub=strict โ€” Functions default to "strub" mode "disabled", and the strict rule applies: only functions tied to "strub"-"callable" modes ("at-calls", "callable" and "always_inline" "internal") can be called by functions with "strub"-enabled modes ("at-calls" and "internal"). ๐Ÿ”’
  • -fstrub=relaxed โ€” Restores the default stack scrub ("strub") setting. That means "strub" only gets enabled when the "strub" attributes on functions and data types ask for it. ๐ŸŒธ Relaxed means strub contexts can only be blocked from calling functions that are explicitly tied to "strub" mode "disabled". This option is only useful for overriding other -fstrub=* options that come before it on the command line. ๐Ÿ”
  • -fstrub=at-calls โ€” Enables "at-calls" "strub" mode wherever it's viable. ๐Ÿงช The main use is testing: it exercises the "strub" machinery in scenarios that stay strictly local to a translation unit. This mode changes function interfaces, so any function visible to other translation units, or any function whose address is taken, won't be affected by this option. Optimization options can also affect viability. Check the "strub" attribute documentation for the details on viability and eligibility requirements. ๐Ÿ“š
  • -fstrub=internal โ€” Enables "internal" "strub" mode wherever it's viable. ๐Ÿงช The primary use is testing. This option is meant to thoroughly exercise the parts of the "strub" machinery that implement the less efficient, but interface-preserving, "strub" mode. Functions that wouldn't be affected by this option are pretty uncommon. ๐Ÿคทโ€โ™€๏ธ
  • -fstrub=all โ€” Enables some "strub" mode wherever it's viable. โœจ When both strub modes are viable, "at-calls" is preferred. -fdump-ipa-strubm adds function attributes that tell you which mode was selected for each function. The main use is testing, to thoroughly exercise the "strub" machinery. ๐Ÿ’…
  • -fvtable-verify=[std|preinit|none] โ€” This one's C++ only, so it's for my fellow C++ girlies ๐Ÿ’œ It turns on (or off, if you use -fvtable-verify=none) the security feature that checks at run time, for every virtual call, that the vtable pointer used for that call is valid for the object's type and hasn't been corrupted or overwritten. ๐Ÿ›ก๏ธ If an invalid vtable pointer is detected at run time, an error gets reported and the program halts immediately. ๐Ÿ’€

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

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

  • -fvtv-debug โ€” Used together with -fvtable-verify=std or -fvtable-verify=preinit, this makes the debug versions of the vtable verification runtime functions get called. ๐Ÿ› It also makes the compiler log which vtable pointers it finds for each class. That info gets written to a file named vtv_set_ptr_data.log in the directory named by the VTV_LOGS_DIR environment variable if it's defined, or in the current working directory otherwise. ๐Ÿ“
Note: This feature appends data to the log file. If you want a fresh log file, make sure you delete any existing one first, bestie! ๐Ÿ—‘๏ธ
  • -fvtv-counts โ€” This is a debugging flag ๐Ÿ” Used together with -fvtable-verify=std or -fvtable-verify=preinit, it makes the compiler keep track of the total number of virtual calls it runs into and the number of verifications it inserts. It also counts how many calls to certain run-time library functions it inserts, and logs that info for each compilation unit. ๐Ÿ“Š Results go to a file named vtv_count_data.log in the directory named by VTV_LOGS_DIR if that's defined, or the current working directory otherwise. It also counts the size of the vtable pointer sets for each class, and writes that to vtv_class_set_sizes.log in the same directory. ๐Ÿงฎ
Note: This feature appends data to the log files. To get fresh log files, delete any existing ones first. ๐Ÿ—‘๏ธ
  • -finstrument-functions โ€” Generates instrumentation calls for function entry and exit. ๐Ÿ”” Right after a function is entered, and right before it exits, the following profiling functions get called with the address of the current function and its call site. (Heads up: on some platforms, __builtin_return_address doesn't work beyond the current function, so the call site info 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 also happens for functions expanded inline into other functions. The profiling calls show where, conceptually, the inline function is entered and exited. That means addressable versions of those functions must be available. If all your uses of a function are expanded inline, this may mean extra code size. ๐Ÿ“ If you use extern inline in your C code, an addressable version of those functions must be provided. (This is 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 be given the no_instrument_function attribute, which skips this instrumentation for it. This is handy for things like the profiling functions listed above, high-priority interrupt routines, and any functions the profiling functions can't safely be called from (like signal handlers, if the profiling routines generate output or allocate memory). ๐Ÿšซ

  • -finstrument-functions-once โ€” This is similar to -finstrument-functions, but the profiling functions only get called once per instrumented function. 1๏ธโƒฃ Specifically, the first profiling function is called after the first entry into the instrumented function, and the second is called before the exit that matches that first entry.

The definition of "once" here is a little vague, because the implementation isn't protected against data races. ๐Ÿ˜ตโ€๐Ÿ’ซ So the implementation only guarantees that the profiling functions get called at least once per process and at most once per thread. The calls are always paired, though: if a thread calls the first function, it will call the second one too, unless it never reaches the exit of the instrumented function. ๐Ÿซถ

  • -finstrument-functions-exclude-file-list=file,file,... โ€” Sets the list of functions that get excluded from instrumentation (see -finstrument-functions above). ๐Ÿšท If the file containing a function definition matches one of the file entries, that function doesn't get instrumented. The match is done on substrings: if the file value is a substring of the file name, it counts as a match. ๐Ÿ”ค

For example:

-finstrument-functions-exclude-file-list=/bits/stl,include/sys

That excludes any inline function defined in files whose pathnames contain /bits/stl or include/sys. ๐Ÿ™Œ

If, for some reason, you want to include the letter , in one of the sym values, write ,,. For example, -finstrument-functions-exclude-file-list=',,tmp' (note the single quote surrounding the option). ๐Ÿง

  • -finstrument-functions-exclude-function-list=sym,sym,... โ€” This is like -finstrument-functions-exclude-file-list, but this one sets the list of function names to exclude from instrumentation. ๐Ÿท๏ธ The name that gets matched is its user-visible name, like "vector<int> blah(const vector<int> &)", not the internal mangled name (for example, "_Z4blahRSt6vectorIiSaIiEE"). The match is done on substrings: if the sym value is a substring of the function name, it counts as a match. For C99 and C++ extended identifiers, the function name has to be given in UTF-8, not using universal character names. ๐ŸŒˆ
  • -fpatchable-function-entry=N[,M] โ€” okay so this one drops N NOPs right at the very start of every function, with the function's entry point sitting before the Mth NOP. If you skip M, it quietly defaults to 0, so the entry point lands right on the first NOP. ๐Ÿงš Those NOPs are basically reserved empty space you can patch instrumentation into at run time, but only if the code segment is writable ๐Ÿ’…
    • The amount of space is controlled indirectly, through how many NOPs you ask for. The NOP instruction used matches what the internal GCC back-end interface gen_nop emits.
    • This 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 (their function entries minus M) also get collected in the __patchable_function_entries section of the final binary ๐Ÿฆ‹

Heads up, bestie: __attribute__ ((patchable_function_entry (N,M))) takes priority over the -fpatchable-function-entry=N,M command-line option. You can use it to make the area bigger or to remove it completely on one specific function. If N=0, no pad location gets recorded ๐Ÿ’€

The NOPs go in at the function entry address, which might be before the prologue depending on M. On PowerPC with the ELFv2 ABI, for a function with dual entry points, the local entry point is this same function entry address โœจ

The max value of N and M is 65535. Also on PowerPC with the ELFv2 ABI, if you've got a function with dual entry points, the supported values for M are 0, 2, 6 and 14 ๐Ÿ”ฅ


๐Ÿงš Options Controlling the Preprocessor ๐Ÿงš

These options control the C preprocessor, which runs on every C source file before the actual compilation happens ๐Ÿ’–

If you use -E, nothing happens 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 search paths for include files, which are documented in Directory Options. Options for preprocessor diagnostics live in Warning Options ๐ŸŽ€

  • -D name โ€” predefines name as a macro, with the definition 1 ๐Ÿ“
  • -D name=definition โ€” the definition gets tokenized and processed as if it showed up during translation phase three in a #define directive. A newline character inside it will truncate the definition ๐Ÿ’…
    • If you're calling the preprocessor from a shell, you might need the shell's quoting syntax to protect characters like spaces that mean something to the shell ๐Ÿซถ
    • Want a function-like macro on the command line? Put its argument list in parentheses before the equals sign. Parentheses mean stuff to most shells, so quote the option. With sh and csh, -D'name(args...)=definition' works โœจ
    • -D and -U options are processed in the order you type them. All -imacros and -include options get processed after every -D and -U ๐Ÿ‘‘
  • -U name โ€” cancels any previous definition of name, whether it was built in or set with a -D option ๐Ÿฆ‹
  • -include file โ€” processes file as if #include "file" showed up as the first line of the primary source file. The big difference is that the first directory searched for file is the preprocessor's working directory, not the directory with the main source file. If it's not found there, it gets searched for in the rest of the #include "..." search chain, like normal ๐ŸŒˆ
    • Multiple -include options get included in the order they appear on the command line ๐Ÿ“
  • -imacros file โ€” works exactly like -include, except any output made by scanning file gets thrown away. The macros it defines stay defined. This lets you grab all the macros from a header without processing its declarations ๐Ÿงš
    • Every -imacros file gets processed before every -include file ๐Ÿ’œ
  • -undef โ€” don't predefine any system-specific or GCC-specific macros. The standard predefined macros stay defined ๐ŸŒธ
  • -pthread โ€” defines the extra macros you need for the POSIX threads library. Use this option consistently for both compiling 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 spitting out the preprocessed result, this outputs a rule that make can use to describe the dependencies of the main source file ๐Ÿ˜ญ
    • The preprocessor outputs one make rule. It has the object file name for that source file, a colon, and the names of all the included files, including the ones from -include or -imacros command-line options ๐Ÿ’–
    • Unless you set it explicitly with -MT or -MQ, the object file name is the source file name with its suffix swapped for the object file suffix, and 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 doesn't suppress the preprocessor's debug output, like -dM. To keep that debug output from mixing with your dependency rules, specify the dependency output file with -MF, or use an environment variable like DEPENDENCIES_OUTPUT. Debug output still goes to the regular output stream as 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 included (directly or indirectly) from those system headers ๐ŸŒˆ
    • This means the choice of angle brackets or double quotes in an #include directive doesn't, by itself, decide whether that header shows up in -MM dependency output ๐Ÿ’…
  • -MF file โ€” when used with -M or -MM, this says which file to write the dependencies to. If you don't give -MF, the preprocessor sends the rules to the same place it would send preprocessed output ๐Ÿ“
    • 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 alongside an option like -M that asks for 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, with no path prepended ๐Ÿงš
    • -MG also suppresses preprocessed output, since a missing header makes that useless ๐Ÿฅบ
    • This feature is used for automatically updating makefiles ๐Ÿ‘‘
  • -Mno-modules โ€” disables dependency generation for compiled module interfaces ๐ŸŒธ
  • -MP โ€” tells CPP to add a phony target for each dependency other than the main file, so each one depends on nothing. These dummy rules work around errors make 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 that dependency generation emits ๐Ÿฆ‹
    • By default, CPP takes the main input file name, deletes any directory components and the file suffix (like .c), and adds the platform's usual object suffix. That result is the target ๐Ÿ’–
    • An -MT option makes the target exactly the string you specify. If you want multiple targets, you can put them in one argument to -MT, or use multiple -MT options ๐ŸŽ€
    • For example, -MT '$(objpfx)foo.o' might give:
$(objpfx)foo.o: foo.c
  • -MQ target โ€” same as -MT, but it quotes any characters that are special to Make ๐Ÿ’…
    • -MQ '$(objpfx)foo.o' gives:
$$(objpfx)foo.o: foo.c
  • The default target is automatically quoted, as if you'd given it with -MQ ๐ŸŒˆ
  • -MD โ€” this is equivalent to -M -MF file, except -E isn't implied ๐ŸŒธ
    • The driver figures out file based on whether an -o option is given. If it is, the driver uses that argument with a .d suffix. Otherwise, it takes the input file name, removes any directory components and suffix, and applies a .d suffix โœจ
    • If -MD is used with -E, any -o switch is understood to specify the dependency output file. But if it's used 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 โ€” tells the preprocessor the input file has already been preprocessed. This suppresses things like macro expansion, trigraph conversion, escaped newline splicing, and processing of most directives ๐Ÿงš
    • The preprocessor still recognizes and removes comments, so you can pass a file preprocessed with -C to the compiler without any problems. In this mode, the integrated preprocessor is basically just a tokenizer for the front ends ๐Ÿฆ‹
    • -fpreprocessed is implicit if the input file has one of the extensions .i, .ii or .mi. Those are the extensions GCC uses for preprocessed files created by -save-temps ๐Ÿ‘‘
  • -fdirectives-only โ€” when preprocessing, this handles directives but does not expand macros ๐Ÿซถ
    • What it does depends on -E and -fpreprocessed.
      • With -E, preprocessing is limited to handling directives like #define, #ifdef, and #error. Other preprocessor operations, like macro expansion and trigraph conversion, don't happen. Also, the -dD option is implicitly enabled ๐Ÿ˜ญ
      • With -fpreprocessed, predefinition of command-line macros and most builtin macros is disabled. Macros like __LINE__, which depend on context, are handled normally. This lets you compile files that were previously preprocessed with -E -fdirectives-only ๐Ÿ’–
      • With both -E and -fpreprocessed, the -fpreprocessed rules take precedence. This enables full preprocessing of files that were previously preprocessed with -E -fdirectives-only ๐ŸŒˆ
  • -fdollars-in-identifiers โ€” accepts $ in identifiers ๐Ÿ’…
  • -fextended-identifiers โ€” ๐ŸŒˆ Lets identifiers use universal character names and extended characters, which is pure main character energy โœจ. It's on by default for C99 (and later C standard versions) and C++, so you're already winning ๐Ÿ’….
  • -fno-canonical-system-headers โ€” ๐Ÿงš When preprocessing, GCC won't shorten system header paths with canonicalization โœจ.
  • -fmax-include-depth=depth โ€” ๐ŸŒธ Sets how deep nested #includes can go. The default is 200, which is honestly a lot of nesting bestie ๐Ÿ’€.
  • -ftabstop=width โ€” ๐Ÿ“ Sets the distance between tab stops. This helps the preprocessor report correct column numbers in warnings or errors, even when tabs show up 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, so when a compile error happens inside a macro, GCC can show the current macro expansion stack. Heads up, though: this makes the preprocessor and compiler eat more memory ๐Ÿ.

The level parameter lets you pick how precise the token tracking is, so you can dial down the memory use if you need to ๐Ÿ’œ:

  • 0 โ€” turns this option off.
  • 1 โ€” degraded mode for minimal memory overhead. All tokens from expanding an argument of a function-like macro end up with the same location.
  • 2 โ€” tracks token locations completely. This is the most memory-hungry one ๐Ÿ˜ญ.

If you don't give it a value, the default level is 2.

Note that -ftrack-macro-expansion=2 is activated by default.
  • -fmacro-prefix-map=old=new โ€” ๐Ÿ—บ๏ธ When preprocessing files that live in directory old, GCC expands __FILE__ and __BASE_FILE__ as if those files lived in directory new instead. Use . for new to turn an absolute path into a relative one, which can lead to more reproducible, location-independent builds ๐Ÿซถ. This also affects __builtin_FILE() during compilation. See also -ffile-prefix-map and -fcanon-prefix-map.
  • -fexec-charset=charset โ€” ๐Ÿ’– Sets the execution character set, used for string and character constants. The default is UTF-8. charset can be any encoding your system's iconv library routine supports ๐ŸŒธ.
  • -fwide-exec-charset=charset โ€” ๐Ÿ‘‘ Sets the wide execution character set, used for wide string and character constants. The default is one of UTF-32BE, UTF-32LE, UTF-16BE, or UTF-16LE, whichever matches the width of wchar_t and the big-endian or little-endian byte order used for code generation ๐ŸŒˆ. Just like -fexec-charset, charset can be any encoding iconv supports.
Heads up: you'll run into problems with encodings that don't fit exactly in wchar_t ๐Ÿ˜ญ.
  • -finput-charset=charset โ€” ๐Ÿฆ‹ Sets the input character set, which is used to translate the input file's characters into the source character set GCC uses. If the locale doesn't specify one, or GCC can't get that info from the locale, the default is UTF-8. The locale or this command-line option can override that, but right now the command-line option wins if there's a conflict ๐Ÿ’…. charset can be any encoding iconv supports.
  • -fpch-deps โ€” ๐Ÿงธ When you're using precompiled headers, this makes the dependency-output flags also list the files from the precompiled header's dependencies. Without it, only the precompiled header gets listed, not the files used to create it, because those files aren't consulted when a PCH is used ๐Ÿ™ˆ.
  • -fpch-preprocess โ€” ๐Ÿ”ฎ Lets you use a precompiled header together with -E. It inserts a special #pragma, namely #pragma GCC pch_preprocess "filename", into the output to mark the place where the precompiled header was found and its filename. When -fpreprocessed is in use, GCC recognizes that #pragma and loads the PCH.

This option is off by default, because the resulting preprocessed output is only really suitable as input to GCC ๐Ÿ’€. It gets switched on by -save-temps.

You should not write this #pragma in your own code ๐Ÿ™…, but it's safe to edit the filename if the PCH file is available in a different location. The filename may be absolute, or relative to GCC's current directory.

  • -fworking-directory โ€” ๐ŸŒท Enables generation of linemarkers in the preprocessor output that let the compiler know the current working directory at the time of preprocessing. When this is enabled, the preprocessor emits, after the initial linemarker, a second linemarker with the current working directory followed by two slashes. GCC uses this directory, when it's present in the preprocessed input, as the directory emitted as the current working directory in some debugging information formats. This option is implicitly enabled if debugging information is enabled, but you can inhibit it with the negated form -fno-working-directory. If the -P flag is present on the command line, this option has no effect, since no #line directives are emitted whatsoever ๐Ÿฅฒ.
  • -A predicate=answer โ€” โœจ Makes an assertion with the predicate predicate and the answer answer. This form is preferred over the older -A predicate(answer), which is still supported, because it doesn't use shell special characters ๐Ÿš.
  • -A -predicate=answer โ€” ๐Ÿšซ Cancels an assertion with the predicate predicate and the answer answer.
  • -C โ€” ๐Ÿ’ฌ Don't throw comments away! All comments are passed through to the output file, except for comments in processed directives, which get deleted along with the directive.
Be prepared for side effects when using -C, because it makes the preprocessor treat comments as tokens in their own right. For example, comments appearing at the start of what would be a directive line turn that line into an ordinary source line, since the first token on the line is no longer a #.
  • -CC โ€” ๐Ÿ’– Don't discard comments, even during macro expansion. It's like -C, except comments contained within macros also get passed through to the output file where the macro is expanded.

In addition to the side effects of the -C option, -CC converts all C++-style comments inside a macro into C-style comments. That stops a later use of the macro from accidentally commenting out the rest of the source line ๐Ÿ™ˆ.

The -CC option is generally used to support lint comments ๐Ÿงน.

  • -P โ€” ๐Ÿ›‘ Inhibits generation of linemarkers in the preprocessor output. This might be useful when you're running the preprocessor on something that isn't C code and will be sent to a program that might get confused by the linemarkers.
  • -traditional, -traditional-cpp โ€” ๐Ÿฆ• Tries to imitate the behavior of pre-standard C preprocessors, instead of ISO C preprocessors. Check the GNU CPP manual for details.
Note that GCC doesn't otherwise try to emulate a pre-standard C compiler, and these options are only supported with the -E switch, or when invoking CPP explicitly.
  • -trigraphs โ€” ๐ŸŒ€ Supports ISO C trigraphs. These are three-character sequences, all starting with ??, that ISO C defines to stand for single characters. For example, ??/ stands for \, so '??/n' is a character constant for a newline ๐Ÿ’….

The nine trigraphs and their replacements are:

  • ??( becomes [
  • ??) becomes ]
  • ??< becomes {
  • ??> becomes }
  • ??= becomes #
  • ??/ becomes \
  • ??' becomes ^
  • ??! becomes |
  • ??- becomes ~

By default, GCC ignores trigraphs, but in standard-conforming modes it converts them. See the -std and -ansi options ๐Ÿ“œ.

  • -remap โ€” ๐Ÿ—‚๏ธ Enables special code to work around file systems that only permit very short file names, such as MS-DOS ๐Ÿ’พ.
  • -H โ€” ๐ŸŒณ Prints the name of each header file used, in addition to the other normal activities. Each name is indented to show how deep it is in the #include stack. Precompiled header files are also printed, even if they turn out to be invalid. An invalid precompiled header file 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 are interpreted by the compiler proper, or reserved for future versions of GCC, so they're silently ignored. If you specify letters whose behavior conflicts, the result is undefined ๐Ÿ’€.
    • -dM โ€” Instead of the normal output, generates a list of #define directives for all the macros defined during the execution of the preprocessor, including predefined macros. This gives you a way of finding out what's predefined in your version of the preprocessor ๐Ÿ”. Assuming you have no file foo.h, the command below shows all the predefined macros โœจ:
touch foo.h; cpp -dM foo.h

If you use -dM without the -E option, -dM is interpreted as a synonym for -fdump-rtl-mach.

  • -dD โ€” Like -dM, except it outputs both the #define directives and the result of preprocessing. Both kinds of output go to the standard output file ๐Ÿ“ค.
  • -dN โ€” Like -dD, but emits only the macro names, not their expansions.
  • -dI โ€” Outputs #include directives in addition to the result of preprocessing.
  • -dU โ€” Like -dD, except only macros that are expanded, or whose definedness is tested in preprocessor directives, are output. The output is delayed until the use or test of the macro, and #undef directives are also output for macros that were tested but undefined at the time ๐Ÿฆ‹.
  • -fdebug-cpp โ€” ๐Ÿ› This option is only useful for debugging GCC. When used from CPP or with -E, it dumps debugging information about location maps. Every token in the output is preceded by the dump of the map its location belongs to.

When used from GCC without -E, this option has no effect.

-Wp,option

  • -Wp,option โ€” Hot tip from bestie: this lets you skip the compiler driver entirely and send option straight to the preprocessor. ๐Ÿงš If option has commas, it gets split up at each comma. BUT, ngl, a lot of options get modified, translated, or interpreted by the driver first, and -Wp totally bypasses that step. The preprocessor's direct interface is undocumented and can change at any time, so whenever possible just let the driver handle your options instead. ๐Ÿ’€

-Xpreprocessor option

  • -Xpreprocessor option โ€” Passes option to the preprocessor as an option. This is clutch for system-specific preprocessor options that GCC doesn't recognize. ๐Ÿ’…

If you want to pass an option that takes an argument, you have to use -Xpreprocessor twice: once for the option and once for the argument. ๐Ÿซถ

-no-integrated-cpp

  • -no-integrated-cpp โ€” Okay so, by default GCC does preprocessing as part of input tokenization and parsing, all integrated and smooth. โœจ With this option, preprocessing happens as a separate pass before compilation instead. The language front end (cc1 for C, cc1plus for C++, and cc1obj for Objective-C) gets invoked twice: once for preprocessing only, and once for the actual compilation of the preprocessed input. This can be super useful together with the -B or -wrapper options if you want an alternate preprocessor or extra processing of your source between normal preprocessing and compilation. ๐Ÿฆ‹

-flarge-source-files

  • -flarge-source-files โ€” Okay this one is for the big leagues ๐Ÿ‘‘. It tells GCC to expect large source files, but it costs you slower compilation and higher memory usage. ๐Ÿ™ˆ

Here's the tea: GCC normally tracks both column numbers and line numbers in source files, and it prints both in diagnostics. Once it has processed a certain number of source lines, though, it stops tracking column numbers and only tracks line numbers. So diagnostics for later lines won't include column numbers. ngl that also means options like -Wmisleading-indentation stop working at that point, although the compiler prints a note if this happens. ๐Ÿ˜ญ Passing -flarge-source-files seriously boosts how many source lines GCC can process before it stops tracking columns. ๐ŸŒˆ


๐ŸŽ€ Passing Options to the Assembler ๐ŸŽ€

You can pass options to the assembler. ๐Ÿฆ‹

-Wa,option

  • -Wa,option โ€” Passes option to the assembler. If option has commas, it gets split into multiple options at the commas. ๐ŸŒธ

-Xassembler option

  • -Xassembler option โ€” Passes option to the assembler as an option. Use this for system-specific assembler options that GCC doesn't recognize. ๐Ÿ’œ

If you want to pass an option that 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. ๐Ÿ’–

object-file-name

  • 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 apart from libraries by checking the file contents, not the name.) If linking happens, these object files get fed into the linker as input. โœจ

-c -S -E

  • -c, -S, -E โ€” If any of these is used, the linker doesn't run, so object file names shouldn't be used as arguments. ๐Ÿ™…

-flinker-output=type

  • -flinker-output=type โ€” Controls code generation of the link-time optimizer. โœจ By default, the linker output is figured out automatically by the linker plugin. For debugging the compiler, or if you want incremental linking with a non-LTO object file, it can be handy to set the type manually. ๐Ÿ”ง

If type is exec, code generation produces a static binary. In this case -fpic and -fpie are both disabled. ๐ŸงŠ

If type is 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. ๐ŸŒˆ

If type is pie, code generation produces an -fpie executable. This gives similar optimizations to exec, except -fpie is not disabled if it was specified at compilation time. ๐Ÿ‘‘

If type is rel, the compiler assumes incremental linking is happening. The sections containing intermediate code for link-time optimization are merged, pre-optimized, and output to the resulting object file. Also, if -ffat-lto-objects is specified, binary code is produced for future non-LTO linking. The object file from incremental linking is smaller than a static library made from the same object files. At link time, the result of incremental linking also loads faster than a static library, assuming most objects in the library are used. ๐Ÿ’ซ

Finally, nolto-rel configures the compiler for incremental linking where code generation is forced, a final binary is produced, and the intermediate code for later link-time optimization gets stripped. When multiple object files are linked together, the resulting code is better optimized than with link-time optimizations disabled (for example, cross-module inlining happens), but most of the benefits of whole program optimizations are lost. ๐Ÿ˜ค

During the incremental link (by -r), the linker plugin defaults to rel. With current interfaces to GNU Binutils, it is however not possible to incrementally link LTO objects and non-LTO objects into a single mixed object file. If any 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 with support for mixed objects. ๐Ÿšจ

-fuse-ld=bfd

  • -fuse-ld=bfd โ€” Uses the bfd linker instead of the default linker. ๐ŸŒธ

-fuse-ld=gold

  • -fuse-ld=gold โ€” Uses the gold linker instead of the default linker. ๐Ÿฅ‡

-fuse-ld=lld

  • -fuse-ld=lld โ€” Uses the LLVM lld linker instead of the default linker. ๐Ÿฆ‹

-fuse-ld=mold

  • -fuse-ld=mold โ€” Uses the Modern Linker (mold) instead of the default linker. โšก

-llibrary -l library

  • -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 straight through to the linker by GCC, so check your linker's documentation for exact details. The general description below applies to the GNU linker. ๐Ÿง

The linker searches a standard list of directories for the library. The directories searched include several standard system directories, plus any you specify with -L. ๐Ÿ—‚๏ธ

Static libraries are archives of object files and have file names like liblibrary.a. Some targets also support shared libraries, which typically have names like liblibrary.so. If both static and shared libraries are found, the linker prefers 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

  • -lobjc โ€” You need this special case of the -l option to link an Objective-C or Objective-C++ program. ๐Ÿ“

-nostartfiles

  • -nostartfiles โ€” Doesn'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

  • -nodefaultlibs โ€” Doesn't use the standard system libraries when linking. Only the libraries you specify get passed to the linker, and options that set linkage for system libraries, like -static-libgcc or -shared-libgcc, are ignored. The standard startup files are still used normally, unless -nostartfiles is used. ๐Ÿ™…โ€โ™€๏ธ

The compiler may generate calls to "memcmp", "memset", "memcpy" and "memmove". These are usually resolved by entries in libc. When this option is specified, these entry points need to be supplied through some other mechanism. ๐Ÿงฉ

-nolibc

  • -nolibc โ€” Doesn'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 like libgnat, libgfortran, or libstdc++, unless options preventing their inclusion are used too. This typically removes -lc from the link command line, along with system libraries that normally go with it and become meaningless when a C library is assumed absent, for example -lpthread or -lm in some configurations. This is meant for bare-board targets where there's really no C library available. ๐Ÿค–

-nostdlib

  • -nostdlib โ€” Doesn't use the standard system startup files or libraries when linking. No startup files are used, and only the libraries you specify get passed to the linker. Options that set linkage for system libraries, like -static-libgcc or -shared-libgcc, are ignored. ๐Ÿงฑ

The compiler may generate calls to "memcmp", "memset", "memcpy" and "memmove". These are usually resolved by entries in libc. When this option is specified, these entry points need to be supplied through some other mechanism. ๐Ÿงฉ

One of the standard libraries bypassed by -nostdlib and -nodefaultlibs is libgcc.a, a library of internal subroutines that GCC uses to work around shortcomings of particular machines, or special needs for some languages. ๐Ÿ”

In most cases, you still need libgcc.a even when you want to avoid other standard libraries. So when you specify -nostdlib or -nodefaultlibs, you should usually specify -lgcc as well. This makes sure you don't have unresolved references to internal GCC library subroutines. (An example of such an internal subroutine is "__main", which is used to make sure C++ constructors get called.) ๐ŸŽ€

-nostdlib++

  • -nostdlib++ โ€” Doesn't implicitly link with standard C++ libraries. ๐Ÿšซ

-e entry --entry=entry

  • -e entry, --entry=entry โ€” Specifies that the program entry point is entry. The linker interprets the argument: the GNU linker accepts either a symbol name or an address. ๐Ÿšช
  • -pie โ€” okay so this one tells the linker to make a dynamically linked position independent executable ๐ŸŽ€ on targets that actually support it โœจ. For predictable results, bestie, you have to use the same compile options too (-fpie, -fPIE, or model suboptions) when you use this linker option ๐Ÿ’….
  • -no-pie โ€” the opposite energy ๐Ÿ™…โ€โ™€๏ธ. It does not make a dynamically linked position independent executable.
  • -static-pie โ€” makes a static position independent executable on targets that support it ๐Ÿฆ‹. It's giving static executable vibes, but it can get loaded at any address with no dynamic linker needed ๐Ÿงš. Same rule as before: match the compile options (-fpie, -fPIE, or model suboptions) for predictable results ๐Ÿ’–.
  • -pthread โ€” links with the POSIX threads library ๐Ÿงต. It works on GNU/Linux, most other Unix derivatives, and also on x86 Cygwin and MinGW targets ๐ŸŒˆ. Heads up: on some targets this also sets flags for the preprocessor, so use it consistently for both compiling and linking โš ๏ธ.
  • -r โ€” produces a relocatable object as output ๐ŸŒธ. This is also called partial linking ๐Ÿซถ.
  • -rdynamic โ€” passes the flag -export-dynamic to the ELF linker, on targets that support it ๐Ÿ”ฅ. It tells the linker to add all symbols, not just the used ones, to the dynamic symbol table ๐Ÿ‘‘. You need this for some uses of dlopen, or to get backtraces from inside a program ๐Ÿ™ˆ.
  • -s โ€” removes all symbol table and relocation information from the executable ๐Ÿ’€.
  • -static โ€” on systems that support dynamic linking, this overrides -pie and stops linking with the shared libraries ๐Ÿšซ. On other systems it does absolutely nothing ๐Ÿคทโ€โ™€๏ธ.
  • -shared โ€” produces a shared object that can be linked with other objects to form an executable ๐Ÿ’œ. Not every system supports this one. For predictable results, match the compile options (-fpic, -fPIC, or model suboptions) when you use this linker option [1].
  • -shared-libgcc, -static-libgcc โ€” on systems that provide libgcc as a shared library, these force the use of the shared or static version, respectively ๐ŸŽ€. If no shared version of libgcc got built when the compiler was configured, these options have no effect ๐Ÿ˜ญ.

There are several situations where an application should use the shared libgcc instead of the static version ๐Ÿง . The most common one is when the application wants to throw and catch exceptions across different shared libraries. In that case, each of the libraries and the application itself should use the shared libgcc ๐Ÿซถ.

So the G++ driver automatically adds -shared-libgcc whenever you build a shared library or a main executable, because C++ programs typically use exceptions. That's the right move, periodt ๐Ÿ’….

If, instead, you use the GCC driver to create shared libraries, they might not always get linked with the shared libgcc ๐Ÿ™ƒ. If GCC finds at its configuration time that you have a non-GNU linker, or a GNU linker that doesn't support option --eh-frame-hdr, it links the shared version of libgcc into shared libraries by default. Otherwise it takes advantage of the linker and optimizes away the linking with the shared version of libgcc, linking with the static version by default. This lets exceptions propagate through those shared libraries without incurring relocation costs at library load time โœจ.

However, if a library or main executable is supposed to throw or catch exceptions, you must link it using the G++ driver, or using the option -shared-libgcc, so that it's linked with the shared libgcc ๐Ÿšจ.
  • -static-libasan โ€” when the -fsanitize=address option is used to link a program, the GCC driver automatically links against libasan ๐Ÿ•ต๏ธโ€โ™€๏ธ. If libasan is available as a shared library, and the -static option is not used, it links against the shared version. This option directs the GCC driver to link libasan statically, without necessarily linking other libraries statically ๐Ÿ’–.
  • -static-libtsan โ€” when the -fsanitize=thread option is used to link a program, the GCC driver automatically links against libtsan ๐Ÿงต. If libtsan is available as a shared library, and the -static option is not used, it links against the shared version. This option directs the GCC driver to link libtsan statically, without necessarily linking other libraries statically ๐Ÿฆ‹.
  • -static-liblsan โ€” when the -fsanitize=leak option is used to link a program, the GCC driver automatically links against liblsan ๐Ÿงน. If liblsan is available as a shared library, and the -static option is not used, it links against the shared version. This option directs the GCC driver to link liblsan statically, without necessarily linking other libraries statically ๐ŸŒธ.
  • -static-libubsan โ€” when the -fsanitize=undefined option is used to link a program, the GCC driver automatically links against libubsan ๐Ÿซง. If libubsan is available as a shared library, and the -static option is not used, it links against the shared version. This option directs 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 the -static option is not used, it links against the shared version, and that's normally fine โœจ. Sometimes though, you want to freeze the version of libstdc++ your program uses without going all the way to a fully static link ๐ŸงŠ. This option directs the g++ driver to link libstdc++ statically, without necessarily linking other libraries statically ๐ŸŽ€.
  • -symbolic โ€” binds references to global symbols when building a shared object ๐Ÿ”—. It warns about any unresolved references, unless you override that with the link editor option -Xlinker -z -Xlinker defs ๐Ÿ‘€. Only a few systems support this option, so it's a bit of a rare flex ๐Ÿ’œ.
  • -T script โ€” uses script as the linker script ๐Ÿ“œ. This option is supported by most systems using the GNU linker. On some targets, like bare-board targets without an operating system, -T may be required when linking to avoid references to undefined symbols ๐Ÿ˜ค.
  • -Xlinker option โ€” passes option along to the linker as an option ๐Ÿš€. Use this to supply system-specific linker options that GCC doesn't recognize.

If you want to pass an option that takes a separate argument, you have to use -Xlinker twice, once for the option and once for the argument ๐Ÿ™ˆ. For example, to pass -assert definitions, you must write -Xlinker -assert -Xlinker definitions. It does not work to write -Xlinker "-assert definitions", because that passes the entire string as one single argument, which is not what the linker expects ๐Ÿ’€.

When you're using the GNU linker, it's usually way more convenient to pass arguments to linker options with the option=value syntax instead of as separate arguments ๐Ÿง. For example, you can write -Xlinker -Map=output.map instead of -Xlinker -Map -Xlinker output.map. Just know that other linkers might not support this syntax for command-line options ๐Ÿคทโ€โ™€๏ธ.

  • -Wl,option โ€” passes option as an option to the linker ๐ŸŽ€. If option contains commas, it gets split into multiple options at those commas. This syntax lets you pass an argument to the option too: for example, -Wl,-Map,output.map passes -Map output.map to the linker โœจ. When using the GNU linker, you can get the same effect with -Wl,-Map=output.map ๐Ÿฆ‹.
NOTE: In Ubuntu 8.10 and later versions, for LDFLAGS, the option -Wl,-z,relro is used. To disable it, use -Wl,-z,norelro ๐Ÿšจ.
  • -u symbol โ€” pretends the symbol symbol is undefined, to force linking of library modules that define it ๐Ÿงš. You can use -u multiple times with different symbols to force loading of additional library modules ๐Ÿ’–.
  • -z keyword โ€” -z is passed straight on to the linker along with the keyword keyword ๐Ÿซถ. Check the section in your linker's documentation for the permitted values and what they mean ๐Ÿ“–.

These options specify the directories to search for header files, for libraries and for parts of the compiler ๐Ÿ—บ๏ธ:

  • -I dir, -iquote dir, -isystem dir, -idirafter dir โ€” adds the directory dir to the list of directories searched for header files during preprocessing ๐Ÿ“‚. If dir begins with = or $SYSROOT, then the = or $SYSROOT is replaced by the sysroot prefix. See --sysroot and -isysroot for more on that ๐ŸŒˆ.

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

You can specify any number or combination of these options on the command line to search for header files in several directories ๐Ÿ”. The lookup order goes like this:

  1. For the quote form of the include directive, the directory of the current file is searched first ๐Ÿ“.
  2. For the quote form of the include directive, the directories specified by -iquote options are searched in left-to-right order, as they appear on the command line โžก๏ธ.
  3. Directories specified with -I options are scanned in left-to-right order ๐Ÿ‘€.
  4. Directories specified with -isystem options are scanned in left-to-right order ๐Ÿ›๏ธ.
  5. Standard system directories are scanned ๐Ÿงฑ.
  6. Directories specified with -idirafter options are scanned in left-to-right order ๐Ÿ.

You can use -I to override a system header file and substitute your own version, since these directories get searched before the standard system header file directories ๐Ÿ”„. However, you should not use this option to add directories that contain vendor-supplied system header files. Use -isystem for that ๐Ÿ™…โ€โ™€๏ธ.

The -isystem and -idirafter options also mark the directory as a system directory, so it gets the same special treatment that's applied to the standard system directories ๐Ÿ‘‘โœจ.

okay so bestie, if a standard system include directory (or one you pass with -isystem) is also given with -I, the -I gets ignored ๐Ÿ™…โ€โ™€๏ธ The directory still gets searched, just as a system directory in its normal spot in the system include chain. This keeps GCC's little fix-up routine for buggy system headers and the ordering for #include_next from getting accidentally messed up ๐Ÿ’… If you really need to change the search order for system directories, reach for -nostdinc and/or -isystem.

  • -I- โ€” splits the include path ๐Ÿฆ‹ This one is deprecated, so please use -iquote for the -I directories that come before the -I-, and then remove the -I- option ๐Ÿซถ

Any directories given with -I before -I- only get searched for headers requested with #include "file". They are NOT searched for #include <file>. If you add more -I directories after the -I-, those get searched for all #include directives.

-I- also blocks the current file's directory from being the first search directory for #include "file". There is no way to override this effect of -I- ๐Ÿ˜ญ

  • -iprefix prefix โ€” picks prefix as the prefix for any later -iwithprefix options ๐ŸŒธ If your 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 result to the include search path โœจ -iwithprefixbefore puts it in the same place -I would, and -iwithprefix puts it where -idirafter would.
  • -isysroot dir โ€” basically the --sysroot option, but it only applies to header files ๐Ÿงš (Except on Darwin targets, where it applies to both header files and libraries.) See the --sysroot option for more information.
  • -imultilib dir โ€” uses dir as a subdirectory of the directory that holds target-specific C++ headers ๐ŸŒˆ
  • -nostdinc โ€” don't search the standard system directories for header files ๐Ÿ™ˆ Only the directories you explicitly give with -I, -iquote, -isystem, and/or -idirafter (plus the directory of the current file, if appropriate) get searched.
  • -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, it's only passed along by the driver ๐Ÿ™…โ€โ™€๏ธ
  • -Ldir โ€” adds dir to the list of directories searched for -l ๐Ÿ“
  • -Bprefix โ€” this is where you tell the compiler where to find its own executables, libraries, include files, and data files ๐ŸŽ€

The compiler driver program runs one or more of the subprograms cpp, cc1, as and ld. It tries prefix as a prefix for each program it tries to run, both with and without machine/version/ for the corresponding target machine and compiler version.

For each subprogram, the driver first tries the -B prefix, if there is one. If that name isn't found, or if -B isn't specified, the driver tries two standard prefixes, /usr/lib/gcc/ and /usr/local/lib/gcc/. If neither of those turns up a file, the unmodified program name gets searched for using the directories in your PATH environment variable.

The compiler checks whether the path given by -B refers to a directory, and if necessary it adds a directory separator character at the end of the path ๐Ÿฆ‹

-B prefixes that effectively specify directory names also apply to libraries in the linker, because the compiler translates these options into -L options for the linker. They also apply to include files in the preprocessor, because the compiler translates these options into -isystem options for the preprocessor. In this case, the compiler appends include to the prefix.

The runtime support file libgcc.a can also be searched for using the -B prefix, if needed. If it isn't found there, the two standard prefixes above are tried, and that is all. The file gets left out of the link if it isn't found by those means ๐Ÿ˜ญ

Another way to specify a prefix that's pretty much like the -B prefix is to use the environment variable GCC_EXEC_PREFIX ๐Ÿ’œ

As a special kludge, if the path given by -B is [dir/]stageN/, where N is a number in the range 0 to 9, then it gets replaced by [dir/]include. This is to help with boot-strapping the compiler ๐Ÿงš

  • -no-canonical-prefixes โ€” don't expand any symbolic links, don't resolve references to /../ or /./, and don't 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 instead searches dir/usr/include and dir/usr/lib.

If you use both this option and the -isysroot option, then --sysroot applies to libraries, but -isysroot applies to header files.

The GNU linker (beginning with version 2.16) has the necessary support for this option. If your linker doesn't support it, the header file side of --sysroot still works, but the library side does not ๐Ÿ’€

  • --no-sysroot-suffix โ€” for some targets, a suffix gets added to the root directory given with --sysroot, depending on the other options you used, so headers might be found in dir/suffix/usr/include instead of dir/usr/include ๐Ÿ™ˆ This option turns off the addition of that suffix.

โœจ Options for Code Generation Conventions โœจ

These machine-independent options control the interface conventions used in code generation ๐Ÿ’…

Most of them have both positive and negative forms, and the negative form of -ffoo is -fno-foo. Below, only one of the forms is listed (the one that is not the default). You can figure out the other form by either removing no- or adding it ๐Ÿซถ

  • -fstack-reuse=reuse-level โ€” controls stack space reuse for user-declared local/auto variables and compiler-generated temporaries ๐ŸŒˆ reuse_level can be all, named_vars, or none. all turns on stack reuse for every local variable and temporary, named_vars only reuses space for user-defined local variables that have names, and none turns stack reuse off 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 defined by the language. When a variable's lifetime ends and it lives in memory, the optimizing compiler is free to reuse its stack space with other temporaries or scoped local variables whose live range doesn't overlap with it.

Legacy code that extends local lifetime is likely to break with the stack reuse optimization ๐Ÿ˜ญ

For example,

int *p;
{
  int local1;

  p = &local1;
  local1 = 10;
  ....
}
{
   int local2;
   local2 = 20;
   ...
}

if (*p == 10)  // out of scope use of local1
  {

  }

Another example:

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

A *ap;

void foo(const A& ar)
{
   ap = &ar;
}

void bar()
{
   foo(A(10)); // temp object's lifetime ends when foo returns

   {
     A a(20);
     ....
   }
   ap->i+= 10;  // ap references out of scope temp whose space
                // is reused with a. What is the value of ap->i?
}

The lifetime of a compiler-generated temporary is well defined by the C++ standard. When a temporary's lifetime ends and it lives in memory, the optimizing compiler is free to reuse its stack space with other temporaries or scoped local variables whose live range doesn't overlap with it. However, some legacy code relies on the behavior of older compilers, where temporaries' stack space wasn't reused, so aggressive stack reuse can lead to runtime errors ๐Ÿ’€ This option controls that temporary stack reuse optimization.

  • -ftrapv โ€” generates traps for signed overflow on addition, subtraction, and multiplication operations ๐Ÿ”ฅ -ftrapv and -fwrapv override each other, so using -ftrapv -fwrapv on the command line results in -fwrapv being effective. Only active options override, though, so using -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 using -ftrapv -fwrapv on the command line results in -fwrapv being effective. Only active options override, so using -ftrapv -fwrapv -fno-wrapv on the command line results in -ftrapv being effective.
  • -fwrapv-pointer โ€” tells the compiler to assume that pointer arithmetic overflow on addition and subtraction wraps around using twos-complement representation ๐ŸŒธ This flag disables some optimizations that assume pointer overflow is invalid.
  • -fstrict-overflow โ€” implies -fno-wrapv -fno-wrapv-pointer, and when negated, implies -fwrapv -fwrapv-pointer ๐Ÿ‘‘
  • -fexceptions โ€” okay bestie, this one switches on exception handling ๐Ÿ’– It generates the extra code needed to propagate exceptions. On some targets it also means GCC builds frame unwind info for every function, which can add serious data size overhead, but it doesn't mess with execution ๐Ÿ™ˆ If you don't say anything, 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. You might need to enable it manually when your C code has to play nicely with exception handlers written in C++ โœจ You might also want to disable it if you're compiling older C++ programs that don't use exception handling.
  • -fnon-call-exceptions โ€” lets trapping instructions throw exceptions ๐Ÿฆ‹ ngl this needs platform-specific runtime support, and that support doesn't exist everywhere. It only lets trapping instructions, meaning memory references or floating-point instructions, throw. It does not let exceptions come out of arbitrary signal handlers like "SIGALRM". This one also turns on -fexceptions.
  • -fdelete-dead-exceptions โ€” instructions that might throw but don't otherwise contribute to the program can be optimized away ๐Ÿงน This doesn't touch calls to functions unless they have the "pure" or "const" attributes. It's on by default for the Ada and C++ compilers, since the language specs allow it. The optimization passes that remove dead exceptions turn on independently at different optimization levels.
  • -funwind-tables โ€” basically the vibe of -fexceptions, except it only generates the needed static data and leaves the generated code alone ๐ŸŒธ You usually don't have to turn this on yourself, because any language processor that needs this handling enables it for you.
  • -fasynchronous-unwind-tables โ€” generates an unwind table in DWARF format, if the target machine supports it ๐Ÿ”ฅ The table is exact at every instruction boundary, so it can be used for stack unwinding from asynchronous events, like a debugger or a garbage collector.
  • -fno-gnu-unique โ€” okay, this one's a little dramatic ๐ŸŒถ๏ธ On systems with a recent GNU assembler and C library, the C++ compiler uses the "STB_GNU_UNIQUE" binding so definitions of template static data members and static local variables in inline functions stay unique, even with "RTLD_LOCAL". That matters so a library used by two different "RTLD_LOCAL" plugins doesn't end up depending on a definition in one of them while disagreeing with the other about the binding of the symbol. BUT, this makes dlclose get ignored for affected DSOs. So if your program relies on reinitializing a DSO through dlclose and dlopen, you can use -fno-gnu-unique ๐Ÿ’…
  • -fpcc-struct-return โ€” returns "short" "struct" and "union" values in memory, just like the longer ones, instead of in registers ๐Ÿงš It's less efficient, but it lets GCC-compiled files play nicely with files built by other compilers, especially the Portable C Compiler (pcc).

The precise convention for returning structures in memory depends on the target configuration macros. Short structures and unions are those whose size and alignment match that of some integer type.

Warning: code compiled with -fpcc-struct-return is not binary compatible with code compiled with -freg-struct-return. 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 than -fpcc-struct-return for small structures.

If you specify neither -fpcc-struct-return nor -freg-struct-return, GCC defaults to whichever convention is standard for the target. If there's no standard convention, GCC defaults to -fpcc-struct-return, except on targets where GCC is the principal compiler. In those cases, GCC gets to choose the standard, and it picks the more efficient register return alternative.

Warning: code compiled with -freg-struct-return is not binary compatible with code compiled with -fpcc-struct-return. Use it to conform to a non-default application binary interface.
  • -fshort-enums โ€” gives an enum type only as many bytes as it needs for its declared range of possible values ๐Ÿ“ Specifically, the enum type becomes the smallest integer type with enough room. This option has no effect on an enumeration type with a fixed underlying type.
Warning: -fshort-enums makes GCC generate code that is not binary compatible with code generated without that switch. Use it to conform to a non-default application binary interface.
  • -fshort-wchar โ€” overrides the underlying type for "wchar_t" to be "short unsigned int" instead of the target's default โœจ It's super useful for building programs that run under WINE.
Warning: -fshort-wchar makes GCC generate code that is not binary compatible with code generated without that switch. 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 ๐ŸŽ€ These are called tentative definitions in the C standard. They're different from declarations with the extern keyword, which don't allocate any storage.

The default is -fno-common, which 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 the tentative definitions of the same variable across different compilation units to one object, or to a non-tentative definition. This behaviour is inconsistent with C++, and on many targets it implies a speed and code size penalty on global variable references. It's mainly useful for getting legacy code to link without errors.

  • -fno-ident โ€” ignores the #ident directive ๐Ÿซถ
  • -finhibit-size-directive โ€” don't output a .size assembler directive, or anything else that would cause trouble if the function gets split in the middle and the two halves end up far apart in memory ๐ŸŒˆ This is used when compiling crtstuff.c, so you shouldn't need it for anything else.
  • -fverbose-asm โ€” adds extra commentary to the generated assembly so it's way easier to read ๐Ÿ“ This one's really for people who actually need to read generated assembly, like when they're debugging the compiler itself.

-fno-verbose-asm, the default, leaves the extra info out, which is clutch when you're comparing two assembler files.

The added comments include:

  • information on the compiler version and command-line options,
  • the source code lines associated with the assembly instructions, in the form FILENAME:LINENUMBER:CONTENT OF LINE,
  • hints on which high-level expressions correspond to the various assembly instruction operands.

For example, given this C source file:

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

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

  return total;
}

Compiling to (x86_64) assembly via -S and emitting the result direct to stdout via -o -:

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

gives output similar to this:

        .file   "test.c"
# GNU C11 (GCC) version 7.0.0 20160809 (experimental) (x86_64-pc-linux-gnu)
  [...snip...]
# options passed:
  [...snip...]

        .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 the comments is subject to change ๐Ÿฆ‹

  • -frecord-gcc-switches โ€” this makes the command line used to invoke the compiler get recorded into the object file being created ๐Ÿ’… It's only implemented on some targets, and the exact format of the recording depends on the target and binary file format. Usually it takes the form of a section containing ASCII text. This switch is related to -fverbose-asm, but that one only records information as comments in the assembler output file, so it never reaches the object file. See also -grecord-gcc-switches for another way of storing compiler options in the object file.
  • -fpic โ€” โœจ okay bestie, this one makes position-independent code (PIC) that's ready to live inside a shared library ๐Ÿ’–, if your target machine supports it. The code reaches every constant address through a global offset table (GOT), and the dynamic loader fills in those GOT entries when the program starts ๐Ÿงš (fun fact: the dynamic loader is NOT part of GCC, it's part of the operating system ๐Ÿ™„). If the GOT for the linked executable goes over a machine-specific maximum, the linker yells that -fpic doesn't work ๐Ÿ’€, and then you just recompile with -fPIC instead. (Those maxes are 8k on the SPARC, 28k on AArch64, and 32k on the m68k and RS/6000. The x86 has no such limit ๐Ÿซถ.)
    • PIC needs special support, so it only works on certain machines ๐Ÿ˜ญ. For the x86, GCC supports PIC for System V but not for the Sun 386i. Code generated for the IBM RS/6000 is always position-independent ๐ŸŒˆ.
    • When this flag is set, the macros "__pic__" and "__PIC__" are defined to 1 โœจ.
  • -fPIC โ€” ๐Ÿ”ฅ if your target supports it, this emits position-independent code that's suitable for dynamic linking and has no limit on the size of the global offset table ๐Ÿ‘‘. This option makes a difference on AArch64, m68k, PowerPC and SPARC.
    • Same deal as above: PIC 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 cousins of -fpic and -fPIC ๐Ÿฆ‹, but the position-independent code can only be linked into executables (not shared libraries) ๐Ÿ™ˆ. Usually you use these when you're compiling code that gets linked with the -pie GCC option.
    • Both -fpie and -fPIE define the macros "__pie__" and "__PIE__". The value is 1 for -fpie and 2 for -fPIE ๐Ÿ’œ.
  • -fno-plt โ€” โœจ this tells GCC to not use the PLT for external function calls in position-independent code ๐ŸŒธ. Instead, it loads the callee address at call sites from the GOT and branches to it. It's giving more efficient code, since it gets rid of PLT stubs and lets GOT loads be optimized ๐Ÿ’–. 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 ๐Ÿซถ. Heads up though: lazy binding needs the PLT, so with -fno-plt all external symbols get resolved at load time โฐ.
    • Want this for just some functions instead? Use the function attribute "noplt" to avoid calls through the PLT for specific external functions ๐Ÿง.
    • In position-dependent code, a few targets also convert calls to functions marked to not use the PLT so they use the GOT instead ๐ŸŒˆ.
  • -fno-jump-tables โ€” ๐Ÿ™…โ€โ™€๏ธ no jump tables for switch statements, even when they'd be more efficient than other code generation strategies. This is handy alongside -fpic or -fPIC when you're building code that's part of a dynamic linker and can't reference the address of a jump table ๐Ÿ”ง. On some targets jump tables don't need a GOT, so this option isn't needed there ๐Ÿ“.
  • -fno-bit-tests โ€” no bit tests for switch statements, even when they'd be more efficient than other code generation strategies ๐Ÿซง.
  • -ffixed-reg โ€” ๐Ÿ“Œ treat the register named reg as a fixed register, so the 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 names depend on the machine and are 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 used for temporaries or variables that don't live across a call. Functions compiled this way do not save and restore reg ๐Ÿ’ซ.
    • It's an error to use this flag with the frame pointer or stack pointer ๐Ÿšซ.
    • Using this on other registers with fixed, pervasive roles in the machine's execution model produces disastrous results ๐Ÿ’€.
    • No negative form here either, since it's a three-way choice ๐Ÿ’….
  • -fcall-saved-reg โ€” ๐Ÿ›ก๏ธ treat the register named reg as an allocable register that's saved by functions. It can be allocated even for temporaries or variables that live across a call. Functions compiled this way save and restore reg if they use it ๐Ÿซถ.
    • Same rule: it's an error to use this with the frame pointer or stack pointer ๐Ÿšซ.
    • Using it on other registers with fixed pervasive roles produces disastrous results ๐Ÿ˜ญ.
    • A different kind of disaster happens if you use this flag on a register that function values may be returned in ๐ŸŒช๏ธ.
    • No negative form, three-way choice ๐Ÿฆ‹.
  • -fpack-struct[=n] โ€” ๐Ÿ“ฆ without a value, this packs all structure members together with no holes. With a value (which has to be a small power of two), it packs structure members according to that value, which is the maximum alignment. So objects with default alignment requirements bigger than that get output potentially unaligned at the next fitting location ๐Ÿงฉ.
โš ๏ธ Warning, bestie: -fpack-struct makes GCC generate code that is not binary compatible with code generated without it. 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 how C symbols are represented in the object file. One use is to help link with legacy assembly code ๐Ÿง“.
โš ๏ธ Warning: -fleading-underscore makes GCC generate code that is not binary compatible with code generated without it ๐Ÿ’”. Use it only to conform to a non-default application binary interface. And not every target fully supports this switch, so check before you count on it ๐Ÿ™ˆ.
  • -ftls-model=model โ€” ๐Ÿงต alter the thread-local storage model. The model argument should be one of global-dynamic, local-dynamic, initial-exec or local-exec ๐ŸŒท. The choice is subject to optimization though, so the compiler might use a more efficient model for symbols that aren't visible outside the translation unit, or if -fpic isn't given on the command line ๐Ÿง .
    • The default without -fpic is initial-exec. With -fpic, the default is global-dynamic โœจ.
  • -ftrampolines โ€” ๐ŸŽ  for targets that normally need trampolines for nested functions, this always generates them instead of using descriptors. For targets that don't need them, like HP-PA or IA-64, it does nothing ๐ŸŒฟ.
    • A trampoline is a tiny piece of code that gets created at run time on the stack when the address of a nested function is taken. It's used to call the nested function indirectly ๐Ÿฆ„. That means the stack has to be made executable for the program to work properly ๐Ÿ˜ณ.
    • -fno-trampolines is enabled by default on a language-by-language basis, so the compiler can skip generating trampolines when it figures that's safe and swap in descriptors instead ๐Ÿง. Descriptors are made up of data only, but the generated code has to be ready to deal with them ๐Ÿ’œ. As of this writing, -fno-trampolines is enabled by default only for Ada ๐Ÿ‘‘.
    • Code compiled with -ftrampolines and code compiled with -fno-trampolines are not binary compatible if nested functions are present. So this option has to be used program-wide, and it needs extreme care ๐Ÿ˜ค.
    • For languages other than Ada, -ftrampolines and -fno-trampolines currently have no effect. Trampolines are always generated on platforms that need them for nested functions ๐ŸŒธ.
  • -ftrampoline-impl=[stack|heap] โ€” ๐Ÿ  by default, trampolines get generated on the stack. But some platforms (like the Apple M1) don't allow an executable stack ๐Ÿ™…โ€โ™€๏ธ. Compiling with -ftrampoline-impl=heap generates calls to __gcc_nested_func_ptr_created and __gcc_nested_func_ptr_deleted, which allocate and deallocate trampoline space on the executable heap ๐Ÿงบ. These functions are implemented in libgcc and only get provided on specific targets: x86_64 Darwin, and x86_64 and aarch64 Linux ๐Ÿง.
๐Ÿšจ PLEASE NOTE: heap trampolines are not guaranteed to be correctly deallocated if you setjmp, instantiate nested functions, and then longjmp back to a state prior to having allocated those nested functions. Be careful, bestie ๐Ÿ’€.
  • -fvisibility=[default|internal|hidden|protected] โ€” ๐Ÿ‘€ this sets the default ELF image symbol visibility to the option you pick. Every symbol gets marked with it unless the code overrides it ๐Ÿ’–. Using this can massively 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, meaning it's available to be linked against from outside the shared object ๐ŸŒˆ. protected and internal are pretty useless in real-world usage, so the only other one people commonly use is hidden ๐Ÿ™ˆ.
    • If you don't specify -fvisibility, the default is default, which makes every symbol public ๐Ÿงš.
    • A great explanation of why correct ELF symbol visibility matters is "How To Write Shared Libraries" by Ulrich Drepper, which you can find at https://www.akkadia.org/drepper/ ๐Ÿ“–. But here's the superior move ๐Ÿ‘‘: instead of marking things hidden when the default is public, make the default hidden and mark the things you want 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 ๐Ÿฆ‹. It's a total boon for anyone working on cross-platform projects ๐Ÿ’…โœจ.

Okay so, if you're adding visibility support to existing code, #pragma GCC visibility is literally your new bestie ๐Ÿซถ. You wrap the declarations you want to control with #pragma GCC visibility push(hidden) and close it off with #pragma GCC visibility pop. โœจ

Real talk though: symbol visibility is part of the API interface contract ๐Ÿ“œ, so all new code should always specify visibility whenever it isn't the default. Declarations that are only for use within the local DSO should ALWAYS be explicitly marked as hidden ๐Ÿ™ˆ, so you dodge PLT indirection overheads. Being super clear about it also helps readability and makes the code self-documenting. Iconic behavior ๐Ÿ’…. Heads up though: due to ISO C++ specification requirements, operator new and operator delete must always be of default visibility. Nonnegotiable ๐Ÿ˜ญ.

Watch out for headers from outside your project ๐Ÿ‘€, especially system headers and headers from any other library you use. They might not be expecting to be compiled with any visibility other than the default. If that's the case, you may need to explicitly say #pragma GCC visibility push(default) before including them. ๐ŸŒธ

extern declarations are NOT affected by -fvisibility ๐Ÿงš, which means a lot of code can be recompiled with -fvisibility=hidden with zero modifications. Lowkey amazing. But here's the catch: calls to extern functions with no explicit visibility use the PLT, so it's way more effective to use __attribute ((visibility)) and/or #pragma GCC visibility to tell the compiler which extern declarations should be treated as hidden ๐Ÿ’–.

Also, -fvisibility does affect C++ vague linkage entities ๐ŸŒˆ. So, for instance, an exception class that gets thrown between DSOs must be explicitly marked with default visibility so the type_info nodes get unified between the DSOs. Don't skip this one bestie ๐Ÿ’€.

If you want the full tea on all these techniques, their benefits, and how to use them, check out the overview at https://gcc.gnu.org/wiki/Visibility. ๐Ÿฆ‹


-fstrict-volatile-bitfields ๐Ÿ“

This one is for when accesses to volatile bit-fields (or other structure fields, although the compiler usually honors those types anyway) should use a single access of the width of the field's type, aligned to a natural alignment if possible. For example, targets with memory-mapped peripheral registers might require all such accesses to be 16 bits wide. With this flag you can declare all peripheral bit-fields as unsigned short (assuming short is 16 bits on these targets) to force GCC to use 16-bit accesses instead of, perhaps, a more efficient 32-bit access. ๐ŸŽ€

If this option is disabled, the compiler uses the most efficient instruction. In the previous example, that might be a 32-bit load instruction, even though that accesses bytes that don't contain any part of the bit-field, or memory-mapped registers unrelated to the one being updated. Yikes ๐Ÿ˜ฌ.

In some cases, such as when the packed attribute is applied to a structure field, it may not be possible to access the field with a single read or write that is correctly aligned for the target machine. In this case GCC falls back to generating multiple accesses rather than code that will fault or truncate the result at run time. Safe and sound ๐Ÿ’œ.

Note: Due to restrictions of the C/C++11 memory model, write accesses are not allowed to touch non bit-field members. It is therefore recommended to define all bits of the field's type as bit-field members. ๐Ÿ™

The default value of this option is determined by the application binary interface for the target processor. โœจ

-fsync-libcalls ๐Ÿ”ฅ

This 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 value of this option is enabled, so the only useful form of the option is -fno-sync-libcalls. This option is used in the implementation of the libatomic runtime library. ๐Ÿ‘‘


๐Ÿฆ‹ GCC Developer Options ๐Ÿฆ‹

This section covers command-line options that are mainly of interest to GCC developers, including options for compiler testing and for 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 compilation and linking tasks. ๐Ÿค“

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

If =filename is omitted, a default dump file name is 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 produced by the compiler if it was explicitly specified and isn't an executable; otherwise it's the source file name. The pass number is determined by the order passes are registered with the compiler's pass manager. This is generally the same as the order of execution, but passes registered by plugins, target-specific passes, or passes that are otherwise registered late are numbered higher than the pass named final, even if they're executed 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 ๐Ÿ•ธ๏ธ

Makes the compiler output callgraph information for the program, on a per-object-file basis. The information is generated in the common VCG format. It can be decorated with additional, per-node and/or per-edge information, if a list of comma-separated markers is also specified. When the su marker is specified, the callgraph is decorated with stack usage information; it's equivalent to -fstack-usage. When the da marker is specified, the callgraph is decorated with information 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 ๐Ÿงšโ€โ™€๏ธ

Says to make debugging dumps during compilation at the times specified by letters. This is used for debugging the RTL-based passes of the compiler. ๐Ÿ”

Some -dletters switches have a different meaning when -E is used for preprocessing. ๐Ÿ™ƒ

Debug dumps can be enabled with a -fdump-rtl switch or some -d option letters. Here's the lineup of possible letters for use in pass and letters, and what each one means ๐Ÿ‘‡

  • -fdump-rtl-alignments โ€” Dumps after branch alignments have been computed. ๐Ÿ“
  • -fdump-rtl-asmcons โ€” Dumps after fixing RTL statements that have unsatisfied in/out constraints. ๐Ÿ› ๏ธ
  • -fdump-rtl-auto_inc_dec โ€” Dumps after auto-inc-dec discovery. This pass is only run on architectures that have auto inc or auto dec instructions. ๐Ÿฆ‹
  • -fdump-rtl-barriers โ€” Dumps after cleaning up the barrier instructions. ๐Ÿงน
  • -fdump-rtl-bbpart โ€” Dumps after partitioning hot and cold basic blocks. ๐Ÿ”ฅโ„๏ธ
  • -fdump-rtl-bbro โ€” Dumps after block reordering. ๐Ÿ”€
  • -fdump-rtl-btl1, -fdump-rtl-btl2 โ€” Enable dumping after the two branch target load optimization passes. ๐ŸŽฏ
  • -fdump-rtl-bypass โ€” Dumps after jump bypassing and control flow optimizations. ๐Ÿ›ค๏ธ
  • -fdump-rtl-combine โ€” Dumps after the RTL instruction combination pass. ๐Ÿงฉ
  • -fdump-rtl-compgotos โ€” Dumps after duplicating the computed gotos. ๐Ÿช„
  • -fdump-rtl-ce1, -fdump-rtl-ce2, -fdump-rtl-ce3 โ€” Enable dumping after the three if conversion passes. ๐Ÿ”
  • -fdump-rtl-cprop_hardreg โ€” Dumps after hard register copy propagation. ๐Ÿ“‹
  • -fdump-rtl-csa โ€” Dumps after combining stack adjustments. ๐Ÿฅž
  • -fdump-rtl-cse1, -fdump-rtl-cse2 โ€” Enable dumping after the two common subexpression elimination passes. ๐ŸŒธ
  • -fdump-rtl-dce โ€” Dumps after the standalone dead code elimination passes. ๐Ÿ—‘๏ธ
  • -fdump-rtl-dbr โ€” Dumps after delayed branch scheduling. โณ
  • -fdump-rtl-dce1, -fdump-rtl-dce2 โ€” Enable dumping after the two dead store elimination passes. ๐Ÿ’€
  • -fdump-rtl-eh โ€” Dumps after finalization of EH handling code. ๐Ÿšจ
  • -fdump-rtl-eh_ranges โ€” Dumps after conversion of EH handling range regions. ๐Ÿ—บ๏ธ
  • -fdump-rtl-expand โ€” Dumps after RTL generation. ๐ŸŒฑ
  • -fdump-rtl-fwprop1, -fdump-rtl-fwprop2 โ€” Enable dumping after the two forward propagation passes. โžก๏ธ
  • -fdump-rtl-gcse1, -fdump-rtl-gcse2 โ€” Enable dumping after global common subexpression elimination. ๐ŸŒ
  • -fdump-rtl-init-regs โ€” Dumps after the initialization of the registers. ๐Ÿ
  • -fdump-rtl-initvals โ€” Dumps after the computation of the initial value sets. ๐ŸŒฑ
  • -fdump-rtl-into_cfglayout โ€” Dumps after converting to cfglayout mode. ๐Ÿงญ
  • -fdump-rtl-ira โ€” Dumps after iterated register allocation. ๐Ÿ—‚๏ธ
  • -fdump-rtl-jump โ€” Dumps after the second jump optimization. ๐Ÿฆ˜
  • -fdump-rtl-loop2 โ€” Enables dumping after the RTL loop optimization passes. ๐Ÿ”„
  • -fdump-rtl-mach โ€” Dumps after performing the machine dependent reorganization pass, if that pass exists. ๐Ÿค–
  • -fdump-rtl-mode_sw โ€” Dumps after removing redundant mode switches. ๐ŸŽš๏ธ
  • -fdump-rtl-rnreg โ€” Dumps after register renumbering. ๐Ÿ”ข
  • -fdump-rtl-outof_cfglayout โ€” Dumps after converting from cfglayout mode. ๐Ÿงญ
  • -fdump-rtl-peephole2 โ€” Dumps after the peephole pass. ๐Ÿ”
  • -fdump-rtl-postreload โ€” Dumps after post-reload optimizations. ๐Ÿ”ง
  • -fdump-rtl-pro_and_epilogue โ€” Dumps after generating the function prologues and epilogues. ๐ŸŽฌ
  • -fdump-rtl-sched1, -fdump-rtl-sched2 โ€” Enable dumping after the basic block scheduling passes. ๐Ÿ—“๏ธ

-fdump-rtl-ree Dump after sign/zero extension elimination.

Hm bestie, I'm not even sure I need to show you a -fdump-rtl-ree example. Okay wait, no, let's get into it ๐Ÿ’…

Okay, -fdump-rtl-ree is the one that dumps right after the sign/zero extension elimination pass. Lowkey iconic.

-fdump-rtl-seqabstr Dump after common sequence discovery.

Okay so -fdump-rtl-seqabstr gives you a dump after common sequence discovery. It's giving pattern-finding energy ๐Ÿ”โœจ

-fdump-rtl-shorten Dump after shortening branches.

-fdump-rtl-shorten dumps after the branch-shortening pass. Main character energy for branches ๐Ÿฆ‹

-fdump-rtl-sibling Dump after sibling call optimizations.

-fdump-rtl-sibling is the one for after sibling call optimizations. Slay ๐Ÿ’–

-fdump-rtl-split1 -fdump-rtl-split2 -fdump-rtl-split3 -fdump-rtl-split4 -fdump-rtl-split5 These options enable dumping after five rounds of instruction splitting.

Okay bestie, these five are the splits. -fdump-rtl-split1 through -fdump-rtl-split5 each give you a dump after one of the five rounds of instruction splitting. Five rounds, no cap ๐ŸŒˆ

-fdump-rtl-sms Dump after modulo scheduling. This pass is only run on some architectures.

-fdump-rtl-sms dumps after modulo scheduling. Heads up, this one only runs on some architectures, so if it's not showing up, that's why ๐Ÿ™ˆ

-fdump-rtl-stack Dump after conversion from GCC's "flat register file" registers to the x87's stack-like registers. This pass is only run on x86 variants.

-fdump-rtl-stack is the dump after GCC turns its "flat register file" registers into the x87's stack-like registers. This pass only runs on x86 variants, so don't be surprised if it's missing elsewhere ๐ŸŽ€

-fdump-rtl-subreg1 -fdump-rtl-subreg2 -fdump-rtl-subreg1 and -fdump-rtl-subreg2 enable dumping after the two subreg expansion passes.

Okay so -fdump-rtl-subreg1 and -fdump-rtl-subreg2 both give you dumps after the two subreg expansion passes. Two passes, two dumps, we love a matching set ๐Ÿงš

-fdump-rtl-unshare Dump after all rtl has been unshared.

-fdump-rtl-unshare dumps after all the RTL has been unshared. Unshared and iconic ๐Ÿ‘‘

-fdump-rtl-vartrack Dump after variable tracking.

-fdump-rtl-vartrack is the one for after variable tracking ๐Ÿซถ

-fdump-rtl-vregs Dump after converting virtual registers to hard registers.

-fdump-rtl-vregs dumps after virtual registers have been converted to hard registers. Virtual to hard, the ultimate glow-up โœจ

-fdump-rtl-web Dump after live range splitting.

-fdump-rtl-web dumps after live range splitting. It's giving web-weaving vibes ๐Ÿ•ธ๏ธ๐Ÿ’œ

-fdump-rtl-regclass -fdump-rtl-subregs_of_mode_init -fdump-rtl-subregs_of_mode_finish -fdump-rtl-dfinit -fdump-rtl-dfinish These dumps are defined but always produce empty files.

Bestie, I have to warn you about these five: -fdump-rtl-regclass, -fdump-rtl-subregs_of_mode_init, -fdump-rtl-subregs_of_mode_finish, -fdump-rtl-dfinit, and -fdump-rtl-dfinish are defined but always produce empty files. Don't waste your time staring at them ๐Ÿ’€

-da -fdump-rtl-all Produce all the dumps listed above.

-da and -fdump-rtl-all both produce all the dumps listed above. The whole buffet ๐Ÿ“

-dA Annotate the assembler output with miscellaneous debugging information.

-dA adds miscellaneous debugging information to the assembler output. Extra annotations, extra cute ๐ŸŽ€

-dD Dump all macro definitions, at the end of preprocessing, in addition to normal output.

-dD dumps all macro definitions at the end of preprocessing, on top of the normal output. Every macro, served ๐Ÿ’…

-dH Produce a core dump whenever an error occurs.

-dH makes GCC produce a core dump whenever an error occurs. Errors, hit different now ๐Ÿ˜ญ

-dp Annotate the assembler output with a comment indicating which pattern and alternative is used. The length and cost of each instruction are also printed.

-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. Receipts for every instruction ๐Ÿงพ๐ŸŒธ

-dP Dump the RTL in the assembler output as a comment before each instruction. Also turns on -dp annotation.

-dP puts the RTL in the assembler output as a comment before each instruction. It also turns on the -dp annotation, so you get both ๐Ÿฆ‹

-dx Just generate RTL for a function instead of compiling it. Usually used with -fdump-rtl-expand.

-dx just generates RTL for a function instead of compiling it all the way. It's usually paired with -fdump-rtl-expand ๐Ÿงšโœจ

-fdump-debug Dump debugging information generated during the debug generation phase.

-fdump-debug dumps the debugging information generated during the debug generation phase. Debug tea, spilled โ˜•

-fdump-earlydebug Dump debugging information generated during the early debug generation phase.

-fdump-earlydebug does the same thing but for the early debug generation phase. Early bird debug gets the worm ๐Ÿ›

-fdump-noaddr When doing debugging dumps, suppress address output. This makes it more feasible to use diff on debugging dumps for compiler invocations with different compiler binaries and/or different text / bss / data / heap / stack / dso start locations.

Okay this one is so useful, bestie. -fdump-noaddr hides address output in debugging dumps, which makes it way easier to diff dumps when your compiler invocations use different compiler binaries, or different text, bss, data, heap, stack, or dso start locations. Less noise, more vibes ๐Ÿซถ๐Ÿ’–

-freport-bug Collect and dump debug information into a temporary file if an internal compiler error (ICE) occurs.

-freport-bug collects and dumps debug information into a temporary file if an internal compiler error (ICE) happens. Ate that ICE, and left no crumbs ๐Ÿฅน

-fdump-unnumbered When doing debugging dumps, suppress instruction numbers and address output. This makes it more feasible to use diff on debugging dumps for compiler invocations with different options, in particular with and without -g.

-fdump-unnumbered suppresses instruction numbers and address output in debugging dumps. That makes diff way more feasible when your invocations use different options, especially with and without -g ๐ŸŒˆ

-fdump-unnumbered-links When doing debugging dumps (see -d option above), suppress instruction numbers for the links to the previous and next instructions in a sequence.

-fdump-unnumbered-links is for when you're doing debugging dumps (see the -d option above). It suppresses instruction numbers for the links to the previous and next instructions in a sequence. Links with no numbers, no drama ๐Ÿ”—๐Ÿ’œ

-fdump-ipa-switch -fdump-ipa-switch-options Control the dumping at various stages of inter-procedural analysis language tree to a file. The file name is generated by appending a switch specific suffix to the source file name, and the file is created in the same directory as the output file. The following dumps are possible:

Okay so -fdump-ipa-switch and -fdump-ipa-switch-options control dumping at various stages of inter-procedural analysis language tree to a file. The file name comes from appending a switch-specific suffix to the source file name, and the file gets created in the same directory as the output file. Here are the dumps you can pick from:

all Enables all inter-procedural analysis dumps.

cgraph Dumps information about call-graph optimization, unused function removal, and inlining decisions.

inline Dump after function inlining.

strubm Dump after selecting "strub" modes, and recording the selections as function attributes.

strub Dump "strub" transformations: interface changes, function wrapping, and insertion of builtin calls for stack scrubbing and watermarking.

Additionally, the options -optimized, -missed, -note, and -all can be provided, with the same meaning as for -fopt-info, defaulting to -optimized.

For example, -fdump-ipa-inline-optimized-missed will emit information on callsites that were inlined, along with callsites that were not inlined.

By default, the dump will contain messages about successful optimizations (equivalent to -optimized) together with low-level details about the analysis.

-fdump-lang Dump language-specific information. The file name is made by appending .lang to the source file name.

-fdump-lang dumps language-specific information. The file name is made by appending .lang to the source file name ๐ŸŒธ

-fdump-lang-all -fdump-lang-switch -fdump-lang-switch-options -fdump-lang-switch-options=filename Control the dumping of language-specific information. The options and filename portions behave as described in the -fdump-tree option. The following switch values are accepted:

-fdump-lang-all, -fdump-lang-switch, -fdump-lang-switch-options, and -fdump-lang-switch-options=filename control the dumping of language-specific information. The options and filename parts work the same way as described under -fdump-tree. These switch values are accepted:

all Enable all language-specific dumps.

class Dump class hierarchy information. Virtual table information is emitted unless 'slim' is specified. This option is applicable to C++ only.

module Dump module information. Options lineno (locations), graph (reachability), blocks (clusters), uid (serialization), alias (mergeable), asmname (Elrond), eh (mapper) & vops (macros) may provide additional information. This option is applicable to C++ only.

raw Dump the raw internal tree data. This option is applicable to C++ only.

-fdump-passes Print on stderr the list of optimization passes that are turned on and off by the current command-line options.

-fdump-passes prints to stderr the list of optimization passes that are turned on and off by your current command-line options ๐Ÿ“‹โœจ

-fdump-statistics-option Enable and control dumping of pass statistics in a separate file. The file name is generated by appending a suffix ending in .statistics to the source file name, and the file is created in the same directory as the output file. If the -option form is used, -stats causes counters to be summed over the whole compilation unit while -details dumps every event as the passes generate them. The default with no option is to sum counters for each function compiled.

-fdump-statistics-option turns on and controls pass statistics dumping into a separate file. The file name comes from appending a suffix ending in .statistics to the source file name, and it gets created in the same directory as the output file. With the -option form, -stats sums counters over the whole compilation unit, while -details dumps every event as the passes generate them. With no option, the default is to sum counters for each function compiled ๐Ÿ“Š๐Ÿ’…

-fdump-tree-all -fdump-tree-switch -fdump-tree-switch-options -fdump-tree-switch-options=filename Control the dumping at various stages of processing the intermediate language tree to a file. If the -options form is used, options is a list of - separated options which control the details of the dump. Not all options are applicable to all dumps; those that are not meaningful are ignored. The following options are available

Okay, -fdump-tree-all, -fdump-tree-switch, -fdump-tree-switch-options, and -fdump-tree-switch-options=filename control 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 apply just get ignored. These are the options available:

address Print the address of each node. Usually this is not meaningful as it changes according to the environment and source file. Its primary use is for tying up a dump file with a debug environment.

asmname If "DECL_ASSEMBLER_NAME" has been set for a given decl, use that in the dump instead of "DECL_NAME". Its primary use is ease of use working backward from mangled names in the assembly file.

slim When dumping front-end intermediate representations, inhibit dumping of members of a scope or body of a function merely because that scope has been reached. Only dump such items when they are directly reachable by some other path.

When dumping pretty-printed trees, this option inhibits dumping the bodies of control structures.

When dumping RTL, print the RTL in slim (condensed) form instead of the default LISP-like representation.

raw Print a raw representation of the tree. By default, trees are pretty-printed into a C-like representation.

details Enable more detailed dumps (not honored by every dump option). Also include information from the optimization passes.

stats Enable dumping various statistics about the pass (not honored by every dump option).

blocks Enable showing basic block boundaries (disabled in raw dumps).

graph For each of the other indicated dump files (-fdump-rtl-pass), dump a representation of the control flow graph suitable for viewing with GraphViz to file.passid.pass.dot. Each function in the file is pretty-printed as a subgraph, so that GraphViz can render them all in a single plot.

This option currently only works for RTL dumps, and the RTL is always dumped in slim form.

vops Enable showing virtual operands for every statement.

lineno Enable showing line numbers for statements.

uid Enable showing the unique ID ("DECL_UID") for each variable.

verbose Enable showing the tree dump for each statement.

eh Enable showing the EH region number holding each statement.

scev Enable showing scalar evolution analysis details.

optimized Enable showing optimization information (only available in certain passes).

missed Enable showing missed optimization information (only available in certain passes).

note Enable other detailed optimization information (only available in certain passes).

all Turn on all options, except raw, slim, verbose and lineno.

optall Turn on all optimization options, i.e., optimized, missed, and note.

To determine what tree dumps are available or find the dump for a pass of interest follow the steps below.

  1. Invoke GCC with -fdump-passes and in the stderr output look for a code that corresponds to the pass you are interested in. For example, the codes "tree-evrp", "tree-vrp1", and "tree-vrp2" correspond to the three Value Range Propagation passes. The number at the end distinguishes distinct invocations of the same pass.
  2. To enable the creation of the dump file, append the pass code to the -fdump- option prefix and invoke GCC with it. For example, to enable the dump from the Early Value Range Propagation pass, invoke GCC with the -fdump-tree-evrp option. Optionally, you may specify the name of the dump file. If you don't specify one, GCC creates as described below.
  3. Hunt down the pass dump in a file whose name has three parts joined by periods: the name of the source file GCC was invoked to compile, a numeric suffix for the pass number followed by t for tree passes (or 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. ngl, the numeric codes are not stable, so they can change from one version of GCC to another ๐Ÿ™ˆ

-fopt-info, -fopt-info-options, -fopt-info-options=filename

Okay so this one controls the optimization dumps coming out of the various optimization passes ๐Ÿ’…. If you use the -options form, options is a list of --separated keywords that pick the dump details and the optimizations you want. Think of it as building a little playlist ๐ŸŽ€

The options come in three groups ๐Ÿ‘‘:

  1. options describing what kinds of messages should be emitted,
  2. options describing the verbosity of the dump, and
  3. options describing which optimizations should be included.

You can mix options from each group freely because they don't overlap ๐Ÿซถ. If there's ever a conflict, the later option on the command line wins.

These options control which kinds of messages get emitted:

  • optimized โ€” Prints information when an optimization is successfully applied. Each pass gets to decide what's relevant. For example, the vectorizer passes print the source location of loops that were successfully vectorized.
  • missed โ€” Prints info about missed optimizations. Individual passes decide what goes in the output.
  • note โ€” Prints verbose info about optimizations, like certain transformations and more detailed messages about decisions.
  • all โ€” Prints detailed optimization info. This includes optimized, missed, and note.

This one controls the dump verbosity:

  • internals โ€” By default, only "high-level" messages are emitted. This turns on extra, more detailed messages that are mostly of interest to GCC developers ๐Ÿค“.

One or more of these 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. This is a superset of the optimization groups listed above.

If options is left out, it defaults to optimized-optall, which means dumping messages about successful optimizations from all the passes while skipping anything marked as "internals" โœจ.

If you give a filename, the dumps from all the applicable optimizations get concatenated into it. Otherwise, the dump goes to stderr. You can use several -fopt-info options, but only one of them can include a filename. If other filenames are provided, all but the first such option get ignored.

Heads up: the output filename gets overwritten when there are multiple translation units. If you want combined output from several of them, use stderr instead.

Here's the example where the optimization info goes to stderr:

gcc -O3 -fopt-info

This one outputs the missed optimization report from all the passes into missed.all:

gcc -O3 -fopt-info-missed=missed.all

And this one prints info about missed optimization opportunities from the vectorization passes on stderr. Fun fact: -fopt-info-vec-missed is equivalent to -fopt-info-missed-vec, and the order of the optimization group names and message types after -fopt-info doesn't matter ๐Ÿ’–:

gcc -O2 -ftree-vectorize -fopt-info-vec-missed

As another example, this outputs info about missed optimizations as well as optimized locations from all the inlining passes into inline.txt ๐Ÿฆ‹:

gcc -O3 -fopt-info-inline-optimized-missed=inline.txt

Finally, consider this one ๐Ÿ‘€:

gcc -fopt-info-vec-missed=vec.miss -fopt-info-loop-optimized=loop.opt

Here, the two output filenames vec.miss and loop.opt are in conflict, since only one output file is allowed. In this case, only the first option takes effect and the subsequent options are ignored. So only vec.miss gets produced, and it 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 inside the compressed JSON file is subject to change.

It's roughly a machine-readable version of -fopt-info-all, as a collection of messages with source file, line number and column number. Each message also comes with this extra data:

  • the execution count of the code being optimized, along with metadata about whether it 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 that 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 controls how much debugging output the scheduler prints to the dump files ๐Ÿง . The levels stack up like this:

  • For n greater than zero, -fsched-verbose outputs the same information as -fdump-rtl-sched1 and -fdump-rtl-sched2.
  • For n greater than one, it also outputs basic block probabilities, detailed ready list information, and unit/insn info.
  • For n greater than two, it includes RTL at the abort point, control-flow, and regions info.
  • For n over four, -fsched-verbose also includes dependence info.

-fenable-kind-pass, -fdisable-kind-pass=range-list

This is a whole set of options for explicitly disabling and enabling optimization passes ๐Ÿ”ง. They're meant for debugging GCC itself, so regular compiler users should use the regular options for enabling and disabling passes instead ๐Ÿ’€.

  • -fdisable-ipa-pass โ€” Disables the IPA pass pass, where pass is the pass name. If the same pass is statically invoked in the compiler multiple times, the pass name should be appended with a sequential number starting from 1.
  • -fdisable-rtl-pass, -fdisable-rtl-pass=range-list โ€” Disables the RTL pass pass, where pass is the pass name. If the same pass is statically invoked 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 the tree pass pass. See -fdisable-rtl for the description of option arguments.
  • -fenable-ipa-pass โ€” Enables the IPA pass pass, where pass is the pass name. If the same pass is statically invoked in the compiler multiple times, the pass name should be appended with a sequential number starting from 1.
  • -fenable-rtl-pass, -fenable-rtl-pass=range-list โ€” Enables the RTL pass pass. See -fdisable-rtl for option argument description and examples.
  • -fenable-tree-pass, -fenable-tree-pass=range-list โ€” Enables the tree pass pass. See -fdisable-rtl for the description of option arguments.

Here are some examples showing how these options get used ๐ŸŒˆ:

# 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 turns on internal consistency checking ๐Ÿง. The default depends on the compiler configuration. -fchecking=2 turns on further internal consistency checking, which might affect code generation.

-frandom-seed=string

This option gives GCC a seed to use in place of random numbers when it generates certain symbol names that have to be different in every compiled file ๐ŸŽฒ. The seed is also used to place unique stamps in coverage data files and in the object files that produce them. You can use the -frandom-seed option to produce reproducibly identical object files ๐ŸŒธ.

The string can be a number (decimal, octal or hex) or an arbitrary string. An arbitrary string gets converted to a number by computing CRC32 ๐Ÿ’œ.

The string has to be different for every single file you compile, no repeats ๐Ÿซถ

  • -save-temps โ€” okay so this one keeps all the usual "temporary" intermediate files permanently ๐Ÿ’พ instead of tossing them. They get named as auxiliary output files, the same way as described under -dumpbase and -dumpdir.

When you pair it with -x, -save-temps is smart enough to avoid overwriting an input source file that shares an extension with an intermediate file ๐Ÿง  If you want that intermediate file, you can rename the source file before using -save-temps.

  • -save-temps=cwd โ€” the same as -save-temps -dumpdir ./. ๐Ÿ“‚
  • -save-temps=obj โ€” the same as -save-temps -dumpdir outdir/, where outdir/ is the directory of the output file given after -o, including any directory separators ๐Ÿ—‚๏ธ If you don't use -o, then -save-temps=obj acts just like -save-temps=cwd.
  • -time[=file] โ€” reports the CPU time each subprocess in the compilation sequence takes โฑ๏ธ For C source files, that's the compiler proper and the assembler (plus the linker if linking happens).

Without an output file, the output looks like this:

# cc1 0.12 0.01
# as 0.00 0.01

The first number on each line is the "user time," which is the time spent executing the program itself. The second is the "system time," which is the time spent in operating system routines on behalf of the program. Both numbers are in seconds โŒ›

With an output file, the output gets appended to the named file and looks like this:

0.12 0.01 cc1 <options>
0.00 0.01 as <options>

The "user time" and "system time" get moved in front of the program name, and the options passed to the program are shown too. That way you can always tell later what file got compiled and with which options ๐Ÿ”

  • -fdump-final-insns[=file] โ€” dumps the final internal representation (RTL) to file ๐Ÿ“œ If you leave out the optional argument (or file is .), the dump file name is made by appending .gkd to the dump base name. See -dumpbase.
  • -fcompare-debug[=opts] โ€” if no error happens during compilation, the compiler runs a second time with opts and -fcompare-debug-second added to its arguments ๐Ÿ” It dumps the final internal representation in both compilations and prints an error if they differ. If you leave off the equal sign, the default -gtoggle is used.

The environment variable GCC_COMPARE_DEBUG, if it's defined, non-empty and nonzero, implicitly enables -fcompare-debug ๐ŸŒธ If GCC_COMPARE_DEBUG is defined to a string starting with a dash, that string gets used for opts. Otherwise, the default -gtoggle is used.

-fcompare-debug=, with the equal sign but without opts, is the same as -fno-compare-debug ๐Ÿ™… That turns off dumping the final representation and the second compilation, and it even stops GCC_COMPARE_DEBUG from taking effect.

To verify full coverage during -fcompare-debug testing, set GCC_COMPARE_DEBUG to -fcompare-debug-not-overridden. GCC rejects that as an invalid option in any actual compilation (rather than preprocessing, assembly or linking) ๐Ÿ’€ If you just want a warning, setting GCC_COMPARE_DEBUG to -w%n-fcompare-debug not overridden will do the job.

  • -fcompare-debug-second โ€” this one gets implicitly passed to the compiler for the second compilation requested by -fcompare-debug, along with options to silence warnings ๐Ÿ”‡ It skips any other options that would make the compiler write output to files or to standard output as a side effect. Dump files and preserved temporary files get renamed to include the extra ".gk" extension during the second compilation, so they don't overwrite the ones from the first run.
When you pass this option to the compiler driver, the first compilation gets skipped. That makes it pretty much only useful for debugging the compiler proper ๐Ÿ™ˆ
  • -gtoggle โ€” turns off debug info generation if leaving out this option would generate it, or turns it on at level 2 otherwise ๐Ÿ”€ Its position in the command line doesn't matter. It takes effect after all other options are processed, and it only does this once, no matter how many times you give it. It's mainly meant to be used with -fcompare-debug.
  • -fvar-tracking-assignments-toggle โ€” toggles -fvar-tracking-assignments the same way -gtoggle toggles -g ๐ŸŽ€
  • -Q โ€” makes the compiler print out each function name as it's compiled, and print some statistics about each pass when it finishes ๐Ÿ–จ๏ธ
  • -ftime-report โ€” makes the compiler print some statistics to stderr about the time consumed by each pass when it finishes โฐ

If SARIF output of diagnostics was requested via -fdiagnostics-format=sarif-file or -fdiagnostics-format=sarif-stderr, then the -ftime-report info gets emitted as JSON inside the SARIF output instead ๐Ÿงพ The exact format of that JSON is subject to change. The values might not match exactly what goes to stderr, since they're written out at a slightly different spot inside the compiler.

  • -ftime-report-details โ€” records the time consumed by infrastructure parts separately for each pass ๐Ÿ”ฌ
  • -fira-verbose=n โ€” controls how verbose the dump file for the integrated register allocator is ๐Ÿงฉ The default value is 5. If n is 10 or greater, the dump output goes to stderr in the same format as n minus 10.
  • -flto-report โ€” prints a report with internal details on how the link-time optimizer works ๐Ÿ”ง What's in the report changes from version to version. It's meant to be helpful to GCC developers when they're processing object files in LTO mode (via -flto). It's disabled by default.
  • -flto-report-wpa โ€” like -flto-report, but only prints for the WPA phase of link-time optimization ๐ŸŽฏ
  • -fmem-report โ€” makes the compiler print some statistics about permanent memory allocation when it finishes ๐Ÿง 
  • -fmem-report-wpa โ€” makes the compiler print some statistics about permanent memory allocation for the WPA phase only ๐ŸŽฏ
  • -fpre-ipa-mem-report, -fpost-ipa-mem-report โ€” makes the compiler print some statistics about permanent memory allocation before or after interprocedural optimization ๐Ÿ“Š

  • -fmultiflags โ€” this option enables multilib-aware "TFLAGS" to be used to build target libraries with options that are different from the ones the compiler is configured to use by default ๐Ÿ› ๏ธ It works through specs set up by compiler internals, by the target, or by builders at configure time.

Like "TFLAGS," this lets target libraries be built for portable baseline environments, while the compiler defaults to more demanding ones ๐Ÿ’… That's useful because users can easily override the compiler's defaults to build their own programs when those defaults aren't ideal for their target environment. Rebuilding the runtime libraries is usually not as easy or desirable, though.

Unlike "TFLAGS," using specs lets different flags be selected for different multilibs โœจ The way to do that is to build with make TFLAGS=-fmultiflags, after configuring --with-specs=%{fmultiflags:...}.

This option is discarded by the driver once it's done processing driver self spec.

It's also handy for checking that "TFLAGS" are being used to build all target libraries ๐Ÿ” Just configure a non-bootstrap compiler with --with-specs='%{!fmultiflags:%emissing TFLAGS}', then build the compiler and target libraries.

  • -fprofile-report โ€” makes the compiler print some statistics about the consistency of the (estimated) profile and the effect of individual passes ๐Ÿ“ˆ
  • -fstack-usage โ€” makes the compiler output stack usage information for the program, on a per-function basis ๐Ÿฅž The filename for the dump is made by appending .su to the auxname. The auxname comes from the name of the output file if it's explicitly specified and isn't an executable. Otherwise, it's the basename of the source file. Each entry has three fields:
    • The name of the function.
    • A number of bytes.
    • One or more qualifiers: "static", "dynamic", "bounded".

The qualifier "static" means the function manages the stack statically: a fixed number of bytes gets allocated for the frame on function entry and released on function exit, and no other stack adjustments happen in the function. The second field is that fixed number of bytes ๐Ÿงฑ

The qualifier "dynamic" means the function manages the stack dynamically. On top of the static allocation, stack adjustments get made in the body of the function, like pushing and popping arguments around function calls ๐ŸŒ€ If "bounded" is also present, the amount of those adjustments is bounded at compile time, and the second field is an upper bound on the total stack used by the function. If "bounded" isn't present, the amount of adjustments isn't bounded at compile time, and the second field only represents the bounded part.

  • -fstats โ€” emits statistics about front-end processing at the end of the compilation ๐Ÿ“‹ Only the C++ front end supports this, and the info is generally only useful to the G++ development team ๐Ÿค“
  • -fdbg-cnt-list โ€” prints the name and the counter upper bound for all debug counters ๐Ÿ”ข
  • -fdbg-cnt=counter-value-list โ€” sets the internal debug counter lower and upper bounds ๐ŸŽš๏ธ counter-value-list is a comma-separated list of name:lower_bound1-upper_bound1 [:lower_bound2-upper_bound2...] tuples. These set the name of the counter and a list of closed intervals. The lower_bound is optional and is zero initialized if it isn't set.

For example, with -fdbg-cnt=dce:2-4:10-11,tail_call:10, dbg_cnt(dce) returns true only for the second, third, fourth, tenth and eleventh invocation ๐ŸŽฏ For dbg_cnt(tail_call), true is returned for the first 10 invocations.

  • -print-file-name=library โ€” prints the full absolute name of the library file library that would be used when linking, and then 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 whichever multilib gets picked by any other switches on your command line ๐Ÿ“‚ It's supposed to exist inside GCC_EXEC_PREFIX โœจ
  • -print-multi-lib: Prints the map from multilib directory names to the switches that turn them on ๐Ÿ—บ๏ธ The directory name is separated from the switches by ;, and each switch starts with @ instead of -, with no spaces between multiple switches. This is supposed to make shell processing way easier ๐Ÿ’…
  • -print-multi-os-directory: Prints the path to OS libraries for the selected multilib, relative to some lib subdirectory ๐ŸŒธ If OS libraries sit in the lib subdirectory and no multilibs are used, it's usually just .. If they're in libsuffix sibling directories, you'll see things like ../lib64, ../lib or ../lib32. If they're in lib/subdir subdirectories, you'll get stuff 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: Basically -print-file-name, but it searches for a program like cpp instead ๐Ÿ”
  • -print-libgcc-file-name: Same as -print-file-name=libgcc.a ๐Ÿ’œ

This one is lowkey clutch when you use -nostdlib or -nodefaultlibs but 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 and a list of the program and library directories gcc searches. It doesn't do anything else, so don't expect a compile ๐Ÿ™ˆ

This is the one you want when gcc yells installation problem, cannot exec cpp0: No such file or directory. To fix that, you either put cpp0 and the other compiler components where gcc expects to find them, or you set the environment variable GCC_EXEC_PREFIX to the directory where you installed them. And don't forget the trailing / ๐Ÿซถ

  • -print-sysroot: Prints the target sysroot directory used during compilation ๐Ÿฐ That's the one set at configure time or with --sysroot, possibly with an extra suffix that depends on your compilation options. If no target sysroot is specified, this prints nothing at all ๐Ÿคทโ€โ™€๏ธ
  • -print-sysroot-headers-suffix: Prints the suffix added to the target sysroot when searching for headers. If the compiler wasn't configured with one, you'll get an error instead, and it won't do anything else ๐Ÿ’€
  • -dumpmachine: Prints the compiler's target machine, like i686-pc-linux-gnu. Then it stops, no other business ๐ŸŒˆ
  • -dumpversion: Prints the compiler version, like 3.0, 6.3.0 or 7, and then it's done โœจ This is the version used in filesystem paths and specs. Depending on how the compiler was configured, it can be one number (the major version), two numbers separated by a dot (major and minor), or three numbers separated by dots (major, minor and patchlevel) ๐Ÿ”ฅ
  • -dumpfullversion: Prints the full compiler version, then stops. The output is always three numbers separated by dots: major, minor and patchlevel ๐Ÿ‘‘
  • -dumpspecs: Prints the compiler's built-in specs and then stops ๐Ÿง  (This is used when GCC itself is being built, so it's mostly for the compiler devs, bestie ๐Ÿซถ)

๐Ÿฆ‹ Machine-Dependent Options ๐Ÿฆ‹

Each target machine GCC supports can have its own options. For example, you might use them to compile for a particular processor variant or ABI, or to 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 additional target-specific options, usually so it plays nicely with other compilers on the same platform โœจ

AArch64 Options

These options are defined for AArch64 implementations ๐Ÿ’…

  • -mabi=name: Generates code for the specified data model ๐ŸŽ€ The permissible values are ilp32, which is a SysV-like data model where int, long int and pointers are 32 bits, and lp64, which is a SysV-like data model where int is 32 bits but long int and pointers are 64 bits.

The default depends on the specific target configuration. Also, the LP64 and ILP32 ABIs are not link-compatible, so you have to compile your entire program with the same ABI and link it with a compatible set of libraries ๐Ÿ™ˆ

  • -mbig-endian: Generates big-endian code ๐Ÿ“ This is the default when GCC is configured for an aarch64_be-*-* target.
  • -mgeneral-regs-only: Generates code that only uses the general-purpose registers ๐Ÿงš This stops the compiler from using floating-point and Advanced SIMD registers, but it won't put any restrictions on the assembler.
  • -mlittle-endian: Generates little-endian code ๐Ÿฆ‹ This is the default when GCC is configured for an aarch64-*-* target but not an aarch64_be-*-* target.
  • -mcmodel=tiny: Generates code for the tiny code model ๐ŸŒธ The program and its statically defined symbols must be within 1MB of each other. Programs can be statically or dynamically linked.
  • -mcmodel=small: Generates code for the small code model ๐ŸŒท The program and its statically defined symbols must be within 4GB of each other. Programs can be statically or dynamically linked. This is the default code model.
  • -mcmodel=large: Generates code for the large code model ๐ŸŒŒ This makes no assumptions about addresses and sizes of sections. Programs can be statically linked only.
The -mcmodel=large option is incompatible with -mabi=ilp32, -fpic and -fPIC. Don't mix them up, bestie ๐Ÿšซ
  • -mtp=name: Specifies the system register to use as a thread pointer ๐Ÿงต The valid values are tpidr_el0, tpidrro_el0, tpidr_el1, tpidr_el2 and tpidr_el3. For backwards compatibility, the aliases el0, el1, el2 and el3 are also accepted. The default setting is tpidr_el0.

It's recommended to compile all code that's meant to interoperate with the same value of this option, so you don't accidentally access a different thread pointer from the wrong exception level ๐Ÿ˜ญ

  • -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 sysreg choice, the options -mstack-protector-guard-reg=reg and -mstack-protector-guard-offset=offset specify which system register to use as the base register for reading the canary, and what offset from that base register to use. 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. The valid values are 12, 24, 32 and 48. This option requires binutils 2.26 or newer ๐Ÿ”ง
  • -mfix-cortex-a53-835769, -mno-fix-cortex-a53-835769: Enables or disables the workaround for ARM Cortex-A53 erratum number 835769 ๐Ÿฉน This involves inserting a NOP instruction between memory instructions and 64-bit integer multiply-accumulate instructions.
  • -mfix-cortex-a53-843419, -mno-fix-cortex-a53-843419: Enables or disables the workaround for ARM Cortex-A53 erratum number 843419 ๐Ÿฉน This erratum workaround is 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 about 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 about 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 about 32 bits for double precision.
  • -mtrack-speculation, -mno-track-speculation: Enables or disables generation of additional code to track speculative execution through conditional branches ๐Ÿ‘€ The tracking state can then be used by the compiler when expanding calls to "__builtin_speculation_safe_copy", so it can generate a more efficient code sequence.
  • -moutline-atomics, -mno-outline-atomics: Enables or disables calls to out-of-line helpers that implement atomic operations ๐Ÿงฉ At runtime, these helpers figure out whether the LSE instructions from ARMv8.1-A can be used. If not, they fall back to the load/store-exclusive instructions that are present in the base ARMv8.0 ISA.

This option is only applicable when compiling for the base ARMv8.0 instruction set. If you're using a later revision, like -march=armv8.1-a or -march=armv8-a+lse, the ARMv8.1-Atomics instructions get used directly. The same goes for -mcpu= when the selected CPU supports the lse feature. This option is on by default ๐Ÿ”ฅ

  • -march=name: Specifies the name of the target architecture and, optionally, one or more feature modifiers ๐Ÿ—๏ธ This option has the form -march=arch{+[no]feature}*.

The table just below sums up the permissible values for arch and the features that each one enables by default ๐Ÿ’…

okay so here's the whole architecture lineup, bestie ๐Ÿ’– each row reads arch value : Architecture : Includes by default, so you can see what every value is and what extra bits come along with it โœจ

arch value : Architecture : Includes by default
armv8-a : Armv8-A : +fp, +simd
armv8.1-a : Armv8.1-A : armv8-a, +crc, +lse, +rdma
armv8.2-a : Armv8.2-A : armv8.1-a
armv8.3-a : Armv8.3-A : armv8.2-a, +pauth
armv8.4-a : Armv8.4-A : armv8.3-a, +flagm, +fp16fml, +dotprod
armv8.5-a : Armv8.5-A : armv8.4-a, +sb, +ssbs, +predres
armv8.6-a : Armv8.6-A : armv8.5-a, +bf16, +i8mm
armv8.7-a : Armv8.7-A : armv8.6-a, +ls64
armv8.8-a : Armv8.8-a : armv8.7-a, +mops
armv8.9-a : Armv8.9-a : armv8.8-a
armv9-a : Armv9-A : armv8.5-a, +sve, +sve2
armv9.1-a : Armv9.1-A : armv9-a, +bf16, +i8mm
armv9.2-a : Armv9.2-A : armv9.1-a, +ls64
armv9.3-a : Armv9.3-A : armv9.2-a, +mops
armv9.4-a : Armv9.4-A : armv9.3-a
armv8-r : Armv8-R : armv8-r

The value native is available on native AArch64 GNU/Linux and makes the compiler pick the architecture of the host system ๐ŸŒˆ If the compiler can't recognize the host system's architecture, this option just does nothing, so no drama ๐Ÿซถ

The permissible values for feature are listed in the sub-section on aarch64-feature-modifiers,,-march and -mcpu Feature Modifiers. If you specify conflicting feature modifiers, the right-most one wins ๐Ÿ‘‘

GCC looks at name to decide what kind of instructions it's allowed to emit when generating assembly code ๐Ÿ’… If you use -march without also using -mtune or -mcpu, the code gets tuned to perform well across a whole range of target processors that implement the target architecture โœจ


๐ŸŽ€ -mtune=name

Here you tell GCC the name of the target processor it should tune the performance of your code for ๐Ÿ’– The permissible values are: generic, cortex-a35, cortex-a53, cortex-a55, cortex-a57, cortex-a72, cortex-a73, cortex-a75, cortex-a76, cortex-a76ae, cortex-a77, cortex-a65, cortex-a65ae, cortex-a34, cortex-a78, cortex-a78ae, cortex-a78c, ares, exynos-m1, emag, falkor, neoverse-512tvb, neoverse-e1, neoverse-n1, neoverse-n2, neoverse-v1, neoverse-v2, qdf24xx, saphira, phecda, xgene1, vulcan, octeontx, octeontx81, octeontx83, octeontx2, octeontx2t98, octeontx2t96, octeontx2t93, octeontx2f95, octeontx2f95n, octeontx2f95mm, a64fx, thunderx, thunderxt88, thunderxt88p1, thunderxt81, tsv110, thunderxt83, thunderx2t99, thunderx3t110, zeus, cortex-a57.cortex-a53, cortex-a72.cortex-a53, cortex-a73.cortex-a35, cortex-a73.cortex-a53, cortex-a75.cortex-a55, cortex-a76.cortex-a55, cortex-r82, cortex-x1, cortex-x1c, cortex-x2, cortex-x3, cortex-x4, cortex-a510, cortex-a520, cortex-a710, cortex-a715, cortex-a720, ampere1, ampere1a, ampere1b, cobalt-100 and native.

The values cortex-a57.cortex-a53, cortex-a72.cortex-a53, cortex-a73.cortex-a35, cortex-a73.cortex-a53, cortex-a75.cortex-a55 and cortex-a76.cortex-a55 tell GCC to tune for a big.LITTLE system ๐Ÿงš

The value neoverse-512tvb tells GCC to tune for Neoverse cores that (a) implement SVE and (b) have a total vector bandwidth of 512 bits per cycle ๐Ÿ”ฅ Basically, the option tells GCC to tune for Neoverse cores that can execute 4 128-bit Advanced SIMD arithmetic instructions a cycle, and that can execute an equivalent number of SVE arithmetic instructions per cycle (2 for 256-bit SVE, 4 for 128-bit SVE). It's more general than tuning for a specific core like Neoverse V1, but more specific than the default tuning described below ๐Ÿฆ‹

Additionally, on native AArch64 GNU/Linux systems, the value native tunes performance to the host system. If the compiler can't recognize the processor of the host system, this option has no effect ๐ŸŒธ

If none of -mtune=, -mcpu= or -march= are specified, the code is tuned to perform well across a range of target processors ๐Ÿ’œ

This option cannot be suffixed by feature modifiers ๐Ÿ™ˆ

๐ŸŒท -mcpu=name

Here you name the target processor, and you can optionally suffix it with one or more feature modifiers โœจ The form is -mcpu=cpu{+[no]feature}*, where the permissible values for cpu are the same as the ones for -mtune ๐Ÿ’– The permissible values for feature are documented in the sub-section on aarch64-feature-modifiers,,-march and -mcpu Feature Modifiers. Again, if feature modifiers conflict, the right-most feature is used ๐Ÿ‘‘

GCC uses name to figure out what kind of instructions it can emit when generating assembly code (just like -march does) and to figure out which target processor to tune for performance (just like -mtune does) ๐Ÿ’… If you use this option together with -march or -mtune, those options take precedence over the matching part of this option ๐Ÿซถ

-mcpu=neoverse-512tvb is special, because it doesn't refer to one specific core. Instead it refers to all Neoverse cores that (a) implement SVE and (b) have a total vector bandwidth of 512 bits a cycle ๐Ÿ˜ญ Unless you override it with -march, -mcpu=neoverse-512tvb generates code that can run on a Neoverse V1 core, since Neoverse V1 is the first Neoverse core with these properties ๐Ÿฆ„ Unless you override it with -mtune, -mcpu=neoverse-512tvb tunes code in the same way as for -mtune=neoverse-512tvb ๐ŸŒˆ

๐Ÿซง -moverride=string

This lets you override the tuning decisions the back-end makes in response to a -mtune= switch ๐Ÿ“

โš ๏ธ The syntax, semantics, and accepted values for string in this option are not guaranteed to be consistent across releases. It's only intended to be useful when developing GCC, so maybe don't go wild with it ๐Ÿ’€

๐Ÿ” -mverbose-cost-dump

This turns on verbose cost model dumping in the debug dump files ๐Ÿง It's provided for debugging the compiler, so it's more of a GCC-dev thing ๐Ÿ’œ

๐ŸŒ™ -mpc-relative-literal-loads / -mno-pc-relative-literal-loads

These enable or disable PC-relative literal loads ๐ŸŒธ With this option on, literal pools get accessed using a single instruction and are emitted after each function. The catch is that this limits the maximum size of functions to 1MB โœจ It's enabled by default for -mcmodel=tiny ๐Ÿฆ‹

๐Ÿชฝ -msign-return-address=scope

This picks the function scope that return address signing gets applied to ๐Ÿ’… The permissible values are none, which disables return address signing; non-leaf, which enables pointer signing for functions that aren't leaf functions; and all, which enables pointer signing for all functions ๐Ÿซถ The default value is none.

โš ๏ธ This option has been deprecated by -mbranch-protection, so switch over when you can ๐Ÿ˜ญ

๐Ÿ›ก๏ธ -mbranch-protection=none|standard|pac-ret[+leaf+b-key]|bti

This selects which branch protection features to use ๐Ÿ” none is the default and turns off all types of branch protection. standard turns on all types of branch protection features, and if a feature has additional tuning options, standard sets it to its standard level ๐Ÿ‘‘

pac-ret[+leaf] turns on return address signing to its standard level, which means signing functions that save the return address to memory (non-leaf functions will practically always do this) using the a-key ๐ŸŒˆ The optional argument leaf can be used to extend the signing to include leaf functions. The optional argument b-key can be used to sign the functions with the B-key instead of the A-key ๐Ÿ™ˆ

bti turns on the branch target identification mechanism ๐ŸŽ€

๐Ÿงฑ -mharden-sls=opts

This 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, while -mharden-sls=none disables all SLS hardening ๐Ÿซง

๐Ÿ•ฐ๏ธ -mearly-ra=scope

This determines when to enable an early register allocation pass โœจ The pass runs before instruction scheduling and tries to find a spill-free allocation of floating-point and vector code. It also tries to make use of strided multi-register instructions, such as SME2's strided LD1 and ST1 ๐Ÿ’…

The possible values of scope are:

  • all โ€” runs the pass on all functions
  • strided โ€” runs the pass on functions that have access to strided multi-register instructions
  • none โ€” disables the pass

-mearly-ra=all is the default for -O2 and above, and for -Os. -mearly-ra=none is the default otherwise ๐ŸŒธ

โšก -mearly-ldp-fusion

This enables the copy of the AArch64 load/store pair fusion pass that runs before register allocation ๐Ÿ”ฅ It's enabled by default at -O and above ๐Ÿ’–

โšก -mlate-ldp-fusion

This enables the copy of the AArch64 load/store pair fusion pass that runs after register allocation ๐Ÿ”ฅ It's also enabled by default at -O and above ๐Ÿ’œ

๐Ÿ“ -msve-vector-bits=bits

This specifies the number of bits in an SVE vector register ๐Ÿฆ‹ It only has an effect when SVE is enabled, so no SVE, no vibes ๐Ÿ™ˆ

GCC supports two forms of SVE code generation. "Vector-length agnostic" output works with any size of vector register, and "vector-length specific" output lets GCC make assumptions about the vector length when that's useful for optimization reasons ๐Ÿงš The possible values of bits are scalable, 128, 256, 512, 1024 and 2048. Specifying scalable selects vector-length agnostic output. At present, -msve-vector-bits=128 also generates vector-length agnostic output for big-endian targets. All other values generate vector-length specific code ๐ŸŒˆ

โš ๏ธ The behaviour of these values may change in future releases, and no value except scalable should be relied on for producing code that's portable across different hardware SVE vector lengths. Be careful out there, bestie ๐Ÿ˜ญ

The default is -msve-vector-bits=scalable, which produces vector-length agnostic code ๐Ÿซถ


โœจ -march and -mcpu Feature Modifiers โœจ

Feature modifiers used with -march and -mcpu can be any of the following, and each one also has an inverse, nofeature ๐ŸŒท

  • crc โ€” enables the CRC extension. This is on by default for -march=armv8.1-a ๐Ÿ”ฅ
  • crypto โ€” enables the Crypto extension. This also enables Advanced SIMD and floating-point instructions ๐Ÿ”
  • fp โ€” enables floating-point instructions. This is on by default for all possible values for options -march and -mcpu ๐Ÿ’œ
  • simd โ€” enables Advanced SIMD instructions. This also enables floating-point instructions. This is on by default for all possible values for options -march and -mcpu ๐Ÿฆ‹
  • sve โ€” enables Scalable Vector Extension instructions. This also enables Advanced SIMD and floating-point instructions ๐Ÿงœ
  • lse โ€” enables Large System Extension instructions. This is on by default for -march=armv8.1-a ๐ŸŒธ
  • rdma โ€” enables Round Double Multiply Accumulate instructions. This is on by default for -march=armv8.1-a โœจ

Okay bestie, the AArch64 feature list is giving main character energy ๐Ÿ’… Every +feature you can flip on, plus which ones come bundled ๐ŸŒˆ

  • fp16 โ€” Turns on the FP16 extension โœจ and brings the floating-point instructions along for the ride ๐Ÿ”ฅ
  • fp16fml โ€” Turns on the FP16 fmla extension ๐Ÿ’–. It also switches on the FP16 extensions and floating-point instructions. It's on by default for -march=armv8.4-a. Using it with anything older than Armv8.2-A is not supported ๐Ÿ™ˆ
  • rcpc โ€” Turns on the RCpc extension ๐Ÿฆ‹. That means the LDAPR instructions get used for load-acquire atomic semantics, and it's passed along to the assembler so inline asm statements can use RCpc instructions too
  • dotprod โ€” Turns on the Dot Product extension ๐ŸŽ€. It also enables Advanced SIMD instructions
  • aes โ€” Turns on the Armv8-a aes and pmull crypto extension ๐Ÿ”. Advanced SIMD instructions come with it
  • sha2 โ€” Turns on the Armv8-a sha2 crypto extension ๐ŸŒธ. Advanced SIMD instructions come with it too
  • sha3 โ€” Turns on the sha512 and sha3 crypto extension ๐Ÿ“. Advanced SIMD instructions come along. Using it with architectures prior to Armv8.2-A is not supported ๐Ÿ’€
  • sm4 โ€” Turns on the sm3 and sm4 crypto extension ๐Ÿงš. Advanced SIMD instructions come along. Using it with architectures prior to Armv8.2-A is not supported ๐Ÿ’€
  • profile โ€” Turns on the Statistical Profiling extension ๐Ÿ“Š. This only enables it at the assembler level, so code generation stays the same
  • rng โ€” Turns on the Armv8.5-a Random Number instructions ๐ŸŽฒ. Assembler level only, so code generation isn't affected
  • memtag โ€” Turns on the Armv8.5-a Memory Tagging Extensions ๐Ÿท๏ธ. Using it with architectures prior to Armv8.5-A is not supported ๐Ÿ’€
  • sb โ€” Turns on the Armv8-a Speculation Barrier instruction ๐Ÿšง. This only enables it at the assembler level and doesn't change code generation. It's on by default for -march=armv8.5-a
  • ssbs โ€” Turns on the Armv8-a Speculative Store Bypass Safe instruction ๐Ÿ›ก๏ธ. Assembler level only, no change to code generation. It's on by default for -march=armv8.5-a
  • predres โ€” Turns on the Armv8-a Execution and Data Prediction Restriction instructions ๐Ÿ”’. Assembler level only, no change to code generation. It's on by default for -march=armv8.5-a
  • sve2 โ€” Turns on the Armv8-a Scalable Vector Extension 2 ๐Ÿ“. It also enables SVE instructions
  • sve2-bitperm โ€” Turns on SVE2 bitperm instructions ๐Ÿช„. It also enables SVE2 instructions
  • sve2-sm4 โ€” Turns on SVE2 sm4 instructions ๐ŸŒŠ. It also enables SVE2 instructions
  • sve2-aes โ€” Turns on SVE2 aes instructions ๐Ÿ”‘. It also enables SVE2 instructions
  • sve2-sha3 โ€” Turns on SVE2 sha3 instructions ๐ŸŒ™. It also enables SVE2 instructions
  • tme โ€” Turns on the Transactional Memory Extension ๐Ÿง 
  • i8mm โ€” Turns on 8-bit Integer Matrix Multiply instructions ๐Ÿงฎ. It also enables Advanced SIMD and floating-point instructions. It's on by default for -march=armv8.6-a. Using it with architectures prior to Armv8.2-A is not supported ๐Ÿ’€
  • f32mm โ€” Turns on 32-bit Floating point Matrix Multiply instructions ๐Ÿ“ˆ. It also enables SVE instructions. Using it with architectures prior to Armv8.2-A is not supported ๐Ÿ’€
  • f64mm โ€” Turns on 64-bit Floating point Matrix Multiply instructions ๐Ÿ“‰. It also enables SVE instructions. Using it with architectures prior to Armv8.2-A is not supported ๐Ÿ’€
  • bf16 โ€” Turns on brain half-precision floating-point instructions ๐Ÿง โœจ. It also enables Advanced SIMD and floating-point instructions. It's on by default for -march=armv8.6-a. Using it with architectures prior to Armv8.2-A is not supported ๐Ÿ’€
  • ls64 โ€” Turns on the 64-byte atomic load and store instructions for accelerators ๐Ÿš€. It's on by default for -march=armv8.7-a
  • mops โ€” Turns on the instructions that speed up memory operations like "memcpy", "memmove", and "memset" ๐Ÿงน. It's on by default for -march=armv8.8-a
  • flagm โ€” Turns on the Flag Manipulation instructions Extension ๐Ÿณ๏ธ
  • pauth โ€” Turns on the Pointer Authentication Extension ๐Ÿ”
  • cssc โ€” Turns on the Common Short Sequence Compression instructions ๐Ÿ—œ๏ธ
  • sme โ€” Turns on the Scalable Matrix Extension ๐ŸงŠ
  • sme-i16i64 โ€” Turns on the FEAT_SME_I16I64 extension to SME ๐Ÿ”ข
  • sme-f64f64 โ€” Turns on the FEAT_SME_F64F64 extension to SME ๐Ÿ”ฃ
Quick heads up: the source has a stray +@item glitch stuck onto the sme-f64f64 entry, so sme2 gets its own bullet below ๐Ÿ™ˆ
  • sme2 โ€” Turns on the Scalable Matrix Extension 2 ๐ŸŒŸ. It also enables SME instructions
  • lse128 โ€” Turns on the LSE128 128-bit atomic instructions extension โš›๏ธ. It also enables LSE instructions
  • d128 โ€” Turns on support for 128-bit system register read/write instructions ๐Ÿ’ฟ. It also enables the LSE128 extension
  • gcs โ€” Turns on support for the Armv9.4-a Guarded Control Stack extension ๐Ÿฐ
  • the โ€” Turns on support for the Armv8.9-a/9.4-a translation hardening extension ๐Ÿ› ๏ธ
  • rcpc3 โ€” Turns on the RCpc3 (Release Consistency) extension ๐ŸŒบ

Feature bundles are linked, so crypto implies aes, sha2, and simd, which implies fp. Going the other way, nofp implies nosimd, which implies nocrypto, noaes and nosha2 ๐Ÿ”—


๐Ÿงš Adapteva Epiphany Options ๐Ÿงš

These -m options are defined for Adapteva Epiphany ๐Ÿฆ‹

  • -mhalf-reg-file โ€” Don't hand out any register in the range "r32"..."r63" ๐Ÿซถ. That lets your code run on hardware variants that don't have those registers
  • -mprefer-short-insn-regs โ€” Gives priority to registers that allow short instruction generation โšก. This can bump up the instruction count, so overall code size could go either way
  • -mbranch-cost=num โ€” Sets the cost of branches to roughly num "simple" instructions ๐ŸŒฟ. It's only a heuristic, so it isn't guaranteed to give consistent results across releases
  • -mcmove โ€” Turns on the generation of conditional moves ๐ŸŽ€
  • -mnops=num โ€” Emits num NOPs before every other generated instruction ๐Ÿ˜ด
  • -mno-soft-cmpsf โ€” For single-precision floating-point comparisons, this emits an fsub instruction and tests the flags ๐ŸŽ๏ธ. It's faster than a software comparison, but it can give incorrect results in the presence of NaNs, or when two different small numbers are compared and their difference is calculated as zero. The default is -msoft-cmpsf, which uses slower but IEEE-compliant software comparisons ๐Ÿข
  • -mstack-offset=num โ€” Sets the offset between the top of the stack and the stack pointer ๐Ÿฅž. E.g., a value of 8 means the eight bytes in the range "sp+0...sp+7" can be used by leaf functions without stack allocation. Values other than 8 or 16 are untested and unlikely to work ๐Ÿ’€
Heads up: this option changes the ABI! Compiling a program with a different stack offset than the libraries were built with generally does not work. It can help you check whether a different stack offset would give you better code, but if you want to actually build working programs with a different stack offset, it's recommended to configure the toolchain with the appropriate --with-stack-offset=num option.
  • -mno-round-nearest โ€” Makes the scheduler assume the rounding mode has been set to truncating ๐Ÿ”„. The default is -mround-nearest
  • -mlong-calls โ€” Unless an attribute says otherwise, this assumes all calls might be beyond the offset range of the "b" / "bl" instructions ๐Ÿ“ž. So the function address gets loaded into a register before the (otherwise direct) call. This is the default
  • -mshort-calls โ€” Unless an attribute says otherwise, this assumes all direct calls are in the range of the "b" / "bl" instructions ๐Ÿ“ฒ, so those instructions get used for direct calls. The default is -mlong-calls
  • -msmall16 โ€” Assumes addresses can be loaded as 16-bit unsigned values ๐Ÿ”ข. This doesn't apply to function addresses where -mlong-calls semantics are in effect
  • -mfp-mode=mode โ€” Sets the prevailing mode of the floating-point unit ๐Ÿงญ. This decides which floating-point mode gets provided and expected at function call and return time. Matching this to the mode you mostly need at function start can make your programs smaller and faster by avoiding unnecessary mode switches โœจ

mode can be set to one of the following values:

  • caller โ€” Any mode at function entry is valid, and it gets retained or restored when the function returns and when it calls other functions ๐Ÿซง. This is handy for compiling libraries or other compilation units you might want to link into programs with different prevailing FPU modes. The convenience of one single object file outweighs the size and speed overhead of any extra mode switching, compared with a more specific choice of prevailing FPU mode
  • truncate โ€” The mode used for floating-point calculations with truncating (i.e. round towards zero) rounding ๐Ÿชต. That includes conversion from floating point to integer
  • round-nearest โ€” The mode used for floating-point calculations with round-to-nearest-or-even rounding ๐ŸŽฏ
  • int โ€” The mode used to perform integer calculations in the FPU ๐Ÿงฎ, e.g. integer multiply, or integer multiply-and-accumulate

The default is -mfp-mode=caller ๐Ÿ’œ

  • -mno-split-lohi, -mno-postinc, -mno-postmodify โ€” Code generation tweaks that disable, respectively, splitting of 32-bit loads, generation of post-increment addresses, and generation of post-modify addresses ๐Ÿ› ๏ธ. The defaults are msplit-lohi, -mpost-inc, and -mpost-modify
  • -mnovect-double โ€” Changes the preferred SIMD mode to SImode ๐ŸŒท. The default is -mvect-double, which uses DImode as the preferred SIMD mode
  • -max-vect-align=num โ€” The maximum alignment for SIMD vector mode types ๐Ÿ“. num may be 4 or 8, and the default is 8
Heads up: this is an ABI change! Many library function interfaces are unaffected, as long as they don't use SIMD vector modes in places that affect the size and/or alignment of relevant types.
  • -msplit-vecmove-early โ€” Splits vector moves into single word moves before reload ๐Ÿช„. In theory this can give better register allocation, but so far the reverse seems to be generally the case ๐Ÿ™ƒ

โœจ AMD GCN Options โœจ

okay so these ones are made specifically for the AMD GCN port ๐Ÿ’…๐Ÿ–ฅ๏ธ

  • -m1reg-reg โ€” okay bestie, this one lets you pick a register to hold the constant -1 ๐Ÿ’– which makes loading small negative constants and certain bitmasks faster โœจ The allowed values for reg are:
    • r43 and r63 โ€” use that register as a fixed register ๐ŸŽ€
    • none โ€” no register gets used for this purpose ๐Ÿซถ
    • The default is -m1reg-none ๐ŸŒธ
  • -march=gpu, -mtune=gpu โ€” set the architecture type or tuning for gpu ๐Ÿ‘‘ Supported values for gpu are:
    • fiji โ€” compile for GCN3 Fiji devices (gfx803) ๐Ÿฆ‹
Support is deprecated ๐Ÿ˜ญ Whether it's available depends on how GCC was configured, so check --with-arch and --with-multilib-list.
  • gfx900 โ€” compile for GCN5 Vega 10 devices (gfx900) โœจ
  • gfx906 โ€” compile for GCN5 Vega 20 devices (gfx906) ๐Ÿ”ฅ
  • gfx908 โ€” compile for CDNA1 Instinct MI100 series devices (gfx908) ๐Ÿ’œ
  • gfx90a โ€” compile for CDNA2 Instinct MI200 series devices (gfx90a) ๐ŸŒˆ
  • gfx1030 โ€” compile for RDNA2 gfx1030 devices (GFX10 series) ๐Ÿงš
  • gfx1036 โ€” compile for RDNA2 gfx1036 devices (GFX10 series) ๐Ÿ“
  • gfx1100 โ€” compile for RDNA3 gfx1100 devices (GFX11 series) โญ
  • gfx1103 โ€” compile for RDNA3 gfx1103 devices (GFX11 series) ๐Ÿฆ‹
  • -msram-ecc=on, -msram-ecc=off, -msram-ecc=any โ€” compile binaries for devices with SRAM-ECC enabled, disabled, or either mode ๐Ÿ›ก๏ธ This feature can be turned on per-process on some devices, and the compiled code must match the device mode ๐Ÿ’€ The default is any, for devices that support it.
  • -mstack-size=bytes โ€” specify how many bytes of stack space get requested for each GPU thread (wave-front) ๐Ÿงต
Heads up, there can be a lot of threads and not much memory, so be careful ๐Ÿ˜ญ The stack size can also affect run-time performance. The default is 32KB when using OpenACC or OpenMP, and 1MB otherwise.
  • -mxnack=on, -mxnack=off, -mxnack=any โ€” compile binaries for devices with the XNACK feature enabled, disabled, or either mode ๐ŸŒธ Some devices always need XNACK, and some let the user configure it. The compiled code must match the device mode. The default is -mxnack=any on devices that support Unified Shared Memory, and -mxnack=no otherwise.

๐ŸŒˆ ARC Options ๐ŸŒˆ

these options are all about controlling which architecture variant your ARC code gets compiled for ๐ŸŽ€ the following are the vibes:

  • -mbarrel-shifter โ€” generate instructions supported by the barrel shifter โš™๏ธ This is the default unless -mcpu=ARC601 or -mcpu=ARCEM is in effect.
  • -mjli-always โ€” force a function call to use the jli_s instruction ๐Ÿฆ‹ This option is only valid for the ARCv2 architecture.
  • -mcpu=cpu โ€” set the architecture type, register usage, and instruction scheduling parameters for cpu ๐Ÿ‘‘ There are also shortcut alias options for backward compatibility and convenience. Supported values for cpu are:
    • arc600 โ€” compile for ARC600. Aliases: -mA6, -mARC600 ๐Ÿงš
    • arc601 โ€” compile for ARC601. Alias: -mARC601 ๐Ÿ“
    • arc700 โ€” compile for ARC700. Aliases: -mA7, -mARC700 โญ This is the default when configured with --with-cpu=arc700.
    • arcem โ€” compile for ARC EM ๐Ÿ’œ
    • archs โ€” compile for ARC HS ๐Ÿ”ฅ
    • em โ€” compile for ARC EM CPU with no hardware extensions ๐ŸŒธ
    • em4 โ€” compile for ARC EM4 CPU โœจ
    • em4_dmips โ€” compile for ARC EM4 DMIPS CPU ๐Ÿฆ‹
    • em4_fpus โ€” compile for ARC EM4 DMIPS CPU with the single-precision floating-point extension ๐Ÿซถ
    • em4_fpuda โ€” compile for ARC EM4 DMIPS CPU with single-precision floating-point and double assist instructions ๐Ÿ’…
    • hs โ€” compile for ARC HS CPU with no hardware extensions except the atomic instructions ๐ŸŽ€
    • hs34 โ€” compile for ARC HS34 CPU ๐ŸŒˆ
    • hs38 โ€” compile for ARC HS38 CPU ๐Ÿ“
    • hs38_linux โ€” compile for ARC HS38 CPU with all hardware extensions on ๐Ÿ”ฅ
    • hs4x โ€” compile for ARC HS4x CPU ๐Ÿ‘‘
    • hs4xd โ€” compile for ARC HS4xD CPU ๐Ÿงš
    • hs4x_rel31 โ€” compile for ARC HS4x CPU release 3.10a โญ
    • arc600_norm โ€” compile for ARC 600 CPU with "norm" instructions enabled ๐Ÿ’–
    • arc600_mul32x16 โ€” compile for ARC 600 CPU with "norm" and 32x16-bit multiply instructions enabled ๐Ÿ’œ
    • arc600_mul64 โ€” compile for ARC 600 CPU with "norm" and "mul64"-family instructions enabled ๐Ÿฆ‹
    • arc601_norm โ€” compile for ARC 601 CPU with "norm" instructions enabled ๐ŸŒธ
    • arc601_mul32x16 โ€” compile for ARC 601 CPU with "norm" and 32x16-bit multiply instructions enabled โœจ
    • arc601_mul64 โ€” compile for ARC 601 CPU with "norm" and "mul64"-family instructions enabled ๐ŸŽ€
    • nps400 โ€” compile for ARC 700 on the NPS400 chip ๐ŸŒˆ
    • em_mini โ€” compile for ARC EM minimalist configuration featuring a reduced register set ๐Ÿงš
  • -mdpfp, -mdpfp-compact โ€” generate double-precision FPX instructions, tuned for the compact implementation ๐Ÿ’…
  • -mdpfp-fast โ€” generate double-precision FPX instructions, tuned for the fast implementation โšก
  • -mno-dpfp-lrsr โ€” disable "lr" and "sr" instructions from using FPX extension aux registers ๐Ÿ™…โ€โ™€๏ธ
  • -mea โ€” generate extended arithmetic instructions ๐Ÿงฎ Currently only "divaw", "adds", "subs", and "sat16" are supported. This is only valid for -mcpu=ARC700.
  • -mno-mpy โ€” do not generate "mpy"-family instructions for ARC700 ๐Ÿ’€
This option is deprecated, so maybe don't build your whole life around it ๐Ÿ˜ญ
  • -mmul32x16 โ€” generate 32x16-bit multiply and multiply-accumulate instructions โœ–๏ธ
  • -mmul64 โ€” generate "mul64" and "mulu64" instructions ๐Ÿ”ข This is only valid for -mcpu=ARC600.
  • -mnorm โ€” generate "norm" instructions ๐ŸŽฏ This is the default if -mcpu=ARC700 is in effect.
  • -mspfp, -mspfp-compact โ€” generate single-precision FPX instructions, tuned for the compact implementation ๐ŸŒธ
  • -mspfp-fast โ€” generate single-precision FPX instructions, tuned for the fast implementation ๐Ÿ”ฅ
  • -msimd โ€” enable generation of ARC SIMD instructions via target-specific builtins ๐ŸŽ€ This is only valid for -mcpu=ARC700.
  • -msoft-float โ€” this option gets ignored ๐Ÿ™ˆ It's only here for compatibility purposes. 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 โ€” generate "swap" instructions ๐Ÿ”„
  • -matomic โ€” enables the use of the locked load/store conditional extension to implement atomic memory built-in functions ๐Ÿ”’ Not available for ARC 6xx or ARC EM cores.
  • -mdiv-rem โ€” enable "div" and "rem" instructions for ARCv2 cores โž—
  • -mcode-density โ€” enable code density instructions for ARC EM โœจ This option is on by default for ARC HS.
  • -mll64 โ€” enable double load/store operations for ARC HS cores ๐Ÿ“ฆ
  • -mtp-regno=regno โ€” specify the thread pointer register number ๐Ÿงต
  • -mmpy-option=multo โ€” compile ARCv2 code with a multiplier design option ๐Ÿงฎ You can specify the option using either a string or a numeric value for multo. wlh1 is the default. The recognized values are:
    • 0 or none โ€” no multiplier available ๐Ÿ™…โ€โ™€๏ธ
    • 1 or w โ€” 16x16 multiplier, fully pipelined. The following instructions are enabled: "mpyw" and "mpyuw" ๐ŸŒธ
    • 2 or wlh1 โ€” 32x32 multiplier, fully pipelined (1 stage). The following instructions are additionally enabled: "mpy", "mpyu", "mpym", "mpymu", and "mpy_s" ๐Ÿ’–
    • 3 or wlh2 โ€” 32x32 multiplier, fully pipelined (2 stages). The following instructions are additionally enabled: "mpy", "mpyu", "mpym", "mpymu", and "mpy_s" ๐Ÿฆ‹
    • 4 or wlh3 โ€” two 16x16 multipliers, blocking, sequential. The following instructions are additionally enabled: "mpy", "mpyu", "mpym", "mpymu", and "mpy_s" ๐Ÿงš
    • 5 or wlh4 โ€” one 16x16 multiplier, blocking, sequential. The following instructions are additionally enabled: "mpy", "mpyu", "mpym", "mpymu", and "mpy_s" ๐Ÿ“
    • 6 or wlh5 โ€” one 32x4 multiplier, blocking, sequential. The following instructions are additionally enabled: "mpy", "mpyu", "mpym", "mpymu", and "mpy_s" โญ
    • 7 or plus_dmpy โ€” ARC HS SIMD support ๐Ÿ‘‘
    • 8 or plus_macd โ€” ARC HS SIMD support ๐Ÿ”ฅ
    • 9 or plus_qmacw โ€” ARC HS SIMD support ๐ŸŒˆ

This option is only available for ARCv2 cores ๐Ÿซถ

  • -mfpu=fpu โ€” enables support for specific floating-point hardware extensions for ARCv2 cores ๐Ÿงฎ 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. This option is 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. This option is 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. This option is 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. This option is only available for ARC EM ๐Ÿ”ฅ
    • fpus_div โ€” enables support for single-precision floating-point, square-root, and divide hardware extensions ๐ŸŽ€
  • fpud_div ๐Ÿ’… is the double-precision bundle: double-precision floating-point plus the square-root and divide hardware extensions. It also includes fpus_div. Not available for ARC EM ๐Ÿ’€
  • fpus_fma โœจ gives you single-precision floating-point and the fused multiply and add hardware extensions. Lowkey the cutest combo ๐Ÿฆ‹
  • fpud_fma ๐Ÿ”ฅ gives you double-precision floating-point and the fused multiply and add hardware extensions. This one includes fpus_fma. Not available for ARC EM.
  • fpus_all ๐ŸŒธ turns on all the single-precision floating-point hardware extensions. Every single one, no skipping.
  • fpud_all ๐Ÿ‘‘ is the whole buffet: all the single- and double-precision floating-point hardware extensions. Not available for ARC EM ๐Ÿ˜ญ
  • -mirq-ctrl-saved=register-range, blink, lp_count ๐Ÿงš tells the compiler which general-purpose registers the processor automatically saves and restores on interrupt entry and exit. The register-range is two registers joined by a dash. It always starts at r0, and the upper limit is the fp register. blink and lp_count are optional. Only valid for ARC EM and ARC HS cores.
  • -mrgf-banked-regs=number โšก sets how many registers get replicated into the second register bank when a fast interrupt fires. Fast interrupts are the highest-priority P0 ones, and they only save the PC and STATUS32 registers so they can skip memory transactions during entry and exit. Use this when you're running fast interrupts on an ARC V2 family processor. Permitted values are 4, 8, 16, and 32.
  • -mlpc-width=width ๐ŸŽ€ sets the width of the lp_count register. Valid widths are 8, 16, 20, 24, 28, and 32 bits. The default is fixed at 32 bits. If the width is less than 32, the compiler won't transform your loops into the zero-delay loop mechanism unless it knows lp_count can actually hold the loop-counter value. Depending on the width, the compiler and run-time library might still use the loop mechanism for various needs. This option defines the __ARC_LPC_WIDTH__ macro with the value of width.
  • -mrf16 ๐Ÿ’œ tells the compiler to generate code for a 16-entry register file. It defines the __ARC_RF16__ preprocessor macro.
  • -mbranch-index ๐Ÿ“ enables use of bi or bih instructions to implement jump tables.

Next up, these ones get passed along to the assembler and set preprocessor macro symbols ๐Ÿซถ

  • -mdsp-packa ๐ŸŒˆ gets passed down to the assembler to enable the DSP Pack A extensions. It also sets the __Xdsp_packa preprocessor symbol. Deprecated. ๐Ÿ’€
  • -mdvbf gets passed down to the assembler to enable the dual Viterbi butterfly extension. It also sets __Xdvbf. Deprecated.
  • -mlock gets passed down to the assembler to enable the locked load/store conditional extension. It also sets __Xlock.
  • -mmac-d16 gets passed down to the assembler and sets __Xxmac_d16. Deprecated.
  • -mmac-24 gets passed down to the assembler and sets __Xxmac_24. Deprecated.
  • -mrtsc gets passed down to the assembler to enable the 64-bit time-stamp counter extension instruction. It also sets __Xrtsc. Deprecated.
  • -mswape gets passed down to the assembler to enable the swap byte ordering extension instruction. It also sets __Xswape.
  • -mtelephony gets passed down to the assembler to enable dual- and single-operand instructions for telephony. It also sets __Xtelephony. Deprecated.
  • -mxy gets passed down to the assembler to enable the XY memory extension. It also sets __Xxy.

These next ones control how the assembly code gets annotated ๐Ÿ“

  • -misize annotates assembler instructions with estimated addresses.
  • -mannotate-align does nothing. It's only hanging around for backward compatibility ๐Ÿ™ˆ

These ones get passed through to the linker ๐Ÿ”—

  • -marclinux gets passed through to the linker to specify use of the arclinux emulation. It's enabled by default in toolchains built for arc-linux-uclibc and arceb-linux-uclibc targets when profiling is not requested.
  • -marclinux_prof gets passed through to the linker to specify use of the arclinux_prof emulation. It's enabled by default in those same toolchains when profiling is requested.

Now the options that control the semantics of the generated code ๐Ÿง 

  • -mlong-calls generates calls as register indirect calls, which gives you access to the full 32-bit address range.
  • -mmedium-calls means don'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 gets suppressed so you can use that 25-bit range instead of the 21-bit range you'd get with conditional branch-and-link. This is the default for toolchains 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 there are double load/store operations.
  • -mno-sdata means no sdata references. This is the default for toolchains built for arc-linux-uclibc and arceb-linux-uclibc targets.
  • -mvolatile-cache uses ordinarily cached memory accesses for volatile references. This is the default ๐Ÿ’–
  • -mno-volatile-cache enables cache bypass for volatile references.

These fine-tune code generation ๐ŸŽ€

  • -malign-call does nothing. Preserved for backward compatibility.
  • -mauto-modify-reg enables the use of pre/post modify with register displacement.
  • -mbbit-peephole does nothing. Preserved for backward compatibility.
  • -mno-brcc disables a target-specific pass in arc_reorg that generates compare-and-branch (brcc) instructions. It has no effect on the generation of these instructions when they're driven by the combiner pass.
  • -mcase-vector-pcrel uses PC-relative switch case tables to enable case table shortening. This is the default for -Os.
  • -mcompact-casesi enables the compact casesi pattern. This is the default for -Os, and it's only available for ARCv1 cores. Deprecated.
  • -mno-cond-exec disables the ARCompact-specific pass that generates conditional execution instructions.

Okay, the tea โ˜• is that delay slot scheduling and the interactions between operand numbers, literal sizes, instruction lengths, and conditional execution support mean the target-independent pass for conditional execution is often lacking. So the ARC port keeps a special pass around that tries to find more conditional execution opportunities after register allocation, branch shortening, and delay slot scheduling have been done. This pass generally, but not always, improves performance and code size, at the cost of extra compilation time, which is why there's an option to switch it off. If you have a problem with call instructions exceeding their allowable offset range because they've been conditionalized, you should consider using -mmedium-calls instead ๐Ÿซ 

  • -mearly-cbranchsi enables pre-reload use of the cbranchsi pattern.
  • -mexpand-adddi expands adddi3 and subdi3 at RTL generation time into add.f, adc etc. Deprecated.
  • -mindexed-loads enables the use of indexed loads. This can be problematic because some optimizers then assume that indexed stores exist, which is not the case โŒ
  • -mlra enables Local Register Allocation. It's still experimental for ARC, so by default the compiler uses standard reload (i.e. -mno-lra) ๐Ÿงช
  • -mlra-priority-none doesn't indicate any priority for target registers.
  • -mlra-priority-compact indicates target register priority for r0..r3 / r12..r15.
  • -mlra-priority-noncompact reduces target register priority for r0..r3 / r12..r15.
  • -mmillicode ๐ŸŒ™ when you're optimizing for size (using -Os), prologues and epilogues that have to save or restore a large number of registers are often shortened by calling a special function in libgcc. This is called a millicode call. Since these calls can pose performance issues, and/or cause linking issues when linking in a nonstandard way, this option lets you turn millicode call generation on or off.
  • -mcode-density-frame enables the compiler to emit enter and leave instructions. These are only valid for CPUs with the code-density feature.
  • -mmixed-code does nothing. Preserved for backward compatibility.
  • -mq-class is deprecated. It enables q instruction alternatives. This is the default for -Os.
  • -mRcq does nothing. Preserved for backward compatibility.
  • -mRcw does nothing. Preserved for backward compatibility.
  • -msize-level=level fine-tunes size optimization with regards to instruction lengths and alignment. The recognized values for level are:
    • 0 means no size optimization. This level is deprecated and treated like 1.
    • 1 means short instructions are used opportunistically.
    • 2 means that, in addition, alignment of loops and of code after barriers is dropped.
    • 3 means that, in addition, optional data alignment is dropped, and the option Os is enabled.

This defaults to 3 when -Os is in effect. Otherwise, the behavior when this is not set is equivalent to level 1 โœจ

  • -mtune=cpu sets instruction scheduling parameters for cpu, overriding any that are 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 โ€” ok this one's for the ARC750D CPU ๐Ÿ’… tuning just for it, no cap โœจ
  • core3 โ€” tunes for the ARCv2 core3 type CPU ๐Ÿฆ‹ and this one unlocks the dbnz instruction, so it's giving main character energy ๐Ÿ‘‘
  • release31a โ€” tunes for ARC4x release 3.10a ๐ŸŒธ
  • -mmultcost=num โ€” sets the cost GCC assumes for a multiply instruction ๐Ÿงฎ where 4 means it's the same cost as a normal instruction ๐Ÿ’–
  • -munalign-prob-threshold=probability โ€” literally does nothing ๐Ÿ™ˆ it's just kept around so older code doesn't cry ๐Ÿ˜ญ

The following options are still around for backward compatibility, but they're deprecated now, so bestie don't build new stuff with them ๐Ÿ’€

These options will be removed in a future release, so start switching now before they vanish! ๐Ÿซถ
  • -margonaut โ€” obsolete FPX, retired and gone ๐Ÿงš
  • -mbig-endian, -EB โ€” compiles code for big-endian targets ๐ŸŒˆ but using these is deprecated now. Big-endian is supported by configuring GCC to build the arceb-elf32 and arceb-linux-uclibc targets instead, and big endian is the default for those ๐Ÿ’œ
  • -mlittle-endian, -EL โ€” compiles code for little-endian targets ๐Ÿ“ also deprecated. Little-endian 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 got replaced by ARC600, ARC601, ARC700 and ARC700-xmac respectively ๐Ÿ‘‘
  • -multcost=num โ€” replaced by -mmultcost ๐ŸŒˆ

โœจ ARM Options โœจ

These -m options are defined for the ARM port ๐Ÿฆ‹ so if you're on ARM, these are your lowkey best friends ๐Ÿ’œ

  • -mabi=name โ€” generates code for the ABI you pick ๐ŸŽ€. The permissible values are apcs-gnu, atpcs, aapcs, aapcs-linux and iwmmxt ๐Ÿ’…
  • -mapcs-frame โ€” makes a stack frame that follows the ARM Procedure Call Standard for all functions ๐Ÿซถ, even when it's not strictly needed for the code to run right. If you pair this with -fomit-frame-pointer, stack frames won't get generated for leaf functions ๐ŸŒธ. The default is -mno-apcs-frame, and this option is deprecated ๐Ÿ’€
  • -mapcs โ€” just a synonym for -mapcs-frame ๐Ÿงš and it's deprecated too ๐Ÿ˜ญ
  • -mthumb-interwork โ€” generates code that can call between the ARM and Thumb instruction sets ๐ŸŒˆ. Without it, on pre-v5 architectures, the two sets can't be reliably used inside one program ๐Ÿ™ˆ. The default is -mno-thumb-interwork, because -mthumb-interwork makes slightly larger code ๐Ÿ“. In AAPCS configurations this option is meaningless ๐Ÿ’€
  • -mno-sched-prolog โ€” stops GCC from reordering instructions in the function prologue, or merging them with the instructions in the function's body ๐Ÿ”ฅ. So every function starts with a recognizable set of instructions (or one from a small set of prologues), and you can use that to find where functions start inside an executable ๐Ÿ‘‘. The default is -msched-prolog โœจ
  • -mfloat-abi=name โ€” picks which floating-point ABI to use ๐Ÿ’–. The values are soft, softfp and hard ๐Ÿฆ‹.
    • soft makes GCC emit library calls for floating-point operations ๐Ÿงฎ
    • softfp lets you use hardware floating-point instructions but still uses the soft-float calling conventions ๐ŸŒธ
    • hard gives you floating-point instructions and FPU-specific calling conventions ๐Ÿ”ฅ

The default depends on the specific target configuration ๐Ÿ’…. Heads up: the hard-float and soft-float ABIs are not link-compatible, so you have to compile your entire 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 doesn't put any restrictions on the assembler ๐Ÿซถ
  • -mlittle-endian โ€” generates code for a processor running in little-endian mode ๐Ÿ“. This is the default for all standard configurations ๐Ÿ’œ
  • -mbig-endian โ€” generates code for a processor running in big-endian mode ๐ŸŒˆ. The default is to compile for a little-endian processor ๐Ÿ’–
  • -mbe8, -mbe32 โ€” when linking a big-endian image, these pick between the BE8 and BE32 formats ๐Ÿงš. They have no effect on little-endian images and get ignored there ๐Ÿ™ˆ. The default depends on the target architecture: ARMv6 and later default to BE8, and older architectures default to BE32 โญ. BE32 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 โœจ. You can use it together with -mcpu=, or instead of it ๐Ÿฆ‹.

The permissible names are armv4t, armv5t, armv5te, armv6, armv6j, armv6k, armv6kz, armv6t2, armv6z, armv6zk, armv7, armv7-a, armv7ve, armv8-a, armv8.1-a, armv8.2-a, armv8.3-a, armv8.4-a, armv8.5-a, armv8.6-a, armv9-a, armv7-r, armv8-r, armv6-m, armv6s-m, armv7-m, armv7e-m, armv8-m.base, armv8-m.main, armv8.1-m.main, armv9-a, iwmmxt and iwmmxt2 ๐Ÿ’…

Also, armv4 is recognized but its support is deprecated ๐Ÿ’€. It's one of the architectures that doesn't support the Thumb execution state ๐Ÿ™ˆ.

Lots of these architectures support extensions ๐ŸŒˆ. You add one by appending +extension to the architecture name ๐Ÿ’œ. Extension options get processed in order and their capabilities stack up ๐Ÿงฎ. An extension also turns on any base extensions it needs ๐Ÿซถ. For example, +crypto will always enable +simd ๐Ÿ”ฅ. The exception to all that stacking is the extensions prefixed with +no...: those turn off the option and any other extensions that depend on it ๐Ÿ˜ญ.

For example, -march=armv7-a+simd+nofp+vfpv4 is the same as writing -march=armv7-a+vfpv4, because the +simd option gets totally disabled by the +nofp that comes after it ๐Ÿ™ˆ.

Most extension names are generic, but what they do depends on the architecture they're applied to ๐Ÿฆ‹. For example, +simd works on both armv7-a and armv8-a, but it turns on the original ARMv7-A Advanced SIMD (Neon) extensions for armv7-a, and the ARMv8-A variant for armv8-a ๐ŸŽ€.

The table below lists the supported extensions for each architecture ๐Ÿงš. Architectures that aren't mentioned don't support any extensions ๐Ÿ’–.

โœจ armv5te, armv6, armv6j, armv6k, armv6kz, armv6t2, armv6z, armv6zk ๐ŸŒธ

  • +fp โ€” the VFPv2 floating-point instructions ๐Ÿงฎ. The extension +vfpv2 can be used as an alias for this one ๐Ÿ’œ
  • +nofp โ€” disables the floating-point instructions ๐Ÿ™…

โœจ armv7 ๐Ÿ”ฅ

This is the common subset of the ARMv7-A, ARMv7-R and ARMv7-M architectures ๐Ÿ‘‘.

  • +fp โ€” the VFPv3 floating-point instructions, with 16 double-precision registers ๐Ÿฆ‹. The extension +vfpv3-d16 can be used as an alias for this one ๐ŸŒˆ. Heads up: floating-point isn't supported by the base ARMv7-M architecture, but it's compatible with both ARMv7-A and ARMv7-R ๐Ÿ’€
  • +nofp โ€” disables the floating-point instructions ๐Ÿ™…

โœจ armv7-a ๐Ÿ’œ

  • +mp โ€” the multiprocessing extension ๐Ÿซถ
  • +sec โ€” the security extension ๐Ÿ”
  • +fp โ€” the VFPv3 floating-point instructions, with 16 double-precision registers ๐Ÿ“. The extension +vfpv3-d16 can be used as an alias for this one ๐Ÿ’…
  • +simd โ€” the Advanced SIMD (Neon) v1 and the VFPv3 floating-point instructions ๐ŸŽ€. The extensions +neon and +neon-vfpv3 can be used as aliases for this 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 and the half-precision floating-point conversion operations ๐ŸŒธ
  • +vfpv3-fp16 โ€” the VFPv3 floating-point instructions, with 32 double-precision registers and the half-precision floating-point conversion operations ๐Ÿ’–
  • +vfpv4-d16 โ€” the VFPv4 floating-point instructions, with 16 double-precision registers ๐Ÿฆ‹
  • +vfpv4 โ€” the VFPv4 floating-point instructions, with 32 double-precision registers ๐Ÿ‘‘
  • +neon-fp16 โ€” the Advanced SIMD (Neon) v1 and the VFPv3 floating-point instructions, with the half-precision floating-point conversion operations ๐Ÿ”ฅ
  • +neon-vfpv4 โ€” the Advanced SIMD (Neon) v2 and the VFPv4 floating-point instructions ๐ŸŒˆ
  • +nosimd โ€” disables the Advanced SIMD instructions (it doesn't disable floating point) ๐Ÿ™ˆ
  • +nofp โ€” disables the floating-point and Advanced SIMD instructions ๐Ÿ˜ญ

โœจ armv7ve ๐ŸŒˆ

This is the extended version of the ARMv7-A architecture, with support for virtualization ๐Ÿงš.

  • +fp โ€” the VFPv4 floating-point instructions, with 16 double-precision registers ๐Ÿซถ. The extension +vfpv4-d16 can be used as an alias for this one ๐Ÿ’œ
  • +simd โ€” the Advanced SIMD (Neon) v2 and the VFPv4 floating-point instructions ๐ŸŽ€. The extension +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 and the half-precision floating-point conversion operations โœจ
  • +vfpv3-fp16 โ€” okay so this one gets you 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, but with 16 double-precision registers ๐ŸŽ€
  • +vfpv4 โ€” the VFPv4 floating-point instructions with 32 double-precision registers, so it's the full-fat version ๐Ÿฆ‹
  • +neon โ€” the Advanced SIMD (Neon) v1 along with the VFPv3 floating-point instructions. You can also write +neon-vfpv3 and it's the same thing, an alias ๐ŸŒˆ
  • +neon-fp16 โ€” the Advanced SIMD (Neon) v1 and VFPv3 floating-point instructions, plus the half-precision floating-point conversion operations ๐Ÿ”ฅ
  • +nosimd โ€” disables the Advanced SIMD instructions. Floating point is still on though, so don't panic ๐Ÿ™ˆ
  • +nofp โ€” disables the floating-point and Advanced SIMD instructions ๐Ÿ’€

๐ŸŒธ armv8-a

  • +crc โ€” the Cyclic Redundancy Check (CRC) instructions ๐Ÿงš
  • +simd โ€” the ARMv8-A Advanced SIMD and floating-point instructions ๐Ÿ’œ
  • +crypto โ€” the cryptographic instructions ๐Ÿ”
  • +nocrypto โ€” disables the cryptographic instructions ๐Ÿ™…โ€โ™€๏ธ
  • +nofp โ€” disables the floating-point, Advanced SIMD and cryptographic instructions. Big yikes energy ๐Ÿ˜ญ
  • +sb โ€” the Speculation Barrier Instruction ๐Ÿ›ก๏ธ
  • +predres โ€” the Execution and Data Prediction Restriction Instructions ๐Ÿซถ

๐ŸŒธ armv8.1-a

  • +simd โ€” the ARMv8.1-A Advanced SIMD and floating-point instructions ๐Ÿ’…
  • +crypto โ€” the cryptographic instructions. This one also turns on the Advanced SIMD and floating-point instructions, so it's giving bundle deal ๐ŸŽ
  • +nocrypto โ€” disables the cryptographic instructions ๐Ÿ™…โ€โ™€๏ธ
  • +nofp โ€” disables the floating-point, Advanced SIMD and cryptographic instructions ๐Ÿ˜ญ
  • +sb โ€” the Speculation Barrier Instruction ๐Ÿ›ก๏ธ
  • +predres โ€” the Execution and Data Prediction Restriction Instructions ๐Ÿซถ

๐ŸŒธ armv8.2-a and armv8.3-a

  • +fp16 โ€” the half-precision floating-point data processing instructions. This also enables the Advanced SIMD and floating-point instructions ๐Ÿ“
  • +fp16fml โ€” the half-precision floating-point fmla extension. This also enables the half-precision floating-point extension and the Advanced SIMD and floating-point instructions, so it's a whole vibe ๐ŸŒŸ
  • +simd โ€” the ARMv8.1-A Advanced SIMD and floating-point instructions ๐Ÿ’…
  • +crypto โ€” the cryptographic instructions. This also enables the Advanced SIMD and floating-point instructions ๐Ÿ”
  • +dotprod โ€” enables the Dot Product extension. This also enables Advanced SIMD instructions โœจ
  • +nocrypto โ€” disables the cryptographic extension ๐Ÿ™…โ€โ™€๏ธ
  • +nofp โ€” disables the floating-point, Advanced SIMD and cryptographic instructions ๐Ÿ˜ญ
  • +sb โ€” the Speculation Barrier Instruction ๐Ÿ›ก๏ธ
  • +predres โ€” the Execution and Data Prediction Restriction Instructions ๐Ÿซถ
  • +i8mm โ€” the 8-bit Integer Matrix Multiply instructions. This also enables Advanced SIMD and floating-point instructions ๐Ÿงฎ
  • +bf16 โ€” the Brain half-precision floating-point instructions. This also enables Advanced SIMD and floating-point instructions ๐Ÿง 

๐ŸŒธ armv8.4-a

  • +fp16 โ€” the half-precision floating-point data processing instructions. This also enables the Advanced SIMD and floating-point instructions, plus the Dot Product extension and the half-precision floating-point fmla extension. Triple threat ๐Ÿ‘‘
  • +simd โ€” the ARMv8.3-A Advanced SIMD and floating-point instructions, plus the Dot Product extension ๐Ÿ’œ
  • +crypto โ€” the cryptographic instructions. This also enables the Advanced SIMD and floating-point instructions, plus the Dot Product extension ๐Ÿ”
  • +nocrypto โ€” disables the cryptographic extension ๐Ÿ™…โ€โ™€๏ธ
  • +nofp โ€” disables the floating-point, Advanced SIMD and cryptographic instructions ๐Ÿ˜ญ
  • +sb โ€” the Speculation Barrier Instruction ๐Ÿ›ก๏ธ
  • +predres โ€” the Execution and Data Prediction Restriction Instructions ๐Ÿซถ
  • +i8mm โ€” the 8-bit Integer Matrix Multiply instructions. This also enables Advanced SIMD and floating-point instructions ๐Ÿงฎ
  • +bf16 โ€” the Brain half-precision floating-point instructions. This also enables Advanced SIMD and floating-point instructions ๐Ÿง 

๐ŸŒธ armv8.5-a

  • +fp16 โ€” the half-precision floating-point data processing instructions. This also enables the Advanced SIMD and floating-point instructions, plus the Dot Product extension and the half-precision floating-point fmla extension ๐Ÿ“
  • +simd โ€” the ARMv8.3-A Advanced SIMD and floating-point instructions, plus the Dot Product extension ๐Ÿ’œ
  • +crypto โ€” the cryptographic instructions. This also enables the Advanced SIMD and floating-point instructions, plus the Dot Product extension ๐Ÿ”
  • +nocrypto โ€” disables the cryptographic extension ๐Ÿ™…โ€โ™€๏ธ
  • +nofp โ€” disables the floating-point, Advanced SIMD and cryptographic instructions ๐Ÿ˜ญ
  • +i8mm โ€” the 8-bit Integer Matrix Multiply instructions. This also enables Advanced SIMD and floating-point instructions ๐Ÿงฎ
  • +bf16 โ€” the Brain half-precision floating-point instructions. This also enables Advanced SIMD and floating-point instructions ๐Ÿง 

๐ŸŒธ armv8.6-a

  • +fp16 โ€” the half-precision floating-point data processing instructions. This also enables the Advanced SIMD and floating-point instructions, plus the Dot Product extension and the half-precision floating-point fmla extension ๐Ÿ“
  • +simd โ€” the ARMv8.3-A Advanced SIMD and floating-point instructions, plus the Dot Product extension ๐Ÿ’œ
  • +crypto โ€” the cryptographic instructions. This also enables the Advanced SIMD and floating-point instructions, plus the Dot Product extension ๐Ÿ”
  • +nocrypto โ€” disables the cryptographic extension ๐Ÿ™…โ€โ™€๏ธ
  • +nofp โ€” disables the floating-point, Advanced SIMD and cryptographic instructions ๐Ÿ˜ญ
  • +i8mm โ€” the 8-bit Integer Matrix Multiply instructions. This also enables Advanced SIMD and floating-point instructions ๐Ÿงฎ
  • +bf16 โ€” the Brain half-precision floating-point instructions. This also enables Advanced SIMD and floating-point instructions ๐Ÿง 

๐ŸŒธ armv7-r

  • +fp.sp โ€” the single-precision VFPv3 floating-point instructions. The extension +vfpv3xd can be used as an alias for this extension ๐Ÿฆ‹
  • +fp โ€” the VFPv3 floating-point instructions with 16 double-precision registers. The extension +vfpv3-d16 can be used as an alias for this extension ๐ŸŽ€
  • +vfpv3xd-d16-fp16 โ€” the single-precision VFPv3 floating-point instructions with 16 double-precision registers and the half-precision floating-point conversion operations ๐Ÿ“
  • +vfpv3-d16-fp16 โ€” the VFPv3 floating-point instructions with 16 double-precision registers and 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, according to the numbers given in the options in the range 0 to 7 ๐Ÿงฉ
  • +pacbti โ€” enables the Pointer Authentication and Branch Target Identification Extension ๐Ÿ”’

๐ŸŒธ armv8-m.main

  • +dsp โ€” the DSP instructions ๐ŸŽถ
  • +nodsp โ€” disables the DSP extension ๐Ÿ™…โ€โ™€๏ธ
  • +fp โ€” the single-precision floating-point instructions โœจ
  • +fp.dp โ€” the single- and double-precision floating-point instructions ๐Ÿ‘‘
  • +nofp โ€” disables the floating-point extension ๐Ÿ™…โ€โ™€๏ธ
  • +cdecp0, +cdecp1, ... , +cdecp7 โ€” enables the Custom Datapath Extension (CDE) on selected coprocessors, according to the numbers given in the options in the range 0 to 7 ๐Ÿงฉ

๐ŸŒธ armv8-r

  • +crc โ€” the Cyclic Redundancy Check (CRC) instructions ๐Ÿงš
  • +fp.sp โ€” the single-precision FPv5 floating-point instructions ๐Ÿฆ‹
  • +simd โ€” the ARMv8-A Advanced SIMD and floating-point instructions ๐Ÿ’œ
  • +crypto โ€” the cryptographic instructions ๐Ÿ”
  • +nocrypto โ€” disables the cryptographic instructions ๐Ÿ™…โ€โ™€๏ธ
  • +nofp โ€” disables the floating-point, Advanced SIMD and cryptographic instructions ๐Ÿ˜ญ

Okay bestie, -march=native is giving auto-detect ๐Ÿ”. It tells the compiler to figure out the architecture of the build computer all by itself. ngl, this only works on GNU/Linux right now, and not every architecture gets recognized ๐Ÿ’€. If the auto-detect doesn't work out, the option just has no effect ๐Ÿซถ.

๐ŸŽ€ -mtune=name

This is how you tell GCC which target ARM processor to tune your code's performance for โœจ For some ARM implementations you can get better performance with this option ๐Ÿฆ‹. The permissible names are arm7tdmi, arm7tdmi-s, arm710t, arm720t, arm740t, strongarm, strongarm110, strongarm1100, strongarm1110, arm8, arm810, arm9, arm9e, arm920, arm920t, arm922t, arm946e-s, arm966e-s, arm968e-s, arm926ej-s, arm940t, arm9tdmi, arm10tdmi, arm1020t, arm1026ej-s, arm10e, arm1020e, arm1022e, arm1136j-s, arm1136jf-s, mpcore, mpcorenovfp, arm1156t2-s, arm1156t2f-s, arm1176jz-s, arm1176jzf-s, generic-armv7-a, cortex-a5, cortex-a7, cortex-a8, cortex-a9, cortex-a12, cortex-a15, cortex-a17, cortex-a32, cortex-a35, cortex-a53, cortex-a55, cortex-a57, cortex-a72, cortex-a73, cortex-a75, cortex-a76, cortex-a76ae, cortex-a77, cortex-a78, cortex-a78ae, cortex-a78c, cortex-a710, ares, cortex-r4, cortex-r4f, cortex-r5, cortex-r7, cortex-r8, cortex-r52, cortex-r52plus, cortex-m0, cortex-m0plus, cortex-m1, cortex-m3, cortex-m4, cortex-m7, cortex-m23, cortex-m33, cortex-m35p, cortex-m52, cortex-m55, cortex-m85, cortex-x1, cortex-x1c, 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, star-mc1, xgene1.

Okay, and this option can also say "tune this for a big.LITTLE system" ๐Ÿงš The permissible names for that are cortex-a15.cortex-a7, cortex-a17.cortex-a7, cortex-a57.cortex-a53, cortex-a72.cortex-a53, cortex-a72.cortex-a35, cortex-a73.cortex-a53, cortex-a75.cortex-a55, cortex-a76.cortex-a55.

-mtune=generic-arch is the move if you want code that runs well on the current most popular processors ๐Ÿ’… It's a blend across the processors within arch, balancing optimizations that help some CPUs in the range while avoiding performance pitfalls on others. Just know the effects may change in future GCC versions as CPU models come and go ๐ŸŒธ

-mtune takes the same extension options as -mcpu, but those extensions don't change the tuning of the generated code ๐Ÿ’œ

-mtune=native auto-detects the CPU of the build computer ๐Ÿ‘‘ Same deal as before: GNU/Linux only, not all architectures are recognized, and if the auto-detect fails, the option has no effect ๐Ÿ™ˆ

๐ŸŒธ -mcpu=name[+extension...]

This one specifies the target ARM processor. GCC uses that name to work out the target ARM architecture (as if you'd passed -march) and the ARM processor type to tune for (as if you'd passed -mtune). If you use this alongside -march or -mtune, those two win for their part of the job ๐Ÿ‘‘

Lots of the supported CPUs have optional architectural extensions, and those are normally enabled by default ๐Ÿงš If implementations that lack the extension exist, you can use the extension syntax to switch off the ones that got left out. For floating-point and Advanced SIMD (Neon) instructions, keep -mfloat-abi and -mfpu in mind too: floating-point and Advanced SIMD instructions are only used if -mfloat-abi isn't set to soft, and any -mfpu setting other than auto overrides the available floating-point and SIMD extension instructions ๐Ÿ”ฅ

For example, cortex-a9 comes in three major configs: integer only, with just a floating-point unit, or with floating-point and Advanced SIMD. The default is to enable all of the instructions, but +nosimd and +nofp can disable just the SIMD, or both the SIMD and floating-point instructions, respectively ๐Ÿ’–

Permissible names for this option are the same as for -mtune.

The following extension options are common to the listed CPUs:

  • +nodsp โ€” Disables the DSP instructions on cortex-m33, cortex-m35p, cortex-m52, cortex-m55 and cortex-m85. It also disables the M-Profile Vector Extension (MVE) integer and single precision floating-point instructions on cortex-m52, cortex-m55 and cortex-m85 ๐ŸŽ€
  • +nopacbti โ€” Disables the Pointer Authentication and Branch Target Identification Extension on cortex-m52 and cortex-m85 ๐Ÿฆ‹
  • +nomve โ€” Disables the M-Profile Vector Extension (MVE) integer and single precision floating-point instructions on cortex-m52, cortex-m55 and cortex-m85 ๐ŸŒˆ
  • +nomve.fp โ€” Disables the M-Profile Vector Extension (MVE) single precision floating-point instructions on cortex-m52, cortex-m55 and cortex-m85 โœจ
  • +cdecp0, +cdecp1, ... , +cdecp7 โ€” Enables the Custom Datapath Extension (CDE) on selected coprocessors, picked by the numbers in the options from 0 to 7, on cortex-m52 and cortex-m55 ๐Ÿงš
  • +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, cortex-m35p, cortex-m52, cortex-m55 and cortex-m85. On generic-armv7-a, cortex-a5, cortex-a7, cortex-a8, cortex-a9, cortex-a12, cortex-a15, cortex-a17, cortex-a15.cortex-a7, cortex-a17.cortex-a7, cortex-a32, cortex-a35, cortex-a53 and cortex-a55, it disables the floating-point and SIMD instructions instead ๐Ÿ’…
  • +nofp.dp โ€” Disables the double-precision component of the floating-point instructions on cortex-r5, cortex-r7, cortex-r8, cortex-r52, cortex-r52plus and cortex-m7 ๐ŸŒธ
  • +nosimd โ€” Disables the SIMD (but not floating-point) instructions on generic-armv7-a, cortex-a5, cortex-a7 and cortex-a9 ๐Ÿ’œ
  • +crypto โ€” Enables the cryptographic instructions on cortex-a32, cortex-a35, cortex-a53, cortex-a55, cortex-a57, cortex-a72, cortex-a73, cortex-a75, exynos-m1, xgene1, cortex-a57.cortex-a53, cortex-a72.cortex-a53, cortex-a73.cortex-a35, cortex-a73.cortex-a53 and cortex-a75.cortex-a55 ๐Ÿ”

Also, the generic-armv7-a pseudo target defaults to VFPv3 with 16 double-precision registers ๐Ÿฆ‹ It supports these extension options: mp, sec, vfpv3-d16, vfpv3, vfpv3-d16-fp16, vfpv3-fp16, vfpv4-d16, vfpv4, neon, neon-vfpv3, neon-fp16, neon-vfpv4. The meanings are the same as for the extensions to -march=armv7-a.

-mcpu=generic-arch is also allowed, and it's equivalent to -march=arch -mtune=generic-arch. Check out -mtune for more info โœจ

-mcpu=native auto-detects the CPU of the build computer ๐Ÿ‘‘ Again, GNU/Linux only, not every architecture is recognized, and if the auto-detect is unsuccessful the option has no effect ๐Ÿ™ˆ

๐Ÿ”ฅ -mfpu=name

This specifies what floating-point hardware (or hardware emulation) is available on the target. The permissible names are auto, vfpv2, vfpv3, vfpv3-fp16, vfpv3-d16, vfpv3-d16-fp16, vfpv3xd, vfpv3xd-fp16, neon-vfpv3, neon-fp16, vfpv4, vfpv4-d16, fpv4-sp-d16, neon-vfpv4, fpv5-d16, fpv5-sp-d16, fp-armv8, neon-fp-armv8 and crypto-neon-fp-armv8. Heads up: neon is an alias for neon-vfpv3, and vfp is an alias for vfpv2 ๐Ÿ’–

auto is the default and it's a special one ๐Ÿงš It makes the compiler pick the floating-point and Advanced SIMD instructions based on the settings of -mcpu and -march.

โš ๏ธ If the selected floating-point hardware includes the NEON extension (e.g. -mfpu=neon), GCC's auto-vectorization pass won't generate floating-point operations unless -funsafe-math-optimizations is also specified. That's because NEON hardware doesn't fully implement the IEEE 754 standard for floating-point arithmetic (denormal values get treated as zero, in particular), so using NEON instructions may lead to a loss of precision ๐Ÿ’€

You can also set the fpu name at function level using the target("fpu=") function attributes or pragmas ๐ŸŒˆ

๐Ÿฆ‹ -mfp16-format=name

This specifies the format of the "__fp16" half-precision floating-point type โœจ The permissible names are none, ieee and alternative. The default is none, which means the "__fp16" type is not defined at all ๐Ÿ™ˆ

๐Ÿงš -mstructure-size-boundary=n

The sizes of all structures and unions get rounded up to a multiple of the number of bits set by this option ๐Ÿ“ The permissible values are 8, 32 and 64. The default varies between toolchains. For the COFF targeted toolchain, the default is 8. A value of 64 is only allowed if the underlying ABI supports it.

Going bigger can produce faster, more efficient code, but it can also increase the size of the program ๐Ÿ’… Different values are potentially incompatible, too. Code compiled with one value can't necessarily work with code or libraries compiled with another value, if they swap information using structures or unions ๐Ÿ˜ญ

๐Ÿ’€ This option is deprecated, so maybe don't build new stuff around it.

๐ŸŒˆ -mabort-on-noreturn

This generates a call to the function "abort" at the end of a "noreturn" function ๐Ÿ”ฅ It gets executed if the function tries to return.

๐Ÿ‘‘ -mlong-calls and -mno-long-calls

These tell the compiler to make 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 of the 64-megabyte addressing range of the offset-based version of the subroutine call instruction.

Okay so even if this switch is on, bestie, not every function call gets turned into a long call ๐Ÿ’… The heuristic (aka the vibe check the compiler runs) says that static functions, functions with the short_call attribute, functions inside the scope of a #pragma no_long_calls directive, and functions whose definitions have already been compiled within the current compilation unit are not turned into long calls ๐Ÿ™…โ€โ™€๏ธ. The exceptions are the main character moments: weak function definitions, functions with the long_call attribute or the section attribute, and functions inside the scope of a #pragma long_calls directive are always turned into long calls ๐Ÿ‘‘.

This feature is not enabled by default โœจ Specifying -mno-long-calls restores the default behavior, and so does putting the function calls inside the scope of a #pragma long_calls_off directive. Also, these switches have zero effect on how the compiler handles function calls made through function pointers, so don't expect them to reach that part ๐Ÿ™ˆ

  • -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 has to set this register to a proper value before execution starts, so that's on it ๐Ÿซถ
  • -mpic-register=reg โ€” Picks the register used for PIC addressing. For the standard PIC base case, the default is any suitable register the compiler decides on. For the single PIC base case, the default is R9 if the target is EABI based or stack-checking is enabled, otherwise it's R10 ๐ŸŽ€
  • -mpic-data-is-text-relative โ€” Assumes the displacement between the text and data segments is fixed at static link time ๐Ÿฆ‹ This lets PC-relative addressing operations access data known to be in the data segment. For non-VxWorks RTP targets, this option is on by default. When it's disabled on those targets, -msingle-pic-base gets enabled by default instead โœจ
  • -mpoke-function-name โ€” Writes the name of each function into the text section, right before the function prologue ๐Ÿงš The generated code looks kind of like this:
t0
    .ascii "arm_poke_function_name", 0
    .align
t1
    .word 0xff000000 + (t1 - t0)
arm_poke_function_name
    mov     ip, sp
    stmfd   sp!, {fp, ip, lr, pc}
    sub     fp, ip, #4

When you're doing a stack backtrace, code can check the value of pc stored at fp + 0. If the trace function then looks at location pc - 12 and the top 8 bits are set, we know there's a function name embedded right before that location, and its length is ((pc[-3]) & 0xff000000) ๐Ÿ”

  • -mthumb, -marm โ€” Pick between generating code that runs in ARM state or Thumb state ๐ŸŒธ Most configurations default to ARM state, but you can change that default by configuring GCC with the --with-mode=state configure option. You can also override ARM or Thumb mode for each function using the target("thumb") and target("arm") function attributes or pragmas ๐Ÿ’œ
  • -mflip-thumb โ€” Switches ARM and Thumb modes on alternating functions ๐Ÿ”€ This one exists for regression testing of mixed Thumb/ARM code generation, so it's not meant for ordinary code compiling ๐Ÿ™…โ€โ™€๏ธ
  • -mtpcs-frame โ€” Generates a stack frame that follows the Thumb Procedure Call Standard for all non-leaf functions. (A leaf function is one that does not call any other functions.) The default is -mno-tpcs-frame ๐Ÿ“
  • -mtpcs-leaf-frame โ€” Generates a stack frame that follows the Thumb Procedure Call Standard for all leaf functions. (A leaf function is one that does not call any other functions.) The default is -mno-apcs-leaf-frame ๐ŸŒˆ
  • -mcallee-super-interworking โ€” Gives all externally visible functions in the file being compiled an ARM instruction set header that switches to Thumb mode before the rest of the function runs โœจ That means these functions can be called from non-interworking code. This option is not valid in AAPCS configurations, because interworking is already enabled by default there ๐Ÿ™ƒ
  • -mcaller-super-interworking โ€” Lets calls through function pointers (including virtual functions) run correctly no matter whether the target code was compiled for interworking or not ๐Ÿซง There's a small overhead when running a function pointer if you turn this on. Same deal as above: this option is not valid in AAPCS configurations because interworking is enabled by default ๐Ÿ’€
  • -mtp=name โ€” Picks the access model for the thread local storage pointer ๐Ÿงต The soft model generates calls to __aeabi_read_tp. The other accepted models are tpidrurw, tpidruro and tpidrprw, which grab the thread pointer straight from the matching system register (supported from the arm6k architecture and later). Those system registers are accessed through the CP15 co-processor interface, and cp15 is also accepted as a convenient alias of tpidruro ๐Ÿ’– The auto argument uses the best available method for the processor you've selected, and auto is the default setting ๐Ÿ‘‘
  • -mtls-dialect=dialect โ€” Picks the dialect used for accessing thread local storage. There are two: gnu and gnu2 ๐ŸŽ€ The gnu dialect selects the original GNU scheme for supporting local and global dynamic TLS models. The gnu2 dialect selects the GNU descriptor scheme, which gives better performance for shared libraries ๐Ÿš€ The GNU descriptor scheme is compatible with the original scheme, but it does need new assembler, linker and library support ๐Ÿซ  Initial and local exec TLS models aren't affected by this option and always use the original scheme.
  • -mword-relocations โ€” Only generates absolute relocations on word-sized values (i.e. R_ARM_ABS32) ๐Ÿงฑ This is on by default on targets (uClinux, SymbianOS) where the runtime loader imposes that restriction, and whenever -fpic or -fPIC is specified. This option conflicts with -mslow-flash-data โŒ
  • -mfix-cortex-m3-ldrd โ€” Some Cortex-M3 cores can corrupt data when ldrd instructions with overlapping destination and base registers are used ๐Ÿ˜ญ This option avoids generating those instructions. It's enabled by default when -mcpu=cortex-m3 is specified ๐Ÿ› ๏ธ
  • -mfix-cortex-a57-aes-1742098, -mno-fix-cortex-a57-aes-1742098, -mfix-cortex-a72-aes-1655431, -mno-fix-cortex-a72-aes-1655431 โ€” Enables (or disables) the mitigation for an erratum on Cortex-A57 and Cortex-A72 that affects the AES cryptographic instructions ๐Ÿ” This option is enabled by default when either -mcpu=cortex-a57 or -mcpu=cortex-a72 is specified ๐Ÿ’…
  • -munaligned-access, -mno-unaligned-access โ€” Enables (or disables) reading and writing of 16- and 32-bit values from addresses that aren't 16- or 32-bit aligned ๐Ÿ™ˆ By default, unaligned access is disabled for all pre-ARMv6, all ARMv6-M and for ARMv8-M Baseline architectures, and enabled for all other architectures. If unaligned access isn't enabled, words in packed data structures get accessed one byte at a time ๐Ÿข

The ARM attribute Tag_CPU_unaligned_access gets set in the generated object file to either true or false, depending on how this option is set ๐Ÿท๏ธ If unaligned access is enabled, the preprocessor symbol __ARM_FEATURE_UNALIGNED is also defined โœจ

  • -mneon-for-64bits โ€” This option is deprecated and has no effect ๐Ÿฅ€
  • -mslow-flash-data โ€” Assumes loading data from flash is slower than fetching instructions, so literal loads get minimized for better performance ๐ŸŒ This option is only supported when compiling for ARMv7 M-profile, and it's off by default. It conflicts with -mword-relocations โŒ
  • -masm-syntax-unified โ€” Assumes inline assembler uses unified asm syntax ๐Ÿงฉ The default is currently off, which implies divided syntax. This option has no impact on Thumb2, but that might change in future GCC releases. Divided syntax should be considered deprecated ๐Ÿ™ƒ
  • -mrestrict-it โ€” Restricts generation of IT blocks so they follow the rules of ARMv8-A ๐Ÿ“ IT blocks can only contain a single 16-bit instruction from a select set of instructions. This option is on by default for ARMv8-A Thumb mode ๐Ÿ’œ
  • -mprint-tune-info โ€” Prints CPU tuning information as a comment in the assembler file ๐Ÿ–จ๏ธ This one is only for regression testing of the compiler and isn't intended for ordinary code compiling. It's disabled by default ๐Ÿ™…โ€โ™€๏ธ
  • -mverbose-cost-dump โ€” Enables verbose cost model dumping in the debug dump files ๐Ÿ•ต๏ธโ€โ™€๏ธ It's provided for debugging the compiler, so that's its whole job ๐Ÿซถ
  • -mpure-code โ€” Doesn't allow constant data to be placed in code sections ๐ŸงŠ When compiling for ELF object format, it also 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", which you can find 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, cortex-m52, cortex-m55, cortex-m85 or star-mc1. You can use -mno-fix-cmse-cve-2021-35465 to disable the mitigation ๐Ÿ™…โ€โ™€๏ธ
  • -mstack-protector-guard=guard, -mstack-protector-guard-offset=offset โ€” Generates stack protection code using a canary at guard. Supported locations are global for a global canary, or tls for a canary accessible via the TLS register ๐Ÿงท The option -mstack-protector-guard-offset= is for use with -fstack-protector-guard=tls and is not for use in user-land code ๐Ÿ™ˆ
  • -mfdpic, -mno-fdpic โ€” okay bestie, this one picks the FDPIC ABI ๐Ÿ’… which uses 64-bit function descriptors to represent pointers to functions โœจ. When the compiler is configured for "arm-*-uclinuxfdpiceabi" targets, it's on by default and implies -fPIE if none of the PIC/PIE-related options is provided ๐Ÿ”ฅ. On other targets it only turns on the FDPIC-specific code generation features, so you have to explicitly pass the PIC/PIE-related options yourself ๐Ÿซถ.

Heads up ๐Ÿ™ˆ static linking is not supported, because it would still involve the dynamic linker when the program self-relocates. If that's acceptable to you, use -static and -Wl,-dynamic-linker options instead.

The opposite -mno-fdpic option is useful (and required) for building the Linux kernel with the same "arm-*-uclinuxfdpiceabi" toolchain you used for your userland programs ๐Ÿงš.

  • -mbranch-protection=none|standard|pac-ret[+leaf][+bti]|bti[+pac-ret[+leaf]] โ€” branch protection features ๐Ÿฆ‹ (armv8.1-m.main only). Here's the vibe check on each value:
    • none โ€” generate code without branch protection or return address signing ๐Ÿ™…โ€โ™€๏ธ.
    • standard[+leaf] โ€” generate code with all branch protection features enabled at their standard level โœจ.
    • pac-ret[+leaf] โ€” generate code with return address signing set to its standard level, which means signing all functions that save the return address to memory ๐Ÿ”.
    • leaf โ€” when return address signing is enabled, also sign leaf functions, even if they don't write the return address to memory ๐Ÿƒ.
    • +bti โ€” add landing-pad instructions at the permitted targets of indirect branch instructions ๐ŸŒธ.

If the +pacbti architecture extension is not enabled, then all branch protection and return address signing operations are constrained to use only the instructions defined in the architectural-NOP space. The generated code stays backwards-compatible with earlier versions of the architecture, but the extra security can be turned on at run time on processors that support the PACBTI extension ๐Ÿ’œ.

Branch target enforcement using BTI can only be enabled at runtime if all code in the application has been compiled with at least -mbranch-protection=bti ๐ŸŽ€.

Any setting other than none is supported only on armv8-m.main or later ๐Ÿ’€.

The default is to generate code without branch protection or return address signing ๐ŸŒˆ.


โœจ AVR Options โœจ

These options are defined for AVR implementations ๐Ÿ.

  • -mmcu=mcu โ€” pick your AVR instruction set architecture (ISA) or device type ๐Ÿ’–. The default for this option is "avr2".

The following AVR devices and ISAs are supported. Note ๐Ÿ“: a complete device support setup consists of startup code crtmcu.o, a device header avr/io*.h, a device library libmcu.a, and a device-specs file specs-mcu (https://gcc.gnu.org/wiki/avr-gcc#spec-files). Only that last one, the device-specs file, is provided by the compiler, according to the supported mcus listed below. The rest comes from AVR-LibC (https://www.nongnu.org/avr-libc/) or from atpack files (https://gcc.gnu.org/wiki/avr-gcc#atpack) supplied by the hardware manufacturer ๐Ÿซถ.

  • 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", "ata5795", "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", "atmega324pb", "atmega325", "atmega325a", "atmega325p", "atmega325pa", "atmega328", "atmega328p", "atmega328pb", "atmega329", "atmega329a", "atmega329p", "atmega329pa", "atmega3250", "atmega3250a", "atmega3250p", "atmega3250pa", "atmega3290", "atmega3290a", "atmega3290p", "atmega3290pa", "atmega406", "atmega64", "atmega64a", "atmega64c1", "atmega64hve", "atmega64hve2", "atmega64m1", "atmega64rfr2", "atmega640", "atmega644", "atmega644a", "atmega644p", "atmega644pa", "atmega644rfr2", "atmega645", "atmega645a", "atmega645p", "atmega649", "atmega649a", "atmega649p", "atmega6450", "atmega6450a", "atmega6450p", "atmega6490", "atmega6490a", "atmega6490p", "ata5790", "ata5790n", "ata5791", "ata6613c", "ata6614q", "ata5782", "ata5831", "ata8210", "ata8510", "ata5787", "ata5835", "ata5700m322", "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", "avr64da28", "avr64da32", "avr64da48", "avr64da64", "avr64db28", "avr64db32", "avr64db48", "avr64db64", "avr64dd14", "avr64dd20", "avr64dd28", "avr64dd32", "avr64du28", "avr64du32", "avr64ea28", "avr64ea32", "avr64ea48".
  • 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", "attiny416auto", "attiny417", "attiny424", "attiny426", "attiny427", "attiny804", "attiny806", "attiny807", "attiny814", "attiny816", "attiny817", "attiny824", "attiny826", "attiny827", "attiny1604", "attiny1606", "attiny1607", "attiny1614", "attiny1616", "attiny1617", "attiny1624", "attiny1626", "attiny1627", "attiny3214", "attiny3216", "attiny3217", "attiny3224", "attiny3226", "attiny3227", "atmega808", "atmega809", "atmega1608", "atmega1609", "atmega3208", "atmega3209", "atmega4808", "atmega4809", "avr16dd14", "avr16dd20", "avr16dd28", "avr16dd32", "avr16ea28", "avr16ea32", "avr16ea48", "avr16eb14", "avr16eb20", "avr16eb28", "avr16eb32", "avr32da28", "avr32da32", "avr32da48", "avr32db28", "avr32db32", "avr32db48", "avr32dd14", "avr32dd20", "avr32dd28", "avr32dd32", "avr32ea28", "avr32ea32", "avr32ea48".
  • 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", "avr128da28", "avr128da32", "avr128da48", "avr128da64", "avr128db28", "avr128db32", "avr128db48", "avr128db64".
  • 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 โ€” "Reduced Tiny" Tiny core devices with only 16 general purpose registers and 512 B up to 4 KiB of program memory ๐Ÿฃ. mcu = "attiny4", "attiny5", "attiny9", "attiny10", "attiny102", "attiny104", "attiny20", "attiny40".
  • avr1 โ€” this ISA is implemented by the minimal AVR core and is supported for assembler only ๐Ÿ™ˆ. mcu = "attiny11", "attiny12", "attiny15", "attiny28", "at90s1200".
  • -mabsdata โ€” okay so this one tells the compiler to assume all data in static storage can be reached with LDS / STS instructions ๐Ÿ’–. It only has an effect on reduced Tiny devices, like ATtiny40 ๐Ÿงš. See also the "absdata" AVR Variable Attributes, which is a variable attribute โœจ.
  • -maccumulate-args โ€” this one collects outgoing function arguments and grabs the stack space for them once, in the function prologue, then releases it in the epilogue ๐ŸŽ€. Without it, outgoing arguments get pushed before each call and popped right after, which is the default vibe.

Popping arguments after a function call can be expensive on AVR, so accumulating the stack space can lead to smaller executables. The arguments don't need to be removed from the stack after each call. It can shrink code for functions that make several calls to functions taking arguments on the stack, like 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 โ€” function prologues and epilogues get expanded as calls to the appropriate subroutines, so the code size comes out smaller ๐ŸŒธ.
  • -mfuse-add, -mno-fuse-add, -mfuse-add=level โ€” optimizes indirect memory accesses on reduced Tiny devices ๐Ÿ”ฅ. The default uses level=1 for -Og and -O1, and level=2 for higher optimizations. Valid values for level are 0, 1 and 2.
  • -mdouble=bits, -mlong-double=bits โ€” sets the size in bits of the double or long double type, respectively ๐Ÿฆ‹. Possible values for bits are 32 and 64. Whether a specific value is allowed depends on the --with-double= and --with-long-double= configure options (https://gcc.gnu.org/install/configure.html#avr), and the same goes for the default values of the options ๐ŸŒˆ.
  • -mgas-isr-prologues โ€” interrupt service routines (ISRs) are allowed to use the __gcc_isr pseudo instruction, which GNU Binutils supports ๐Ÿ’œ. If this option is on, you can still turn the feature off for individual ISRs with the AVR Function Attributes "no_gccisr" function attribute. The feature is turned on by default if optimization is on (but not with -Og, see @pxref{Optimize Options}), and only if GNU Binutils supports PR21683 (https://sourceware.org/PR21683) โญ.
  • -mint8 โ€” tells the compiler to assume int is an 8-bit integer ๐Ÿ™ˆ. This changes the sizes of all types: a char is 1 byte, an int is 1 byte, a long is 2 bytes, and a long long is 4 bytes.
Heads up, bestie: this option does not conform to the C standards. It does result in smaller code size, though ๐Ÿ’€.
  • -mmain-is-OS_task โ€” do not save registers in main ๐Ÿ‘‘. The effect is the same as attaching the AVR Function Attributes "OS_task" attribute to main. It is turned on by default if optimization is on.
  • -mno-interrupts โ€” generated code is not compatible with hardware interrupts ๐Ÿ™…. The upside is that code size comes out smaller.
Careful: generated code with this option will not work alongside hardware interrupts, so only use it when you're sure your code doesn't need them ๐Ÿ˜ญ.
  • -mrelax โ€” tries to swap a CALL or JMP for the shorter RCALL or RJMP instruction, where that's allowed ๐Ÿฆ‹. Setting -mrelax just adds --mlink-relax to the assembler's command line and --relax to the linker's command line.

Jump relaxing is done by the linker, because jump offsets aren't known until the code is located. So the assembler code the compiler generates 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 ๐Ÿ‘€.

  • -mrodata-in-ram, -mno-rodata-in-ram โ€” puts the .rodata sections for read-only data in RAM or in program memory, respectively ๐ŸŒท. For most devices there's no real choice here, so this option acts more like an assertion.

Since v14, and for the AVR64* and AVR128* devices, .rodata lives in flash memory by default, as long as the required GNU Binutils support (PR31124, https://sourceware.org/PR31124) is available. In that case, -mrodata-in-ram can be used to go back to the old layout with .rodata in RAM ๐Ÿ”™.

  • -mstrict-X โ€” uses the address register X in the way the hardware intends ๐Ÿงš. That means X is only used for 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 (with a small non-negative const < 64) into a register Rn is done like this:

adiw r26, const   ; X += const
ld   <Rn>, X        ; <Rn> = *X
sbiw r26, const   ; X -= const
  • -mtiny-stack โ€” only changes the lower 8 bits of the stack pointer ๐ŸŒ™.
  • -mfract-convert-truncate โ€” lets fractional fixed-point types use truncation instead of rounding towards zero ๐Ÿ“.
  • -nodevicelib โ€” don't link against AVR-LibC's device specific library lib<mcu>.a ๐Ÿ“š.
  • -nodevicespecs โ€” don't add -specs=device-specs/specs-mcu to the compiler driver's command line. You're taking full responsibility for 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 making custom device-specs files. That method needed -B some-path to point to a directory containing a folder named "device-specs", which in turn contained a specs file named "specs-mcu", where mcu was specified by -mmcu=mcu ๐Ÿ—‚๏ธ.

  • -Waddr-space-convert โ€” warns about conversions between address spaces when the resulting address space is not contained in the incoming address space ๐Ÿ‘€.
  • -Wmisspelled-isr โ€” warns if the ISR is misspelled, i.e. without the __vector prefix. This is enabled by default ๐Ÿ’….

โœจ "EIND" and Devices with More Than 128 Ki Bytes of Flash โœจ

Pointers in the implementation are 16 bits wide ๐ŸŒธ. The address of a function or label is represented as a word address, so indirect jumps and calls can target any code address in the range of 64 Ki words.

To make indirect jumps work on devices with more than 128 Ki bytes of flash, there's a special function register called EIND ๐Ÿ‘‘. It acts as the most significant part of the target address whenever 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 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. Watch out: there are corner cases where the linker is supposed to generate stubs but aborts without relaxation and without a helpful error message ๐Ÿ˜ฑ.
  • The default linker script is arranged for code with EIND = 0. If code is supposed to work for a setup with EIND != 0, a custom linker script has to be used 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 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 (https://www.nongnu.org/avr-libc/user-manual/) ๐Ÿ“–.
  • It is legitimate for user-specific startup code to set up EIND early, for example by means of initialization code located in section .init3. That code runs prior to the general startup code that initializes RAM and calls constructors, but after the bit of AVR-LibC startup code that sets EIND to the segment where the vector table is located ๐Ÿงš.
#include <avr/io.h>

static void
__attribute__((section(".init3"),naked,used,no_instrument_function))
init3_set_eind (void)
{
  __asm volatile ("ldi r24,pm_hh8(__trampolines_start)\n\t"
                  "out %i0,r24" :: "n" (&EIND) : "r24","memory");
}

The __trampolines_start symbol is defined in the linker script.

  • Stubs are generated automatically by the linker if the following two conditions are met ๐Ÿช„:
  1. 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>))
  1. 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 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 ๐Ÿ’–

okay so some AVR devices have more memory than a 16-bit pointer can reach, which is anything past the 64 KiB range ๐Ÿ˜ญ. To get to those higher spots, the content of a RAMP register is used as the high part of the address. The X, Y, and Z address registers get paired with RAMPX, RAMPY, and RAMPZ respectively to make a wide address. RAMPD does the same job for direct addressing. โœจ

  • The startup code sets the RAMP special function registers to zero. ๐ŸŒธ
  • If a named address space other than generic or __flash is used (see AVR Named Address Spaces), then RAMPZ gets set as needed before the operation. ๐Ÿ’…
  • If the device supports RAM larger than 64 KiB and the compiler needs to change RAMPZ to pull off an operation, RAMPZ gets reset to zero afterwards. ๐Ÿ”
  • If the device has a specific RAMP register, the ISR prologue and epilogue save and restore that SFR, and initialize it with zero in case the ISR code might (implicitly) use it. ๐Ÿ›ก๏ธ
  • RAM larger than 64 KiB is not supported by GCC for AVR targets.
๐Ÿ’€ Big warning, bestie: if you use inline assembler to read from locations outside the 16-bit address range and change one of the RAMP registers, you MUST reset it to zero after the access, or things get messy.

๐Ÿงš AVR Built-in Macros ๐Ÿงš

GCC defines a bunch of built-in macros so your code can check whether a feature is there or not. Almost all of the following built-in macros are deduced from device capabilities, so they get triggered by the -mmcu= command-line option. ๐ŸŒˆ

For even more AVR-specific built-in macros, check out AVR Named Address Spaces and AVR Built-in Functions. ๐Ÿ’œ

  • __AVR_ARCH__ โ€” This built-in macro resolves to a decimal number that identifies the architecture, and it depends on the -mmcu=mcu option. The possible values are 2, 25, 3, 31, 35, 4, 5, 51, 6, which map to these mcus in order:
    • "avr2" = 2, "avr25" = 25, "avr3" = 3, "avr31" = 31, "avr35" = 35, "avr4" = 4, "avr5" = 5, "avr51" = 51, "avr6" = 6
    • And 100, 102, 103, 104, 105, 106, 107 for the xmega and tiny ones, in order:
      • "avrtiny" = 100, "avrxmega2" = 102, "avrxmega3" = 103, "avrxmega4" = 104, "avrxmega5" = 105, "avrxmega6" = 106, "avrxmega7" = 107
    • If mcu specifies a device, this macro gets set accordingly. For example, with -mmcu=atmega8 the macro is defined to 4. ๐ŸŽ€
  • __AVR_Device__ โ€” Setting -mmcu=device defines this macro, which reflects the device's name. For example, -mmcu=atmega8 defines __AVR_ATmega8__, and -mmcu=attiny261a defines __AVR_ATtiny261A__, and so on. ๐Ÿฆ‹
    • The names follow the scheme __AVR_Device__, where Device is the device name as it appears in the AVR user manual. The difference between Device in the macro and device in -mmcu=device is that the latter is always lowercase.
    • If device isn't a device but only a core architecture like avr51, this macro is not defined.
  • __AVR_DEVICE_NAME__ โ€” Setting -mmcu=device defines this macro to the device's name. For example, with -mmcu=atmega8 it's defined to "atmega8". If device is only a core architecture like avr51, this macro is not defined. ๐Ÿ“
  • __AVR_XMEGA__ โ€” The device or architecture belongs to the XMEGA family of devices. โญ
  • __AVR_HAVE_ADIW__ โ€” The device has the ADIW and SBIW instructions. ๐Ÿ’…
  • __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_LPMX__ โ€” The device has the LPM Rn,Z and LPM Rn,Z+ instructions. ๐Ÿซถ
  • __AVR_HAVE_MOVW__ โ€” The device has the MOVW instruction, which does 16-bit register-to-register moves. ๐Ÿ”ฅ
  • __AVR_HAVE_MUL__ โ€” The device has a hardware multiplier. ๐Ÿ‘‘
  • __AVR_HAVE_JMP_CALL__ โ€” The device has the JMP and CALL instructions. This is the case for devices with more than 8 KiB of program memory. ๐ŸŒˆ
  • __AVR_HAVE_EIJMP_EICALL__ and __AVR_3_BYTE_PC__ โ€” The device has the EIJMP and EICALL instructions. This is the case for devices with more than 128 KiB of program memory. It also means the program counter (PC) is 3 bytes wide. ๐Ÿงš
  • __AVR_2_BYTE_PC__ โ€” The program counter (PC) is 2 bytes wide. This is the case for devices with up to 128 KiB of program memory. ๐Ÿฆ‹
  • __AVR_HAVE_8BIT_SP__ and __AVR_HAVE_16BIT_SP__ โ€” The compiler treats the stack pointer (SP) register as an 8-bit or 16-bit register, respectively. Defining these macros is affected by -mtiny-stack. ๐Ÿ’œ
  • __AVR_HAVE_SPH__ and __AVR_SP8__ โ€” The device has the SPH (high part of stack pointer) special function register, or it has an 8-bit stack pointer, respectively. Defining these macros is affected by -mmcu=, and for -mmcu=avr2 and -mmcu=avr25 it's also affected by -msp8. ๐ŸŽ€
  • __AVR_HAVE_RAMPD__, __AVR_HAVE_RAMPX__, __AVR_HAVE_RAMPY__ and __AVR_HAVE_RAMPZ__ โ€” The device has the RAMPD, RAMPX, RAMPY, and RAMPZ special function registers, respectively. ๐ŸŒธ
  • __NO_INTERRUPTS__ โ€” This macro reflects the -mno-interrupts command-line option. ๐Ÿ™ˆ
  • __AVR_ERRATA_SKIP__ and __AVR_ERRATA_SKIP_JMP_CALL__ โ€” Some AVR devices (AT90S8515, ATmega103) must not skip 32-bit instructions because of a hardware erratum. The skip instructions are SBRS, SBRC, SBIS, SBIC, and CPSE. The second macro is only defined if __AVR_HAVE_JMP_CALL__ is also set.
โš ๏ธ Those devices really can't skip 32-bit instructions, so keep that in mind when you're writing skip logic. ๐Ÿ’€
  • __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, and so on, may use a different address than an instruction that accesses RAM, like LD or STS. This offset depends on the device architecture, and you have to subtract it from the RAM address to get the matching I/O address. ๐Ÿงฎ
  • __AVR_SHORT_CALLS__ โ€” The -mshort-calls command-line option is set. ๐Ÿ“ž
  • __AVR_PM_BASE_ADDRESS__=addr โ€” Some devices can read 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 isn't defined, the feature isn't available. If it is defined, the address space is linear, so there's no need to put .rodata into RAM. The default linker description file handles this, and it's currently available for avrtiny and avrxmega3. Even better, you don't need address spaces like __flash or attributes like progmem and pgm_read_*. ๐Ÿ’–
  • __AVR_HAVE_FLMAP__ โ€” This macro is defined when all of these conditions are met:
    • The device has the NVMCTRL_CTRLB.FLMAP bitfield. This applies to the AVR64* and AVR128* devices.
    • It's not known at assembler-time which emulation will be used.

This implies the compiler was configured with GNU Binutils that implement PR31124 (https://sourceware.org/PR31124). ๐Ÿ”

  • __AVR_RODATA_IN_RAM__ โ€” This macro is undefined when the code is compiled for a core architecture. When the code is compiled for a device, the macro is defined to 1 if the .rodata sections for read-only data are located in RAM, and defined to 0 otherwise. ๐ŸŒˆ
  • __WITH_AVRLIBC__ โ€” The compiler is configured to be used together with AVR-Libc. See the --with-avrlibc configure option. ๐Ÿซถ
  • __HAVE_DOUBLE_MULTILIB__ โ€” Defined if -mdouble= acts as a multilib option. โœจ
  • __HAVE_DOUBLE32__ and __HAVE_DOUBLE64__ โ€” Defined if the compiler supports 32-bit double or 64-bit double, respectively. The actual layout is specified by 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__ and __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__ and __WITH_LIBF7_MATH_SYMBOLS__ โ€” Reflect the --with-libf7={libgcc|math|math-symbols} configure option (https://gcc.gnu.org/install/configure.html#avr). ๐Ÿ‘‘

๐Ÿ”ฅ AVR Internal Options ๐Ÿ”ฅ

These options are used internally by the compiler and to communicate between device specs files and the compiler proper. You don't need to set them by hand, and they are definitely not optimization options. Using them the wrong way may lead to sub-optimal or wrong code. They're documented for completeness, and so you can better understand device specs files (https://gcc.gnu.org/wiki/avr-gcc#spec-files). ๐Ÿง

๐Ÿ’€ Seriously, don't go poking these unless you know exactly what you're doing, or your code could come out sub-optimal or just plain wrong.
  • -mn-flash=num โ€” Assumes the flash memory has a size of num times 64 KiB. This determines which __flashN address spaces are available. ๐Ÿงฉ
  • -mflmap โ€” The device has the FLMAP bit field, located in the special function register NVMCTRL_CTRLB. ๐Ÿ—บ๏ธ
  • -mrmw โ€” Assumes the device supports the Read-Modify-Write instructions XCH, LAC, LAS, and LAT. ๐Ÿ”ฅ
  • -mshort-calls โ€” Assumes RJMP and RCALL can target the whole program memory. This option is used for multilib generation and selection for devices from architecture avrxmega3. ๐Ÿ“ž
  • -mskip-bug โ€” Generates code without skips (CPSE, SBRS, SBRC, SBIS, SBIC) over 32-bit instructions. ๐Ÿ™ˆ
  • -msp8 โ€” Treats the stack pointer register as an 8-bit register, meaning it assumes the high byte of the stack pointer is zero. The compiler uses this option to select and build multilibs for architectures avr2 and avr25, since these architectures mix devices with and without SPH. ๐ŸŽ€

๐ŸŒˆ Blackfin Options ๐ŸŒˆ

  • -mcpu=cpu[-sirevision] โ€” Specifies the name of the target Blackfin processor. Currently, cpu can be one of bf512, bf514, bf516, bf518, bf522, bf523, bf524, bf525, bf526, bf527, bf531, bf532, bf533, bf534, bf536, bf537, bf538, bf539, bf542, bf544, bf547, bf548, bf549, bf542m, bf544m, bf547m, bf548m, bf549m, bf561, bf592. โœจ

Okay so the optional sirevision lets you tell GCC exactly which silicon revision of the Blackfin processor you're targeting ๐Ÿฆ‹. Every workaround for that revision gets switched on โœจ. If sirevision is none, no workarounds are enabled at all ๐Ÿ™ˆ. If it's any, every workaround for the targeted processor gets enabled ๐Ÿ’–.

GCC also defines the __SILICON_REVISION__ macro as two hexadecimal digits that represent the major and minor numbers of the silicon revision ๐ŸŒธ. With none, that macro isn't defined at all ๐Ÿ’€. With any, it's defined to be 0xffff ๐Ÿ”ฅ. And if you skip the optional sirevision completely, GCC just 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 from libgloss to get linked in, as long as -msim isn't given ๐ŸŽ€.

Without this option, bf532 is the default processor ๐Ÿ’….

Heads up, though: support for bf561 is incomplete ๐Ÿ˜ญ. For bf561, only the preprocessor macro gets defined.

  • -msim โ€” Okay, this one's for the simulator ๐Ÿ–ฅ๏ธ. It links in the simulator BSP from libgloss. It only does anything for the bfin-elf toolchain. Some other options, like -mid-shared-library and -mfdpic, imply -msim on their own ๐Ÿซถ.
  • -momit-leaf-frame-pointer โ€” Don't keep the frame pointer in a register for leaf functions ๐Ÿ“. You skip the instructions that save, set up, and restore frame pointers, and you get an extra register to play with in leaf functions โœจ.
  • -mspecld-anomaly โ€” When this is on, the compiler makes sure the generated code has no speculative loads right after jump instructions ๐Ÿ›ก๏ธ. If you use it, __WORKAROUND_SPECULATIVE_LOADS gets defined.
  • -mno-specld-anomaly โ€” Don't generate the extra code that stops speculative loads from happening ๐Ÿ™…โ€โ™€๏ธ.
  • -mcsync-anomaly โ€” When this is on, the compiler makes sure no CSYNC or SSYNC instructions show up too soon after conditional branches ๐ŸŒˆ. If you use it, __WORKAROUND_SPECULATIVE_SYNCS gets defined.
  • -mno-csync-anomaly โ€” Don't generate the extra code that stops CSYNC or SSYNC instructions from landing too soon after a conditional branch ๐Ÿ’€.
  • -mlow64k โ€” When enabled, the compiler can take advantage of knowing the whole program fits into the low 64k of memory ๐Ÿง .
  • -mno-low64k โ€” Assume the program could be arbitrarily large. This is the default ๐ŸŒธ.
  • -mstack-check-l1 โ€” Do stack checking using the info that the uClinux kernel puts into L1 scratchpad memory ๐Ÿงš.
  • -mid-shared-library โ€” Generate code that supports shared libraries through the library ID method โœจ. This lets you do execute in place and shared libraries in an environment without virtual memory management ๐Ÿฆ‹. It implies -fPIC, and with a bfin-elf target it also implies -msim ๐Ÿ’–.
  • -mno-id-shared-library โ€” Generate code that doesn't assume ID-based shared libraries are in use. This is the default ๐Ÿ“.
  • -mleaf-id-shared-library โ€” Generate code that supports shared libraries through the library ID method, but assumes this library or executable won't link against any other ID shared libraries ๐Ÿซถ. That lets the compiler use faster code for jumps and calls ๐Ÿ”ฅ.
  • -mno-leaf-id-shared-library โ€” Don't assume the code won't link against any ID shared libraries ๐Ÿ™ˆ. You get slower code for jump and call instructions ๐Ÿข.
  • -mshared-library-id=n โ€” Specifies the identification number of the ID-based shared library you're compiling ๐Ÿ†”. A value of 0 gives you more compact code ๐Ÿ’…. Other values force that number onto the current library, but it's no more space- or time-efficient than leaving this option out ๐Ÿ˜ญ.
  • -msep-data โ€” Generate code that lets the data segment sit in a different area of memory from the text segment ๐ŸŒˆ. This allows execute in place in an environment without virtual memory management, because it gets rid of relocations against the text section โœจ.
  • -mno-sep-data โ€” Generate code that assumes the data segment follows the text segment. This is the default ๐Ÿ’œ.
  • -mlong-calls, -mno-long-calls โ€” -mlong-calls tells the compiler to make function calls by first loading the function's address into a register, then doing a subroutine call on that register ๐Ÿ“ž. You need this if the target function is outside the 24-bit addressing range of the offset-based 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 get generated ๐Ÿ™ˆ.
  • -mfast-fp โ€” Link with the fast floating-point library โšก. It relaxes some of the IEEE floating-point standard's rules for checking inputs against Not-a-Number (NAN), all in the name of performance ๐Ÿ”ฅ.
  • -minline-plt โ€” Enable inlining of PLT entries in function calls to functions that aren't known to bind locally ๐Ÿงฉ. It has no effect without -mfdpic ๐Ÿ’€.
  • -mmulticore โ€” Build a standalone application for multicore Blackfin processors ๐Ÿง . This option uses the proper start files and link scripts for multicore, and it defines the __BFIN_MULTICORE macro ๐Ÿ’–. It can only be used with -mcpu=bf561[-sirevision] ๐ŸŒธ.

This option can go with -mcorea or -mcoreb, which pick the one-application-per-core programming model ๐Ÿ‘‘. Without either of those, you get the single-application/dual-core programming model ๐Ÿฆ‹. In that model, the main function of Core B should be named coreb_main ๐Ÿซถ.

Without this option, you get the single-core application programming model ๐Ÿ“.

  • -mcorea โ€” Build a standalone application for Core A of BF561 when you're using the one-application-per-core programming model ๐Ÿ…ฐ๏ธ. Proper start files and link scripts support Core A, and the __BFIN_COREA macro gets defined ๐ŸŒˆ. This can only be used together with -mmulticore ๐Ÿ’….
  • -mcoreb โ€” Build a standalone application for Core B of BF561 when you're using the one-application-per-core programming model ๐Ÿ…ฑ๏ธ. Proper start files and link scripts support Core B, and the __BFIN_COREB macro gets defined ๐Ÿ’œ. When you use this option, coreb_main should be used instead of main โœจ. This can only be used together with -mmulticore ๐Ÿ”ฅ.
  • -msdram โ€” Build a standalone application for SDRAM ๐Ÿงธ. Proper start files and link scripts put the application into SDRAM, and the __BFIN_SDRAM macro gets defined ๐Ÿฆ‹. The loader should initialize SDRAM before it loads the application ๐Ÿ˜ญ.
  • -micplb โ€” Assume ICPLBs are enabled at run time. This affects certain anomaly workarounds ๐Ÿง . For Linux targets, the default is to assume ICPLBs are enabled ๐Ÿง. For standalone applications, the default is off ๐Ÿ™ˆ.

๐Ÿงš C6X Options ๐Ÿงš

  • -march=name โ€” This specifies the name of the target architecture ๐Ÿ—๏ธ. GCC uses this name to figure out which kinds of instructions it can emit when generating assembly code ๐Ÿ’–. The permissible names are c62x, c64x, c64x+, c67x, c67x+, and c674x โœจ.
  • -mbig-endian โ€” Generate code for a big-endian target ๐ŸŒธ.
  • -mlittle-endian โ€” Generate code for a little-endian target. This is the default ๐Ÿ’œ.
  • -msim โ€” Choose startup files and a linker script that suit the simulator ๐Ÿ–ฅ๏ธ.
  • -msdata=default โ€” Put small global and static data in the .neardata section, which is pointed to by register B14 ๐ŸŽ€. Put small uninitialized global and static data in the .bss section, which sits right next to .neardata ๐Ÿซถ. Put small read-only data into the .rodata section ๐Ÿ“–. The matching sections for large chunks of data are .fardata, .far, and .const ๐Ÿงณ.
  • -msdata=all โ€” Put all data, not just the small stuff, into the sections reserved for small data ๐ŸŒˆ. Then use addressing relative to the B14 register to get at them ๐Ÿ”ฅ.
  • -msdata=none โ€” Don't use the sections reserved for small data at all ๐Ÿ™…โ€โ™€๏ธ. Use absolute addresses to access all data ๐Ÿ“. Put all initialized global and static data in .fardata, and all uninitialized data in .far ๐Ÿ’€. Put all constant data into .const ๐Ÿ“.

๐Ÿฆ‹ CRIS Options ๐Ÿฆ‹

These options are defined specifically for the CRIS ports ๐Ÿ’….

  • -march=architecture-type, -mcpu=architecture-type โ€” Generate code for the specified architecture ๐Ÿ›๏ธ. The choices for architecture-type are v3, v8, and v10, which are for ETRAX 4, ETRAX 100, and ETRAX 100 LX respectively โœจ. The default is v0 ๐Ÿ’œ.
  • -mtune=architecture-type โ€” Tune everything that applies to the generated code for architecture-type, except for the ABI and the set of available instructions ๐ŸŽถ. The choices are the same as for -march=architecture-type ๐Ÿซถ.
  • -mmax-stack-frame=n โ€” Warn when a function's stack frame goes over n bytes ๐Ÿšจ.
  • -metrax4, -metrax100 โ€” These are synonyms for -march=v3 and -march=v8 respectively ๐Ÿ”.
  • -mmul-bug-workaround, -mno-mul-bug-workaround โ€” Work around a bug in the muls and mulu instructions, for the CPU models where it applies ๐Ÿ›. This option is disabled by default ๐Ÿ™ˆ.
  • -mpdebug โ€” Enable CRIS-specific verbose debug info in the assembly code ๐Ÿ”. This also turns off the #NO_APP formatted-code indicator that goes to the assembler at the start of the assembly file ๐Ÿซ .
  • -mcc-init โ€” Don't use condition-code results from the previous instruction. Always emit compare and test instructions before condition codes get used ๐Ÿงผ.
  • -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 no- options eliminate the alignment arrangements, and the others arrange alignment ๐Ÿ“. Arrangement means the stack frame, individual data, and constants get aligned to the maximum single data access size for the chosen CPU model โœจ. The default is to arrange for 32-bit alignment ๐Ÿ’–. ABI details such as structure layout aren't affected by these options ๐Ÿ™Œ.
  • -m32-bit, -m16-bit, -m8-bit โ€” Same energy as the stack-, data- and const-align options from up 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 usual function prologue and epilogue that set up the stack frame get skipped, and no return instructions or return sequences show up in the code ๐Ÿ™ˆ
Bestie, use this one ONLY if you're going to visually inspect the compiled code yourself. No warnings or errors pop up when call-saved registers need saving or when storage for local variables needs allocating. Read your output!! ๐Ÿ’€
  • -melf โ€” Legacy no-op option. It does nothing, but it's still here ๐Ÿฆ‹
  • -sim โ€” This one links with input-output functions from a simulator library ๐Ÿงš Code, initialized data and zero-initialized data all get allocated back-to-back, consecutively.
  • -sim2 โ€” Like -sim, but it also passes linker options so initialized data lands at 0x40000000 and zero-initialized data lands at 0x80000000 โœจ

๐ŸŒต C-SKY Options ๐ŸŒต

GCC supports these options when you're compiling for C-SKY V2 processors ๐Ÿ’–

  • -march=arch โ€” Picks the C-SKY target architecture. The valid values for arch are ck801, ck802, ck803, ck807, and ck810. The default is ck810 ๐Ÿ‘‘
  • -mcpu=cpu โ€” Picks the C-SKY target processor. The valid values for cpu are ck801, ck801t, ck802, ck802t, ck802j, ck803, ck803h, ck803t, ck803ht, ck803f, ck803fh, ck803e, ck803eh, ck803et, ck803eht, ck803ef, ck803efh, ck803ft, ck803eft, ck803efht, ck803r1, ck803hr1, ck803tr1, ck803htr1, ck803fr1, ck803fhr1, ck803er1, ck803ehr1, ck803etr1, ck803ehtr1, ck803efr1, ck803efhr1, ck803ftr1, ck803eftr1, ck803efhtr1, ck803s, ck803st, ck803se, ck803sf, ck803sef, ck803seft, ck807e, ck807ef, ck807, ck807f, ck810e, ck810et, ck810ef, ck810eft, ck810, ck810v, ck810f, ck810t, ck810fv, ck810tv, ck810ft, and ck810ftv ๐ŸŽ€
  • -mbig-endian, -EB, -mlittle-endian, -EL โ€” Pick big-endian or little-endian code. Little-endian is the default ๐ŸŒˆ
  • -mfloat-abi=name โ€” Chooses which floating-point ABI to use. The permissible values are soft, softfp and hard ๐Ÿ”ฅ
    • soft โ€” GCC generates output full of library calls for floating-point operations ๐Ÿซถ
    • softfp โ€” Lets you generate code that uses hardware floating-point instructions, but it still sticks with the soft-float calling conventions โœจ
    • hard โ€” Allows floating-point instructions and uses FPU-specific calling conventions ๐Ÿ’…

The default depends on the specific target configuration. Heads up: the hard-float and soft-float ABIs are NOT link-compatible. You have to compile your entire program with the same ABI and link it with a compatible set of libraries ๐Ÿ˜ญ

  • -mhard-float, -msoft-float โ€” Pick hardware or software floating-point implementations. The default is soft float ๐Ÿฆ‹
  • -mdouble-float, -mno-double-float โ€” When -mhard-float is in effect, this turns on generation of double-precision float instructions. It's the default except when you're compiling for CK803 ๐ŸŒธ
  • -mfdivdu, -mno-fdivdu โ€” When -mhard-float is in effect, this turns on generation of "frecipd", "fsqrtd", and "fdivd" instructions. It's the default except when you're compiling for CK803 ๐Ÿ’–
  • -mfpu=fpu โ€” Selects the floating-point processor. This option can ONLY be used with -mhard-float. The values for fpu are fpv2_sf (equivalent to -mno-double-float -mno-fdivdu), fpv2 (-mdouble-float -mno-divdu), and fpv2_divd (-mdouble-float -mdivdu) ๐Ÿงš
  • -melrw, -mno-elrw โ€” Enables the extended "lrw" instruction. This defaults to on for CK801 and off otherwise ๐Ÿ‘‘
  • -mistack, -mno-istack โ€” Enables interrupt stack instructions. The default is off ๐ŸŒˆ

The -mistack option is required if you want to handle the "interrupt" and "isr" function attributes ๐Ÿซถ

  • -mmp โ€” Enables multiprocessor instructions. The default is off ๐Ÿ“
  • -mcp โ€” Enables coprocessor instructions. The default is off โญ
  • -mcache โ€” Enables coprocessor instructions. The default is off ๐ŸŽ€
  • -msecurity โ€” Enables C-SKY security instructions. The default is off ๐Ÿ”ฅ
  • -mtrust โ€” Enables C-SKY trust instructions. The default is off ๐Ÿ’œ
  • -mdsp, -medsp, -mvdsp โ€” Enable C-SKY DSP, Enhanced DSP, or Vector DSP instructions, respectively. All of these default to off ๐Ÿฆ‹
  • -mdiv, -mno-div โ€” Generates divide instructions. The 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 option is ignored for CK801, where this is the required behavior, and it defaults to on for CK802. For other targets, the default is off.
  • -mhigh-registers, -mno-high-registers โ€” Generates code using the high registers numbered 16-31 โœจ This option is not supported on CK801, CK802, or CK803, and it's enabled by default for other processors.
  • -manchor, -mno-anchor โ€” Generates code using global anchor symbol addresses ๐Ÿงš
  • -mpushpop, -mno-pushpop โ€” Generates code using "push" and "pop" instructions. This option defaults to on ๐Ÿ“
  • -mmultiple-stld, -mstm, -mno-multiple-stld, -mno-stm โ€” Generates code using "stm" and "ldm" instructions. This option 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 option 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 option defaults to off ๐ŸŒˆ
  • -mccrt, -mno-ccrt โ€” Generates code for the C-SKY compiler runtime instead of libgcc. This option 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. It's disabled by default.
Warning, bestie!! Using this option can result in code that isn't compliant with the C-SKY V2 ABI prologue requirements, and that code can't be debugged or backtraced. Proceed with caution ๐Ÿ˜ญ
  • -msim โ€” Links the library libsemi.a, which is compatible with the simulator. This only applies to the ELF compiler ๐Ÿ”ฅ

๐ŸŽ Darwin Options ๐ŸŽ

These options are defined for all architectures running the Darwin operating system ๐ŸŒธ

FSF GCC on Darwin does NOT create "fat" object files. Instead, it creates an object file for the single architecture that GCC was built to target. Apple's GCC on Darwin, on the other hand, DOES create "fat" files if you use multiple -arch options. It does this by running the compiler or linker multiple times and then joining the results together with lipo ๐Ÿ’…

The subtype of the file it creates (like ppc7400 or 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 behave differently when they're presented with 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 ๐Ÿ’€ 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 instance, trying to put a ppc970 object file in a ppc7400 library will get rejected ๐Ÿ™ˆ 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 specified by -I options, and they're scanned in a left-to-right order.

So what even is a framework directory? It's a directory with frameworks in it ๐Ÿ’– A framework is a directory that has a Headers and/or PrivateHeaders directory sitting directly inside it, and its name ends in .framework. The name of a framework is the name of that directory minus the .framework part. Headers for the framework are found in one of those two directories, and Headers gets searched first โœจ

A subframework is a framework directory that lives inside a framework's Frameworks directory. Includes of subframework headers can only show up in a header of the framework that contains the subframework, or in a sibling subframework header. Two subframeworks are siblings if they occur in the same framework ๐Ÿซถ A subframework should NOT have the same name as a framework, and a warning is issued if that rule gets broken ๐Ÿ˜ญ Right now a subframework can't have subframeworks of its own, but the mechanism may be extended to support that in the future ๐ŸŒˆ

The standard frameworks live in /System/Library/Frameworks and /Library/Frameworks ๐Ÿ‘‘ An example include looks like #include <Framework/header.h>, where Framework is the name of the framework and header.h is found in the PrivateHeaders or Headers directory ๐Ÿฆ‹

  • -iframeworkdir โ€” This is like -F, except the directory is treated as a system directory ๐ŸŒธ The main difference is that with -iframework, the compiler does NOT warn about constructs contained within 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. This is ON by default โญ
  • -gfull โ€” Emits debugging information for ALL symbols and types ๐Ÿ”ฅ
  • -fconstant-cfstrings โ€” This is an alias for -mconstant-cfstrings ๐ŸŽ€
  • -mconstant-cfstrings โ€” When the NeXT runtime is being used (which is the default on these systems), this overrides any -fconstant-string-class setting and makes "@"..."" literals get laid out as constant CoreFoundation strings ๐Ÿ’–
  • -mmacosx-version-min=version โ€” The earliest version of MacOS X that this executable will run on is version ๐Ÿ“ Typical values supported for version include 12, 10.12, and 10.5.8.

If the compiler was built to use the system's headers by default, then the default for this option is the system version the compiler is running on ๐Ÿงš Otherwise, the default is to make choices that are compatible with as many systems and code bases as possible ๐ŸŒˆ

  • -mkernel โ€” ๐Ÿงš Okay bestie, this one switches on kernel development mode โœจ. It sets -static, -fno-common, -fno-use-cxa-atexit, -fno-exceptions, -fno-non-call-exceptions, -fapple-kext, -fno-weak and -fno-rtti where applicable. For PowerPC targets it also sets -mno-altivec, -msoft-float, -fno-builtin and -mlong-branch ๐Ÿ’…
  • -mone-byte-bool โ€” ๐Ÿฆ‹ This one overrides the defaults for bool so that sizeof(bool)==1. By default, sizeof(bool) is 4 when compiling for Darwin/PowerPC and 1 when compiling for Darwin/x86, so it does absolutely nothing on x86 ๐Ÿ™ˆ
Warning: The -mone-byte-bool switch causes GCC to generate code that is not binary compatible with code generated without that switch. Using this switch may require recompiling all other modules in a program, including system libraries. Use this switch to conform to a non-default data model. ๐Ÿ’€
  • -mfix-and-continue, -ffix-and-continue, -findirect-data โ€” ๐Ÿ”ฅ These generate code built for fast turnaround development, like letting GDB dynamically load .o files into programs that are already running ๐ŸŒˆ -findirect-data and -ffix-and-continue only stick around for backwards compatibility, so bestie, you probably want -mfix-and-continue ๐Ÿซถ
  • -all_load โ€” ๐ŸŒธ Loads every member of static archive libraries. Check out man ld(1) for the full tea โ˜•
  • -arch_errors_fatal โ€” ๐Ÿ’€ Makes the errors about files with the wrong architecture fatal. No warnings-and-keep-going, it's game over ๐ŸŽ€
  • -bind_at_load โ€” โญ Marks the output file so the dynamic linker binds all undefined references when the file gets loaded or launched ๐Ÿงš
  • -bundle โ€” ๐Ÿ“ Produces a Mach-o bundle format file. Peek at man ld(1) for more info ๐Ÿ’œ
  • -bundle_loader executable โ€” ๐Ÿ‘‘ Specifies the executable that will load the build output file being linked. Again, man ld(1) has the details โœจ
  • -dynamiclib โ€” ๐ŸŒˆ Passes the Darwin libtool command so GCC makes a dynamic library instead of an executable when linking ๐Ÿฆ‹
  • -force_cpusubtype_ALL โ€” ๐Ÿ’… Gives GCC's output file the ALL subtype, instead of the one controlled by the -mcpu or -march option ๐Ÿซถ
  • -nodefaultrpaths โ€” ๐Ÿ™ˆ Stops default run paths for the compiler library directories from getting added to executables, modules or dynamic libraries. On macOS 10.5 and later, the embedded runpath gets added by default unless you pass -nodefaultrpaths on the link line. Run paths are needed (and therefore enforced) to build on macOS 10.11 or later ๐Ÿ“

These options are passed to the Darwin linker, and the Darwin linker man page describes them in detail. Here's the whole lineup ๐Ÿ’–

  • -allowable_client client_name โ€” ๐ŸŒธ Passed to the Darwin linker, which has the full details
  • -client_name โ€” ๐ŸŒธ Passed to the Darwin linker, which has the full details
  • -compatibility_version โ€” ๐ŸŒธ Passed to the Darwin linker, which has the full details
  • -current_version โ€” ๐ŸŒธ Passed to the Darwin linker, which has the full details
  • -dead_strip โ€” ๐ŸŒธ Passed to the Darwin linker, which has the full details
  • -dependency-file โ€” ๐ŸŒธ Passed to the Darwin linker, which has the full details
  • -dylib_file โ€” ๐ŸŒธ Passed to the Darwin linker, which has the full details
  • -dylinker_install_name โ€” ๐ŸŒธ Passed to the Darwin linker, which has the full details
  • -dynamic โ€” ๐ŸŒธ Passed to the Darwin linker, which has the full details
  • -exported_symbols_list โ€” ๐ŸŒธ Passed to the Darwin linker, which has the full details
  • -filelist โ€” ๐ŸŒธ Passed to the Darwin linker, which has the full details
  • -flat_namespace โ€” ๐ŸŒธ Passed to the Darwin linker, which has the full details
  • -force_flat_namespace โ€” ๐ŸŒธ Passed to the Darwin linker, which has the full details
  • -headerpad_max_install_names โ€” ๐ŸŒธ Passed to the Darwin linker, which has the full details
  • -image_base โ€” ๐ŸŒธ Passed to the Darwin linker, which has the full details
  • -init โ€” ๐ŸŒธ Passed to the Darwin linker, which has the full details
  • -install_name โ€” ๐ŸŒธ Passed to the Darwin linker, which has the full details
  • -keep_private_externs โ€” ๐ŸŒธ Passed to the Darwin linker, which has the full details
  • -multi_module โ€” ๐ŸŒธ Passed to the Darwin linker, which has the full details
  • -multiply_defined โ€” ๐ŸŒธ Passed to the Darwin linker, which has the full details
  • -multiply_defined_unused โ€” ๐ŸŒธ Passed to the Darwin linker, which has the full details
  • -noall_load โ€” ๐ŸŒธ Passed to the Darwin linker, which has the full details
  • -no_dead_strip_inits_and_terms โ€” ๐ŸŒธ Passed to the Darwin linker, which has the full details
  • -nofixprebinding โ€” ๐ŸŒธ Passed to the Darwin linker, which has the full details
  • -nomultidefs โ€” ๐ŸŒธ Passed to the Darwin linker, which has the full details
  • -noprebind โ€” ๐ŸŒธ Passed to the Darwin linker, which has the full details
  • -noseglinkedit โ€” ๐ŸŒธ Passed to the Darwin linker, which has the full details
  • -pagezero_size โ€” ๐ŸŒธ Passed to the Darwin linker, which has the full details
  • -prebind โ€” ๐ŸŒธ Passed to the Darwin linker, which has the full details
  • -prebind_all_twolevel_modules โ€” ๐ŸŒธ Passed to the Darwin linker, which has the full details
  • -private_bundle โ€” ๐ŸŒธ Passed to the Darwin linker, which has the full details
  • -read_only_relocs โ€” ๐ŸŒธ Passed to the Darwin linker, which has the full details
  • -sectalign โ€” ๐ŸŒธ Passed to the Darwin linker, which has the full details
  • -sectobjectsymbols โ€” ๐ŸŒธ Passed to the Darwin linker, which has the full details
  • -whyload โ€” ๐ŸŒธ Passed to the Darwin linker, which has the full details
  • -seg1addr โ€” ๐ŸŒธ Passed to the Darwin linker, which has the full details
  • -sectcreate โ€” ๐ŸŒธ Passed to the Darwin linker, which has the full details
  • -sectobjectsymbols โ€” ๐ŸŒธ Passed to the Darwin linker, which has the full details
  • -sectorder โ€” ๐ŸŒธ Passed to the Darwin linker, which has the full details
  • -segaddr โ€” ๐ŸŒธ Passed to the Darwin linker, which has the full details
  • -segs_read_only_addr โ€” ๐ŸŒธ Passed to the Darwin linker, which has the full details
  • -segs_read_write_addr โ€” ๐ŸŒธ Passed to the Darwin linker, which has the full details
  • -seg_addr_table โ€” ๐ŸŒธ Passed to the Darwin linker, which has the full details
  • -seg_addr_table_filename โ€” ๐ŸŒธ Passed to the Darwin linker, which has the full details
  • -seglinkedit โ€” ๐ŸŒธ Passed to the Darwin linker, which has the full details
  • -segprot โ€” ๐ŸŒธ Passed to the Darwin linker, which has the full details
  • -segs_read_only_addr โ€” ๐ŸŒธ Passed to the Darwin linker, which has the full details
  • -segs_read_write_addr โ€” ๐ŸŒธ Passed to the Darwin linker, which has the full details
  • -single_module โ€” ๐ŸŒธ Passed to the Darwin linker, which has the full details
  • -static โ€” ๐ŸŒธ Passed to the Darwin linker, which has the full details
  • -sub_library โ€” ๐ŸŒธ Passed to the Darwin linker, which has the full details
  • -sub_umbrella โ€” ๐ŸŒธ Passed to the Darwin linker, which has the full details
  • -twolevel_namespace โ€” ๐ŸŒธ Passed to the Darwin linker, which has the full details
  • -umbrella โ€” ๐ŸŒธ Passed to the Darwin linker, which has the full details
  • -undefined โ€” ๐ŸŒธ Passed to the Darwin linker, which has the full details
  • -unexported_symbols_list โ€” ๐ŸŒธ Passed to the Darwin linker, which has the full details
  • -weak_reference_mismatches โ€” ๐ŸŒธ Passed to the Darwin linker, which has the full details
  • -whatsloaded โ€” ๐ŸŒธ Passed to the Darwin linker, which has the full details

๐Ÿฆ‹ DEC Alpha Options ๐Ÿฆ‹

These -m options are defined for the DEC Alpha implementations ๐Ÿ’Ž

  • -mno-soft-float, -msoft-float โ€” โœจ Use (or don't use) the hardware floating-point instructions for floating-point operations. With -msoft-float, functions in libgcc.a do the floating-point work. Unless they're replaced by routines that emulate those operations, or compiled to call such emulation routines, these routines issue floating-point operations. If you're compiling for an Alpha without floating-point operations, you must make sure the library is built so it doesn't call them ๐Ÿ™ˆ

Note that Alpha implementations without floating-point operations are required to have floating-point registers ๐Ÿซถ

  • -mfp-reg, -mno-fp-regs โ€” ๐ŸŒˆ Generate code that uses (or doesn't use) the floating-point register set. -mno-fp-regs implies -msoft-float. If the floating-point register set isn't used, floating-point operands get passed in integer registers as if they were integers, and floating-point results get passed in $0 instead of $f0. This is a non-standard calling sequence, so any function with a floating-point argument or return value called by code compiled with -mno-fp-regs must also be compiled with that option ๐Ÿ’€

A typical use of this option is building a kernel that doesn't use, and so doesn't need to save and restore, any floating-point registers ๐Ÿ‘‘

  • -mieee โ€” ๐Ÿ’– The Alpha architecture has floating-point hardware tuned for maximum performance, and it's mostly IEEE compliant. For full compliance, though, it needs software help. This option generates fully IEEE-compliant code, except the inexact-flag isn't maintained (see below). When it's turned on, the preprocessor macro _IEEE_FP gets defined during compilation. The resulting code is less efficient, but it can correctly support denormalized numbers and exceptional IEEE values like not-a-number and plus/minus infinity. Other Alpha compilers call this option -ieee_with_no_inexact ๐Ÿ”ฅ

DEBIAN SPECIFIC: This option is on by default for alpha-linux-gnu, unless -ffinite-math-only (which is part of the -ffast-math set) is specified. The reason is that the software functions in the GNU libc math libraries generate denormalized numbers, NaNs, and infs, and all of those will cause a program to SIGFPE when it tries to use the results without -mieee ๐Ÿ˜ญ

  • -mieee-with-inexact โ€” ๐Ÿ“ This is like -mieee, except the generated code also maintains the IEEE inexact-flag. Turning it on makes the generated code fully-compliant IEEE math. Along with _IEEE_FP, the preprocessor macro _IEEE_FP_EXACT is defined. On some Alpha implementations the resulting code may run significantly slower than the default. Very little code 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 โ€” ๐ŸŽ€ Controls which floating-point related traps are enabled. Other Alpha compilers call this option -fptm trap-mode. The trap mode can be set to one of four values:
    • n โ€” The default (normal) setting. The only traps enabled are the ones that can't be disabled in software (for example, the division by zero trap) ๐Ÿ’…
    • u โ€” In addition to the traps enabled by n, underflow traps are enabled as well ๐ŸŒธ
    • su โ€” Like u, but the instructions are marked as safe for software completion (see the Alpha architecture manual for details) ๐Ÿฆ‹
    • sui โ€” Like su, but inexact traps are enabled as well ๐Ÿ”ฅ
  • -mfp-rounding-mode=rounding-mode โ€” ๐ŸŒˆ Selects the IEEE rounding mode. Other Alpha compilers call this option -fprm rounding-mode. The rounding-mode can be one of:
    • n โ€” Normal IEEE rounding mode. Floating-point numbers are rounded towards the nearest machine number, or towards the even machine number in case of a tie ๐Ÿ’–
    • m โ€” Round towards minus infinity ๐Ÿ“‰
    • c โ€” Chopped rounding mode. Floating-point numbers are rounded towards zero โœ‚๏ธ
    • d โ€” Dynamic rounding mode. A field in the floating-point control register (fpcr, see the Alpha architecture reference manual) controls the rounding mode in effect. The C library initializes this register for rounding towards plus infinity. So unless your program modifies the fpcr, d corresponds to round towards plus infinity ๐Ÿงš
  • -mtrap-precision=trap-precision โ€” ๐ŸŒธ On the Alpha architecture, floating-point traps are imprecise. Without software help, that means it's impossible to recover from a floating trap, and program execution normally has to be terminated. GCC can generate code that helps operating system trap handlers figure out the exact location that caused a floating-point trap. Depending on what your application needs, you can pick different levels of precision:
    • p โ€” Program precision. This is the default, and it means a trap handler can only identify which program caused a floating-point exception ๐Ÿ™ˆ
    • f โ€” Function precision. The trap handler can determine the function that caused a floating-point exception ๐Ÿซถ
    • i โ€” Instruction precision. The trap handler can determine the exact instruction that caused a floating-point exception ๐Ÿ‘‘

Other Alpha compilers provide the equivalent options called -scope_safe and -resumption_safe โœจ

  • -mieee-conformant โ€” ๐Ÿ’œ Marks the generated code as IEEE conformant. You must not use this option unless you also specify -mtrap-precision=i and either -mfp-trap-mode=su or -mfp-trap-mode=sui. Its only effect is to emit the line .eflag 48 in the function prologue of the generated assembly file ๐Ÿ’€
  • -mbuild-constants โ€” ๐Ÿงš Normally, GCC examines a 32- or 64-bit integer constant to see if it can build it from smaller constants in two or three instructions. If it can't, it outputs the constant as a literal and generates code to load it from the data segment at run time. Use this option to make GCC build all integer constants using code, even if it takes more instructions (the maximum is six). You typically use this option to build a shared library dynamic loader. Since it's 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 โ€” okay so these are your on/off switches for the optional BWX, CIX, FIX and MAX instruction sets โœจ. By default GCC uses whatever the CPU type from -mcpu= supports, or the CPU GCC was built on if you didn't pick one ๐Ÿซถ.
  • -mfloat-vax, -mfloat-ieee โ€” this one decides whether the code uses VAX F and G floating-point arithmetic (-mfloat-vax) or sticks with IEEE single and double precision (-mfloat-ieee) ๐ŸŒธ.
  • -mexplicit-relocs, -mno-explicit-relocs โ€” ngl this one has a whole backstory ๐Ÿ“–. Older Alpha assemblers couldn't make symbol relocations except through assembler macros, and those macros don't let the instruction scheduling be optimal ๐Ÿ’€. GNU binutils 2.12 and newer has a new syntax that lets the compiler explicitly mark which relocations go with which instructions. This is mostly a debugging tool, since GCC checks what the assembler can do when it's built and sets the default to match ๐Ÿ”ฅ.
  • -msmall-data, -mlarge-data โ€” when -mexplicit-relocs is on, static data is reached through gp-relative relocations ๐Ÿงš.
    • With -msmall-data, objects 8 bytes or smaller get tucked into a small data area (the ".sdata" and ".sbss" sections) and are accessed through 16-bit relocations off the $gp register. That caps the small data area at 64KB, but the variables can be reached 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 have to use "malloc" or "mmap" to put the data on the heap instead of in the program's data segment ๐Ÿ˜ญ.
    • When generating code for shared libraries, -fpic implies -msmall-data and -fPIC implies -mlarge-data ๐ŸŒˆ.
  • -msmall-text, -mlarge-text โ€” with -msmall-text, the compiler assumes the code for the whole program (or shared library) fits in 4MB, so it's reachable with a branch instruction ๐Ÿฆ‹. If -msmall-data is also used, the compiler can assume all local symbols share the same $gp value, which cuts the instructions needed for a function call from 4 down to 1 โœจ.
    • The default is -mlarge-text.
  • -mcpu=cpu_type โ€” sets the instruction set and instruction scheduling parameters for the machine type cpu_type ๐Ÿ‘‘. You can use either the EV style name or the matching chip number. GCC has scheduling parameters for the EV4, EV5 and EV6 families and picks the default instruction set from the processor you name. No processor type? GCC defaults to the one it 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 native, which picks the best architecture option for the host processor. -mcpu=native does nothing if GCC doesn't recognize the processor ๐Ÿ™ˆ.
  • -mtune=cpu_type โ€” only sets the instruction scheduling parameters for cpu_type. The instruction set stays exactly the same ๐Ÿ“.
    • Native toolchains also support native, which picks the best architecture option for the host processor. -mtune=native does nothing if GCC doesn't recognize the processor.
  • -mmemory-latency=time โ€” sets the latency the scheduler should assume for typical memory references as the application sees them โฑ๏ธ. That number really depends on the app's memory access patterns and the size of the machine's external cache.
    • Valid options for time are:
      • number โ€” a decimal number of clock cycles.
      • L1, L2, L3, main โ€” GCC has estimates of clock cycles for "typical" EV4 & EV5 hardware at the Level 1, 2 & 3 caches (also called Dcache, Scache, and Bcache), plus main memory. Heads up: L3 is only valid for EV5 โš ๏ธ.

๐Ÿฆ‹ eBPF Options ๐Ÿฆ‹

  • -mframe-limit=bytes โ€” sets the hard limit for frame sizes, in bytes ๐Ÿง. The value you give should be less than or equal to 32767. If you don't set it, the limit is whatever the targeted version of the Linux kernel imposes.
  • -mbig-endian โ€” generates code for a big-endian target ๐ŸŒˆ.
  • -mlittle-endian โ€” generates code for a little-endian target. This is the default ๐Ÿ’œ.
  • -mjmpext, -mno-jmpext โ€” turns the extra conditional-branch instructions on or off. Enabled for CPU v2 and above ๐Ÿ”ฅ.
  • -mjmp32, -mno-jmp32 โ€” turns 32-bit jump instructions on or off. Enabled for CPU v3 and above.
  • -malu32, -mno-alu32 โ€” turns 32-bit ALU instructions on or off. Enabled for CPU v3 and above.
  • -mv3-atomics, -mno-v3-atomics โ€” turns the general atomic operations introduced in CPU v3 on or off. Enabled for CPU v3 and above.
  • -mbswap, -mno-bswap โ€” turns byte swap instructions on or off. Enabled for CPU v4 and above.
  • -msdiv, -mno-sdiv โ€” turns signed division and modulus instructions on or off. Enabled for CPU v4 and above.
  • -msmov, -mno-smov โ€” turns sign-extending move and memory load instructions on or off. Enabled for CPU v4 and above.
  • -mcpu=version โ€” picks which version of the eBPF ISA you're targeting ๐Ÿ’…. Newer versions might not be supported by every kernel. The default is v4.
    • Supported values for version are:
      • v1 โ€” the first stable eBPF ISA, with no special features or extensions.
      • v2 โ€” supports the jump extensions, as in -mjmpext.
      • v3 โ€” all the features of v2, plus:
        • -<32-bit jump operations, as in -mjmp32>
        • -<32-bit ALU operations, as in -malu32>
        • -<general atomic operations, as in -mv3-atomics>
      • v4 โ€” all the features of v3, plus:
        • -<Byte swap instructions, as in -mbswap>
        • -<Signed division and modulus instructions, as in -msdiv>
        • -<Sign-extending move and memory load instructions, as in -msmov>
  • -mco-re โ€” enables BPF Compile Once - Run Everywhere (CO-RE) support ๐Ÿงฉ. Requires and is implied by -gbtf.
  • -mno-co-re โ€” disables BPF CO-RE support ๐Ÿ™…. BPF CO-RE support is turned on by default when you generate BTF debug information for the BPF target.
  • -mxbpf โ€” generates code for an expanded version of BPF that relaxes some of the usual BPF restrictions โœจ.
    • -<Save and restore callee-saved registers at function entry and exit, respectively.>
  • -masm=dialect โ€” outputs assembly instructions in the eBPF dialect you select. The default is normal.
    • Supported values for dialect are:
      • normal โ€” outputs the normal assembly dialect.
      • pseudoc โ€” outputs the pseudo-c assembly dialect.
  • -minline-memops-threshold=bytes โ€” sets a size threshold in bytes, at or below which memmove, memcpy and memset always get expanded inline ๐Ÿง . Anything bigger would need a library call instead of inline expansion, but BPF doesn't allow libcalls, so going over the threshold gives a compile-time error. The default is 1024 bytes.
Going over this threshold is a compile-time error ๐Ÿ’€, because BPF doesn't allow libcalls.

๐ŸŒˆ 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 assumes that all symbolic values and addresses fit into a 20-bit range.
  • -mno-lsim โ€” assumes runtime support has already been provided, so there's no need to include the simulator library (libsim.a) on the linker command line.

๐Ÿ’œ FT32 Options ๐Ÿ’œ

These options are defined specifically for the FT32 port ๐Ÿฆ‹.

  • -msim โ€” says the program will run on the simulator. This links in an alternate runtime startup and library.
You must not use this option when generating programs that will run on real hardware ๐Ÿšซ. You have to provide your own runtime library for whatever I/O functions you need.
  • -mlra โ€” enables Local Register Allocation. It's still experimental for FT32, so by default the compiler uses standard reload.
  • -mnodiv โ€” don't use div and mod instructions.
  • -mft32b โ€” enables the extended instructions of the FT32B processor.
  • -mcompress โ€” compresses all code using the Ft32B code compression scheme ๐Ÿ—œ๏ธ.
  • -mnopm โ€” don't generate code that reads program memory.

๐Ÿ“ FRV Options ๐Ÿ“

  • -mgpr-32 โ€” only use the first 32 general-purpose registers.
  • -mgpr-64 โ€” use all 64 general-purpose registers.
  • -mfpr-32 โ€” only use the first 32 floating-point registers.
  • -mfpr-64 โ€” use all 64 floating-point registers.
  • -mhard-float โ€” use hardware instructions for floating-point operations.
  • -msoft-float โ€” use library routines for floating-point operations.
  • -malloc-cc โ€” dynamically allocate condition code registers.
  • -mfixed-cc โ€” don't try to dynamically allocate condition code registers. Only use "icc0" and "fcc0".
  • -mdword โ€” changes the ABI to use double word instructions.
  • -mno-dword โ€” don't use double word instructions.
  • -mdouble โ€” use floating-point double instructions.
  • -mno-double โ€” don't use floating-point double instructions.
  • -mmedia โ€” use media instructions.
  • -mno-media โ€” don't use media instructions.
  • -mmuladd โ€” use multiply and add/subtract instructions.
  • -mno-muladd โ€” don't use multiply and add/subtract instructions.
  • -mfdpic โ€” ๐Ÿฆ‹ Okay so this picks the FDPIC ABI, which uses function descriptors to stand in for pointers to functions. With no PIC/PIE options at all, it implies -fPIE. With -fpic or -fpie, GOT entries and small data are assumed to sit within a 12-bit range from the GOT base address. With -fPIC or -fPIE, GOT offsets get computed with 32 bits. On a bfin-elf target, this also implies -msim ๐Ÿ’…
  • -minline-plt โ€” โœจ This turns on inlining of PLT entries for function calls to functions that aren't known to bind locally. It does nothing without -mfdpic. It's on by default when you're optimizing for speed and compiling shared libraries (that's -fPIC or -fpic), or when something like -O3 or higher shows up on the command line ๐Ÿ”ฅ
  • -mTLS โ€” ๐ŸŒธ Assumes a large TLS segment when generating thread-local code.
  • -mtls โ€” ๐Ÿ“ The opposite energy: does not assume a large TLS segment when generating thread-local code.
  • -mgprel-ro โ€” ๐Ÿงš This enables "GPREL" relocations in the FDPIC ABI for data known to be in read-only sections. It's on by default, except with -fpic or -fpie. Even though it might shrink the global offset table, it trades 1 instruction for 4 there. With -fPIC or -fPIE, it trades 3 instructions for 4 (one of which can be shared by multiple symbols), and it skips needing a GOT entry for the referenced symbol, so it's more likely to be a win ๐Ÿ‘‘ If it isn't, -mno-gprel-ro turns it off.
  • -multilib-library-pic โ€” ๐Ÿ“š Links with the (library, not FD) pic libraries. It's implied by -mlibrary-pic, and also by -fPIC and -fpic without -mfdpic. You should basically never have to use it explicitly ๐Ÿ™ˆ
  • -mlinked-fp โ€” ๐ŸŽ€ Follows the EABI rule of always creating a frame pointer whenever a stack frame gets allocated. It's on by default, and you can turn it off with -mno-linked-fp.
  • -mlong-calls โ€” ๐ŸŒˆ Uses indirect addressing to call functions outside the current compilation unit. This lets those functions live anywhere in the 32-bit address space.
  • -malign-labels โ€” ๐Ÿซถ Tries to align labels to an 8-byte boundary by slipping NOPs into the previous packet. This only does anything when VLIW packing is enabled. It doesn't make new packets, it just adds NOPs to packets that already exist.
  • -mlibrary-pic โ€” ๐Ÿ’œ Generates position-independent EABI code.
  • -macc-4 โ€” ๐Ÿฆ‹ Uses only the first four media accumulator registers.
  • -macc-8 โ€” ๐Ÿ”ฅ Uses all eight media accumulator registers.
  • -mpack โ€” ๐Ÿ’– Packs VLIW instructions.
  • -mno-pack โ€” ๐Ÿ™…โ€โ™€๏ธ Does not pack VLIW instructions.
  • -mno-eflags โ€” ๐ŸŒธ Does not mark ABI switches in e_flags.
  • -mcond-move โ€” โœจ Enables conditional-move instructions (this is the default). ๐Ÿ› ๏ธ This switch is mainly for debugging the compiler and will likely be removed in a future version.
  • -mno-cond-move โ€” ๐Ÿ’… Disables conditional-move instructions. ๐Ÿ› ๏ธ This switch is mainly for debugging the compiler and will likely be removed in a future version.
  • -mscc โ€” ๐Ÿง  Enables conditional set instructions (default). ๐Ÿ› ๏ธ This switch is mainly for debugging the compiler and will likely be removed in a future version.
  • -mno-scc โ€” ๐Ÿšซ Disables conditional set instructions. ๐Ÿ› ๏ธ This switch is mainly for debugging the compiler and will likely be removed in a future version.
  • -mcond-exec โ€” ๐Ÿ“ Enables conditional execution (default). ๐Ÿ› ๏ธ This switch is mainly for debugging the compiler and will likely be removed in a future version.
  • -mno-cond-exec โ€” ๐Ÿ™ˆ Disables conditional execution. ๐Ÿ› ๏ธ This switch is mainly for debugging the compiler and will likely be removed in a future version.
  • -mvliw-branch โ€” ๐Ÿงš Runs a pass that packs branches into VLIW instructions (default). ๐Ÿ› ๏ธ This switch is mainly for debugging the compiler and will likely be removed in a future version.
  • -mno-vliw-branch โ€” ๐ŸŒˆ Does not run the pass that packs branches into VLIW instructions. ๐Ÿ› ๏ธ This switch is mainly for debugging the compiler and will likely be removed in a future version.
  • -mmulti-cond-exec โ€” ๐Ÿ‘‘ Enables optimization of "&&" and "||" in conditional execution (default). ๐Ÿ› ๏ธ This switch is mainly for debugging the compiler and will likely be removed in a future version.
  • -mno-multi-cond-exec โ€” ๐Ÿ’€ Disables optimization of "&&" and "||" in conditional execution. ๐Ÿ› ๏ธ This switch is mainly for debugging the compiler and will likely be removed in a future version.
  • -mnested-cond-exec โ€” ๐Ÿฆ‹ Enables nested conditional execution optimizations (default). ๐Ÿ› ๏ธ This switch is mainly for debugging the compiler and will likely be removed in a future version.
  • -mno-nested-cond-exec โ€” ๐Ÿซถ Disables nested conditional execution optimizations. ๐Ÿ› ๏ธ This switch is mainly for debugging the compiler and will likely be removed in a future version.
  • -moptimize-membar โ€” ๐Ÿงน This one cleans house by removing redundant "membar" instructions from the compiler-generated code. It's enabled by default.
  • -mno-optimize-membar โ€” ๐Ÿ™…โ€โ™€๏ธ Turns off that automatic removal of redundant "membar" instructions from the generated code.
  • -mtomcat-stats โ€” ๐Ÿ“Š Makes gas print out tomcat statistics.
  • -mcpu=cpu โ€” ๐Ÿ’– Picks the processor type you want code generated for. The possible values are frv, fr550, tomcat, fr500, fr450, fr405, fr400, fr300 and simple ๐Ÿ’…

โœจ GNU/Linux Options โœจ

Okay, these -m options are defined just for GNU/Linux targets ๐Ÿง

  • -mglibc โ€” ๐Ÿ‘‘ Uses the GNU C library. This is the default, except on *-*-linux-*uclibc*, *-*-linux-*musl* and *-*-linux-*android* targets.
  • -muclibc โ€” ๐ŸŒธ Uses the uClibc C library. This is the default on *-*-linux-*uclibc* targets.
  • -mmusl โ€” ๐Ÿฆ‹ Uses the musl C library. This is the default on *-*-linux-*musl* targets.
  • -mbionic โ€” ๐Ÿค– Uses the Bionic C library. This is the default on *-*-linux-*android* targets.
  • -mandroid โ€” ๐Ÿ“ฑ Compiles code that's compatible with the Android platform. This is the default on *-*-linux-*android* targets. When compiling, this option turns on -mbionic, -fPIC, -fno-exceptions and -fno-rtti by default. When linking, it makes the GCC driver pass Android-specific options to the linker. It also causes the preprocessor macro "__ANDROID__" to be defined ๐Ÿซถ
  • -tno-android-cc โ€” ๐Ÿ™…โ€โ™€๏ธ Turns off the compilation effects of -mandroid. So it does not enable -mbionic, -fPIC, -fno-exceptions and -fno-rtti by default.
  • -tno-android-ld โ€” ๐Ÿ”— Turns off the linking effects of -mandroid, so standard Linux linking options get passed to the linker.

โœจ H8/300 Options โœจ

These -m options are defined for the H8/300 implementations ๐Ÿงš

  • -mrelax โ€” ๐Ÿ’œ Shortens some address references at link time, when that's possible. It uses the linker option -relax.
  • -mh โ€” ๐ŸŒˆ Generates code for the H8/300H.
  • -ms โ€” ๐Ÿ”ฅ Generates code for the H8S.
  • -mn โ€” ๐ŸŽ€ Generates code for the H8S and H8/300H in the normal mode. This switch has to be used with either -mh or -ms.
  • -ms2600 โ€” โญ Generates code for the H8S/2600. This switch has to be used with -ms.
  • -mexr โ€” ๐Ÿง  Extended registers get stored on the stack before a function with the monitor attribute runs. The default is -mexr. This option is only valid for H8S targets.
  • -mno-exr โ€” ๐Ÿšซ Extended registers do not get stored on the stack before a function with the monitor attribute runs. The default is -mno-exr. This option is only valid for H8S targets.
  • -mint32 โ€” ๐Ÿ’– Makes "int" data 32 bits by default.
  • -malign-300 โ€” ๐Ÿ“ On the H8/300H and H8S, this uses the same alignment rules as the H8/300. By default, the H8/300H and H8S align longs and floats on 4-byte boundaries, but -malign-300 makes them align on 2-byte boundaries instead. It has no effect on the H8/300.

โœจ HPPA Options โœจ

These -m options are defined for the HPPA family of computers ๐Ÿ–ฅ๏ธ

  • -march=architecture-type โ€” ๐Ÿฆ‹ Generates code for the specified architecture. The choices for architecture-type are 1.0 for PA 1.0, 1.1 for PA 1.1, and 2.0 for PA 2.0 processors. To figure out the right architecture option for your machine, check /usr/lib/sched.models on an HP-UX system. Code compiled for lower numbered architectures runs on higher numbered ones, but not the other way around ๐Ÿ’…
  • -mpa-risc-1-0, -mpa-risc-1-1, -mpa-risc-2-0 โ€” ๐Ÿ‘ฏ These are synonyms for -march=1.0, -march=1.1, and -march=2.0 respectively.
  • -matomic-libcalls โ€” โš›๏ธ Generates libcalls for atomic loads and stores when sync libcalls are disabled. This is enabled by default, and it only affects atomic libcall generation by the HPPA backend. Both the sync and libatomic libcall implementations use locking, so processor stores aren't atomic with respect to other atomic operations. Processor loads up to DImode are atomic with respect to other atomic operations, as long as they're implemented as a single access. The PA-RISC architecture doesn't support any atomic operations in hardware except for the "ldcw" instruction. So all atomic support is implemented using sync and atomic libcalls. Sync libcall support lives in libgcc.a, and atomic libcall support lives in libatomic. This option generates "__atomic_exchange" calls for atomic stores. It also gives special handling to atomic DImode accesses on 32-bit targets ๐Ÿ”ฅ
  • -mbig-switch โ€” ๐Ÿคทโ€โ™€๏ธ Does nothing. It's only kept around for backward compatibility.
  • -mcaller-copies โ€” ๐Ÿ“ฆ The caller copies function arguments that get passed by hidden reference. Use this with care, because it isn't compatible with the default 32-bit runtime. Only aggregates larger than eight bytes are passed by hidden reference, though, and this option gives better compatibility with OpenMP ๐Ÿซถ
  • -mcoherent-ldcw โ€” ๐ŸงŠ Uses the ldcw/ldcd coherent cache-control hint.
  • -mdisable-fpregs โ€” ๐Ÿšซ Disables floating-point registers. It's equivalent to "-msoft-float".
  • -mdisable-indexing โ€” ๐Ÿ™ˆ Stops the compiler from using indexing address modes. This avoids some pretty obscure problems when compiling MIG generated code under MACH.
  • -mfast-indirect-calls โ€” ๐Ÿš€ Generates code that assumes calls never cross space boundaries, so GCC can emit code that makes indirect calls faster.
โš ๏ธ Heads up, bestie: this option does not work in the presence of shared libraries or nested functions. Don't use it there!
  • -mfixed-range=register-range โ€” okay so this one tells GCC to treat the register range you give it as fixed registers ๐Ÿ”’, which means the register allocator is not allowed to touch them. It's super handy when compiling kernel code ๐Ÿ’ป. A register range is two registers separated by a dash, and you can list several ranges separated by a comma โœจ.
  • -mgas โ€” turns on assembler directives that only GAS understands ๐Ÿงš
  • -mgnu-ld โ€” this one uses options specific to GNU ld ๐Ÿฆ‹ and passes -shared to ld when you build a shared library. It's the default when GCC is configured (explicitly or implicitly) with the GNU linker. Just so you know, it doesn't change which ld gets called. It only changes the parameters that get passed to it ๐Ÿ™ˆ
    • The ld that gets called is decided by the --with-ld configure option, then GCC's program search path, and finally your 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 โ€” the HP version of the GNU ld vibe ๐Ÿ’… It passes -b to ld when building a shared library and passes +Accept TypeMismatch to ld on all links. It's the default when GCC is configured (explicitly or implicitly) with the HP linker ๐ŸŒธ
    • Same deal as above: this doesn't change which ld is called, only the parameters passed to it.
    • The ld that is called is determined by the --with-ld configure option, GCC's program search path, and finally by the user's PATH.
    • The linker GCC uses can be printed using which gcc -print-prog-name=ld.
    • This option is only available on the 64-bit HP-UX GCC, i.e. configured with hppa*64*-*-hpux*.
  • -mlinker-opt โ€” enables the optimization pass in the HP-UX linker ๐Ÿ”ฅ
โš ๏ธ bestie, this makes symbolic debugging impossible ๐Ÿ˜ญ It also triggers a bug in the HP-UX 8 and HP-UX 9 linkers, where they give bogus error messages when linking some programs. Not it. ๐Ÿ’€
  • -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 (whichever applies) goes over a predefined limit set by the branch type being used.
    • The limits for normal calls are 7,600,000 and 240,000 bytes, respectively, for the PA 2.0 and PA 1.X architectures. Sibcalls are always limited at 240,000 bytes.
    • Distances are measured from the beginning of functions when using the -ffunction-sections option, or when using the -mgas and -mno-portable-runtime options together under HP-UX with the SOM linker.
    • It's normally not desirable to use this option, since 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 on 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 ๐Ÿฅฒ
  • -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.
  • -mjump-in-delay โ€” this one is ignored and only here for compatibility purposes ๐Ÿซถ
  • -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 ๐Ÿ‘‘
  • -mordered โ€” assumes memory references are ordered, so barriers are not needed ๐Ÿ“
  • -mportable-runtime โ€” uses the portable calling conventions HP proposed for ELF systems ๐ŸŒˆ
  • -mschedule=cpu-type โ€” schedules code according to the constraints for the machine type cpu-type ๐Ÿ—“๏ธ The choices for cpu-type are 700 7100, 7100LC, 7200, 7300 and 8000. If you want to figure out the right scheduling option for your machine, check out /usr/lib/sched.models on an HP-UX system ๐Ÿ” The default scheduling is 8000.
  • -msio โ€” generates the predefine _SIO for server IO ๐Ÿ–ฅ๏ธ The default is -mwsio. This generates the predefines __hp9000s700, __hp9000s700__ and _WSIO for workstation IO. These options are available under HP-UX and HI-UX ๐Ÿ’–
  • -msoft-float โ€” generates output containing library calls for floating point ๐ŸŽ€
โš ๏ธ the requisite libraries are not available for all HPPA targets. Normally the facilities of the machine's usual C compiler are used, but this can't be done directly in cross-compilation. You have to make your own arrangements to provide suitable library functions for cross-compilation ๐Ÿ˜ฌ

Also, -msoft-float changes the calling convention in the output file, so it's only useful if you compile all of a program with this option ๐Ÿ™… In particular, you need to compile libgcc.a, the library that comes with GCC, with -msoft-float for this to work.

  • -msoft-mult โ€” uses software integer multiplication ๐Ÿงฎ This disables the use of the xmpyu instruction.
  • -munix=unix-std โ€” generates compiler predefines and selects a startfile for the UNIX standard you pick ๐Ÿ“š 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 defaults are 93 for HP-UX 10.00, 95 for HP-UX 10.10 through 11.00, and 98 for HP-UX 11.11 and later ๐Ÿ—‚๏ธ
    • -munix=93 provides the same predefines as GCC 3.3 and 3.4.
    • -munix=95 provides additional predefines for "XOPEN_UNIX" and "_XOPEN_SOURCE_EXTENDED", and the startfile unix95.o.
    • -munix=98 provides additional predefines for "_XOPEN_UNIX", "_XOPEN_SOURCE_EXTENDED", "_INCLUDE__STDC_A1_SOURCE" and "_INCLUDE_XOPEN_SOURCE_500", and the startfile unix98.o.
๐Ÿšจ this option changes the interfaces for various library routines, and it also affects the operational behavior of the C library. Thus, extreme care is needed when using it, bestie ๐Ÿ’€

Library code that is meant to work with more than one UNIX standard has to test, set and restore the variable "__xpg4_extended_mask" as appropriate. Most GNU software doesn't provide this capability ๐Ÿฅบ

  • -nolibdld โ€” suppresses the generation of link options that search libdld.sl when -static is specified on HP-UX 10 and later ๐Ÿ™…โ€โ™€๏ธ
  • -static โ€” okay so the HP-UX implementation of setlocale in libc depends on libdld.sl, and there isn't an archive version of libdld.sl ๐Ÿ˜ฉ That means when -static is specified, special link options are needed to resolve this dependency.
    • On HP-UX 10 and later, the GCC driver adds the necessary options to link with libdld.sl when -static is specified. This causes the resulting binary to be dynamic. On the 64-bit port, the linkers generate dynamic binaries by default in any case.
    • The -nolibdld option can be used to stop the GCC driver from adding these link options.
  • -threads โ€” adds support for multithreading with the dce thread library under HP-UX ๐Ÿงต This option sets flags for both the preprocessor and the linker.

๐Ÿฆ‹ IA-64 Options ๐Ÿฆ‹

These are the -m options defined for the Intel IA-64 architecture ๐Ÿ’œ

  • -mbig-endian โ€” generates code for a big-endian target ๐Ÿ‘ This is the default for HP-UX.
  • -mlittle-endian โ€” generates code for a little-endian target ๐ŸŒท This is the default for AIX5 and GNU/Linux.
  • -mgnu-as, -mno-gnu-as โ€” generates (or doesn't) code for the GNU assembler โœจ This is the default.
  • -mgnu-ld, -mno-gnu-ld โ€” generates (or doesn't) code for the GNU linker ๐Ÿ”— This is the default.
  • -mno-pic โ€” generates code that does not use a global pointer register ๐Ÿ™ƒ
๐Ÿšซ the result is not position independent code, and it violates the IA-64 ABI. Use with caution, babe.
  • -mvolatile-asm-stop, -mno-volatile-asm-stop โ€” generates (or doesn't) a stop bit immediately before and after volatile asm statements ๐Ÿ›‘
  • -mregister-names, -mno-register-names โ€” generates (or doesn't) in, loc, and out register names for the stacked registers ๐Ÿ“ This may make assembler output more readable, and honestly it's giving clarity ๐Ÿง 
  • -mno-sdata, -msdata โ€” disables (or enables) optimizations that use the small data section ๐Ÿ—ƒ๏ธ This may be useful for working around optimizer bugs ๐Ÿ›
  • -mconstant-gp โ€” generates code that uses a single constant global pointer value ๐Ÿ“Œ This is useful when compiling kernel code ๐Ÿ‘ฉโ€๐Ÿ’ป
  • -mauto-pic โ€” generates code that is self-relocatable ๐Ÿ” This implies -mconstant-gp. It's useful when compiling firmware code ๐Ÿ”ง
  • -minline-float-divide-min-latency โ€” generates code for inline divides of floating-point values using the minimum latency algorithm โšก
  • -minline-float-divide-max-throughput โ€” generates code for inline divides of floating-point values using the maximum throughput algorithm ๐Ÿš„
  • -mno-inline-float-divide โ€” does not generate inline code for divides of floating-point values ๐Ÿ™…
  • -minline-int-divide-min-latency โ€” generates code for inline divides of integer values using the minimum latency algorithm โšก
  • -minline-int-divide-max-throughput โ€” generates code for inline divides of integer values using the maximum throughput algorithm ๐Ÿš„
  • -mno-inline-int-divide โ€” does not generate inline code for divides of integer values ๐Ÿ™…
  • -minline-sqrt-min-latency โ€” generates code for inline square roots using the minimum latency algorithm โšก
  • -minline-sqrt-max-throughput โ€” generates code for inline square roots using the maximum throughput algorithm ๐Ÿš„
  • -mno-inline-sqrt โ€” does not generate inline code for "sqrt" ๐Ÿซ 
  • -mfused-madd, -mno-fused-madd โ€” does (or doesn't) generate code that uses the fused multiply/add or multiply/subtract instructions ๐Ÿงช The default is to use these instructions ๐Ÿ’…
  • -mno-dwarf2-asm, -mdwarf2-asm โ€” doesn't (or does) generate assembler code for the DWARF line number debugging info ๐Ÿ—บ๏ธ This may be useful when not using the GNU assembler.
  • -mearly-stop-bits, -mno-early-stop-bits โ€” allows stop bits to be placed earlier than immediately preceding the instruction that triggered the stop bit โฉ This can improve instruction scheduling, but it does not always do so ๐Ÿคทโ€โ™€๏ธ
  • -mfixed-range=register-range โ€” okay so this one tells the compiler to treat the register range you give it as fixed registers ๐Ÿ”’. A fixed register is one the register allocator isn't allowed to touch. It's super useful when you're compiling kernel code ๐Ÿ’ป. You write a range as two registers joined by a dash, and you can list several ranges separated by commas โœจ.
  • -mtls-size=tls-size โ€” this sets the bit size of immediate TLS offsets ๐ŸŽ€. The valid values are 14, 22, and 64.
  • -mtune=cpu-type โ€” tunes the instruction scheduling for one particular CPU ๐Ÿฆ‹. The valid values are itanium, itanium1, merced, itanium2, and mckinley.
  • -milp32, -mlp64 โ€” these make code for a 32-bit or 64-bit environment ๐ŸŒธ. The 32-bit one sets int, long, and pointers to 32 bits. The 64-bit one sets int to 32 bits and long and pointers to 64 bits. Heads up: these are HP-UX specific flags ๐Ÿ™ˆ.
  • -mno-sched-br-data-spec, -msched-br-data-spec โ€” the -mno- one disables data speculative scheduling before reload and the plain one turns it on ๐Ÿ’…. When it's on you get ld.a instructions plus their check instructions (ld.c / chk.a). It's disabled by default.
  • -msched-ar-data-spec, -mno-sched-ar-data-spec โ€” plain turns on data speculative scheduling after reload, and -mno- turns it off ๐Ÿ”ฅ. This also gives you ld.a instructions with the matching check instructions (ld.c / chk.a). It's enabled by default โœจ.
  • -mno-sched-control-spec, -msched-control-spec โ€” the -mno- one disables control speculative scheduling and plain turns it on ๐Ÿง . It only works during region scheduling (aka before reload). When it's active you get ld.s instructions plus chk.s check instructions. It's disabled by default.
  • -msched-br-in-data-spec, -mno-sched-br-in-data-spec โ€” plain enables and -mno- disables speculative scheduling of instructions that depend on data speculative loads before reload ๐ŸŒˆ. This only does anything if -msched-br-data-spec is turned on. It's enabled by default.
  • -msched-ar-in-data-spec, -mno-sched-ar-in-data-spec โ€” same vibe, but for after reload ๐Ÿ’œ. Plain enables it and -mno- disables it. It only matters when -msched-ar-data-spec is enabled, and it's enabled by default.
  • -msched-in-control-spec, -mno-sched-in-control-spec โ€” plain enables and -mno- disables speculative scheduling of instructions that depend on control speculative loads โญ. It's only effective when -msched-control-spec is enabled, and the default is enabled.
  • -mno-sched-prefer-non-data-spec-insns, -msched-prefer-non-data-spec-insns โ€” if you turn the plain one on, data-speculative instructions only get picked for scheduling when there are no other choices at the moment ๐Ÿ™ƒ. This makes data speculation way more conservative. It's disabled by default.
  • -mno-sched-prefer-non-control-spec-insns, -msched-prefer-non-control-spec-insns โ€” same energy, but for control-speculative instructions ๐Ÿ“. Turn on the plain one and they're only scheduled when nothing else is available, which makes control speculation much more conservative. It's disabled by default.
  • -mno-sched-count-spec-in-critical-path, -msched-count-spec-in-critical-path โ€” if the plain one is enabled, speculative dependencies get counted when the instruction priorities are computed ๐Ÿงฎ. That makes speculation a bit more conservative. It's disabled by default.
  • -msched-spec-ldc โ€” uses a simple data speculation check ๐Ÿซถ. It's on by default.
  • -msched-control-spec-ldc โ€” uses a simple check for control speculation ๐ŸŒธ. It's on by default too.
  • -msched-stop-bits-after-every-cycle โ€” places a stop bit after every cycle when scheduling โน๏ธ. It's on by default.
  • -msched-fp-mem-deps-zero-cost โ€” assumes floating-point stores and loads won't likely conflict when they end up in the same instruction group ๐Ÿคž. It's disabled by default.
  • -msel-sched-dont-check-control-spec โ€” generates checks for control speculation in selective scheduling ๐Ÿ”. Disabled by default.
  • -msched-max-memory-insns=max-insns โ€” puts a limit on how many memory insns can go in one instruction group ๐Ÿง. Later memory insns trying to schedule into the same group get lower priority. This is often handy for stopping cache bank conflicts ๐Ÿ’€. The default value is 1.
  • -msched-max-memory-insns-hard-limit โ€” turns the msched-max-memory-insns limit into a hard limit ๐Ÿšซ, so you can't go over that number in an instruction group. Without it, the limit is "soft", which means non-memory operations get preferred once the limit is hit, 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 ๐Ÿง‘โ€๐Ÿ’ป.

๐Ÿงš LoongArch Options

These command-line options are defined for LoongArch targets ๐Ÿ’–:

  • -march=cpu-type โ€” tells GCC to generate instructions for a specific machine type ๐Ÿš€. Here's the tea: -mtune=cpu-type only tunes the code for that CPU, but -march=cpu-type lets GCC generate code that might not run at all on other processors ๐Ÿ˜ญ. Specifying -march=cpu-type implies -mtune=cpu-type, unless noted otherwise. The choices for cpu-type are:
    • native โ€” picks the CPU to generate code for at compile time by checking the processor type of the machine doing the compiling ๐Ÿ–ฅ๏ธ. -march=native enables every instruction subset the local machine supports, so the result might not run on other machines. -mtune=native gives code optimized for the local machine within the limits of the chosen instruction set.
    • loongarch64 โ€” a generic CPU with 64-bit extensions ๐ŸŒŸ.
    • la464 โ€” the LoongArch LA464 CPU, with LBT, LSX, LASX, and LVZ ๐Ÿ’….
  • -mtune=cpu-type โ€” optimizes the output for the given processor, specified by its microarchitecture name ๐ŸŽฏ.
  • -mabi=base-abi-type โ€” generates code for the calling convention you pick ๐Ÿ“ž. base-abi-type can be one of:
    • lp64d โ€” uses 64-bit general purpose registers and 32/64-bit floating-point registers for parameter passing ๐Ÿ’œ. The data model is LP64, where int is 32 bits and long int and pointers are 64 bits.
    • lp64f โ€” uses 64-bit general purpose registers and 32-bit floating-point registers for parameter passing ๐ŸŒธ. The data model is LP64, where int is 32 bits and long int and pointers are 64 bits.
    • lp64s โ€” uses 64-bit general purpose registers and no floating-point registers for parameter passing ๐Ÿซง. The data model is LP64, where int is 32 bits and long int and pointers are 64 bits.
  • -mfpu=fpu-type โ€” generates code for the FPU type you specify, which can be one of these ๐Ÿ”ง:
    • 64 โ€” allows hardware floating-point instructions for 32-bit and 64-bit operations ๐Ÿ’ช.
    • 32 โ€” allows hardware floating-point instructions for 32-bit operations only ๐ŸŒ™.
    • none, 0 โ€” stops hardware floating-point instructions from being used ๐Ÿ™…โ€โ™€๏ธ.
  • -msimd=simd-type โ€” turns on LoongArch SIMD instructions for vectorization and builtin functions โšก. The value can be one of:
    • lasx โ€” enables generating instructions from the 256-bit LoongArch Advanced SIMD Extension (LASX) and the 128-bit LoongArch SIMD Extension (LSX) ๐Ÿฆ„.
    • lsx โ€” enables generating instructions from the 128-bit LoongArch SIMD Extension (LSX) only ๐ŸŽ€.
    • none โ€” no LoongArch SIMD instruction may be generated ๐Ÿšซ.
  • -msoft-float โ€” forces -mfpu=none and stops floating-point registers from being used for parameter passing ๐Ÿซ . This one may change the target ABI.
  • -msingle-float โ€” forces -mfpu=32 and lets you use 32-bit floating-point registers for parameter passing ๐Ÿฆ‹. This one may change the target ABI too.
  • -mdouble-float โ€” forces -mfpu=64 and lets you use 32/64-bit floating-point registers for parameter passing ๐ŸŒˆ. Also may change the target ABI.
  • -mlasx, -mno-lasx, -mlsx, -mno-lsx โ€” these tweak the scope of the SIMD extensions (none / LSX / LASX) the compiler can use for code generation, one step at a time ๐Ÿงฉ. Enabling LASX with mlasx automatically enables LSX, and disabling LSX with mno-lsx automatically disables LASX. These are driver-only options. They act on the final msimd configuration and make incremental changes in the order they show up on the GCC driver's command line, which gives the final, canonicalized msimd option passed to the compiler proper โœจ.
  • -mbranch-cost=n โ€” sets the cost of branches to roughly n instructions ๐Ÿ›ฃ๏ธ.
  • -mcheck-zero-division, -mno-check-zero-divison โ€” the first one traps on integer division by zero, and the -mno- one doesn't trap โš ๏ธ. The default is -mcheck-zero-division for -O0 or -Og, and -mno-check-zero-division for other optimization levels ๐Ÿง.
  • -mcond-move-int, -mno-cond-move-int โ€” conditional moves for integral data in general-purpose registers are enabled by plain and disabled by -mno- ๐ŸŒท. The default is -mcond-move-int.
  • -mcond-move-float, -mno-cond-move-float โ€” same deal for floating-point registers ๐ŸŒผ. Plain enables them and -mno- disables them. The default is -mcond-move-float.
  • -mmemcpy, -mno-memcpy โ€” plain forces the use of memcpy for non-trivial block moves, and -mno- makes sure it isn't forced ๐Ÿง . The default is -mno-memcpy, which lets GCC inline most constant-sized copies. Setting the optimization level to -Os also forces memcpy, but -mno-memcpy can override that if you set it explicitly, no matter what order the options appear on the command line ๐Ÿ‘‘.
  • -mstrict-align, -mno-strict-align โ€” the plain one avoids generating memory accesses that might not be aligned on a natural object boundary, as described in the architecture specification, and -mno- allows them ๐Ÿซถ. The default is -mno-strict-align.
  • -msmall-data-limit=number โ€” puts global and static data smaller than number bytes into a special section (on some targets) ๐Ÿ“. The default value is 0.
  • -mmax-inline-memcpy-size=*n* โ€” okay bestie, this one tells GCC to inline all block moves (like memcpy calls or structure copies) that are less than or equal to n bytes ๐Ÿ“ฆโœจ The default for n is 1024.
  • -mcmodel=code-model โ€” lets you pick your code model ๐Ÿ’… The options are:
    • tiny-static โ€” not implemented yet ๐Ÿ™ˆ
    • tiny โ€” not implemented yet ๐Ÿ™ˆ
    • normal โ€” the text segment has to live within a 128MB addressing space, and the data segment has to live within a 2GB addressing space ๐ŸŒธ
    • medium โ€” both the text segment and the data segment have to fit within a 2GB addressing space ๐Ÿฆ‹
    • large โ€” not implemented yet ๐Ÿ™ˆ
    • extreme โ€” no limits on how big the code segment and data segment can be ๐ŸŒˆ
Heads up, bestie: -mcmodel=extreme does NOT play nicely with -fplt and/or -mexplicit-relocs=none ๐Ÿ’€

The default code model is normal ๐Ÿ’–

  • -mexplicit-relocs=*style* โ€” this decides when GCC uses assembler relocation operators for symbolic addresses โœจ The other option is assembler macros, which can limit instruction scheduling but still let the linker relax things ๐Ÿงš The styles are:
    • none โ€” assembler macros are always used ๐Ÿ™…โ€โ™€๏ธ
    • always โ€” assembler relocation operators are always used ๐Ÿ’œ
    • auto โ€” the compiler uses relocation operators where linker relaxation is impossible and it helps the code quality, and macros everywhere else ๐Ÿซถ

The default depends on what the assembler can do when GCC gets built, plus the setting of -mrelax. It's -mexplicit-relocs=none if the assembler doesn't support relocation operators at all. It's -mexplicit-relocs=always if the assembler supports them but -mrelax isn't enabled. And it's -mexplicit-relocs=auto if the assembler supports them AND -mrelax is enabled ๐Ÿ”ฅ

  • -mexplicit-relocs โ€” an alias of -mexplicit-relocs=always, kept around for backward compatibility ๐ŸŽ€
  • -mno-explicit-relocs โ€” an alias of -mexplicit-relocs=none, also kept for backward compatibility ๐ŸŽ€
  • -mdirect-extern-access, -mno-direct-extern-access โ€” this one controls whether the GOT gets used to access external symbols ๐Ÿง The default is -mno-direct-extern-access, so the GOT is used for external symbols with default visibility, but not for other external symbols. With -mdirect-extern-access, the GOT is skipped completely and every external symbol gets PC-relative addressing. This is only suitable where no dynamic linking happens, like firmware, OS kernels, or executables linked with -static or -static-pie ๐Ÿ‘‘ And -mdirect-extern-access is not compatible with -fPIC or -fpic.
  • -mrelax, -mno-relax โ€” takes (or doesn't take) advantage of linker relaxations โœจ If -mpass-mrelax-to-as is enabled, this option gets passed to the assembler too. The default gets figured out when GCC is built, by checking what the assembler supports. It's -mrelax if the assembler supports both the -mrelax option AND conditional branch relaxation. That second part is required, otherwise the .align directives and conditional branch instructions in GCC's assembly output might get rejected by the assembler because of a relocation overflow ๐Ÿ˜ญ Otherwise the default is -mno-relax.
  • -mpass-mrelax-to-as, -mno-pass-mrelax-to-as โ€” passes (or doesn't pass) the -mrelax or -mno-relax option to the assembler ๐Ÿฆ‹ The default is found at GCC build-time too. It's -mpass-mrelax-to-as if the assembler supports the -mrelax option, and -mno-pass-mrelax-to-as otherwise. This one is mostly useful for debugging, or for playing nice with assemblers that aren't the same one used at build-time ๐Ÿ”
  • -mrecip โ€” this turns on the reciprocal estimate and reciprocal square root estimate instructions, with extra Newton-Raphson steps to boost precision ๐Ÿงฎ It's used instead of doing a divide, or a square root and then a divide, on floating-point arguments. These instructions only get generated when -funsafe-math-optimizations is enabled together with -ffinite-math-only and -fno-trapping-math. It's off by default. Before you use it, make sure the target CPU supports the frecipe and frsqrte instructions ๐Ÿ’… The sequence has higher throughput than the non-reciprocal instruction, BUT the precision can drop by up to 2 ulp (i.e. the inverse of 1.0 comes out as 0.99999994) ๐Ÿ’€
  • -mrecip=*opt* โ€” this controls which reciprocal estimate instructions are allowed to be used ๐ŸŒˆ opt is a comma-separated list of options, and any of them can get a ! in front to invert it. The choices are:
    • all โ€” enables every estimate instruction ๐Ÿ”ฅ
    • default โ€” enables the default instructions, same as -mrecip ๐ŸŒธ
    • none โ€” disables all estimate instructions, same as -mno-recip ๐Ÿ™…โ€โ™€๏ธ
    • div โ€” enables the approximation for scalar division โœจ
    • vec-div โ€” enables the approximation for vectorized division ๐Ÿงš
    • sqrt โ€” enables the approximation for scalar square root ๐Ÿฆ‹
    • vec-sqrt โ€” enables the approximation for vectorized square root ๐Ÿ’œ
    • rsqrt โ€” enables the approximation for scalar reciprocal square root ๐Ÿซถ
    • vec-rsqrt โ€” enables the approximation for vectorized reciprocal square root ๐Ÿ‘‘

So for example, -mrecip=all,!sqrt turns on ALL of the reciprocal approximations EXCEPT scalar square root ๐Ÿ˜ญ

  • -mfrecipe, -mno-frecipe โ€” uses (or doesn't use) the frecipe.{s/d} and frsqrte.{s/d} instructions ๐ŸŽ€ When you build with -march=la664, this is enabled by default. The default otherwise is -mno-frecipe ๐Ÿ’–
  • -mdiv32, -mno-div32 โ€” uses (or doesn't use) the div.w[u] and mod.w[u] instructions with input that is NOT sign-extended ๐Ÿง  When you build with -march=la664, it's enabled by default. The default otherwise is -mno-div32 โœจ
  • -mlam-bh, -mno-lam-bh โ€” uses (or doesn't use) the am{swap/add}[_db].{b/h} instructions ๐ŸŒธ When you build with -march=la664, it's enabled by default. The default is -mno-lam-bh ๐Ÿ’…
  • -mlamcas, -mno-lamcas โ€” uses (or doesn't use) the amcas[_db].{b/h/w/d} instructions ๐Ÿ”ฅ When you build with -march=la664, it's enabled by default. The default is -mno-lamcas ๐Ÿฆ‹
  • -mld-seq-sa, -mno-ld-seq-sa โ€” decides whether a load-load barrier (dbar 0x700) is needed ๐Ÿง When you build with -march=la664, it's enabled by default. The default is -mno-ld-seq-sa, which means the load-load barrier IS needed ๐Ÿซถ
  • -mtls-dialect=*opt* โ€” controls which TLS dialect can be used for the general dynamic and local dynamic TLS models ๐ŸŒˆ The choices are:
    • trad โ€” uses traditional TLS, and this is the default โœจ
    • desc โ€” uses TLS descriptors ๐Ÿ’œ
  • loongarch-vect-unroll-limit โ€” the vectorizer uses the available tuning info to figure out whether it'd be worth unrolling the main vectorized loop, and by how much ๐Ÿงš This sets the upper bound on how much the vectorizer will unroll the main loop. The default value is six ๐ŸŽ€

๐ŸŒธ M32C Options ๐ŸŒธ

  • -mcpu=name โ€” picks the CPU that code gets generated for ๐Ÿ’– name can be one of r8c for the R8C/Tiny series, m16c for the M16C (up to /60) series, m32cm for the M16C/80 series, or m32c for the M32C/80 series โœจ
  • -msim โ€” tells GCC the program will run on the simulator ๐Ÿ–ฅ๏ธ This links in an alternate runtime library that supports stuff like file I/O, for example.
Warning, bestie: do NOT use this option when generating programs that will run on real hardware ๐Ÿ’€ You have to provide your own runtime library for whatever I/O functions you need.
  • -memregs=*number* โ€” specifies how many memory-based pseudo-registers GCC uses during code generation ๐Ÿง  These get used like real registers, so there's a tradeoff between GCC fitting your code into the available registers and the performance penalty of using memory instead ๐Ÿ’… Every module in a program has to be compiled with the same value for this option. Because of that, you must NOT use this option with GCC's default runtime libraries ๐Ÿ™ˆ

๐Ÿฆ‹ M32R/D Options ๐Ÿฆ‹

These -m options are defined for Renesas M32R/D architectures ๐Ÿงš

  • -m32r2 โ€” generates code for the M32R/2 ๐ŸŒธ
  • -m32rx โ€” generates code for the M32R/X ๐Ÿ’œ
  • -m32r โ€” generates code for the M32R ๐Ÿ‘‘ This is the default โœจ
  • -mmodel=small โ€” assumes all objects live in the lower 16MB of memory, so their addresses can be loaded with the ld24 instruction, and assumes all subroutines are reachable with the bl instruction ๐Ÿซถ This is the default โœจ

The addressability of a particular object can be set with the model attribute ๐Ÿ’–

  • -mmodel=medium โ€” assumes objects may be anywhere in the 32-bit address space (the compiler generates seth/add3 instructions to load their addresses), and assumes all subroutines are reachable with the bl instruction ๐ŸŒˆ
  • -mmodel=large โ€” assumes objects may be anywhere in the 32-bit address space (the compiler generates seth/add3 instructions to load their addresses), and assumes subroutines may NOT be reachable with the bl instruction ๐Ÿข In that case the compiler generates the much slower seth/add3/jl instruction sequence ๐Ÿ˜ญ
  • -msdata=none โ€” disables use of the small data area ๐Ÿ™…โ€โ™€๏ธ Variables get put into one of .data, .bss, or .rodata (unless the section attribute has been specified). This is the default ๐Ÿ’…

The small data area consists of the .sdata and .sbss sections. Objects can be explicitly put in the small data area with the section attribute, using one of these sections ๐Ÿง

  • -msdata=sdata โ€” puts small global and static data in the small data area, but doesn't generate any special code to reference them ๐ŸŒธ
  • -msdata=use โ€” puts small global and static data in the small data area AND generates special instructions to reference them ๐Ÿ”ฅ
  • -G *num* โ€” puts global and static objects less than or equal to num bytes into the small data or BSS sections, instead of the normal data or BSS sections ๐Ÿ“ฆ The default value of num is 8. The -msdata option has to be set to either sdata or use for this option to do anything โœจ

All modules should be compiled with the same -G num value ๐Ÿซถ Compiling with different values of num may or may not work. If it doesn't, the linker gives an error message, so incorrect code is NOT generated ๐Ÿ›ก๏ธ

  • -mdebug โ€” makes the M32R-specific code in the compiler display some statistics that might help you debug your programs ๐Ÿ”
  • -malign-loops โ€” aligns all loops to a 32-byte boundary ๐ŸŒŸ
  • -mno-align-loops โ€” Skip the 32-byte alignment for loops ๐Ÿ’… This is already the default, so you're basically set โœจ
  • -missue-rate=number โ€” Tells the compiler how many instructions to issue per cycle ๐Ÿ”ฅ number can only be 1 or 2, no other vibes allowed.
  • -mbranch-cost=number โ€” number can only be 1 or 2 ๐ŸŒธ If it's 1, branches get the VIP pass over conditional code. If it's 2, it's the opposite.
  • -mflush-trap=number โ€” Picks the trap number used to flush the cache ๐Ÿงš The default is 12, and valid numbers are 0 through 15 inclusive.
  • -mno-flush-trap โ€” Says the cache can't be flushed by using a trap ๐Ÿ™ˆ
  • -mflush-func=name โ€” Names the operating system function to call for flushing the cache ๐Ÿ’œ The default is _flush_cache, but the function call only gets used if a trap isn't available.
  • -mno-flush-func โ€” Says there's no OS function for flushing the cache ๐Ÿ’€

โœจ M680x0 Options โœจ

These are the -m options for M680x0 and ColdFire processors ๐Ÿฆ‹ The defaults depend on which architecture was picked when the compiler was configured, so the defaults for the most common choices are listed below.

  • -march=arch โ€” Generates code for a specific M680x0 or ColdFire instruction set architecture ๐Ÿ‘‘ For M680x0, the allowed values of arch are 68000, 68010, 68020, 68030, 68040, 68060 and cpu32. ColdFire architectures get picked using Freescale's ISA classification, and the allowed values are isaa, isaaplus, isab and isac.

GCC defines the macro __mcfarch__ whenever it's generating code for a ColdFire target ๐Ÿงš The arch in that macro is one of the -march arguments from above.

When you use -march and -mtune together, you get code that runs on a whole family of similar processors but is optimized for one particular microarchitecture โœจ

  • -mcpu=cpu โ€” Generates code for a specific M680x0 or ColdFire processor ๐ŸŽ€ The M680x0 cpus are 68000, 68010, 68020, 68030, 68040, 68060, 68302, 68332 and cpu32. The ColdFire cpus are in the table below, which also sorts them into families:
Family : -mcpu arguments
51 : 51 51ac 51ag 51cn 51em 51je 51jf 51jg 51jm 51mm 51qe 51qm
5206 : 5202 5204 5206
5206e : 5206e
5208 : 5207 5208
5211a : 5210a 5211a
5213 : 5211 5212 5213
5216 : 5214 5216
52235 : 52230 52231 52232 52233 52234 52235
5225 : 5224 5225
52259 : 52252 52254 52255 52256 52258 52259
5235 : 5232 5233 5234 5235 523x
5249 : 5249
5250 : 5250
5271 : 5270 5271
5272 : 5272
5275 : 5274 5275
5282 : 5280 5281 5282 528x
53017 : 53011 53012 53013 53014 53015 53016 53017
5307 : 5307
5329 : 5327 5328 5329 532x
5373 : 5372 5373 537x
5407 : 5407
5475 : 5470 5471 5472 5473 5474 5475 547x 5480 5481 5482 5483 5484
5485

-mcpu=cpu overrides -march=arch if arch is compatible with cpu ๐Ÿ’– Any other combos of -mcpu and -march get rejected ๐Ÿ™…

GCC defines the macro __mcf_cpu_cpu when a ColdFire target cpu is selected. It also defines __mcf_family_family, where the value of family comes from the table above ๐ŸŒˆ

  • -mtune=tune โ€” Tunes the code for a particular microarchitecture, but still within the limits set by -march and -mcpu ๐Ÿฆ‹ The M680x0 microarchitectures are 68000, 68010, 68020, 68030, 68040, 68060 and cpu32. The ColdFire microarchitectures are cfv1, cfv2, cfv3, cfv4 and cfv4e.

You can also use -mtune=68020-40 for code that needs to run relatively well on 68020, 68030 and 68040 targets ๐Ÿ“ -mtune=68020-60 is similar, but it also includes 68060 targets. 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 that range ๐Ÿซถ

GCC also defines the macro __muarch__ when tuning for ColdFire microarchitecture uarch, where uarch is one of the arguments listed 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 one for microcontrollers with a 68000 or EC000 core, including the 68008, 68302, 68306, 68307, 68322, 68328 and 68356 ๐Ÿงš

  • -m68010 โ€” Generates output for a 68010 โœจ This is the default when the compiler is configured for 68010-based systems. It's equivalent to -march=68010.
  • -m68020, -mc68020 โ€” Generates output for a 68020 ๐ŸŒธ This is the default when the compiler is configured for 68020-based systems. It's equivalent to -march=68020.
  • -m68030 โ€” Generates output for a 68030 ๐ŸŽ€ This is the default when the compiler is configured for 68030-based systems. It's equivalent to -march=68030.
  • -m68040 โ€” Generates output for a 68040 ๐Ÿ”ฅ This is the default when the compiler is configured for 68040-based systems. It's equivalent to -march=68040.

This option stops the use of 68881/68882 instructions that would have to be emulated in software on the 68040. Use it if your 68040 doesn't have code to emulate those instructions ๐Ÿ™ˆ

  • -m68060 โ€” Generates output for a 68060 ๐Ÿ‘‘ This is the default when the compiler is configured for 68060-based systems. It's equivalent to -march=68060.

This option stops the use of 68020 and 68881/68882 instructions that would have to be emulated in software on the 68060. Use it if your 68060 doesn't have code to emulate those instructions ๐Ÿ’œ

  • -mcpu32 โ€” Generates output for a CPU32 ๐Ÿฆ‹ This is the default when the compiler is configured for CPU32-based systems. It's equivalent to -march=cpu32.

Use this one 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 it's now deprecated in favor of that option ๐Ÿฅ€

Use this one for microcontrollers with a 5200 core, including the MCF5202, MCF5203, MCF5204 and MCF5206 ๐Ÿงš

  • -m5206e โ€” Generates output for a 5206e ColdFire CPU ๐Ÿ™ƒ It's now deprecated in favor of the equivalent -mcpu=5206e.
  • -m528x โ€” Generates output for a member of the ColdFire 528X family ๐Ÿซ  It's now deprecated in favor of the equivalent -mcpu=528x.
  • -m5307 โ€” Generates output for a ColdFire 5307 CPU ๐Ÿ’€ It's now deprecated in favor of the equivalent -mcpu=5307.
  • -m5407 โ€” Generates output for a ColdFire 5407 CPU โœจ It's now deprecated in favor of the equivalent -mcpu=5407.
  • -mcfv4e โ€” Generates output for a ColdFire V4e family CPU (e.g. 547x/548x) ๐Ÿ”ฅ This includes hardware floating-point instructions. It's equivalent to -mcpu=547x, and it's now deprecated in favor of that option.
  • -m68020-40 โ€” Generates output for a 68040, without using any of the new instructions ๐ŸŒธ This gives code that can run relatively efficiently on a 68020/68881, a 68030 or a 68040. The generated code does use the 68881 instructions that get emulated on the 68040.

The option is equivalent to -march=68020 -mtune=68020-40.

  • -m68020-60 โ€” Generates output for a 68060, without using any of the new instructions ๐ŸŽ€ This gives code that can run relatively efficiently on a 68020/68881, a 68030 or a 68040. The generated code does use the 68881 instructions that get emulated on the 68060.

The option is equivalent to -march=68020 -mtune=68020-60.

  • -mhard-float, -m68881 โ€” Generates floating-point instructions ๐Ÿ’– This is the default for 68020 and above, and for ColdFire devices that have an FPU. It defines the macro __HAVE_68881__ on M680x0 targets and __mcffpu__ on ColdFire targets.
  • -msoft-float โ€” Doesn't generate floating-point instructions; uses library calls instead ๐Ÿงš This is the default for 68000, 68010, and 68832 targets. It's also the default for ColdFire devices that have no FPU.
  • -mdiv, -mno-div โ€” Generates (or doesn't generate) ColdFire hardware divide and remainder instructions โž— If -march is used without -mcpu, the default is "on" for ColdFire architectures and "off" for M680x0 architectures. Otherwise, the default comes from the target CPU (either the default CPU, or the one specified by -mcpu). For example, the default is "off" for -mcpu=5206 and "on" for -mcpu=5206e.

GCC defines the macro __mcfhwdiv__ when this option is enabled ๐ŸŒˆ

  • -mshort โ€” Treats type "int" as 16 bits wide, like "short int" ๐Ÿฆ‹ Parameters passed on the stack are also aligned to a 16-bit boundary, even on targets whose API mandates promotion to 32-bit.
  • -mno-short โ€” Doesn't treat type "int" as 16 bits wide ๐Ÿ’… This is the default.
  • -mnobitfield, -mno-bitfield โ€” Doesn't use the bit-field instructions ๐Ÿ™ˆ The -m68000, -mcpu32 and -m5200 options imply -mnobitfield.
  • -mbitfield โ€” Does use the bit-field instructions ๐Ÿซถ The -m68020 option implies -mbitfield. This is the default if you use a configuration designed for a 68020.
  • -mrtd โ€” Uses a different function-calling convention โœจ Functions that take a fixed number of arguments return with the "rtd" instruction, which pops their arguments while returning. This 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 ๐Ÿฅบ

Also, you must provide function prototypes for all functions that take variable numbers of arguments (including "printf"). Otherwise, incorrect code is generated for calls to those functions ๐Ÿšจ
In addition, seriously incorrect code results if you call a function with too many arguments. (Normally, extra arguments are harmlessly ignored.) ๐Ÿ’€

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, bestie, so you only get it if you ask. ๐Ÿ’…

  • -malign-int, -mno-align-int โ€” Okay so this one decides whether int, long, long long, float, double, and long double variables get lined up on a 32-bit boundary (-malign-int) or a 16-bit boundary (-mno-align-int). The 32-bit version runs somewhat faster on processors with 32-bit busses, but it eats more memory. Trade-offs, babe ๐Ÿงš
โš ๏ธ Warning: if you use -malign-int, GCC lines up structures containing those types differently than most published application binary interface specifications for the m68k. Not me being dramatic, this is a real heads-up ๐Ÿ’€
  • -mpcrel โ€” Uses the 68000's pc-relative addressing mode directly, so there's no global offset table. For now this implies -fpic, which allows at most a 16-bit offset for pc-relative addressing. -fPIC isn't supported alongside -mpcrel yet, though it could be for 68020 and higher processors ๐ŸŒธ
  • -mno-strict-align, -mstrict-align โ€” Doesn't assume (-mno-strict-align) or does assume (-mstrict-align) that the system handles unaligned memory references for you ๐Ÿซถ
  • -msep-data โ€” Generates code where the data segment can live in a totally different area of memory from the text segment. This is what makes execute-in-place work without virtual memory management. It implies -fPIC ๐Ÿฆ‹
  • -mno-sep-data โ€” Generates code that assumes the data segment follows the text segment. This is the default ๐Ÿ“
  • -mid-shared-library โ€” Generates code that supports shared libraries through the library ID method. That means execute-in-place and shared libraries, again without virtual memory management. It implies -fPIC โœจ
  • -mno-id-shared-library โ€” Generates code that doesn't assume ID-based shared libraries are in use. This is the default ๐Ÿ’œ
  • -mshared-library-id=n โ€” Sets the identification number of the ID-based shared library being compiled. Using 0 gives you more compact code. Other values force that number onto the current library, but it's no more space- or time-efficient than skipping this option ๐ŸŽ€
  • -mxgot, -mno-xgot โ€” When you're making position-independent code for ColdFire, -mxgot generates code that still works if the GOT has more than 8192 entries. It's bigger and slower than the normal stuff. On M680x0 processors you don't need it, since -fPIC is enough ๐ŸŒˆ

GCC normally loads values from the GOT with a single instruction. That's pretty efficient, but it only works if the GOT is smaller than about 64k. Anything bigger and the linker throws an error that looks something like this:

relocation truncated to fit: R_68K_GOT16O foobar

If you see that, recompile your code with -mxgot. It should then work with very large GOTs. Just know that code built with -mxgot is less efficient, because 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've got one of those, you should only need -mxgot when compiling a single object file that accesses more than 8192 GOT entries. Very few linkers need it, honestly iykyk ๐Ÿ‘‘

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. Main character energy ๐Ÿ‘‘

  • -mhardlit, -mno-hardlit โ€” Inlines constants into the code stream if it can be done in two instructions or less ๐ŸŒธ
  • -mdiv, -mno-div โ€” Uses the divide instruction. (Enabled by default). โœจ
  • -mrelax-immediate, -mno-relax-immediate โ€” Allows arbitrary-sized immediates in bit operations ๐Ÿฆ‹
  • -mwide-bitfields, -mno-wide-bitfields โ€” Always treats bit-fields as "int"-sized ๐ŸŽ€
  • -m4byte-functions, -mno-4byte-functions โ€” Forces all functions to be aligned to a 4-byte boundary ๐Ÿ“
  • -mcallgraph-data, -mno-callgraph-data โ€” Emits callgraph information ๐Ÿงš
  • -mslow-bytes, -mno-slow-bytes โ€” Prefers word access when reading byte quantities ๐Ÿ’…
  • -mlittle-endian, -mbig-endian โ€” Generates code for a little-endian target ๐Ÿ’–
  • -m210, -m340 โ€” Generates code for the 210 processor ๐ŸŒˆ
  • -mno-lsim โ€” Assumes runtime support has already been provided, so it leaves the simulator library (libsim.a) off the linker command line ๐Ÿซถ
  • -mstack-increment=size โ€” Sets the maximum amount for a single stack increment operation. Big 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 ๐Ÿ˜ญ

โœจ MicroBlaze Options โœจ

  • -msoft-float โ€” Uses software emulation for floating point (default) ๐ŸŒธ
  • -mhard-float โ€” Uses hardware floating-point instructions ๐Ÿ”ฅ
  • -mmemcpy โ€” Doesn't optimize block moves, and uses "memcpy" instead ๐Ÿ’œ
  • -mno-clearbss โ€” Deprecated. Use -fno-zero-initialized-in-bss instead ๐Ÿ’€
  • -mcpu=cpu-type โ€” Uses the features of, and schedules code for, the given CPU. Supported values are in the format vX.YY.Z, where X is a major version, YY is the minor version, and Z is compatibility code. Example values are v3.00.a, v4.00.b, v5.00.a, v5.00.b, v6.00.a โœจ
  • -mxl-soft-mul โ€” Uses software multiply emulation (default) ๐ŸŽ€
  • -mxl-soft-div โ€” Uses software emulation for divides (default) ๐Ÿงš
  • -mxl-barrel-shift โ€” Uses the hardware barrel shifter ๐Ÿฆ‹
  • -mxl-pattern-compare โ€” Uses pattern compare instructions ๐Ÿ’–
  • -msmall-divides โ€” Uses table lookup optimization for small signed integer divisions ๐Ÿ“
  • -mxl-stack-check โ€” Deprecated. Use -fstack-check instead ๐Ÿ’€
  • -mxl-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.
    • xmdstub โ€” for use with the Xilinx Microprocessor Debugger (XMD) based software intrusive debug agent called xmdstub. This uses the startup file crt1.o and sets the start address of the program to 0x800.
    • bootstrap โ€” for applications that are loaded using a bootloader. This model uses the startup file crt2.o, which does not contain a processor reset vector handler. It's suitable for handing control to the bootloader on a processor reset instead of the application ๐Ÿงš
    • novectors โ€” for applications that don't need any of the MicroBlaze vectors. This can be useful for apps running inside a monitoring application. This model uses crt3.o as its startup file ๐Ÿฆ‹

Heads up: -xl-mode-app-model is a deprecated alias for -mxl-mode-app-model ๐Ÿ’€

  • -mpic-data-is-text-relative โ€” Assumes the displacement between the text and data segments is fixed at static link time. This lets data be referenced by offset from the start of the text address instead of through the GOT, since PC-relative addressing isn't supported ๐ŸŒˆ

โœจ MIPS Options โœจ

  • -EB โ€” Generates big-endian code ๐Ÿ’–
  • -EL โ€” Generates little-endian code. This is the default for mips*el-*-* configurations ๐ŸŒธ
  • -march=arch โ€” Generates code that runs on arch, which can be the name of a generic MIPS ISA or the name of a particular processor ๐Ÿซถ

The ISA names are: mips1, mips2, mips3, mips4, mips32, mips32r2, mips32r3, mips32r5, mips32r6, mips64, mips64r2, mips64r3, mips64r5 and mips64r6.

The processor names are: 4kc, 4km, 4kp, 4ksc, 4kec, 4kem, 4kep, 4ksd, 5kc, 5kf, 20kc, 24kc, 24kf2_1, 24kf1_1, 24kec, 24kef2_1, 24kef1_1, 34kc, 34kf2_1, 34kf1_1, 34kn, 74kc, 74kf2_1, 74kf1_1, 74kf3_2, 1004kc, 1004kf2_1, 1004kf1_1, i6400, i6500, interaptiv, loongson2e, loongson2f, loongson3a, gs464, gs464e, gs264e, m4k, m14k, m14kc, m14ke, m14kec, m5100, m5101, octeon, octeon+, octeon2, octeon3, orion, p5600, p6600, r2000, r3000, r3900, r4000, r4400, r4600, r4650, r4700, r5900, r6000, r8000, rm7000, rm9000, r10000, r12000, r14000, r16000, sb1, sr71000, vr4100, vr4111, vr4120, vr4130, vr4300, vr5000, vr5400, vr5500, xlr and xlp. The special value from-abi selects the most compatible architecture for the selected ABI (that is, mips1 for 32-bit ABIs and mips3 for 64-bit ABIs) ๐Ÿ‘‘

The native Linux/GNU toolchain also supports the value native, which selects the best architecture option for the host processor. -march=native has no effect if GCC does not recognize the processor ๐Ÿ”ฅ

In processor names, a final 000 can be abbreviated as k (for example, -march=r2k). Prefixes are optional, and vr may be written r ๐Ÿฆ‹

Names of the form nf2_1 refer to processors with FPUs clocked at half the rate of the core, names of the form nf1_1 refer to processors with FPUs clocked at the same rate as the core, and names of the form nf3_2 refer to processors with FPUs clocked at a ratio of 3:2 with respect to the core. For compatibility reasons, nf is accepted as a synonym for nf2_1, while nx and bfx are accepted as synonyms for nf1_1 ๐ŸŽ€

GCC defines two macros based on the value of this option. The first is "_MIPS_ARCH", which gives the name of the target architecture as a string. The second has the form "_MIPS_ARCH_foo", where foo is the capitalized value of "_MIPS_ARCH". For example, -march=r2000 sets "_MIPS_ARCH" to "r2000" and defines the macro "_MIPS_ARCH_R2000" ๐Ÿงš

Note that the "_MIPS_ARCH" macro uses the processor names given above. In other words, it has the full prefix and does not abbreviate 000 as k. In the case of from-abi, the macro names the resolved architecture (either "mips1" or "mips3"). It names the default architecture when no -march option is given ๐Ÿ’–

  • -mtune=arch โ€” okay so this one is all about tuning for one specific chip ๐Ÿ’… It optimizes for arch, and among other things it controls how instructions get scheduled and the perceived cost of arithmetic operations. The list of arch values is the same as for -march.

When you skip this flag, GCC optimizes for whatever processor -march picked. Using -march and -mtune together is the move if you want code that runs on a whole family of processors but gets optimized for one particular member of that family ๐Ÿฆ‹

-mtune also defines the macros _MIPS_TUNE and _MIPS_TUNE_foo, which work the same way as the -march ones we covered above โœจ

  • -mips1 โ€” same as -march=mips1 ๐ŸŒธ
  • -mips2 โ€” same as -march=mips2 ๐ŸŒธ
  • -mips3 โ€” same as -march=mips3 ๐ŸŒธ
  • -mips4 โ€” same as -march=mips4 ๐ŸŒธ
  • -mips32 โ€” same as -march=mips32 ๐ŸŒธ
  • -mips32r3 โ€” same as -march=mips32r3 ๐ŸŒธ
  • -mips32r5 โ€” same as -march=mips32r5 ๐ŸŒธ
  • -mips32r6 โ€” same as -march=mips32r6 ๐ŸŒธ
  • -mips64 โ€” same as -march=mips64 ๐ŸŒธ
  • -mips64r2 โ€” same as -march=mips64r2 ๐ŸŒธ
  • -mips64r3 โ€” same as -march=mips64r3 ๐ŸŒธ
  • -mips64r5 โ€” same as -march=mips64r5 ๐ŸŒธ
  • -mips64r6 โ€” same as -march=mips64r6 ๐ŸŒธ
  • -mips16, -mno-mips16 โ€” okay this is the MIPS16 toggle ๐Ÿงš -mips16 makes GCC generate MIPS16 code, and -mno-mips16 says "absolutely not" to it. If you're targeting MIPS32 or MIPS64, GCC uses the MIPS16e ASE to get there.

MIPS16 generation can also be controlled per function with the "mips16" and "nomips16" attributes, so you can be extra specific about which functions get the treatment ๐Ÿ’œ

  • -mmips16e2, -mno-mips16e2 โ€” use (or don't use) the MIPS16e2 ASE. This one changes how -mips16 behaves, because it makes that flag target the MIPS16e2 ASE instead ๐ŸŽ€
  • -mflip-mips16 โ€” generates MIPS16 code on alternating functions. This is only here for regression testing of mixed MIPS16/non-MIPS16 code generation, so please don't use it for your everyday code. It is not intended for ordinary use in compiling user code ๐Ÿ™ˆ
  • -minterlink-compressed, -mno-interlink-compressed โ€” require (or don't require) that code using the standard (uncompressed) MIPS ISA be link-compatible with MIPS16 and microMIPS code, and the other way around too ๐Ÿ”—

For example, code using the standard ISA encoding can't jump directly to MIPS16 or microMIPS code. It has to use a call or an indirect jump instead. So -minterlink-compressed disables direct jumps unless GCC knows the jump target isn't compressed ๐Ÿ’…

  • -minterlink-mips16, -mno-interlink-mips16 โ€” these are just aliases of -minterlink-compressed and -mno-interlink-compressed. They're older than the microMIPS ASE and only hang around for backwards compatibility ๐Ÿง“
  • -mabi=32, -mabi=o64, -mabi=n32, -mabi=64, -mabi=eabi โ€” generate code for the ABI you pick ๐Ÿ‘‘

Heads up: the EABI comes in a 32-bit and a 64-bit variant. GCC normally makes 64-bit code when you pick a 64-bit architecture, but if you want 32-bit code anyway, use -mgp32 ๐Ÿซถ

If you want the details on the O64 ABI, check out <https://gcc.gnu.org/projects/mipso64-abi.html> ๐Ÿ“š

GCC also supports a version of the o32 ABI where the floating-point registers are 64 bits wide instead of 32. You get this combo with -mabi=32 -mfp64. This ABI depends 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 rides in a single 64-bit register instead of a pair of 32-bit ones. So for example, scalar floating-point values get returned in $f0 only, not a $f0/$f1 pair. The set of call-saved registers also stays the same, meaning the even-numbered double-precision registers are the ones that get saved โœจ

Two more variants of the o32 ABI exist to help with the jump from 32-bit to 64-bit registers. They're FPXX (-mfpxx) and FP64A (-mfp64 -mno-odd-spreg) ๐Ÿฆ‹ The FPXX extension says all code has to run correctly with 32-bit or 64-bit registers. It can be interlinked with either FP32 or FP64, but never both at once. FP64A is kind of like FP64, except it forbids the use of odd-numbered single-precision registers. It can be paired with the "FRE" mode of FPUs in MIPS32R5 processors, which lets FP32 and FP64A code interlink and run in the same process without changing FPU modes ๐ŸŒˆ

  • -mabicalls, -mno-abicalls โ€” generate (or don't generate) code that works with SVR4-style dynamic objects. -mabicalls is the default on SVR4-based systems ๐Ÿ“
  • -mshared, -mno-shared โ€” generate (or don't generate) code that's fully position-independent, so it can be linked into shared libraries. This option only affects -mabicalls ๐Ÿงš

All -mabicalls code has traditionally been position-independent, no matter what you pass like -fPIC or -fpic. BUT, as an extension, the GNU toolchain lets executables use absolute accesses for locally-binding symbols. It can also use shorter GP initialization sequences and generate direct calls to locally-defined functions. That mode gets selected by -mno-shared ๐Ÿ’–

-mno-shared depends on binutils 2.16 or higher, and it generates objects that can only be linked by the GNU linker. The good news is it doesn't change the ABI of the final executable. It only changes the ABI of relocatable objects. Using -mno-shared generally makes executables both smaller and quicker ๐ŸŽ๏ธ

-mshared is the default โœจ

  • -mplt, -mno-plt โ€” assume (or don't assume) that the static and dynamic linkers support PLTs and copy relocations. This only affects -mno-shared -mabicalls. For the n64 ABI, this option does nothing without -msym32 ๐Ÿคทโ€โ™€๏ธ

You can make -mplt the default by configuring GCC with --with-mips-plt. Otherwise the default is -mno-plt ๐Ÿ’…

  • -mxgot, -mno-xgot โ€” lift (or don't lift) the usual restrictions on the size of the global offset table ๐ŸŒธ

GCC normally uses a single instruction to load values from the GOT. It's pretty efficient, but it only works if the GOT is smaller than about 64k. Anything bigger makes the linker report an error like this:

relocation truncated to fit: R_MIPS_GOT16 foobar

If that happens, recompile your code with -mxgot. It works with very large GOTs, but the code is less efficient because it takes three instructions to fetch the value of a global symbol ๐Ÿ˜ญ

Some linkers can create multiple GOTs. If you have one of those, you should only need -mxgot when a single object file accesses more than 64k's worth of GOT entries. Very few linkers do that, honestly ๐Ÿ™ˆ

These options have no effect unless GCC is generating position-independent code ๐Ÿซถ

  • -mgp32 โ€” assumes general-purpose registers are 32 bits wide ๐ŸŽ€
  • -mgp64 โ€” assumes general-purpose registers are 64 bits wide ๐ŸŽ€
  • -mfp32 โ€” assumes floating-point registers are 32 bits wide ๐ŸŒˆ
  • -mfp64 โ€” assumes floating-point registers are 64 bits wide ๐ŸŒˆ
  • -mfpxx โ€” doesn't assume anything about the width of floating-point registers ๐Ÿฆ‹
  • -mhard-float โ€” use the floating-point coprocessor instructions ๐Ÿ’ช
  • -msoft-float โ€” don't use the floating-point coprocessor instructions. Floating-point math gets done with library calls instead ๐Ÿ“š
  • -mno-float โ€” same as -msoft-float, but it also swears that the program being compiled does zero floating-point operations ๐Ÿ™…โ€โ™€๏ธ Right now this is only supported by some bare-metal MIPS configurations, where it might pick a special set of libraries that have no floating-point support at all. That includes stuff like the floating-point "printf" formats.
If code compiled with -mno-float accidentally has floating-point operations in it, it's likely to fail at link time or at run time. Be careful, bestie ๐Ÿ’€
  • -msingle-float โ€” assumes the floating-point coprocessor only supports single-precision operations ๐ŸŒธ
  • -mdouble-float โ€” assumes the floating-point coprocessor supports double-precision operations. This is the default ๐Ÿ’–
  • -modd-spreg, -mno-odd-spreg โ€” enable (or disable) the use of odd-numbered single-precision floating-point registers for the o32 ABI. Enabled is the default for processors known to support these registers. When you're using the o32 FPXX ABI, -mno-odd-spreg gets set by default ๐Ÿงš
  • -mabs=2008, -mabs=legacy โ€” these control how the special not-a-number (NaN) IEEE 754 floating-point data gets treated by the abs.fmt and neg.fmt machine instructions ๐Ÿ”

By default, or when you use -mabs=legacy, you get the legacy treatment. Here those instructions count as arithmetic, so GCC avoids them wherever correct operation matters and the input might be a NaN. Instead it uses a longer sequence of instructions that manually manipulates the sign bit of the floating-point datum, unless -ffinite-math-only was also specified ๐Ÿซ 

-mabs=2008 selects the IEEE 754-2008 treatment. In this case those instructions count as non-arithmetic, so they work correctly in all cases, including when the input operand is a NaN. That means these instructions are always used for the respective operations ๐Ÿ”ฅ

  • -mnan=2008, -mnan=legacy โ€” these control how the special not-a-number (NaN) IEEE 754 floating-point data gets encoded ๐ŸŒˆ

-mnan=legacy selects the legacy encoding. Here, quiet NaNs (qNaNs) are marked by the first bit of their trailing significand field being 0, while signaling NaNs (sNaNs) are marked by that first bit being 1 ๐Ÿ’œ

-mnan=2008 selects the IEEE 754-2008 encoding. Here, qNaNs are marked by the first bit of their trailing significand field being 1, while sNaNs are marked by that first bit being 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 the atomic memory built-in functions. If you specify neither option, GCC uses those instructions as long as the target architecture supports them ๐Ÿ’…

Okay so -mllsc is clutch when the runtime can emulate those instructions, and -mno-llsc slays when you're compiling for nonstandard ISAs ๐Ÿ”ง. You can make either one the default by configuring GCC with --with-llsc or --without-llsc, respectively. Heads up: --with-llsc is already the default for some configurations, so check the installation docs for the deets ๐Ÿ“š.

  • -mdsp, -mno-dsp โ€” Use (do not use) revision 1 of the MIPS DSP ASE ๐Ÿ’–
    • This option defines the preprocessor macro __mips_dsp. It also defines __mips_dsp_rev to 1.
  • -mdspr2, -mno-dspr2 โ€” Use (do not use) revision 2 of the MIPS DSP ASE โœจ
    • This option defines the preprocessor macros __mips_dsp and __mips_dspr2. It also defines __mips_dsp_rev to 2.
  • -msmartmips, -mno-smartmips โ€” Use (do not use) the MIPS SmartMIPS ASE ๐ŸŽ€
  • -mpaired-single, -mno-paired-single โ€” Use (do not use) paired-single floating-point instructions ๐Ÿฆ‹
    • This option requires hardware floating-point support to be enabled.
  • -mdmx, -mno-mdmx โ€” Use (do not use) MIPS Digital Media Extension instructions ๐ŸŒธ
    • This option can only be used when generating 64-bit code and requires hardware floating-point support to be enabled.
  • -mips3d, -mno-mips3d โ€” Use (do not use) the MIPS-3D ASE ๐Ÿงš
    • The option -mips3d implies -mpaired-single.
  • -mmicromips, -mno-micromips โ€” Generate (do not generate) microMIPS code ๐Ÿ’œ
    • MicroMIPS code generation can also be controlled on a per-function basis by means of micromips and nomicromips attributes.
  • -mmt, -mno-mt โ€” Use (do not use) MT Multithreading instructions ๐Ÿซถ
  • -mmcu, -mno-mcu โ€” Use (do not use) the MIPS MCU ASE instructions ๐Ÿ“
  • -meva, -mno-eva โ€” Use (do not use) the MIPS Enhanced Virtual Addressing instructions ๐Ÿ‘‘
  • -mvirt, -mno-virt โ€” Use (do not use) the MIPS Virtualization (VZ) instructions ๐ŸŒˆ
  • -mxpa, -mno-xpa โ€” Use (do not use) the MIPS eXtended Physical Address (XPA) instructions โญ
  • -mcrc, -mno-crc โ€” Use (do not use) the MIPS Cyclic Redundancy Check (CRC) instructions ๐Ÿ’…
  • -mginv, -mno-ginv โ€” Use (do not use) the MIPS Global INValidate (GINV) instructions ๐Ÿ”ฅ
  • -mloongson-mmi, -mno-loongson-mmi โ€” Use (do not use) the MIPS Loongson MultiMedia extensions Instructions (MMI) ๐ŸŽ€
  • -mloongson-ext, -mno-loongson-ext โ€” Use (do not use) the MIPS Loongson EXTensions (EXT) instructions ๐Ÿฆ‹
  • -mloongson-ext2, -mno-loongson-ext2 โ€” Use (do not use) the MIPS Loongson EXTensions r2 (EXT2) instructions ๐ŸŒธ
  • -mlong64 โ€” Force long types to be 64 bits wide ๐Ÿ’–
    • See -mlong32 for an explanation of the default and the way that the pointer size is determined.
  • -mlong32 โ€” Force long, int, and pointer types to be 32 bits wide ๐Ÿงš
    • The default size of ints, longs and pointers depends on the ABI. All the supported ABIs use 32-bit ints. The n64 ABI uses 64-bit longs, as does the 64-bit EABI; the others use 32-bit longs. Pointers are the same size as longs, or the same size as integer registers, whichever is smaller.
  • -msym32, -mno-sym32 โ€” Assume (do not assume) that all symbols have 32-bit values, regardless of the selected ABI ๐ŸŒˆ
    • This option is useful in combination with -mabi=64 and -mno-abicalls because it allows GCC to 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 (do not extend) the -G behavior to local data too, such as to static variables in C โœจ
    • -mlocal-sdata is the default for all configurations.
    • If the linker complains that an application is using too much small data, you might want to try rebuilding the less performance-critical parts with -mno-local-sdata. You might also want to build large libraries with -mno-local-sdata, so that the libraries leave more room for the main program.
  • -mextern-sdata, -mno-extern-sdata โ€” Assume (do not assume) that externally-defined data is in a small data section if the size of that data is within the -G limit ๐Ÿซถ
    • -mextern-sdata is the default for all configurations.
    • If you compile a module Mod with -mextern-sdata -G num -mgpopt, and Mod references a variable Var that is no bigger than num bytes, you must make sure that Var is placed in a small data section. If Var is defined by another module, 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 of satisfying these restrictions is to compile and link every module with the same -G option. However, you may wish to build a library that supports several different small data limits. You can do this by compiling the library with the highest supported -G setting and additionally using -mno-extern-sdata to stop the library from making assumptions about externally-defined data.
  • -mgpopt, -mno-gpopt โ€” Use (do not use) GP-relative accesses for symbols that are known to be in a small data section; see -G, -mlocal-sdata and -mextern-sdata ๐Ÿ”ฅ
    • -mgpopt is the default for all configurations.
    • -mno-gpopt is useful for cases where the $gp register might not hold the value of _gp. For example, if the code is part of a library that might be used in a boot monitor, programs that call boot monitor routines pass an unknown value in $gp. (In such situations, the boot monitor itself is usually compiled with -G0.)
    • -mno-gpopt implies -mno-local-sdata and -mno-extern-sdata.
  • -membedded-data, -mno-embedded-data โ€” Allocate variables to the read-only data section first if possible, then next in the small data section if possible, otherwise in data ๐ŸŒธ
    • This gives slightly slower code than the default, but reduces the amount of RAM required when executing, and thus may be preferred for some embedded systems.
  • -muninit-const-in-rodata, -mno-uninit-const-in-rodata โ€” Put uninitialized const variables in the read-only data section ๐Ÿ“
    • This option is only meaningful in conjunction with -membedded-data.
  • -mcode-readable=setting โ€” Specify whether GCC may generate code that reads from executable sections ๐Ÿ’–
    • There are three possible settings:
      • -mcode-readable=yes โ€” Instructions may freely access executable sections. This is the default setting. ๐Ÿฆ‹
      • -mcode-readable=pcrel โ€” MIPS16 PC-relative load instructions can access executable sections, but other instructions must not do so. This option is useful on 4KSc and 4KSd processors when the code TLBs have the Read Inhibit bit set. It is also useful on processors that can be configured to have a dual instruction/data SRAM interface and that, like the M4K, automatically redirect PC-relative loads to the instruction RAM. ๐Ÿงš
      • -mcode-readable=no โ€” Instructions must not access executable sections. This option can be useful on targets that are configured to have a dual instruction/data SRAM interface but that (unlike the M4K) do not automatically redirect PC-relative loads to the instruction RAM. ๐Ÿ’œ
  • -msplit-addresses, -mno-split-addresses โ€” Enable (disable) use of the %hi() and %lo() assembler relocation operators ๐ŸŒˆ
    • This option has been superseded by -mexplicit-relocs but is retained for backwards compatibility.
  • -mexplicit-relocs=none, -mexplicit-relocs=base, -mexplicit-relocs=pcrel, -mexplicit-relocs, -mno-explicit-relocs โ€” These options control whether explicit relocs (such as %gp_rel) are used โญ
    • The default value depends on the version of GAS when GCC itself was built.
    • The base explicit-relocs support was introduced into GAS in 2001.
    • The pcrel explicit-relocs support was introduced into GAS in 2014, and it supports %pcrel_hi and %pcrel_lo.
  • -mcheck-zero-division, -mno-check-zero-division โ€” Trap (do not 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 ๐Ÿ”ฅ
    • Using traps results in smaller code, but is only supported on MIPS II and later. Also, some versions of the Linux kernel have a bug that prevents trap from generating the proper signal (SIGFPE). Use -mdivide-traps to allow conditional traps on architectures that support them and -mdivide-breaks to force the use of breaks.
    • The default is usually -mdivide-traps, but this can be overridden at configure time using --with-divide=breaks. Divide-by-zero checks can be completely disabled using -mno-check-zero-division.
  • -mload-store-pairs, -mno-load-store-pairs โ€” Enable (disable) an optimization that pairs consecutive load or store instructions to enable load/store bonding ๐ŸŽ€
    • This option is enabled by default but only takes effect when the selected architecture is known to support bonding.
  • -mstrict-align, -mno-strict-align, -munaligned-access, -mno-unaligned-access โ€” Disable (enable) direct unaligned access for MIPS Release 6 ๐Ÿฆ‹
    • MIPSr6 requires load/store unaligned-access support, by hardware or trap&emulate. So -mstrict-align may be needed by kernel.
    • > The options -munaligned-access and -mno-unaligned-access are obsoleted, and only for backward-compatible.
  • -mmemcpy, -mno-memcpy โ€” Force (do not force) the use of memcpy for non-trivial block moves ๐ŸŒธ
    • The default is -mno-memcpy, which allows GCC to inline most constant-sized copies.
  • -mlong-calls, -mno-long-calls โ€” Disable (do not disable) use of the jal instruction ๐Ÿงš
    • Calling functions using jal is more efficient but requires the caller and callee to be in the same 256 megabyte segment.
    • This option has no effect on abicalls code. The default is -mno-long-calls.
  • -mmad, -mno-mad โ€” Enable (disable) use of the mad, madu and mul instructions, as provided by the R4650 ISA ๐Ÿ’œ
  • -mimadd, -mno-imadd โ€” okay so these turn the madd and msub integer instructions on (-mimadd) or off (-mno-imadd) ๐Ÿ’… The default is -mimadd on architectures that support madd and msub, except the 74k architecture, where it was found to generate slower code ๐Ÿข
  • -mfused-madd, -mno-fused-madd โ€” this one enables or disables the floating-point multiply-accumulate instructions whenever they're available โœจ The default is -mfused-madd.
    • Heads up, bestie ๐Ÿ’€ On the R8000 CPU, when multiply-accumulate instructions are used, the intermediate product is calculated to infinite precision and is not subject to the FCSR Flush to Zero bit. This may be undesirable in some circumstances.
    • On other processors, the result is numerically identical to the equivalent computation using separate multiply, add, subtract and negate instructions.
  • -nocpp โ€” tells the MIPS assembler to skip its preprocessor when it assembles user assembler files with a .s suffix ๐Ÿงš
  • -mfix-24k, -mno-fix-24k โ€” works around the 24K E48 errata (lost data on stores during refill) ๐Ÿ› ๏ธ The assembler handles these workarounds, not 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 โ€” basically, don't try to schedule the preceding instruction into the delay slot of a branch sitting at the end of a short loop of six instructions or fewer. Always put a nop there instead ๐Ÿ™ˆ The short loop bug can make loops run only once or twice because of a hardware bug in the R5900 chip. The assembler does this workaround, not GCC.
  • -mfix-rm7000, -mno-fix-rm7000 โ€” works around the RM7000 dmult/dmultu errata ๐Ÿ’œ The assembler handles the workarounds, not GCC.
  • -mfix-vr4120, -mno-fix-vr4120 โ€” works around certain VR4120 errata ๐Ÿฆ‹
    • dmultu does not always produce the correct result.
    • div and ddiv do not always produce the correct result if one of the operands is negative.
    • The workarounds for the division errata rely on special functions in libgcc.a. At present, these functions are only provided by the mips64vr*-elf configurations.
    • Other VR4120 errata require a NOP to be inserted between certain pairs of instructions. These are handled by the assembler, not by GCC itself.
  • -mfix-vr4130 โ€” works around the VR4130 mflo/mfhi errata โœจ The assembler does the workarounds, 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 only works around the SB-1 revision 2 "F1" and "F2" floating-point errata.)
  • -mr10k-cache-barrier=setting โ€” decides whether GCC should insert cache barriers to avoid the side effects of speculation on R10K processors ๐Ÿ‘‘
    • Like lots of processors, the R10K tries to guess the outcome of a conditional branch and speculatively runs instructions from the "taken" branch. It later aborts them if the guess was wrong. But on the R10K, even aborted instructions can leave side effects behind.
    • This problem only affects kernel stores and, depending on the system, kernel loads. For example, a speculatively-executed store may load the target memory into cache and mark the cache line as dirty, even if the store itself is later aborted. If a DMA operation writes to the same area of memory before the "dirty" line is flushed, the cached data overwrites the DMA-ed data. See the R10K processor manual for a full description, including other potential problems.
    • One workaround is to insert cache barrier instructions before every memory access that might be speculatively executed and that might have side effects even if aborted. -mr10k-cache-barrier=setting controls GCC's implementation of this workaround. It assumes that aborted accesses to any byte in the following regions do not have side effects:
      1. the memory occupied by the current function's stack frame;
      2. the memory occupied by an incoming stack argument;
      3. the memory occupied by an object with a link-time-constant address.
    • It is the kernel's responsibility to ensure that speculative accesses to these regions are indeed safe.
    • If the input program contains a function declaration such as void foo (void);, then the implementation of foo must allow j foo and jal foo to be executed speculatively. GCC honors this restriction for functions it compiles itself. It expects non-GCC functions (such as hand-written assembly code) to do the same.
    • The option has three forms:
      • -mr10k-cache-barrier=load-store โ€” inserts a cache barrier before a load or store that might be speculatively executed and that might have side effects even if aborted.
      • -mr10k-cache-barrier=store โ€” inserts a cache barrier before a store that might be speculatively executed and that might have side effects even if aborted.
      • -mr10k-cache-barrier=none โ€” disables the insertion of cache barriers. This is the default setting.
  • -mflush-func=func, -mno-flush-func โ€” picks the function to call to flush the I and D caches, or tells GCC to not call any such function ๐Ÿงน If it's called, the function must take the same arguments as the common _flush_func: the address of the memory range being flushed, the size of that memory range, and the number 3 (to flush both caches). The default depends on the target GCC was configured for, but it's commonly either _flush_func or __cpu_flush.
  • -mbranch-cost=num โ€” sets the cost of branches to roughly num "simple" instructions ๐Ÿ’– This cost is only a heuristic and isn't guaranteed to produce 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 default is for the selected architecture ๐ŸŒˆ By default, Branch Likely instructions may be generated if the selected architecture supports them. The exception is the MIPS32 and MIPS64 architectures, plus processors that implement those architectures. For those, Branch Likely instructions are not generated by default, because the MIPS32 and MIPS64 architectures specifically deprecate their use.
  • -mcompact-branches=never, -mcompact-branches=optimal, -mcompact-branches=always โ€” these control which form of branches gets generated ๐Ÿฆ„ The default is -mcompact-branches=optimal.
    • -mcompact-branches=never ensures that compact branch instructions are never generated.
    • -mcompact-branches=always ensures that a compact branch instruction is generated if one is available, for MIPS Release 6 onwards. If a compact branch instruction is not available (or the target is pre-R6), a delay slot form of the branch is used instead.
    • If it's used for MIPS16/microMIPS targets, it will just be ignored for now. The behaviour for MIPS16/microMIPS may change in the future, since they do have some compact branch instructions.
    • -mcompact-branches=optimal causes a delay slot branch to be used if one is available in the current ISA and the delay slot is successfully filled. If the delay slot isn't filled, a compact branch is chosen if one is available.
  • -mfp-exceptions, -mno-fp-exceptions โ€” specifies whether FP exceptions are enabled โญ This affects how FP instructions get scheduled for some processors. The default is that FP exceptions are enabled.
    • For instance, on the SB-1, if FP exceptions are disabled and we're emitting 64-bit code, then we can use both FP pipes. Otherwise, we can only use one FP pipe.
  • -mvr4130-align, -mno-vr4130-align โ€” the VR4130 pipeline is two-way superscalar, but it can only issue two instructions together if the first one is 8-byte aligned ๐Ÿ“ When this option is enabled, GCC aligns pairs of instructions that it thinks should execute in parallel.
    • This option only has an effect when optimizing for the VR4130. It normally makes code faster, but at the expense of making it bigger. It is enabled by default at optimization level -O3.
  • -msynci, -mno-synci โ€” enables (or disables) generation of synci instructions on architectures that support it ๐Ÿ”ฅ The synci instructions (if enabled) are generated when __builtin___clear_cache is compiled.
    • This option defaults to -mno-synci, but the default can be overridden by configuring GCC with --with-synci.
    • > When compiling code for single-processor systems, it is generally safe to use synci. However, on many multi-core (SMP) systems, it does not 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.

Okay so -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, the assembler and linker can handle this optimization all on their own, no compiler help needed ๐Ÿฆ‹

  • -mmcount-ra-address, -mno-mcount-ra-address โ€” Okay, this one is giving return address drama ๐ŸŽ€ With -mmcount-ra-address, GCC emits code that lets _mcount change the calling function's return address. It basically extends the usual _mcount interface with a new ra-address parameter. That parameter is type intptr_t * and gets passed in register $12. So _mcount can change the return address by doing both of these:
    • Returning the new address in register $31.
    • Storing the new address in *ra-address, but only if ra-address is nonnull.

The default is -mno-mcount-ra-address ๐Ÿ’–

  • -mframe-header-opt, -mno-frame-header-opt โ€” This one is a lil bit of stack tidying โœจ In the o32 ABI, calling functions normally reserve 16 bytes on the stack so the called function has somewhere to write out its register arguments. With -mframe-header-opt, GCC skips reserving that frame header if it can tell it's unused. -mno-frame-header-opt turns that off. This optimization is off by default at all optimization levels ๐ŸŒธ
  • -mlxc1-sxc1, -mno-lxc1-sxc1 โ€” When it applies, -mlxc1-sxc1 lets GCC generate lwxc1, swxc1, ldxc1 and sdxc1 instructions, and -mno-lxc1-sxc1 stops it. It's enabled by default ๐Ÿฆ‹
  • -mmadd4, -mno-madd4 โ€” When it applies, -mmadd4 lets GCC generate 4-operand madd.s, madd.d and related instructions. -mno-madd4 says no thanks. Enabled by default ๐Ÿ’œ

๐ŸŒธ MMIX Options ๐ŸŒธ

These options are defined for the MMIX ๐Ÿงš

  • -mlibfuncs, -mno-libfuncs โ€” -mlibfuncs says you're compiling intrinsic library functions, so every value gets passed in registers, no matter how big it is. -mno-libfuncs is the opposite vibe ๐Ÿ“
  • -mepsilon, -mno-epsilon โ€” -mepsilon makes GCC generate floating-point comparison instructions that compare with respect to the rE epsilon register. -mno-epsilon skips that โœจ
  • -mabi=mmixware, -mabi=gnu โ€” -mabi=mmixware generates code where function parameters and return values are seen as registers $0 and up, in the called function. The GNU ABI, on the other hand, uses global registers $231 and up. Pick your fighter ๐Ÿ‘‘
  • -mzero-extend, -mno-zero-extend โ€” When reading data from memory in sizes shorter than 64 bits, -mzero-extend uses zero-extending load instructions by default, instead of sign-extending ones. -mno-zero-extend means don't use them ๐ŸŒˆ
  • -mknuthdiv, -mno-knuthdiv โ€” -mknuthdiv makes the remainder of a division have the same sign as the divisor. With the default, -mno-knuthdiv, the remainder's sign follows the sign of the dividend. Both methods are arithmetically valid, but the latter is the one almost everyone uses ๐Ÿงฎ
  • -mtoplevel-symbols, -mno-toplevel-symbols โ€” -mtoplevel-symbols puts a : in front of all global symbols, so your assembly code can work with the PREFIX assembly directive. -mno-toplevel-symbols doesn't add the colon ๐Ÿ’…
  • -melf โ€” Generates an executable in the ELF format, instead of the default mmo format that the mmix simulator uses ๐Ÿฆ‹
  • -mbranch-predict, -mno-branch-predict โ€” -mbranch-predict uses the probable-branch instructions when static branch prediction says a branch is probable. -mno-branch-predict doesn't use them ๐Ÿ”ฅ
  • -mbase-addresses, -mno-base-addresses โ€” -mbase-addresses generates code that uses base addresses. Using a base address automatically makes a request, which the assembler and linker take care of, for a constant to be set up in a global register. That register then gets 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 you can address is limited. So if your program has lots of static data, you might need -mno-base-addresses ๐Ÿ™ˆ
  • -msingle-exit, -mno-single-exit โ€” -msingle-exit forces the generated code to have a single exit point in each function. -mno-single-exit doesn't force that ๐ŸŽ€

๐Ÿ“ MN10300 Options ๐Ÿ“

These -m options are defined for Matsushita MN10300 architectures ๐ŸŒˆ

  • -mmult-bug โ€” Generates code that avoids bugs in the multiply instructions for MN10300 processors. This is the default ๐Ÿ’–
  • -mno-mult-bug โ€” Does not generate code to avoid those multiply bugs for MN10300 processors โญ
  • -mam33 โ€” Generates code using features specific to the AM33 processor โœจ
  • -mno-am33 โ€” Does not generate code using AM33-specific features. This is the default ๐Ÿซถ
  • -mam33-2 โ€” Generates code using features specific to the AM33/2.0 processor ๐Ÿฆ‹
  • -mam34 โ€” Generates code using features specific to the AM34 processor ๐ŸŒธ
  • -mtune=cpu-type โ€” Uses the timing characteristics of the CPU type you give when scheduling instructions. This does not change the targeted processor type. The CPU type must be one of mn10300, am33, am33-2 or am34 ๐Ÿงš
  • -mreturn-pointer-on-d0 โ€” When generating a function that returns a pointer, the pointer gets returned in both a0 and d0. Otherwise, the pointer is only returned in a0, and trying to call those functions without a prototype results in errors. Note that this option is on by default, so use -mno-return-pointer-on-d0 to turn it off ๐Ÿ’…
  • -mno-crt0 โ€” Does not link in the C run-time initialization object file ๐Ÿ™ˆ
  • -mrelax โ€” Tells the linker to run a relaxation optimization pass that shortens branches, calls and absolute memory addresses. This option only has an effect when it's used on the command line for the final link step.
Heads up: this option makes symbolic debugging impossible ๐Ÿ’€
  • -mliw โ€” Lets the compiler generate Long Instruction Word instructions if the target is AM33 or later. This is the default. This option defines the preprocessor macro __LIW__ ๐Ÿ”ฅ
  • -mno-liw โ€” Stops the compiler from generating Long Instruction Word instructions. This option defines the preprocessor macro __NO_LIW__ ๐ŸŒˆ
  • -msetlb โ€” Lets the compiler generate SETLB and Lcc instructions if the target is AM33 or later. This is the default. This option defines the preprocessor macro __SETLB__ ๐Ÿ‘‘
  • -mno-setlb โ€” Stops the compiler from generating SETLB or Lcc instructions. This option defines the preprocessor macro __NO_SETLB__ ๐Ÿ’œ

๐Ÿงš Moxie Options ๐Ÿงš

  • -meb โ€” Generates big-endian code. This is the default for moxie-*-* configurations ๐ŸŒธ
  • -mel โ€” Generates little-endian code ๐Ÿฆ‹
  • -mmul.x โ€” Generates mul.x and umul.x instructions. This is the default for moxiebox-*-* configurations โœจ
  • -mno-crt0 โ€” Does not link in the C run-time initialization object file ๐ŸŽ€

๐Ÿ’œ MSP430 Options ๐Ÿ’œ

These options are defined for the MSP430 ๐Ÿซถ

  • -masm-hex โ€” Forces assembly output to always use hex constants. Normally these constants are signed decimals, but this option is there for testsuite and/or aesthetic purposes ๐Ÿ’…
  • -mmcu= โ€” Selects the MCU to target. This creates a C preprocessor symbol based on the MCU name, converted to upper case and pre- and post-fixed with __. The msp430.h header file then uses that symbol to pick an MCU-specific supplementary header file ๐Ÿงš

This option also sets the ISA to use. If the MCU name is one that's known to only support the 430 ISA, that one gets selected. Otherwise, the 430X ISA is selected. The generic MCU name msp430 can also be used to select 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 supported for the different MCUs are hard-coded into GCC. However, an external devices.csv file can extend device support beyond those hard-coded ones ๐Ÿ“

GCC searches for devices.csv using the methods below, in this precedence order. 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 of the directories specified by include paths and linker library search paths.
  2. Path specified by the environment variable MSP430_GCC_INCLUDE_DIR: Set the global environment variable MSP430_GCC_INCLUDE_DIR to the full path of the directory containing devices.csv, and GCC will search that directory for devices.csv. If devices.csv is found there, the directory also gets registered as an include path and a linker library path. Header files and linker scripts in this directory can then be used without manually specifying -I and -L on the command line โœจ
  3. The msp430-elf{,bare}/include/devices directory: GCC will examine msp430-elf{,bare}/include/devices from the toolchain root directory. This directory doesn't exist in a default installation, but if you've created it and copied devices.csv into it, the MCU data gets read. As above, this directory also gets registered as an include path and a linker library path ๐ŸŒธ

If none of the above search methods find devices.csv, the hard-coded MCU data is used ๐Ÿ’–

  • -mwarn-mcu, -mno-warn-mcu โ€” -mwarn-mcu turns on warnings about conflicts between the MCU name set by -mmcu and the ISA set by -mcpu and/or the hardware multiply support set by -mhwmult. It also toggles warnings about unrecognized MCU names. This option is on by default. -mno-warn-mcu turns all of those warnings off ๐Ÿ™ˆ
  • -mcpu= โ€” Specifies the ISA to use. Accepted values are msp430, msp430x and msp430xv2.
Deprecated: this option is deprecated. The -mmcu= option should be used to select the ISA ๐Ÿ’€
  • -msim โ€” Links to the simulator runtime libraries and linker script. This overrides any scripts that would be selected by the -mmcu= option ๐Ÿ”ฅ
  • -mlarge โ€” Uses large-model addressing, with 20-bit pointers and a 20-bit size_t ๐Ÿ‘‘
  • -msmall โ€” Uses small-model addressing, with 16-bit pointers and a 16-bit size_t ๐ŸŒˆ
  • -mrelax โ€” This option gets passed to the assembler and linker, and it lets the linker do certain optimizations that can't happen until the final link ๐Ÿฆ‹
  • -mhwmult= โ€” okay so this one tells GCC what kind of hardware multiply your chip actually has ๐Ÿงฎโœจ The accepted values are:
    • none โ€” no hardware multiply, bestie ๐Ÿ’€
    • 16bit โ€” the original 16-bit-only multiply from the early MCUs ๐ŸŒธ
    • 32bit โ€” the 16/32-bit multiply on the later MCUs ๐Ÿ”ฅ
    • f5series โ€” the 16/32-bit multiply on F5-series MCUs ๐Ÿ‘‘
    • auto โ€” the default ๐Ÿ’… It tells GCC to figure out the hardware multiply support from the MCU name you gave to -mmcu. If you skip -mmcu or the MCU name isn't recognized, GCC assumes no hardware multiply support at all.

Hardware multiplies usually get handled by calling a library routine, which saves space in the generated code ๐ŸŽ€ But when you compile at -O3 or higher, the hardware multiplier gets invoked inline instead. That makes the code bigger but faster, so it's a total glow-up trade-off ๐Ÿฆ‹

The hardware multiply routines turn off interrupts while they run and then restore the previous interrupt state when they're done ๐Ÿซถ That's the reason they're safe to use inside interrupt handlers as well as in normal code โœจ

  • -minrt โ€” enables a minimum runtime environment, which means no static initializers or constructors ๐Ÿงš It's made for memory-constrained devices. The compiler slips special symbols into some objects so the linker and runtime know which code fragments are required ๐Ÿ’œ
  • -mtiny-printf โ€” enables reduced code size printf and puts library functions ๐ŸŒˆ Heads up though: these tiny versions are not reentrant, so you have to be careful with them in multi-threaded apps ๐Ÿ˜ญ

Stream support has been removed, so the string you print always goes to stdout through the write syscall. It isn't buffered before it gets sent to write ๐Ÿ’… This option requires Newlib Nano IO, which means GCC must be configured with --enable-newlib-nano-formatted-io ๐Ÿ“

  • -mmax-inline-shift= โ€” takes an integer from 0 to 64 inclusive and sets the maximum number of inline shift instructions that can be emitted for a shift by a constant amount ๐Ÿฆ‹ Once that limit would be exceeded, an mspabi helper function gets used instead. The default is 4 โœจ

This only matters when a shift by multiple positions can't be done with one instruction, like all shifts greater than 1 on the 430 ISA ๐Ÿ™ˆ Shifts of a 32-bit value are at least twice as costly, so the value you pass gets divided by 2 and that result is used instead ๐Ÿงฎ

  • -mcode-region= and -mdata-region= โ€” these tell the compiler where to put 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. The first three behave like the matching attribute, and any is the default ๐ŸŒธ With any, placement is left entirely up to the linker script and how it assigns the standard sections (.text, .data, etc.) to the memory regions ๐Ÿซถ
  • -msilicon-errata= โ€” passes a request to the assembler to enable the fixes for the named silicon errata ๐Ÿ”งโœจ
  • -msilicon-errata-warn= โ€” passes a request to the assembler to turn on warning messages for when a silicon errata might need to be applied ๐Ÿ‘€
  • -mwarn-devices-csv and -mno-warn-devices-csv โ€” warn if devices.csv isn't found or there are problems parsing it (default: on) ๐Ÿ“„๐Ÿ’œ

โœจ NDS32 Options โœจ

These options are defined for NDS32 implementations ๐ŸŒˆ

  • -mbig-endian โ€” generates code in big-endian mode ๐Ÿณ
  • -mlittle-endian โ€” generates code in little-endian mode ๐ŸŒท
  • -mreduced-regs โ€” uses 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 these:
    • small โ€” all the data and read-only data segments must be within 512KB of addressing space, and the text segment must be within 16MB of addressing space ๐ŸŒท
    • medium โ€” the data segment must be within 512KB, while the read-only data segment can be within 4GB of addressing space. The text segment should still be within 16MB of addressing space ๐Ÿฆ‹
    • large โ€” all the text and data segments can be within 4GB of addressing space ๐Ÿ‘‘
  • -mctor-dtor โ€” enables the constructor/destructor feature ๐Ÿงš
  • -mrelax โ€” guides the linker to relax instructions ๐Ÿซถ

โœจ Nios II Options โœจ

These are the options defined for the Altera Nios II processor ๐Ÿ’–

  • -G num โ€” puts global and static objects 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, and -mno-gpopt โ€” generate (or don't generate) GP-relative accesses ๐Ÿงญ The following option names are recognized:
    • none โ€” does not generate GP-relative accesses ๐Ÿ™…โ€โ™€๏ธ
    • local โ€” generates GP-relative accesses for small data objects that are not external, weak, or uninitialized common symbols. It also uses GP-relative addressing for objects that have been explicitly placed in a small data section via a section attribute ๐ŸŒธ
    • global โ€” works like local, but also generates GP-relative accesses for small data objects that are external, weak, or common. If you use this option, you must make sure that all parts of your program (including libraries) are compiled with the same -G setting ๐Ÿซถ
    • data โ€” generates GP-relative accesses for all data objects in the program. If you use this option, the entire data and BSS segments of your program must fit in 64K of memory, and you must use an appropriate linker script to allocate them within the addressable range of the global pointer ๐Ÿ”ฅ
    • all โ€” generates GP-relative addresses for function pointers as well as data pointers. If you use this option, the entire text, data, and BSS segments of your program must fit in 64K of memory, and you must use an appropriate linker script to allocate them within the addressable range of the global pointer ๐Ÿ’€

-mgpopt is equivalent to -mgpopt=local, and -mno-gpopt is equivalent to -mgpopt=none ๐Ÿงš

The default is -mgpopt unless -fpic or -fPIC is specified to generate position-independent code ๐ŸŒˆ Note that the Nios II ABI does not permit GP-relative accesses from shared libraries ๐Ÿ˜ญ

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 โ€” specifies additional section names that can be accessed via GP-relative addressing ๐Ÿ“ It's most useful alongside section attributes on variable declarations and a custom linker script. The regexp is a POSIX Extended Regular Expression ๐Ÿ’œ

This option doesn't affect how -G behaves. The specified sections are in addition to the standard .sdata and .sbss small-data sections that are recognized by -mgpopt ๐Ÿฆ‹

  • -mr0rel-sec=regexp โ€” specifies names of sections that can be accessed via a 16-bit offset from r0, meaning in the low 32K or high 32K of the 32-bit address space ๐ŸงŠ It's most useful alongside section attributes on variable declarations and a custom linker script. The regexp is a POSIX Extended Regular Expression ๐ŸŽ€

Unlike GP-relative addressing for small data, zero-based addressing is never generated by default, and there are no conventional section names used in standard linker scripts for sections in the low or high areas of memory ๐Ÿ™…โ€โ™€๏ธ

  • -mel and -meb โ€” generate little-endian (default) or big-endian (experimental) code, respectively ๐ŸŒท
  • -march=arch โ€” specifies the name of the target Nios II architecture ๐Ÿน GCC uses this name to figure out what kind of instructions it can emit when generating assembly code. The permissible names are r1 and r2 โœจ

The preprocessor macro __nios2_arch__ is available to programs, with a value of 1 or 2, indicating the targeted ISA level ๐Ÿง 

  • -mbypass-cache and -mno-bypass-cache โ€” force 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 and -mcache-volatile โ€” volatile memory access bypasses the cache using the I/O variants of the load and store instructions ๐ŸงŠ The default is not to bypass the cache ๐Ÿฅ€
  • -mno-fast-sw-div and -mfast-sw-div โ€” -mno-fast-sw-div stops the use of table-based fast divide for small numbers ๐Ÿ™ˆ The default is to use the fast divide at -O3 and above โšก
  • -mno-hw-mul, -mhw-mul, -mno-hw-mulx, -mhw-mulx, -mno-hw-div, and -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, and -mno-cdx โ€” enable or disable generation of Nios II R2 BMX (bit manipulation) and CDX (code density) instructions ๐Ÿฆ‹ Enabling these instructions also requires -march=r2. Since they're optional extensions to the R2 architecture, the default is not to emit them ๐ŸŒˆ

-mcustom-insn=N, -mno-custom-insn

Okay bestie, so -mcustom-insn=N lets you hand a custom instruction with encoding N to any insn you pick ๐Ÿ’… For example, -mcustom-fadds=253 makes single-precision float adds use custom instruction 253 instead of the default library call. Iconic ๐Ÿฆ‹

The supported values of insn are below. Unless noted otherwise, floating-point ops are expected to follow normal IEEE 754 semantics and match the C operators or the equivalent GCC built-in functions โœจ

๐Ÿ’– Single-precision floating point

  • fadds, fsubs, fdivs, fmuls โ€” binary arithmetic ops ๐Ÿงฎ
  • fnegs โ€” unary negation
  • fabss โ€” unary absolute value
  • fcmpeqs, fcmpges, fcmpgts, fcmples, fcmplts, fcmpnes โ€” comparisons ๐Ÿ‘€
  • fmins, fmaxs โ€” floating-point min and max. These only get generated if -ffinite-math-only is specified ๐Ÿ™ˆ
  • fsqrts โ€” unary square root
  • fcoss, fsins, ftans, fatans, fexps, flogs โ€” floating-point trig and exponential functions. These only get generated if -funsafe-math-optimizations is also specified โš ๏ธ

๐ŸŒˆ Double-precision floating point

  • faddd, fsubd, fdivd, fmuld โ€” binary arithmetic ops ๐Ÿงฎ
  • fnegd โ€” unary negation
  • fabsd โ€” unary absolute value
  • fcmpeqd, fcmpged, fcmpgtd, fcmpled, fcmpltd, fcmpned โ€” comparisons ๐Ÿ‘€
  • fmind, fmaxd โ€” double-precision min and max. These only get generated if -ffinite-math-only is specified ๐Ÿ™ˆ
  • fsqrtd โ€” unary square root
  • fcosd, fsind, ftand, fatand, fexpd, flogd โ€” double-precision trig and exponential functions. These only get generated if -funsafe-math-optimizations is also specified โš ๏ธ

๐ŸŽ€ Conversions

  • fextsd โ€” single precision to double precision ๐Ÿฆ‹
  • ftruncds โ€” double precision to single precision ๐Ÿฆ‹
  • fixsi, fixsu, fixdi, fixdu โ€” floating point to signed or unsigned integers, truncating toward zero โœ‚๏ธ
  • round โ€” single-precision float to signed integer, rounding to the nearest integer with ties going away from zero. This matches the "__builtin_lroundf" function when -fno-math-errno is used ๐Ÿ“
  • floatis, floatus, floatid, floatud โ€” signed or unsigned integers to floating point ๐ŸŒธ

Also, ngl, every double-precision instruction needs these transfer instructions for the internal registers X and Y to be provided first ๐Ÿซถ Custom instructions that take two double-precision source operands expect the first operand in the 64-bit register X. The other operand (or the only operand of a unary op) goes 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 gives back the most significant 32 bits in the destination register, and the other half lands in the 32-bit register Y. GCC handles the setup code for writing X and/or reading Y automatically whenever you use double-precision instructions, so you don't have to ๐Ÿ’…

  • fwrx โ€” writes src1 into the least significant half of X and src2 into the most significant half of X
  • fwry โ€” writes src1 into Y
  • frdxhi, frdxlo โ€” reads the most or least significant half of X (respectively) and stores it in dest
  • frdy โ€” reads Y and stores it into dest

Note that you can get more local control over Nios II custom instruction generation with the target("custom-insn=N") and target("no-custom-insn") function attributes or pragmas ๐Ÿ”ฅ

  • -mcustom-fpu-cfg=name โ€” this enables a predefined, named set of custom instruction encodings (see -mcustom-insn above). Currently these 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

-mcustom-fpu-cfg=fph2 is equivalent to: -mcustom-fabss=224 -mcustom-fnegs=225 -mcustom-fcmpnes=226 -mcustom-fcmpeqs=227 -mcustom-fcmpges=228 -mcustom-fcmpgts=229 -mcustom-fcmples=230 -mcustom-fcmplts=231 -mcustom-fmaxs=232 -mcustom-fmins=233 -mcustom-round=248 -mcustom-fixsi=249 -mcustom-floatis=250 -mcustom-fsqrts=251 -mcustom-fmuls=252 -mcustom-fadds=253 -mcustom-fsubs=254 -mcustom-fdivs=255

Heads up, bestie ๐Ÿ™ˆ Custom instruction assignments from individual -mcustom-insn= options always beat the ones from -mcustom-fpu-cfg=, no matter what order they show up in on the command line ๐Ÿ’…

Note that you can get more local control over which FPU configuration gets picked by using the target("custom-fpu-cfg=name") function attribute or pragma ๐ŸŽ€

The name fph2 is short for Nios II Floating Point Hardware 2 Component ๐Ÿงš Also, the custom instructions enabled by -mcustom-fmins=233 and -mcustom-fmaxs=234 only get generated if -ffinite-math-only is specified. The custom instruction enabled by -mcustom-round=248 only gets generated if -fno-math-errno is specified. Unlike the other configurations, -fsingle-precision-constant is not set here ๐Ÿ˜ญ

These extra -m options are available for the Altera Nios II ELF (bare-metal) target ๐Ÿฆ‹

  • -mhal โ€” links with the HAL BSP. This skips the GCC-provided C runtime startup and termination code, and it's usually paired with -msys-crt0= to point at the alternate startup code from the HAL BSP ๐Ÿงš
  • -msmallc โ€” links with a limited version of the C library, -lsmallc, instead of Newlib ๐ŸŒธ
  • -msys-crt0=startfile โ€” startfile is the file name of the startfile (crt0) to use when linking. This only works together with -mhal ๐Ÿ’œ
  • -msys-lib=systemlib โ€” systemlib is the library name for the low-level system calls the C library needs, like "read" and "write". This is usually used to link with a library from a HAL BSP โœจ

๐Ÿ’œ Nvidia PTX Options

These options are defined for Nvidia PTX ๐Ÿฆ‹

  • -m64 โ€” ignored, but kept around for backward compatibility. Only the 64-bit ABI is supported ๐Ÿซถ
  • -march=architecture-string โ€” generates code for the specified PTX ISA target architecture (e.g. sm_35). Valid architecture strings are sm_30, sm_35, sm_53, sm_70, sm_75 and sm_80. The default depends on how the compiler was configured, see --with-arch ๐Ÿ”ฅ

This option also sets the preprocessor macro "__PTX_SM__". For example, for sm_35 it has the value 350 ๐Ÿ“

  • -misa=architecture-string โ€” alias of -march= ๐Ÿ’…
  • -march-map=architecture-string โ€” picks the closest available -march= value that isn't more capable. For instance, -march-map=sm_50 selects -march=sm_35, and -march-map=sm_53 selects -march=sm_53 ๐Ÿง 
  • -mptx=version-string โ€” generates code for the specified PTX ISA version (e.g. 7.0). Valid version strings include 3.1, 6.0, 6.3, and 7.0. The default PTX ISA version is 6.0, unless a higher version is needed for the PTX ISA target architecture given via -march= ๐Ÿ‘‘

This option sets the values of the preprocessor macros "__PTX_ISA_VERSION_MAJOR__" and "__PTX_ISA_VERSION_MINOR__". For instance, for 3.1 the macros have the values 3 and 1, respectively ๐ŸŒˆ

  • -mmainkernel โ€” links in code for a __main kernel. This is for stand-alone execution instead of offloading ๐Ÿงš
  • -moptimize โ€” applies partitioned execution optimizations. This is the default whenever any level of optimization is selected โœจ
  • -msoft-stack โ€” generates code that doesn't use ".local" memory directly for stack storage. Instead, a per-warp stack pointer gets maintained explicitly. This enables variable-length stack allocation (with variable-length arrays or "alloca"), and when global memory is used as the underlying storage, it makes it possible to access automatic variables from other threads, or with atomic instructions. This 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 all threads in each warp execute, while keeping memory state and side effects as if only one thread in each warp were active outside of OpenMP SIMD regions. All atomic operations and calls to the runtime (malloc, free, vprintf) are conditionally executed (iff the current lane index equals the master lane index), and the register being assigned is copied via a shuffle instruction from the master lane. Outside of SIMD regions, lane 0 is the master; inside, each thread sees itself as the master. The shared memory array int __nvptx_uni[] stores all-zeros or all-ones bitmasks for each warp, indicating the current mode (0 outside of SIMD regions). Each thread can bitwise-and the bitmask at position tid.y with the current lane index to compute the master lane index ๐ŸŒธ
  • -mgomp โ€” generates code for OpenMP offloading. It enables -msoft-stack and -muniform-simt and selects the corresponding multilib variant ๐Ÿ’–

๐ŸŒธ OpenRISC Options

These options are defined for OpenRISC ๐Ÿงš

  • -mboard=name โ€” configures a board-specific runtime. This gets passed to the linker for newlib board library linking. The default is "or1ksim" ๐Ÿ“
  • -mnewlib โ€” Total ghost energy ๐Ÿ‘ป This option is ignored and only hangs around for compatibility. It used to pick linker and preprocessor options for newlib ๐ŸŽ€
  • -msoft-div, -mhard-div โ€” Choose software or hardware divide (l.div, l.divu) instructions ๐Ÿ’… Hardware divide is the default, so you're already getting the good stuff โœจ
  • -msoft-mul, -mhard-mul โ€” Choose software or hardware multiply (l.mul, l.muli) instructions ๐Ÿ”ฅ Hardware multiply is the default, no notes ๐Ÿ’–
  • -msoft-float, -mhard-float โ€” Pick software or hardware for floating point operations ๐Ÿฆ‹ Software is the default, so it's a whole vibe.
  • -mdouble-float โ€” When -mhard-float is selected, this turns on double-precision floating point instructions ๐ŸŒธ By default, functions from libgcc handle double-precision floating point operations.
  • -munordered-float โ€” When -mhard-float is selected, this unlocks 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 โ€” Turns on conditional move (l.cmov) instructions โญ Without it, the same result is made with set and branch.
  • -mror โ€” Turns on rotate right (l.ror) instructions ๐ŸŒˆ By default, functions from libgcc handle rotate right operations.
  • -mrori โ€” Turns on rotate right with immediate (l.rori) instructions ๐Ÿงš By default, functions from libgcc handle rotate right with immediate operations.
  • -msext โ€” Turns on sign extension (l.ext*) instructions ๐Ÿ’œ By default, memory loads do the sign extension work.
  • -msfimm โ€” Turns on 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 โ€” Turns on shift with immediate (l.srai, l.srli, l.slli) instructions ๐ŸŽ€ By default, extra instructions get generated to store the immediate in a register first.
  • -mcmodel=small โ€” Generates OpenRISC code for the small model ๐Ÿฆ‹ The GOT is limited to 64k. This is the default model.
  • -mcmodel=large โ€” Generates OpenRISC code for the large model ๐Ÿ‘‘ The GOT may grow up to 4G in size.

๐Ÿงš PDP-11 Options ๐Ÿงš

These options are defined for the PDP-11:

  • -mfpu โ€” Uses hardware FPP floating point ๐Ÿ’… This is the default. (FIS floating point on the PDP-11/40 is not supported.) Implies -m45.
  • -msoft-float โ€” Does not use hardware floating point ๐Ÿซ 
  • -mac0 โ€” Returns floating-point results in ac0 (fr0 in Unix assembler syntax) โœจ
  • -mno-ac0 โ€” Returns floating-point results in memory ๐ŸŒธ This is the default.
  • -m40 โ€” Generates code for a PDP-11/40 ๐Ÿ’– Implies -msoft-float -mno-split.
  • -m45 โ€” Generates code for a PDP-11/45 ๐Ÿ”ฅ This is the default.
  • -m10 โ€” Generates code for a PDP-11/10 ๐Ÿ“ Implies -msoft-float -mno-split.
  • -mint16, -mno-int32 โ€” Uses 16-bit int ๐Ÿ‘‘ This is the default.
  • -mint32, -mno-int16 โ€” Uses 32-bit int ๐ŸŒˆ
  • -msplit โ€” The target has split instruction and data space ๐Ÿฆ‹ Implies -m45.
  • -munix-asm โ€” Uses Unix assembler syntax ๐Ÿงš
  • -mdec-asm โ€” Uses DEC assembler syntax ๐Ÿ’œ
  • -mgnu-asm โ€” Uses GNU assembler syntax ๐ŸŽ€ This is the default.
  • -mlra โ€” Uses the new LRA register allocator โญ By default, the old reload allocator is used.

๐Ÿ’– PowerPC Options ๐Ÿ’–

These are listed under


๐ŸŒˆ PRU Options ๐ŸŒˆ

These command-line options are defined for PRU target:

  • -minrt โ€” Links with a minimum runtime environment ๐Ÿซถ This can significantly shrink the final ELF binary, but some standard C runtime features get removed.

This option disables support for static initializers and constructors ๐Ÿ’€ Beware that the compiler could still generate code with static initializers and constructors. It is up to the programmer to make sure the source program won't use those features.

The minimal startup code would not pass argc and argv arguments to main, so main must be declared as int main (void). This is already the norm for most firmware projects โœจ

  • -mmcu=mcu โ€” Specifies the PRU hardware variant to use ๐Ÿ”ฅ A correspondingly named spec file would be loaded, passing the memory region sizes to the linker and defining hardware-specific C macros.

Newlib provides only the sim spec, which is meant for running regression tests using a simulator ๐Ÿงช Specs for real hardware can be obtained by installing the GnuPruMcu (https://github.com/dinuxbg/gnuprumcu/) package.

  • -mno-relax โ€” Makes GCC pass the --no-relax command-line option to the linker instead of the --relax option ๐ŸŒธ
  • -mloop โ€” Allows (or does not 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 are passed by 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 is not 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 cannot be built, and it is omitted when linking with -mabi=ti.

Relaxation is a GNU feature, and for safety reasons it is disabled when using -mabi=ti ๐Ÿ’€ The TI toolchain does not emit relocations for QBBx instructions, so the GNU linker cannot adjust them when shortening adjacent LDI32 pseudo instructions.

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

These command-line options are defined for RISC-V targets:

  • -mbranch-cost=n โ€” Sets the cost of branches to roughly n instructions ๐Ÿ’œ
  • -mplt, -mno-plt โ€” When generating PIC code, do or don't allow the use of PLTs ๐ŸŽ€ Ignored for non-PIC. The default is -mplt.
  • -mabi=ABI-string โ€” Specifies the integer and floating-point calling convention ๐ŸŒˆ ABI-string has two parts: the size of integer types and the registers used for floating-point types. For example, -march=rv64ifd -mabi=lp64d means that long and pointers are 64-bit (implicitly defining int to be 32-bit), and that floating-point values up to 64 bits wide are passed in F registers. Contrast this with -march=rv64ifd -mabi=lp64f, which still lets the compiler generate code that uses the F and D extensions, but only allows floating-point values up to 32 bits long to be passed in registers. Or there's -march=rv64ifd -mabi=lp64, where no floating-point arguments get passed in registers ๐Ÿงš

The default for this argument is system dependent, so users who want a specific calling convention should specify one explicitly ๐Ÿ’– The valid calling conventions are: ilp32, ilp32f, ilp32d, lp64, lp64f, and lp64d. Some calling conventions are impossible to implement on some ISAs: for example, -march=rv32if -mabi=ilp32d is invalid, because the ABI requires 64-bit values to be passed in F registers, but F registers are only 32 bits wide ๐Ÿ™…โ€โ™€๏ธ There's also the ilp32e ABI, which can only be used with the rv32e architecture, and the lp64e ABI, which can only be used with rv64e. Those ABIs are not well specified at present and are subject to change.

  • -mfdiv, -mno-fdiv โ€” Do or don't use hardware floating-point divide and square root instructions โญ This requires the F or D extensions for floating-point registers. The default is to use them if the specified architecture has these instructions.
  • -mdiv, -mno-div โ€” Do or don't use hardware instructions for integer division ๐Ÿ”ฅ This requires the M extension. The default is to use them if the specified architecture has these instructions.
  • -misa-spec=ISA-spec-string โ€” Specifies the version of the RISC-V Unprivileged (formerly User-Level) ISA specification to produce code conforming to ๐Ÿซถ The possibilities for ISA-spec-string are:
    • 2.2 โ€” Produce code conforming to version 2.2.
    • 20190608 โ€” Produce code conforming to version 20190608.
    • 20191213 โ€” Produce code conforming to version 20191213.

The default is -misa-spec=20191213, unless GCC has been configured with --with-isa-spec= specifying a different default version ๐ŸŒธ

  • -march=ISA-string โ€” Generates code for the given RISC-V ISA (e.g. rv64im) ๐Ÿ’… ISA strings must be lower-case. Examples include rv64i, rv32g, rv32e, and rv32imaf. There's also a special value, help (-march=help), that lists all supported extensions ๐Ÿฆ‹

The syntax of the ISA string is defined as follows:

  • "The string must start with rv32 or rv64, followed by" i, e, or g, referred to as the base ISA ๐Ÿงš
  • "The subsequent part of the string is a list of extension names. Extension names" can be categorized as multi-letter (e.g. zba) and single-letter (e.g. v). Single-letter extensions can appear consecutively, but multi-letter extensions must be separated by underscores ๐ŸŒˆ
  • "An underscore can appear anywhere after the base ISA. It has no specific effect" but is used to improve readability and can act as a separator ๐Ÿ’œ
  • "Extension names may include an optional version number, following the syntax" <major>p<minor> or <major>, (e.g. m2p1 or m2) ๐ŸŽ€

Supported extensions are listed below ๐Ÿ‘‘

Extension Name : Supported Version : Description
i   @tab 2.0, 2.1 @tab Base integer extension.
e   @tab 2.0 @tab Reduced base integer extension.
g   @tab - @tab General-purpose computing base extension, g will expand to i, m, a, f, d, zicsr and zifencei.
m   @tab 2.0 @tab Integer multiplication and division extension.
a   @tab 2.0, 2.1 @tab Atomic extension.
f   @tab 2.0, 2.2 @tab Single-precision floating-point extension.
d   @tab 2.0, 2.2 @tab Double-precision floating-point extension.
c   @tab 2.0 @tab Compressed extension.
h   @tab 1.0 @tab Hypervisor extension.
  • v (1.0) โ€” ๐ŸŒˆ the Vector extension, the main vibe for all things vector! โœจ
  • zicsr (2.0) โ€” ๐Ÿ’… control and status register access, literally the CSR stuff ๐Ÿ”ฅ
  • zifencei (2.0) โ€” ๐Ÿงš the instruction-fetch fence extension ๐Ÿซถ
  • zicond (1.0) โ€” ๐Ÿ’– integer conditional operations, lowkey so useful
  • za64rs (1.0) โ€” ๐ŸŽ€ reservation set size of 64 bytes
  • za128rs (1.0) โ€” ๐ŸŽ€ reservation set size of 128 bytes, the bigger sibling
  • zawrs (1.0) โ€” โณ wait-on-reservation-set extension, patience is a vibe ๐ŸŒธ
  • zba (1.0) โ€” ๐Ÿฆ‹ address calculation extension
  • zbb (1.0) โ€” ๐Ÿง  basic bit manipulation, very smart energy ๐Ÿ’œ
  • zbc (1.0) โ€” โœจ carry-less multiplication extension
  • zbs (1.0) โ€” ๐Ÿ“ single-bit operation extension
  • zfinx (1.0) โ€” ๐Ÿ”ฅ single-precision floating-point in integer registers extension
  • zdinx (1.0) โ€” ๐Ÿ”ฅ double-precision floating-point in integer registers extension
  • zhinx (1.0) โ€” ๐Ÿ”ฅ half-precision floating-point in integer registers extension
  • zhinxmin (1.0) โ€” ๐Ÿ”ฅ the minimal half-precision version of the integer-register floating-point extension
  • zbkb (1.0) โ€” ๐Ÿ” cryptography bit-manipulation extension
  • zbkc (1.0) โ€” ๐Ÿ” cryptography carry-less multiply extension
  • zbkx (1.0) โ€” ๐Ÿ” cryptography crossbar permutation extension
  • zkne (1.0) โ€” ๐Ÿ—๏ธ AES encryption extension
  • zknd (1.0) โ€” ๐Ÿ—๏ธ AES decryption extension
  • zknh (1.0) โ€” ๐Ÿซถ hash function extension
  • zkr (1.0) โ€” ๐ŸŽฒ entropy source extension, very random, very cute
  • zksed (1.0) โ€” ๐Ÿ” SM4 block cipher extension
  • zksh (1.0) โ€” ๐Ÿ” SM3 hash function extension
  • zkt (1.0) โ€” โฑ๏ธ data independent execution latency extension
  • zk (1.0) โ€” ๐Ÿ’œ standard scalar cryptography extension, the whole crypto package
  • zkn (1.0) โ€” ๐Ÿ’œ NIST algorithm suite extension
  • zks (1.0) โ€” ๐Ÿ’œ ShangMi algorithm suite extension
  • zihintntl (1.0) โ€” ๐ŸŒท non-temporal locality hints extension
  • zihintpause (1.0) โ€” โธ๏ธ pause hint extension, chill moment
  • zicboz (1.0) โ€” ๐ŸงŠ cache-block zero extension
  • zicbom (1.0) โ€” ๐ŸงŠ cache-block management extension
  • zicbop (1.0) โ€” ๐ŸงŠ cache-block prefetch extension
  • zic64b (1.0) โ€” ๐ŸงŠ the cache block size is 64 bytes, no cap
  • ziccamoa (1.0) โ€” ๐Ÿง  main memory supports all atomics in A
  • ziccif (1.0) โ€” ๐Ÿง  main memory supports instruction fetch with an atomicity requirement
  • zicclsm (1.0) โ€” ๐Ÿง  main memory supports misaligned loads and stores
  • ziccrse (1.0) โ€” ๐Ÿง  main memory supports forward progress on LR/SC sequences
  • zicntr (2.0) โ€” โฐ standard extension for base counters and timers
  • zihpm (2.0) โ€” ๐Ÿ“ˆ standard extension for hardware performance counters
  • ztso (1.0) โ€” ๐Ÿงฑ total store ordering extension
  • zve32x (1.0) โ€” ๐ŸŒธ vector extensions for embedded processors
  • zve32f (1.0) โ€” ๐ŸŒธ vector extensions for embedded processors
  • zve64x (1.0) โ€” ๐ŸŒธ vector extensions for embedded processors
  • zve64f (1.0) โ€” ๐ŸŒธ vector extensions for embedded processors
  • zve64d (1.0) โ€” ๐ŸŒธ vector extensions for embedded processors
  • zvl32b (1.0) โ€” ๐Ÿ“ minimum vector length standard extension
  • zvl64b (1.0) โ€” ๐Ÿ“ minimum vector length standard extension
  • zvl128b (1.0) โ€” ๐Ÿ“ minimum vector length standard extension
  • zvl256b (1.0) โ€” ๐Ÿ“ minimum vector length standard extension
  • zvl512b (1.0) โ€” ๐Ÿ“ minimum vector length standard extension
  • zvl1024b (1.0) โ€” ๐Ÿ“ minimum vector length standard extension
  • zvl2048b (1.0) โ€” ๐Ÿ“ minimum vector length standard extension
  • zvl4096b (1.0) โ€” ๐Ÿ“ minimum vector length standard extension
  • zvbb (1.0) โ€” ๐Ÿง  vector basic bit-manipulation extension
  • zvbc (1.0) โ€” โœจ vector carry-less multiplication extension
  • zvkb (1.0) โ€” ๐Ÿ” vector cryptography bit-manipulation extension
  • zvkg (1.0) โ€” ๐Ÿ” vector GCM/GMAC extension
  • zvkned (1.0) โ€” ๐Ÿ—๏ธ vector AES block cipher extension
  • zvknha (1.0) โ€” ๐Ÿซถ vector SHA-2 secure hash extension
  • zvknhb (1.0) โ€” ๐Ÿซถ vector SHA-2 secure hash extension
  • zvksed (1.0) โ€” ๐Ÿ” vector SM4 block cipher extension
  • zvksh (1.0) โ€” ๐Ÿ” vector SM3 secure hash extension
  • zvkn (1.0) โ€” ๐Ÿ’œ vector NIST algorithm suite extension, and it expands to zvkned, zvknhb, zvkb and zvkt ๐Ÿ‘‘
  • zvknc (1.0) โ€” ๐Ÿ’œ vector NIST algorithm suite with carry-less multiply extension, and it expands to zvkn and zvbc ๐Ÿ‘‘
  • zvkng (1.0) โ€” ๐Ÿ’œ vector NIST algorithm suite with GCM extension, and it expands to zvkn and zvkg ๐Ÿ‘‘
  • zvks (1.0) โ€” ๐Ÿ’œ vector ShangMi algorithm suite extension, and it expands to zvksed, zvksh, zvkb and zvkt ๐Ÿ‘‘
  • zvksc (1.0) โ€” ๐Ÿ’œ vector ShangMi algorithm suite with carry-less multiplication extension, and it expands to zvks and zvbc ๐Ÿ‘‘
  • zvksg (1.0) โ€” ๐Ÿ’œ vector ShangMi algorithm suite with GCM extension, and it expands to zvks and zvkg ๐Ÿ‘‘
  • zvkt (1.0) โ€” โฑ๏ธ vector data independent execution latency extension
  • zfh (1.0) โ€” ๐Ÿ”ฅ half-precision floating-point extension
  • zfhmin (1.0) โ€” ๐Ÿ”ฅ minimal half-precision floating-point extension
  • zvfh (1.0) โ€” ๐Ÿ”ฅ vector half-precision floating-point extension
  • zvfhmin (1.0) โ€” ๐Ÿ”ฅ vector minimal half-precision floating-point extension
  • zvfbfmin (1.0) โ€” ๐Ÿ”ฅ vector BF16 converts extension
  • zfa (1.0) โ€” โž• additional floating-point extension
  • zmmul (1.0) โ€” โœ–๏ธ integer multiplication extension
  • zca (1.0) โ€” ๐Ÿ—œ๏ธ integer compressed instruction extension
  • zcf (1.0) โ€” ๐Ÿ—œ๏ธ compressed single-precision floating-point loads and stores extension
  • zcd (1.0) โ€” ๐Ÿ—œ๏ธ compressed double-precision floating-point loads and stores extension
  • zcb (1.0) โ€” ๐Ÿ—œ๏ธ simple compressed instruction extension
  • zce (1.0) โ€” ๐Ÿ—œ๏ธ compressed instruction extensions for embedded processors
  • zcmp (1.0) โ€” ๐Ÿ“š compressed push and pop extension
  • zcmt (1.0) โ€” ๐Ÿ“š table jump instruction extension
  • smaia (1.0) โ€” ๐Ÿ›Ž๏ธ advanced interrupt architecture extension
  • smepmp (1.0) โ€” ๐Ÿ›ก๏ธ PMP enhancements for memory access and execution prevention in machine mode
  • smstateen (1.0) โ€” ๐ŸŒˆ state enable extension
  • ssaia (1.0) โ€” ๐Ÿ›Ž๏ธ advanced interrupt architecture extension for supervisor mode
  • sscofpmf (1.0) โ€” ๐Ÿ“ˆ count overflow and filtering extension
  • ssstateen (1.0) โ€” ๐ŸŒˆ state-enable extension for supervisor mode
  • sstc (1.0) โ€” โฐ supervisor-mode timer interrupts extension
  • svinval (1.0) โ€” ๐Ÿงน fine-grained address-translation cache invalidation extension
  • svnapot (1.0) โ€” ๐Ÿ—บ๏ธ NAPOT translation contiguity extension
  • svpbmt (1.0) โ€” ๐Ÿ—บ๏ธ page-based memory types extension
  • xcvmac (1.0) โ€” ๐Ÿค– Core-V multiply-accumulate extension
  • xcvalu (1.0) โ€” ๐Ÿค– Core-V miscellaneous ALU extension
  • xcvelw (1.0) โ€” ๐Ÿค– Core-V event load word extension
  • xtheadba (1.0) โ€” ๐Ÿ‰ T-Head address calculation extension
  • xtheadbb (1.0) โ€” ๐Ÿ‰ T-Head basic bit-manipulation extension
  • xtheadbs (1.0) โ€” ๐Ÿ‰ T-Head single-bit instructions extension
  • xtheadcmo (1.0) โ€” ๐Ÿ‰ T-Head cache management operations extension
  • xtheadcondmov (1.0) โ€” ๐Ÿ‰ T-Head conditional move extension
  • xtheadfmemidx (1.0) โ€” ๐Ÿ‰ T-Head indexed memory operations for floating-point registers extension
  • xtheadfmv (1.0) โ€” ๐Ÿ‰ T-Head double floating-point high-bit data transmission extension
  • xtheadint (1.0) โ€” ๐Ÿ‰ T-Head acceleration interruption extension
  • xtheadmac (1.0) โ€” ๐Ÿ‰ T-Head multiply-accumulate extension
  • xtheadmemidx (1.0) โ€” ๐Ÿ‰ T-Head indexed memory operation extension
  • xtheadmempair (1.0) โ€” ๐Ÿ‰ T-Head two-GPR memory operation extension
  • xtheadsync (1.0) โ€” ๐Ÿ‰ T-Head multi-core synchronization extension
  • xventanacondops (1.0) โ€” ๐ŸŒŸ Ventana integer conditional operations extension

When -march= is not specified, use the setting from -mcpu. ๐Ÿซถ

If both -march and -mcpu= are not specified, the default for this argument is system dependent, so bestie, if you want a specific architecture extension, you should specify one explicitly. ๐Ÿ’…

โœจ -mcpu=processor-string

Use the architecture of, and optimize the output for, the given processor, specified by a particular CPU name. ๐ŸŽ€ Permissible values for this option are: sifive-e20, sifive-e21, sifive-e24, sifive-e31, sifive-e34, sifive-e76, sifive-s21, sifive-s51, sifive-s54, sifive-s76, sifive-u54, sifive-u74, sifive-x280, sifive-xp450 and sifive-x670. ๐Ÿฆ‹

Note that -mcpu does not override -march or -mtune. ๐Ÿ™ˆ

๐ŸŒธ -mtune=processor-string

Optimize the output for the given processor, specified by microarchitecture or a particular CPU name. โญ Permissible values for this option are: rocket, sifive-3-series, sifive-5-series, sifive-7-series, thead-c906, size, sifive-p400-series, sifive-p600-series, and all valid options for -mcpu=. ๐Ÿ’–

When -mtune= is not specified, use the setting from -mcpu. The default is rocket if both are not specified. ๐Ÿงš

โš ๏ธ The size choice is not intended for use by end-users, bestie, so hands off! ๐Ÿ™… It is used when -Os is specified. It overrides the instruction cost info provided by -mtune=, but it does not override the pipeline info. This helps reduce code size while still giving good performance. ๐Ÿ‘‘
  • -mpreferred-stack-boundary=num โ€” okay so this one tries to keep the stack boundary lined up to a 2 raised to num byte boundary ๐Ÿ“โœจ. If you don't specify it, the default is 4 (that's 16 bytes or 128-bits) ๐Ÿ’….
โš ๏ธ Warning, bestie ๐Ÿšจ: if you use this switch, you HAVE to build every single module with the same value, libraries included. That covers the system libraries and startup modules too ๐Ÿ˜ญ.
  • -msmall-data-limit=n โ€” puts global and static data smaller than n bytes into a special section ๐Ÿงš, but only on some targets ๐ŸŒˆ.
  • -msave-restore, -mno-save-restore โ€” these decide whether you get the smaller-but-slower prologue and epilogue code that calls library functions ๐Ÿข. The default is the fast inline prologues and epilogues โšก, so you're only switching to the slow lane if you ask for it ๐Ÿ’œ.
  • -mmovcc, -mno-movcc โ€” this one is giving branchless conditional-move code sequences ๐Ÿฆ‹, even on targets that don't have special instructions for conditional operations. If it's enabled, sequences of ALU operations get built from base integer ISA instructions wherever that's profitable ๐Ÿ”ฅ.
  • -minline-atomics, -mno-inline-atomics โ€” choose between smaller but slower subword atomic emulation that calls libatomic functions ๐ŸŒ, or the fast inline subword atomics that don't need libatomic at all ๐Ÿ’–. The default is the fast inline version, obviously ๐Ÿ‘‘.
  • -minline-strlen, -mno-inline-strlen โ€” you can ask GCC to try inlining strlen calls if it's possible ๐ŸŒธ. It'll only actually do it if the string is properly aligned and the accelerated instructions are around โœจ. By default, it does NOT inline strlen calls ๐Ÿ™ˆ.
  • -minline-strcmp, -mno-inline-strcmp โ€” same vibe as strlen, but for strcmp calls ๐Ÿ’…. Inlining only happens when the strings are properly aligned and the accelerated instructions are available ๐Ÿ”ฅ. The default is to not inline strcmp calls ๐Ÿซถ.

The --param riscv-strcmp-inline-limit=n parameter controls the maximum number of bytes compared by the inlined code ๐Ÿ“. Its default value is 64 ๐ŸŒˆ.

  • -minline-strncmp, -mno-inline-strncmp โ€” the strncmp version of the same story ๐ŸŽ€. Inlining only happens when the strings are properly aligned and the accelerated instructions exist โœจ. Default is to not inline strncmp calls ๐Ÿฆ‹.

Same deal with --param riscv-strcmp-inline-limit=n: it sets the maximum number of bytes compared by the inlined code, and the default is 64 ๐Ÿ’œ.

  • -mshorten-memrefs, -mno-shorten-memrefs โ€” this one is lowkey genius ๐Ÿง . It tries to use more compressed load/store instructions by swapping a load/store of base register + large offset for a new load/store of new base + small offset ๐Ÿช„. If that new base lands in a compressed register, the new load/store can be compressed too ๐Ÿ—œ๏ธ. Right now it only targets 32-bit integer load/stores ๐ŸŽฏ.
  • -mstrict-align, -mno-strict-align โ€” decides whether unaligned memory accesses get generated or not ๐Ÿ™…โ€โ™€๏ธ. The default depends on whether the processor you're optimizing for supports fast unaligned access ๐Ÿƒโ€โ™€๏ธ.
  • -mcmodel=medlow โ€” generates code for the medium-low code model ๐ŸŒ™. The program and its statically defined symbols have to live inside a single 2 GiB address range, sitting 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 just need to be within any single 2 GiB address range ๐Ÿ’ซ. Programs can be statically or dynamically linked ๐Ÿงš.

Heads up though ๐Ÿšจ: the code from medium-any is position-independent, but it's NOT guaranteed to work correctly when linked into position-independent executables or libraries ๐Ÿ’€.

  • -mexplicit-relocs, -mno-exlicit-relocs โ€” you either use assembler relocation operators when dealing with symbolic addresses ๐Ÿงฉ, or you don't. The alternative is assembler macros instead, and those might limit optimization ๐Ÿ™ˆ.
  • -mrelax, -mno-relax โ€” takes advantage of linker relaxations ๐Ÿชถ to cut down on the number of instructions needed to materialize symbol addresses โœ‚๏ธ. The default is to take advantage of linker relaxations ๐Ÿ’–.
  • -mriscv-attribute, -mno-riscv-attribute โ€” emits (or doesn't emit) a RISC-V attribute that records extra information into ELF objects ๐Ÿ“ฆ. This feature needs at least binutils 2.32 ๐Ÿ› ๏ธ.
  • -mcsr-check, -mno-csr-check โ€” enables or disables the CSR checking ๐Ÿ”.
  • -malign-data=type โ€” controls how GCC aligns variables and constants of array, structure, or union types ๐Ÿ“. The supported values for type are xlen, which uses the x register width as the alignment value, and natural, which uses natural alignment ๐ŸŽ€. xlen is the default ๐Ÿ’….
  • -mbig-endian โ€” generates big-endian code ๐Ÿ˜. This is the default when GCC is configured for a riscv64be-*-* or riscv32be-*-* target ๐ŸŒŠ.
  • -mlittle-endian โ€” generates little-endian code ๐Ÿฃ. This is the default when GCC is configured for a riscv64-*-* or riscv32-*-* target, but NOT a riscv64be-*-* or riscv32be-*-* target ๐Ÿฆ‹.
  • -mstack-protector-guard=guard, -mstack-protector-guard-reg=reg, -mstack-protector-guard-offset=offset โ€” generates stack protection code using a canary at guard ๐Ÿ›ก๏ธ. The supported locations are global for a global canary, or tls for a per-thread canary in the TLS block ๐Ÿงต.

With the tls choice, -mstack-protector-guard-reg=reg and -mstack-protector-guard-offset=offset get to decide which register is used as the base register for reading the canary ๐ŸŽฏ, and what offset from that base register it's read from ๐Ÿ“. There's no default register or offset here, 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 ๐Ÿงตโœจ.
  • -mtls-dialect=trad โ€” uses traditional TLS as the thread-local storage mechanism for dynamic accesses of TLS variables ๐Ÿ•ฐ๏ธ. This 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 you want ๐Ÿงฎ. 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" ๐Ÿฆ‹.

Also, a C preprocessor macro gets defined based on this setting ๐Ÿช„. The possible values are "__RL78_MUL_NONE__", "__RL78_MUL_G13__", or "__RL78_MUL_G14__" โœจ.

  • -mcpu=g10, -mcpu=g13, -mcpu=g14, -mcpu=rl78 โ€” specifies which RL78 core you're targeting ๐ŸŽฏ. The default is the G14 core, which is also known as an S3 core or just RL78 ๐Ÿ‘‘. The G13 (or S2) core doesn't have multiply or divide instructions, so 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 you set this option, it also picks the type of hardware multiply support to use ๐Ÿ’–, unless you override it with an explicit -mmul=none on the command line. So -mcpu=g13 turns on the G13 hardware multiply peripheral, and -mcpu=g10 turns hardware multiplications off altogether ๐Ÿ™…โ€โ™€๏ธ.

Now, the RL78/G14 core is the default target, BUT specifying -mcpu=g14 or -mcpu=rl78 on the command line really does change how the toolchain behaves ๐Ÿ˜ญ, because it also enables G14 hardware multiply support. If you don't specify these on the command line, software multiplication routines get used even though the code targets the RL78 core ๐Ÿข. That's there for backwards compatibility with older toolchains that didn't have hardware multiply and divide support ๐Ÿซถ.

And yep, a C preprocessor macro gets defined based on this setting too ๐ŸŒˆ. The possible values are "__RL78_G10__", "__RL78_G13__", or "__RL78_G14__" ๐Ÿ’œ.

  • -mg10, -mg13, -mg14, -mrl78 โ€” these are aliases for the matching -mcpu= option ๐Ÿ”. They only exist 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 on, those registers can be used in ordinary functions as well ๐Ÿ”“.
  • -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 โ€” says whether interrupt handler functions should preserve the MDUC registers ๐Ÿ›ก๏ธ. This is only necessary if normal code might use the MDUC registers, like when it does multiplication and division operations โœ–๏ธโž—. The default is to ignore the MDUC registers, because that makes the interrupt handlers faster โšก. The target option -mg13 needs to be passed for this to work, since this feature is only available on the G13 target (S2 core) ๐Ÿ”ง. The MDUC registers only get saved if the interrupt handler 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 say which instructions are available on the processor you're using ๐ŸŽ€. The default value of these options gets determined when GCC is configured ๐Ÿ› ๏ธ. Specifying -mcpu=cpu_type overrides whatever you set with these options ๐Ÿ™…โ€โ™€๏ธ, so we recommend using the -mcpu=cpu_type option instead of the options listed above ๐Ÿซถ.

Specifying -mpowerpc-gpopt lets GCC use the optional PowerPC architecture instructions in the General Purpose group, including floating-point square root ๐Ÿ”ฅ. Specifying -mpowerpc-gfxopt lets GCC use the optional PowerPC architecture instructions in the Graphics group, including floating-point select โœจ.

The POWER feature flags are next, bestie, and they're a whole vibe ๐ŸŒธ Each one switches on an instruction set that a specific chip family shipped with ๐Ÿฆ‹

  • -mmfcrf โ€” lets GCC emit the move from condition register field instruction ๐Ÿ’… That's the one from the POWER4 processor, plus other chips that support the PowerPC V2.01 architecture.
  • -mpopcntb โ€” unlocks the popcount and double-precision FP reciprocal estimate instruction โœจ That's from the POWER5 processor, plus other chips that support the PowerPC V2.02 architecture.
  • -mpopcntd โ€” unlocks the popcount instruction ๐Ÿ”ฅ That's from the POWER7 processor, plus other chips that support the PowerPC V2.06 architecture.
  • -mfprnd โ€” unlocks the FP round to integer instructions ๐ŸŒˆ That's from the POWER5+ processor, plus other chips that support the PowerPC V2.03 architecture.
  • -mcmpb โ€” unlocks the compare bytes instruction ๐Ÿ“ That's from the POWER6 processor, plus other chips that support the PowerPC V2.05 architecture.
  • -mhard-dfp โ€” unlocks the decimal floating-point instructions, which show up on some POWER processors ๐Ÿงš

The -mpowerpc64 option lets GCC generate the extra 64-bit instructions from 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 on purpose.

  • -mcpu=cpu_type โ€” this one sets the architecture type, register usage, and instruction scheduling parameters for the machine type you name ๐Ÿ‘‘ 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.

Bestie, -mcpu=powerpc, -mcpu=powerpc64, and -mcpu=powerpc64le are the generic ones ๐Ÿซถ They give you pure 32-bit PowerPC (either endian), 64-bit big endian PowerPC, and 64-bit little endian PowerPC architecture machine types. GCC assumes an appropriate, generic processor model for scheduling purposes.

Specifying native as the cpu type detects the host processor of the system doing the compilation and picks the architecture option that matches it ๐Ÿฆ‹ -mcpu=native has no effect if GCC doesn't recognize the processor, so it just does nothing, which is fine.

The other values name one specific processor. Code generated for those runs best on that chip, and it may not run at all on others.

Heads up, babe: if you target a specific processor, the code might not run on anything else at all ๐Ÿ’€ Keep that in mind before you ship it.

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
-mquad-memory  -mquad-memory-atomic  -mfloat128 -mfloat128-hardware
-mprefixed -mpcrel -mmma -mrop-protect

The exact set for each CPU changes between compiler versions. GCC picks whatever seems to produce 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. Main character move ๐Ÿ’…

On AIX, -maltivec and -mpowerpc64 aren't enabled or disabled by -mcpu right now, because AIX doesn't have full support for those options yet ๐Ÿ˜ญ You can still turn them on or off one at a time if you're sure it'll work in your environment.

  • -mtune=cpu_type โ€” this sets only the instruction scheduling parameters for the machine type you name โœจ It does not set the architecture type or register usage the way -mcpu=cpu_type does. The same values for cpu_type work for -mtune as for -mcpu. If you specify both, the code uses the architecture and registers from -mcpu, but the scheduling parameters come from -mtune.
  • -mcmodel=small โ€” generates PowerPC64 code for the small model, where the TOC is limited to 64k ๐Ÿงš
  • -mcmodel=medium โ€” generates PowerPC64 code for the medium model, where the TOC and other static data can total up to 4G in size. This is the default for 64-bit Linux ๐ŸŒˆ
  • -mcmodel=large โ€” generates PowerPC64 code for the large model, where the TOC can be up to 4G in size. Other data and code is only limited by the 64-bit address space ๐Ÿ‘‘
  • -maltivec, -mno-altivec โ€” makes GCC generate (or not generate) AltiVec instructions, and also turns on (or off) 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 you use -maltivec, the element order for AltiVec intrinsics like vec_splat, vec_extract, and vec_insert matches the array element order for the target's endianness ๐Ÿซถ On a big-endian target, element zero is the leftmost element in a vector register. On a little-endian target, element zero is the rightmost element in a vector register.

  • -mvrsave, -mno-vrsave โ€” makes GCC generate (or not generate) VRSAVE instructions when it's generating AltiVec code ๐Ÿ’…
  • -msecure-plt โ€” generates code that lets ld and ld.so build executables and shared libraries with non-executable .plt and .got sections ๐Ÿ”’ This is a PowerPC 32-bit SYSV ABI option.
  • -mbss-plt โ€” generates code that uses a BSS .plt section that ld.so fills in. It requires .plt and .got sections that are both writable and executable ๐Ÿ™ˆ This is a PowerPC 32-bit SYSV ABI option.
  • -misel, -mno-isel โ€” turns the generation of ISEL instructions on or off โœจ
  • -mvsx, -mno-vsx โ€” makes GCC generate (or not generate) vector/scalar (VSX) instructions, and also turns on (or off) built-in functions that give you more direct access to the VSX instruction set ๐Ÿ”ฅ
  • -mcrypto, -mno-crypto โ€” enables (or disables) the built-in functions that give you direct access to the cryptographic instructions added in version 2.07 of the PowerPC ISA ๐Ÿฆ‹
  • -mhtm, -mno-htm โ€” enables (or disables) the built-in functions that give you direct access to the Hardware Transactional Memory (HTM) instructions added in version 2.07 of the PowerPC ISA ๐ŸŒธ
  • -mpower8-fusion, -mno-power8-fusion โ€” the first one generates code that keeps some integer operations adjacent, so the instructions can be fused together on POWER8 and later processors ๐Ÿงš The second one generates code that does not keep them adjacent.
  • -mquad-memory, -mno-quad-memory โ€” makes GCC generate (or not generate) the non-atomic quad word memory instructions ๐Ÿ“ -mquad-memory requires 64-bit mode.
  • -mquad-memory-atomic, -mno-quad-memory-atomic โ€” makes GCC generate (or not generate) the atomic quad word memory instructions ๐Ÿ“ -mquad-memory-atomic requires 64-bit mode.
  • -mfloat128, -mno-float128 โ€” enables or disables the __float128 keyword for IEEE 128-bit floating point, and picks either software emulation or hardware instructions for it ๐Ÿ’œ

The VSX instruction set (-mvsx) has to be enabled before you can use IEEE 128-bit floating point support ๐Ÿซถ Also, IEEE 128-bit floating point is only supported on Linux.

Only Linux gets IEEE 128-bit floating point support, so it's a no-go anywhere else ๐Ÿ’€

The default for -mfloat128 is enabled on PowerPC Linux systems that use the VSX instruction set, and disabled on other systems โœจ

If you use the ISA 3.0 instruction set (-mcpu=power9) on a 64-bit system, IEEE 128-bit floating point support also enables 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 is done with software emulation.

  • -mfloat128-hardware, -mno-float128-hardware โ€” enables (or disables) using ISA 3.0 hardware instructions to support the __float128 data type ๐Ÿ”ฅ

The default for -mfloat128-hardware is enabled on PowerPC Linux systems that use the ISA 3.0 instruction set, and disabled on other systems ๐Ÿ‘‘

  • -m32, -m64 โ€” generates code for 32-bit or 64-bit environments on Darwin and SVR4 targets, including GNU/Linux ๐ŸŒˆ The 32-bit environment sets int, long, and pointer to 32 bits, and generates code that runs on any PowerPC variant. The 64-bit environment sets int to 32 bits, sets long and pointer to 64 bits, and generates code for PowerPC64, as if you'd used -mpowerpc64.
  • -mfull-toc, -mno-fp-in-toc, -mno-sum-in-toc, -mminimal-toc โ€” these change how the TOC (Table Of Contents) is generated. Every executable file gets one ๐Ÿงš -mfull-toc is selected by default. With it, GCC allocates at least one TOC entry for each unique non-automatic variable reference in your program, and it also puts floating-point constants in the TOC. The catch is that only 16,384 entries are available in the TOC ๐Ÿ˜ญ

If the linker tells you that you've overflowed the available TOC space, you can shrink the TOC usage with -mno-fp-in-toc and -mno-sum-in-toc ๐Ÿซถ -mno-fp-in-toc stops GCC from putting floating-point constants in the TOC. -mno-sum-in-toc makes GCC generate code that calculates the sum of an address and a constant at run time, instead of storing that sum in the TOC. You can use one or both. Each one makes the code very slightly slower and larger, which is the price of saving TOC space.

If you still run out of TOC space even with both of those, use -mminimal-toc instead ๐Ÿ’€ It makes GCC create only one TOC entry for every file. The code is slower and larger, but it uses extremely little TOC space. You might only want to use it on files with less frequently-executed code.

  • -maix64, -maix32 โ€” enables the 64-bit AIX ABI and calling convention, with 64-bit pointers, a 64-bit long type, and the infrastructure needed to support them โœจ Specifying -maix64 implies -mpowerpc64, while -maix32 disables the 64-bit ABI and implies -mno-powerpc64. GCC defaults to -maix32.
  • -mxl-compat, -mno-xl-compat โ€” okay so this one makes your code act more like IBM XL compiler output when you're on the AIX-compatible ABI ๐Ÿ’…โœจ It passes floating-point arguments to prototyped functions past the register save area (RSA) on the stack, in addition to the argument FPRs ๐Ÿฆ‹ It also stops assuming that the most significant double in a 128-bit long double is properly rounded when you compare values and convert to double ๐Ÿ™ˆ And it uses XL symbol names for long double support routines ๐Ÿซถ

The AIX calling convention got extended, but that wasn't documented at first. It was for an obscure K&R C situation: calling a function that takes the address of its arguments with fewer arguments than it declares ๐Ÿ’€ IBM XL compilers read floating-point arguments that don't fit in the RSA from the stack when a subroutine is compiled without optimization. Storing floating-point arguments on the stack all the time is inefficient and rarely needed, so this is not on by default. You only need it when calling subroutines that IBM XL compiled without optimization ๐ŸŒธ

  • -mpe โ€” slay, support for the IBM RS/6000 SP Parallel Environment (PE) ๐ŸŒˆ It links an app 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/), or you need to override the specs file with -specs= to point at the right directory ๐Ÿ—บ๏ธ Heads up: PE doesn't support threads, so -mpe and -pthread are incompatible ๐Ÿšซ
  • -malign-natural, -malign-power โ€” on AIX, 32-bit Darwin, and 64-bit PowerPC GNU/Linux, -malign-natural overrides the ABI-defined alignment of 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 the default, and -malign-power is not supported there ๐Ÿ™…โ€โ™€๏ธ

  • -msoft-float, -mhard-float โ€” -msoft-float generates code that doesn't touch the floating-point register set, and -mhard-float generates code that does use it ๐Ÿ”ง With -msoft-float, software floating-point emulation is provided, but you have to pass the option to GCC when linking too ๐Ÿ’–
  • -mmultiple, -mno-multiple โ€” -mmultiple generates code that uses the load multiple word and store multiple word instructions, and -mno-multiple generates code that doesn't ๐Ÿงฉ These are generated by default on POWER systems, and not on PowerPC systems. Do not use -mmultiple on little-endian PowerPC systems, since those instructions don't work when the processor is in little-endian mode ๐Ÿ˜ญ The exceptions are PPC740 and PPC750, which do permit these instructions in little-endian mode ๐Ÿฆ‹
  • -mupdate, -mno-update โ€” -mupdate generates code that uses load or store instructions that update the base register to the address of the calculated memory location, and -mno-update generates code that doesn't ๐Ÿ’… These instructions are generated by default. If you use -mno-update, there's a small window between the time the stack pointer gets updated and the time the address of the previous frame is stored.
Careful bestie! With -mno-update, 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 does not avoid them ๐ŸŒŠ Indexed instructions can take a performance hit on Power6 processors in certain situations, like stepping through big 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 floating-point multiply and accumulate instructions, and -mno-fused-madd generates code that doesn't ๐Ÿงš These are generated by default if hardware floating point is used. The machine-dependent -mfused-madd is now mapped to the machine-independent -ffp-contract=fast option, and -mno-fused-madd is mapped to -ffp-contract=off ๐Ÿ”ฅ
  • -mmulhw, -mno-mulhw โ€” -mmulhw generates code that uses the half-word multiply and multiply-accumulate instructions on the IBM 405, 440, 464 and 476 processors, and -mno-mulhw generates code that doesn't ๐ŸŒธ These are generated by default when targeting those processors ๐Ÿ’œ
  • -mdlmzb, -mno-dlmzb โ€” -mdlmzb generates code that uses the string-search dlmzb instruction on the IBM 405, 440, 464 and 476 processors, and -mno-dlmzb generates code that doesn't ๐Ÿ” This instruction is generated by default when targeting those processors ๐ŸŽ€
  • -mno-bit-align, -mbit-align โ€” 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 ๐Ÿงธ

Here's the tea โ˜• By default, a structure with nothing but 8 "unsigned" bit-fields of length 1 is aligned to a 4-byte boundary and has a size of 4 bytes. With -mno-bit-align, that same structure is aligned to a 1-byte boundary and is only 1 byte in size ๐Ÿคฏ

  • -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, and -mstrict-align does assume that ๐Ÿซถ
  • -mrelocatable, -mno-relocatable โ€” -mrelocatable generates code that allows a static executable to be relocated to a different address at run time, and -mno-relocatable generates code that doesn't ๐Ÿฆ‹ A simple embedded PowerPC system loader should relocate the entire contents of .got2 and 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 linked together must be compiled with -mrelocatable or -mrelocatable-lib. Also, -mrelocatable code aligns the stack to an 8-byte boundary ๐Ÿ“
  • -mrelocatable-lib, -mno-relocatable-lib โ€” just like -mrelocatable, -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 of -mrelocatable. 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 contains a pointer to a global area pointing to the addresses used in the program, and -mtoc does assume it ๐Ÿงญ
  • -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 / macOS systems, this compiles code so that it is not relocatable, but its external references are relocatable ๐ŸŽ The resulting code is suitable for applications, but not for shared libraries ๐Ÿ™…โ€โ™€๏ธ
  • -msingle-pic-base โ€” this 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 โ€” this controls the priority assigned to dispatch-slot restricted instructions during the second scheduling pass ๐Ÿ—‚๏ธ The argument priority takes the value 0, 1, or 2, which assigns no priority, highest priority, or second-highest priority (respectively) to dispatch-slot restricted instructions โœจ
  • -msched-costly-dep=dependence_type โ€” this 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 โ€” this controls which NOP insertion scheme is 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. Insert exactly as many NOPs as needed to force an insn to a new group, according to the estimated processor grouping ๐ŸŽฏ
    • number โ€” insert NOPs to force costly dependent insns into separate groups. Insert number NOPs to force an insn to a new group ๐Ÿงš
  • -mcall-sysv โ€” on System V.4 and embedded PowerPC systems, this compiles code using calling conventions that follow the March 1995 draft of the System V Application Binary Interface, PowerPC processor supplement ๐Ÿ“œ This is the default unless you configured GCC using powerpc-*-eabiaix ๐ŸŒˆ
  • -mcall-sysv-eabi, -mcall-eabi โ€” these specify both -mcall-sysv and -meabi options ๐Ÿ’œ
  • -mcall-sysv-noeabi โ€” this specifies both -mcall-sysv and -mno-eabi options ๐Ÿฆ‹
  • -mcall-aixdesc โ€” on System V.4 and embedded PowerPC systems, this compiles code for the AIX operating system ๐ŸŽ
  • -mcall-linux โ€” on System V.4 and embedded PowerPC systems, this compiles code for the Linux-based GNU system ๐Ÿง
  • -mcall-freebsd โ€” on System V.4 and embedded PowerPC systems, this compiles code for the FreeBSD operating system ๐Ÿ˜ˆ
  • -mcall-netbsd โ€” on System V.4 and embedded PowerPC systems, this compiles code for the NetBSD operating system ๐Ÿก
  • -mcall-openbsd โ€” on System V.4 and embedded PowerPC systems, this compiles code for the OpenBSD operating system ๐Ÿก
  • -mtraceback=traceback_type โ€” this selects the type of traceback table ๐Ÿงพ Valid values for traceback_type are full, part, and no โœจ
  • -maix-struct-return โ€” returns all structures in memory, as specified by the AIX ABI ๐Ÿ“ฆ
  • -msvr4-struct-return โ€” returns structures smaller than 8 bytes in registers, as specified by the SVR4 ABI ๐Ÿงบ
  • -mabi=abi-type โ€” this extends the current ABI with a particular extension, or removes that extension ๐ŸŒˆ Valid values are: altivec, no-altivec, ibmlongdouble, ieeelongdouble, elfv1, elfv2, and for AIX: vec-extabi, vec-default ๐Ÿ‘‘
  • -mabi=ibmlongdouble โ€” okay so this one switches the ABI over to IBM extended-precision long double ๐Ÿ’…. Heads up though, it's not likely to work if your system already defaults to IEEE extended-precision long double ๐Ÿ˜ญ. If you change long double away from IEEE extended-precision, the compiler will warn you unless you add -Wno-psabi. You also need -mlong-double-128 enabled for this to work ๐Ÿซถ.
  • -mabi=ieeelongdouble โ€” the mirror image of the one above โœจ. It switches the ABI to IEEE extended-precision long double, but 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, and -mlong-double-128 has to be enabled too ๐ŸŒธ.
  • -mabi=elfv1 โ€” this sets the ABI to ELFv1, which is the default for big-endian PowerPC 64-bit Linux ๐Ÿ“. Overriding the default needs special system support, and it's likely to fail in spectacular ways ๐Ÿ’€๐Ÿ”ฅ.
  • -mabi=elfv2 โ€” this one sets the ABI to ELFv2, the default for little-endian PowerPC 64-bit Linux ๐Ÿงš. Overriding the default also needs special system support, and it's likely to fail in spectacular ways ๐Ÿ™ˆ.
  • -mgnu-attribute, -mno-gnu-attribute โ€” the first one emits .gnu_attribute assembly directives that set tag/value pairs in a .gnu.attributes section. Those pairs spell out ABI variations in function parameters or return values ๐Ÿฆ‹.
  • -mprototype, -mno-prototype โ€” on System V.4 and embedded PowerPC systems, -mprototype 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"), so it can tell whether floating-point values get passed in the floating-point registers ๐Ÿ˜ญ. With -mprototype, only calls to prototyped variable argument functions set or clear that bit โœจ.
  • -msim โ€” on embedded PowerPC systems, this assumes the startup module is called sim-crt0.o and the standard C libraries are libsim.a and libc.a ๐ŸŽ€. It's the default for powerpc-*-eabisim configurations ๐ŸŒˆ.
  • -mmvme โ€” on embedded PowerPC systems, this assumes the startup module is called crt0.o and the standard C libraries are libmvme.a and libc.a ๐Ÿ’œ.
  • -mads โ€” on embedded PowerPC systems, this assumes the startup module is called crt0.o and the standard C libraries are libads.a and libc.a ๐Ÿฆ‹.
  • -myellowknife โ€” on embedded PowerPC systems, this assumes the startup module is called crt0.o and the standard C libraries are libyk.a and libc.a ๐ŸŒธ.
  • -mvxworks โ€” on System V.4 and embedded PowerPC systems, this tells the compiler you're building for a VxWorks system ๐Ÿงš.
  • -memb โ€” on embedded PowerPC systems, this sets the "PPC_EMB" bit in the ELF flags header, which signals that eabi extended relocations are being used ๐Ÿซถ.
  • -meabi, -mno-eabi โ€” on System V.4 and embedded PowerPC systems, -meabi makes the compiler adhere to the Embedded Applications Binary Interface (EABI), a set of modifications to the System V.4 specs ๐Ÿ’…. With it, the stack is aligned to an 8-byte boundary, a function __eabi gets called from main to set up the EABI environment, and the -msdata option can use both r2 and r13 to point to two separate small data areas โœจ. -mno-eabi does the opposite: the stack is aligned to a 16-byte boundary, no EABI initialization function gets 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 systems, small initialized const global and static data goes in the .sdata2 section, which r2 points to ๐ŸŒˆ. Small initialized non-const global and static data goes in .sdata, which r13 points to ๐Ÿ’–. Small uninitialized global and static data goes in .sbss, which sits right next to .sdata โญ. Heads up: -msdata=eabi is incompatible with -mrelocatable ๐Ÿ’€. It also sets -memb ๐Ÿ”ฅ.
  • -msdata=sysv โ€” on System V.4 and embedded PowerPC systems, small global and static data goes in .sdata, which r13 points to ๐Ÿ“. Small uninitialized global and static data goes in .sbss, next to .sdata ๐Ÿงš. This one's incompatible with -mrelocatable too ๐Ÿ™ˆ.
  • -msdata=default, -msdata โ€” on System V.4 and embedded PowerPC systems, if -meabi is used, this compiles the code the same way as -msdata=eabi ๐Ÿ’…. Otherwise, it compiles it the same way as -msdata=sysv โœจ.
  • -msdata=data โ€” on System V.4 and embedded PowerPC systems, small global data goes in .sdata ๐Ÿฆ‹. Small uninitialized global data goes in .sbss ๐ŸŒธ. The catch is that r13 doesn't get used to address small data here ๐Ÿซถ. This is the default behaviour unless other -msdata options are used ๐Ÿ‘‘.
  • -msdata=none, -mno-sdata โ€” on embedded PowerPC systems, all initialized global and static data goes in .data, and all uninitialized data goes in .bss ๐Ÿ’œ.
  • -mreadonly-in-sdata โ€” puts read-only objects in .sdata as well ๐ŸŽ€. 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 (both non-loop and loop) of block compare gets 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 handle 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 systems, puts global and static items that are less than or equal to num bytes into the small data or BSS sections, instead of the normal data or BSS section ๐ŸŒˆ. By default, num is 8 โญ. The -G num switch also gets passed to the linker ๐Ÿ”ฅ. All modules should be compiled with the same -G num value, bestie, or things get messy ๐Ÿ’….
  • -mregnames, -mno-regnames โ€” on System V.4 and embedded PowerPC systems, -mregnames makes the compiler emit register names in the assembly output using symbolic forms, and -mno-regnames makes it not do that ๐Ÿฆ‹.
  • -mlongcall, -mno-longcall โ€” by default, the compiler assumes every call is far away, so it uses a longer and more expensive calling sequence ๐Ÿ’œ. This is required for calls farther than 32 megabytes (33,554,432 bytes) from the current location ๐Ÿซถ. A short call only gets generated if the compiler knows the call can't be that far away โœจ. This setting can be overridden by the shortcall function attribute, or by #pragma longcall(0) ๐Ÿ‘‘.

Some linkers can spot out-of-range calls and generate glue code on the fly ๐Ÿ”ฅ. On those systems, long calls are unnecessary and generate slower code ๐Ÿ’€. As of this writing, the AIX linker can do this, and so can the GNU linker for PowerPC/64 ๐ŸŒธ. Adding this feature to the GNU linker for 32-bit PowerPC systems is planned 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 tells the compiler to emit the glue for every direct call, and then 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 โ€” -mpltseq implements -fno-plt and long calls using an inline PLT call sequence, which supports lazy linking and long calls to functions in dlopen'd shared libraries ๐Ÿ‘‘. -mno-pltseq means it doesn't implement them that way ๐Ÿซถ. 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 gets detected when configuring GCC, and, for 32-bit PowerPC, if GCC is configured with --enable-secureplt โญ. Heads up: -mpltseq code and -mbss-plt 32-bit PowerPC relocatable objects may not be linked together ๐Ÿ’€.
  • -mtls-markers, -mno-tls-markers โ€” -mtls-markers marks calls to __tls_get_addr with a relocation that specifies the function argument ๐Ÿงš. -mno-tls-markers doesn't do the marking ๐Ÿ™ˆ. The relocation lets the linker reliably associate the function call with the argument setup instructions for TLS optimization ๐Ÿฆ‹, which in turn lets GCC schedule the sequence better ๐Ÿ’œโœจ.
  • -mrecip, -mno-recip โ€” okay bestie, this one turns on the reciprocal estimate and reciprocal square root estimate instructions, then adds extra Newton-Raphson steps to win back precision ๐Ÿงฎโœจ So instead of doing a full divide (or square root and then divide) for floating-point args, GCC can take the faster route ๐ŸŽ๏ธ. You should pair -mrecip with -ffast-math ๐Ÿ’… (or at least -funsafe-math-optimizations, -ffinite-math-only, -freciprocal-math and -fno-trapping-math). The catch: the throughput is usually higher than the non-reciprocal instruction, but the precision can slip by up to 2 ulp for reciprocal square roots ๐Ÿ˜ญ (like, the inverse of 1.0 comes out as 0.99999994). Not a vibe for every app, so check your math ๐Ÿค“
  • -mrecip=opt โ€” this lets you pick exactly which estimate instructions are allowed ๐ŸŽ€ opt is a comma-separated list, and you can put a ! in front of any item to flip it ๐Ÿ™ƒ
    • all โ€” enable all the estimate instructions, every single one ๐Ÿ”ฅ
    • default โ€” enable the default instructions, same as -mrecip ๐ŸŒธ
    • none โ€” disable all estimate instructions, same as -mno-recip ๐Ÿ™…โ€โ™€๏ธ
    • div โ€” enable the reciprocal approximation instructions for both single and double precision ๐Ÿ’–
    • divf โ€” enable the single-precision reciprocal approximation instructions ๐Ÿฆ‹
    • divd โ€” enable the double-precision reciprocal approximation instructions ๐Ÿงš
    • rsqrt โ€” enable the reciprocal square root approximation instructions for both single and double precision โœจ
    • rsqrtf โ€” enable the single-precision reciprocal square root approximation instructions ๐Ÿ’œ
    • rsqrtd โ€” enable the double-precision reciprocal square root approximation instructions ๐ŸŒˆ

So, for example, -mrecip=all,!rsqrtd turns on every reciprocal estimate instruction except the FRSQRTE, XSRSQRTEDP, and XVRSQRTEDP ones, which handle the double-precision reciprocal square root math ๐Ÿ‘‘ that's a whole main character move right there ๐Ÿ’…

  • -mrecip-precision, -mno-recip-precision โ€” this tells GCC whether 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 turns -mrecip-precision on automatically ๐Ÿซถ Also, the double-precision square root estimate instructions aren't generated by default on low-precision machines, because they don't converge after three steps ๐Ÿ™ˆ
  • -mveclibabi=type โ€” this picks the ABI type for vectorizing intrinsics using an external library ๐Ÿ“š The only type supported right now is mass, which means using IBM's Mathematical Acceleration Subsystem (MASS) libraries to vectorize intrinsics ๐Ÿ”ฅ When you're generating code for power7, GCC emits calls to these functions (that's the whole squad ๐Ÿ’…):
acosd2, acosf4, acoshd2, acoshf4, asind2, asinf4, asinhd2, asinhf4, atan2d2, atan2f4, atand2, atanf4, atanhd2, atanhf4, cbrtd2, cbrtf4, cosd2, cosf4, coshd2, coshf4, erfcd2, erfcf4, erfd2, erff4, exp2d2, exp2f4, expd2, expf4, expm1d2, expm1f4, hypotd2, hypotf4, lgammad2, lgammaf4, log10d2, log10f4, log1pd2, log1pf4, log2d2, log2f4, logd2, logf4, powd2, powf4, sind2, sinf4, sinhd2, sinhf4, sqrtd2, sqrtf4, tand2, tanf4, tanhd2, tanhf4

Both -ftree-vectorize and -funsafe-math-optimizations also have to be on ๐ŸŽ€ And the MASS libraries must be specified at link time, no skipping that step ๐Ÿ™…โ€โ™€๏ธ

  • -mfriz, -mno-friz โ€” this tells GCC whether to generate the friz instruction ๐Ÿฆ‹ It only kicks in when -funsafe-math-optimizations is on, and it speeds up rounding floating-point values to 64-bit integers and back again โœจ Heads up though: friz doesn't give back the same value if the float is too big to fit in an integer ๐Ÿ˜ญ so be careful, bestie
  • -mpointers-to-nested-functions, -mno-pointers-to-nested-functions โ€” this makes GCC generate (or skip) code that loads the static chain register (r11) when calling through a pointer on AIX and 64-bit Linux systems ๐ŸŒธ That's when a function pointer points to a 3-word descriptor holding the function address, the TOC value to load into r2, and the static chain value to load into r11 ๐Ÿงš -mpointers-to-nested-functions is on by default ๐Ÿ’– But 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 โ€” this decides whether GCC saves the TOC value in the reserved stack location in the function prologue, when the function calls through a pointer on AIX and 64-bit Linux ๐ŸŒˆ If it isn't saved in the prologue, it gets saved just before the call through the pointer ๐Ÿซถ -mno-save-toc-indirect is the default, so that's your baseline ๐Ÿ’…
  • -mcompat-align-parm, -mno-compat-align-parm โ€” this makes GCC generate (or not generate) code that passes structure parameters with a max alignment of 64 bits, so it matches older versions of GCC ๐Ÿ•ฐ๏ธ

Older GCC versions (before 4.9.0) messed up by not aligning a structure parameter on a 128-bit boundary when that structure had a member needing 128-bit alignment ๐Ÿ’€ Newer versions fixed it, but if you need to play nice with functions compiled by the older ones, this option is your friend ๐Ÿซถ

-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 โ€” these generate stack protection code using a canary at the 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 with GNU libc 2.4 or later) ๐Ÿงต

With tls, -mstack-protector-guard-reg=reg and -mstack-protector-guard-offset=offset pick the base register used to read the canary, plus the offset from that base register ๐ŸŽฏ If you don't set them, the defaults come from the relevant ABI ๐Ÿ™‚ And -mstack-protector-guard-symbol=symbol overrides the offset with a symbol reference to a canary in the TLS block ๐Ÿ”ฅ

  • -mpcrel, -mno-pcrel โ€” this makes GCC generate (or not generate) pc-relative addressing ๐Ÿ“ -mpcrel needs the medium code model (-mcmodel=medium) and prefixed addressing (-mprefixed) to be enabled first ๐Ÿงš
  • -mprefixed, -mno-prefixed โ€” this makes GCC generate (or not generate) addressing modes that use prefixed load and store instructions โœจ -mprefixed requires -mcpu=power10 (or later) to be enabled ๐Ÿ‘‘
  • -mmma, -mno-mma โ€” this makes GCC generate (or not generate) the MMA instructions ๐Ÿ’œ The -mma option requires -mcpu=power10 (or later) to be enabled ๐ŸŒˆ
  • -mrop-protect, -mno-rop-protect โ€” this makes GCC generate (or not generate) ROP protection instructions when the target processor supports them ๐Ÿ›ก๏ธ Heads up: right now this option disables the shrink-wrap optimization (-fshrink-wrap) ๐Ÿ˜ญ
  • -mprivileged, -mno-privileged โ€” this makes GCC generate (or not generate) code that runs in privileged state ๐Ÿ‘‘ Use with care, bestie ๐Ÿ’€
  • -mblock-ops-unaligned-vsx, -mno-block-ops-unaligned-vsx โ€” this makes GCC generate (or not generate) unaligned VSX loads and stores for inline expansion of memcpy and memmove ๐Ÿš€
  • --param rs6000-vect-unroll-limit= โ€” the vectorizer checks with target info to decide whether unrolling the main vectorized loop would help, and by how much ๐Ÿ” This parameter sets the upper bound on how much it'll unroll the main loop ๐ŸŒธ The default value is four ๐Ÿ“

๐ŸŒธ RX Options ๐ŸŒธ

These command-line options are defined for RX targets ๐Ÿฆ‹

  • -m64bit-doubles, -m32bit-doubles โ€” this makes the double data type 64 bits (-m64bit-doubles) or 32 bits (-m32bit-doubles) ๐Ÿ’– The default is -m32bit-doubles, and the reason is that RX floating-point hardware only works on 32-bit values ๐Ÿค“
  • -fpu, -nofpu โ€” -fpu enables the use of RX floating-point hardware, and -nofpu disables it ๐Ÿ”Œ The default is enabled 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 in play ๐Ÿ™ˆ

If -fpu is enabled, -funsafe-math-optimizations gets turned on automatically too ๐Ÿ’€ That's because the RX FPU instructions are themselves unsafe.
  • -mcpu=name โ€” this picks which type of RX CPU you're targeting ๐ŸŽฏ 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 you select it ๐Ÿซถ

  • -mbig-endian-data, -mlittle-endian-data โ€” this stores data (but not code) in big-endian format โœจ The default is -mlittle-endian-data, which means data gets stored in little-endian format ๐ŸŒท
  • -msmall-data-limit=N โ€” this sets the max size in bytes of global and static variables that can be placed into the small data area ๐Ÿ“ฆ Using the small data area can lead to smaller and faster code ๐ŸŽ๏ธ But the area is limited, so it's on the programmer to make sure it doesn't overflow ๐Ÿ˜ฌ Also, when the small data area is used, one of the RX's registers (usually r13) gets reserved to point to that area, so the compiler can't use it anymore ๐Ÿ’€ That can mean slower and/or larger code if variables get pushed onto the stack instead of being held in that register ๐Ÿ™ˆ

Note: common variables (ones that haven't been initialized) and constants aren't placed into the small data area, because they get assigned to other sections in the output executable ๐Ÿง

okay so the default is 0, which means this feature is switched off ๐Ÿ™…โ€โ™€๏ธ it's NOT turned on at higher optimization levels (-O2 etc) bc reserving a register can be detrimental ๐Ÿ˜ญ so it's up to you to experiment and see if it actually helps your program ๐Ÿ”ฌ for how the register that holds the small data area pointer gets picked, check out the -mpid entry ๐Ÿ‘€

  • -msim, -mno-sim โ€” use the simulator runtime ๐Ÿ–ฅ๏ธ the default is the libgloss board-specific runtime
  • -mas100-syntax, -mno-as100-syntax โ€” when making assembler output, this makes it use a syntax that's compatible with Renesas's AS100 assembler ๐Ÿงต GAS can handle it too, but it has some restrictions, so it's not generated by default
  • -mmax-constant-size=N โ€” sets the max size, in bytes, of a constant that can be used as an operand in an RX instruction ๐Ÿ’… RX lets you use constants up to 4 bytes, but a bigger value = a bigger instruction, so sometimes it's smart to limit this ๐Ÿง  constants that are too big get tossed into a constant pool and referenced via register indirection ๐Ÿ“ฆ

The value N can be between 0 and 4. A value of 0 (the default) or 4 means constants of any size are allowed โœจ

  • -mrelax โ€” turns on linker relaxation ๐Ÿช„ this is where the linker tries to shrink your program by finding shorter versions of instructions. It's disabled by default
  • -mint-register=N โ€” sets how many registers get reserved for fast interrupt handler functions ๐Ÿ”’ N can be between 0 and 4
    • 1 reserves "r13" for the exclusive use of fast interrupt handlers
    • 2 reserves "r13" and "r12"
    • 3 reserves "r13", "r12" and "r11"
    • 4 reserves "r13" through "r10"

0 (the default) doesn't reserve any registers ๐Ÿซถ

  • -msave-acc-in-interrupts โ€” tells interrupt handler functions to preserve the accumulator register ๐Ÿ’œ this is only needed if normal code might use the accumulator, like if it does 64-bit multiplications ๐Ÿ”ข the default is to ignore the accumulator, bc that makes the interrupt handlers faster ๐ŸŽ๏ธ
  • -mpid, -mno-pid โ€” turns on generation of position independent data ๐Ÿฆ‹ when it's on, any access to constant data is done via an offset from a base address held in a register. This lets the location of constant data get 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: using this feature reserves a register, usually "r13", for the constant data base address ๐Ÿ’€ this can make code slower and/or larger, especially in complicated functions

Which register actually gets picked for the constant data base address depends on whether -msmall-data-limit and/or -mint-register are turned on ๐Ÿงฉ starting at "r13" and going downwards, registers are allocated first to satisfy -mint-register, then -mpid, and finally -msmall-data-limit. So it's totally possible for the small data area register to be "r8" if both -mint-register=4 and -mpid are on the command line ๐Ÿคฏ

By default this feature is NOT enabled. You can restore the default with the -mno-pid command-line option ๐Ÿ”„

  • -mno-warn-multiple-fast-interrupts, -mwarn-multiple-fast-interrupts โ€” stops GCC from giving a warning if it finds more than one fast interrupt handler while compiling a file ๐Ÿ™ˆ the default is to warn for each extra fast interrupt handler it finds, bc 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" "SWHILE" and also the "RMPA" instruction ๐Ÿงต these might prefetch data, which is NOT safe if you're accessing an I/O register ๐Ÿšซ (see section 12.2.7 of the RX62N Group User's Manual for more info ๐Ÿ“–)

The default is to allow these instructions. BUT GCC can't reliably detect every situation where a string instruction might touch an I/O register, so they can't be disabled automatically ๐Ÿ˜ฌ it's on you to use -mno-allow-string-insns if your program accesses I/O space ๐Ÿซ 

When the instructions are enabled, GCC defines the C preprocessor symbol "__RX_ALLOW_STRING_INSNS__". Otherwise it defines "__RX_DISALLOW_STRING_INSNS__" ๐Ÿท๏ธ

  • -mjsr, -mno-jsr โ€” uses only (or not only) JSR instructions to access functions ๐ŸŽฏ you can use this when code size goes beyond the range of BSR instructions. Note that -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 the registers "r10", "r11", "r12" and/or "r13", and only if the normal use of the corresponding registers has been restricted via the -ffixed-reg or -mint-register command-line options ๐Ÿ”


โœจ S/390 and zSeries Options โœจ

These are the -m options defined for the S/390 and zSeries architecture ๐Ÿงš

  • -mhard-float, -msoft-float โ€” use (or don't use) the hardware floating-point instructions and registers for floating-point operations โšก with -msoft-float, functions in libgcc.a do the floating-point work. With -mhard-float, the compiler generates IEEE floating-point instructions. This is the default ๐Ÿ’–
  • -mhard-dfp, -mno-hard-dfp โ€” use (or don't use) the hardware decimal-floating-point instructions for decimal-floating-point operations ๐Ÿ”ข with -mno-hard-dfp, functions in libgcc.a are used instead. With -mhard-dfp, the compiler generates decimal-floating-point hardware instructions. This is the default for -march=z9-ec or higher ๐ŸŒˆ
  • -mlong-double-64, -mlong-double-128 โ€” these control the size of the "long double" type ๐Ÿ“ a size of 64 bits makes "long double" equivalent to "double". This is the default ๐Ÿ“
  • -mbackchain, -mno-backchain โ€” stores (or doesn't store) the address of the caller's frame as a backchain pointer into the callee's stack frame ๐Ÿ”— a backchain may be needed to allow debugging with tools that don't understand DWARF call frame information ๐Ÿ” with -mno-packed-stack in effect, the backchain pointer is stored at the bottom of the stack frame. With -mpacked-stack in effect, the backchain is placed into the topmost word of the 96/160 byte register save area ๐Ÿงฑ

In general, code compiled with -mbackchain is call-compatible with code compiled with -mno-backchain. However, using the backchain for debugging usually requires the whole binary to be built with -mbackchain ๐Ÿ› ๏ธ the combination of -mbackchain, -mpacked-stack and -mhard-float is NOT supported โŒ to build a linux kernel, use -msoft-float ๐Ÿง

The default is to not maintain the backchain ๐Ÿ™…โ€โ™€๏ธ

  • -mpacked-stack, -mno-packed-stack โ€” 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 is way more efficient with the 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. Heads up: some non-FSF releases of GCC 2.95 for S/390 or zSeries generated code that uses the stack frame backchain at run time, not just for debugging ๐Ÿ˜ณ that code is NOT call-compatible with code compiled with -mpacked-stack. Also, the combination of -mbackchain, -mpacked-stack and -mhard-float is NOT supported. For a linux kernel, use -msoft-float ๐Ÿง

The default is to not use the packed stack layout ๐Ÿ™…โ€โ™€๏ธ

  • -msmall-exec, -mno-small-exec โ€” generates (or doesn't generate) code using the "bras" instruction to do subroutine calls ๐Ÿ“ž this only works reliably if the total executable size does not exceed 64k ๐Ÿ“‰ the default is to use the "basr" instruction instead, which doesn't have that limitation ๐Ÿ’ซ
  • -m64, -m31 โ€” when -m31 is specified, code gets generated compliant to the GNU/Linux for S/390 ABI ๐Ÿงญ when -m64 is specified, code is generated compliant to the GNU/Linux for zSeries ABI. This lets GCC in particular generate 64-bit instructions ๐Ÿš€ for the s390 targets, the default is -m31, while the s390x targets default to -m64 ๐ŸŽ€
  • -mzarch, -mesa โ€” with -mzarch, code is generated using the instructions available on z/Architecture ๐Ÿ›๏ธ with -mesa, code is generated using the instructions available on ESA/390. Note that -mesa is NOT possible with -m64 โŒ when generating code compliant to the GNU/Linux for S/390 ABI, the default is -mesa. When generating code compliant to the GNU/Linux for zSeries ABI, the default is -mzarch ๐Ÿฐ
  • -mhtm, -mno-htm โ€” -mhtm enables a set of builtins that make use of instructions available with the transactional execution facility, introduced with the IBM zEnterprise EC12 machine generation ๐ŸŒธ see S/390 System z Built-in Functions for the details ๐Ÿ“š -mhtm is enabled by default when using -march=zEC12 ๐Ÿ’œ

Okay so bestie, -mvx turns on the vector extension facility that came with the IBM z13 machine generation ๐Ÿ’–. It's giving ABI drama though, because it changes how some vector type values get aligned and how they're passed around in calls ๐Ÿ’…. If vector types show up somewhere the ABI cares about, GCC adds a GAS .gnu_attribute command so the binary gets marked with the ABI it used ๐Ÿซถ. And -mvx is switched on by default whenever you use -march=z13 โœจ.

  • -mvx, -mno-vx โ€” generate code with the vector extension facility (the one from IBM z13) ๐Ÿฆ‹. This changes the ABI for some vector type values, so it's a whole vibe with alignment and calling conventions. Adds a GAS .gnu_attribute marker for the ABI in ABI-relevant contexts. -mvx is on by default with -march=z13.
  • -mzvector, -mno-zvector โ€” enables vector language extensions and builtins using those same z13 vector instructions ๐Ÿ’œ. It makes vector work as a keyword for declaring vector type variables and arguments ๐ŸŽ€. Heads up: vector only works when GNU extensions are on, and it won't expand if you ask for strict standard compliance like -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 โ€” generate code using the "mvcle" instruction for block moves ๐Ÿšš. With -mno-mvcle, GCC uses an "mvc" loop instead ๐Ÿ”. Using "mvcle" is the default unless you're optimizing for size.
  • -mdebug, -mno-debug โ€” print extra debug info while compiling ๐Ÿ›. The default is to not print it ๐Ÿ™….
  • -march=cpu-type โ€” generate code that runs on cpu-type, which is the name of a system representing a certain processor type ๐Ÿ–ฅ๏ธ. The valid values are z900/arch5, z990/arch6, z9-109, z9-ec/arch7, z10/arch8, z196/arch9, zEC12, z13/arch11, z14/arch12, z15/arch13, z16/arch14, and native. The default is -march=z900. Picking native selects the best architecture option for your host processor ๐Ÿง . -march=native has no effect if GCC doesn't recognize the processor ๐Ÿ˜ฌ.
  • -mtune=cpu-type โ€” tune everything applicable in the generated code for cpu-type, except for the ABI and the set of available instructions ๐ŸŽฏ. It takes the same list of values as -march. The default is whatever value -march is using.
  • -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 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 โญ๏ธ. That gives you the ability to selectively skip function trace entries for TPF OS. This is off by default, even when you're compiling for TPF OS and specifying -mtpf-trace.
  • -mfused-madd, -mno-fused-madd โ€” uses (or doesn't use) the floating-point multiply and accumulate instructions ๐Ÿงฎ. These are generated by default if hardware floating point is in use.
  • -mwarn-framesize=framesize โ€” emits a warning if the current function exceeds the given frame size โš ๏ธ. It's 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 are most likely to cause a stack overflow, which makes it 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 ๐Ÿšจ. That's generally a bad idea when the stack size is limited.
  • -mstack-guard=stack-guard, -mstack-size=stack-size โ€” debugging stack overflow problems ๐Ÿž. When these are provided, the S/390 back end adds extra instructions to the function prologue that trigger a trap if the stack goes stack-guard bytes above stack-size. (Remember, the stack on S/390 grows downward ๐Ÿ“‰.) If you leave out stack-guard, GCC picks the smallest power of 2 larger than the frame size of the compiled function ๐Ÿ”ข. The extra code causes only a little overhead, so it's fine for production-like systems too ๐Ÿš€. 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 ๐Ÿงฉ. The stack-guard option can only be used together with stack-size.
  • -mhotpatch=pre-halfwords,post-halfwords โ€” if the hotpatch option is enabled, a "hot-patching" function prologue gets generated for all functions in the compilation unit ๐Ÿ”ฅ. The function label is prepended with the given number of two-byte NOP instructions (pre-halfwords, maximum 1000000) ๐Ÿซง. After the label, 2 * post-halfwords bytes are appended, using the largest NOP-like instructions the architecture allows (maximum 1000000) ๐Ÿงธ. If both arguments are zero, hotpatching is disabled ๐Ÿšซ. You can override this for individual functions with the "hotpatch" attribute ๐Ÿ‘‘.

๐ŸŒธ SH Options ๐ŸŒธ

These -m options are defined for the SH implementations ๐Ÿ’œ:

  • -m1 โ€” generate code for the SH1.
  • -m2 โ€” generate code for the SH2.
  • -m2e โ€” generate code for the SH2e.
  • -m2a-nofpu โ€” generate code for the SH2a without FPU, or for an SH2a-FPU in a way that the floating-point unit isn't used.
  • -m2a-single-only โ€” generate code for the SH2a-FPU so that no double-precision floating-point operations are used.
  • -m2a-single โ€” generate code for the SH2a-FPU, assuming the floating-point unit is in single-precision mode by default.
  • -m2a โ€” generate code for the SH2a-FPU, assuming the floating-point unit is in double-precision mode by default.
  • -m3 โ€” generate code for the SH3.
  • -m3e โ€” generate code for the SH3e.
  • -m4-nofpu โ€” generate code for the SH4 without a floating-point unit.
  • -m4-single-only โ€” generate code for the SH4 with a floating-point unit that only supports single-precision arithmetic.
  • -m4-single โ€” generate code for the SH4, assuming the floating-point unit is in single-precision mode by default.
  • -m4 โ€” generate code for the SH4.
  • -m4-100 โ€” generate code for SH4-100.
  • -m4-100-nofpu โ€” generate code for SH4-100 in a way that the floating-point unit isn't used.
  • -m4-100-single โ€” generate code for SH4-100, assuming the floating-point unit is in single-precision mode by default.
  • -m4-100-single-only โ€” generate code for SH4-100 so that no double-precision floating-point operations are used.
  • -m4-200 โ€” generate code for SH4-200.
  • -m4-200-nofpu โ€” generate code for SH4-200 without the floating-point unit being used.
  • -m4-200-single โ€” generate code for SH4-200, assuming the floating-point unit is in single-precision mode by default.
  • -m4-200-single-only โ€” generate code for SH4-200 so that no double-precision floating-point operations are used.
  • -m4-300 โ€” generate code for SH4-300.
  • -m4-300-nofpu โ€” generate code for SH4-300 without the floating-point unit being used.
  • -m4-300-single โ€” generate code for SH4-300 so that no double-precision floating-point operations are used.
  • -m4-300-single-only โ€” generate code for SH4-300 so that no double-precision floating-point operations are used.
  • -m4-340 โ€” generate code for SH4-340 (no MMU, no FPU) ๐Ÿ™ˆ.
  • -m4-500 โ€” generate code for SH4-500 (no FPU). It passes -isa=sh4-nofpu to the assembler ๐Ÿงฉ.
  • -m4a-nofpu โ€” generate code for the SH4al-dsp, or for an SH4a in a way that the floating-point unit isn't used.
  • -m4a-single-only โ€” generate code for the SH4a so that no double-precision floating-point operations are used.
  • -m4a-single โ€” generate code for the SH4a, assuming the floating-point unit is in single-precision mode by default.
  • -m4a โ€” generate code for the SH4a.
  • -m4al โ€” same as -m4a-nofpu, except it implicitly passes -dsp to the assembler. GCC doesn't generate any DSP instructions at the moment ๐Ÿซ .
  • -mb โ€” compile code for the processor in big-endian mode ๐ŸŒŠ.
  • -ml โ€” compile code for the processor in little-endian mode ๐ŸŒŠ.
  • -mdalign โ€” align doubles at 64-bit boundaries. Heads up: this changes the calling conventions, so some functions from the standard C library won't work unless you recompile them first with -mdalign ๐Ÿšจ.
  • -mrelax โ€” shorten some address references at link time, when possible. It uses the linker option -relax ๐Ÿ”—.
  • -mbigtable โ€” use 32-bit offsets in "switch" tables. The default is to use 16-bit offsets ๐Ÿ“.
  • -mbitops โ€” enables the use of bit manipulation instructions on SH2A ๐Ÿง .
  • -mfmovd โ€” enables the use of the instruction "fmovd". Check -mdalign for alignment constraints ๐Ÿ“.
  • -mrenesas โ€” comply with the calling conventions defined by Renesas ๐Ÿท๏ธ.
  • -mno-renesas โ€” comply with the calling conventions defined for GCC before the Renesas conventions were available. This 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 โ€” control the IEEE compliance of floating-point comparisons, which affects how cases with unordered comparison results are handled ๐Ÿงฎ. By default, -mieee is implicitly enabled. If -ffinite-math-only is enabled, -mno-ieee is implicitly set, which gives you faster floating-point greater-equal and less-equal comparisons ๐ŸŽ๏ธ. The implicit settings can be overridden by specifying either -mieee or -mno-ieee explicitly ๐Ÿ’….
  • -minline-ic_invalidate โ€” okay bestie, this one inlines code that invalidates instruction cache entries right after it sets up nested function trampolines ๐Ÿงšโœจ It does nothing if -musermode is on and your code gen option (like -m4) doesn't allow the icbi instruction ๐Ÿ™ˆ If your code gen option doesn't allow icbi and -musermode is not on, the inlined code pokes the instruction cache address array directly with an associative write.
๐Ÿ’€ That write needs privileged mode at run time, AND it fails if the cache line got mapped via the TLB and then became unmapped. Be careful out there, babe!
  • -misize โ€” dump instruction size and location in the assembly code ๐Ÿ“๐ŸŽ€
  • -mpadstruct โ€” this one is deprecated, so let's not be doing it ๐Ÿ™…โ€โ™€๏ธ It pads structures to a multiple of 4 bytes, which is incompatible with the SH ABI.
  • -matomic-model=model โ€” this is where you set the model for atomic operations, plus any extra parameters, as a comma separated list ๐Ÿ’… For the full tea on atomic built-in functions, check __atomic Builtins. Here are the models and parameters that are supported:
    • none โ€” turns off compiler generated atomic sequences and emits library calls for atomic operations instead ๐Ÿ˜Œ This is the default if the target is not sh*-*-linux*.
    • soft-gusa โ€” generates GNU/Linux compatible gUSA software atomic sequences for the atomic built-in functions ๐Ÿฆ‹ These need extra help from the system's interrupt/exception handling code and are only suitable for SH3* and SH4* single-core systems. This is turned on by default when the target is sh*-*-linux* and SH3* or SH4*. On SH4A, it also partially uses the hardware atomic instructions movli.l and movco.l for more efficient code, unless strict is specified.
    • soft-tcb โ€” generates software atomic sequences that use a variable in the thread control block ๐Ÿง  It's a variation of the gUSA sequences that can also be used on SH1* and SH2* targets. It needs extra support from the interrupt/exception handling code and is only suitable for single-core systems. When you use this model, the gbr-offset= parameter has to be specified too.
    • soft-imask โ€” generates software atomic sequences that temporarily disable interrupts by setting SR.IMASK = 1111 ๐Ÿ”’ This model only works when the program runs in privileged mode and is only suitable for single-core systems. You don't need extra support from the interrupt/exception handling code for this one. It's enabled by default when the target is sh*-*-linux* and SH1* or SH2*.
    • hard-llcs โ€” generates hardware atomic sequences using only the movli.l and movco.l instructions ๐Ÿ”ฅ This is only available on SH4A and is suitable for multi-core systems. The hardware instructions only support 32 bit atomic variables, so access to 8 or 16 bit variables gets emulated with 32 bit accesses. Code compiled with this option is also compatible with other software atomic model interrupt/exception handling systems if it runs on an SH4A system. No additional support from the interrupt/exception handling code is required for this model.
    • gbr-offset= โ€” this parameter sets the offset in bytes of the variable in the thread control block structure that the generated atomic sequences should use when the soft-tcb model is selected ๐ŸŽฏ For other models this parameter gets ignored. The value must be an integer multiple of four and in the range 0-1020.
    • strict โ€” prevents mixing multiple atomic models, even if they're compatible, and makes the compiler generate atomic sequences of the specified model only ๐Ÿšซ
  • -mtas โ€” generates the tas.b opcode for __atomic_test_and_set ๐Ÿ’ซ Notice that depending on your hardware and software setup, this can hurt overall performance because of the operand cache line flushes that the tas.b instruction implies.
โš ๏ธ On multi-core SH4A processors, the tas.b instruction has to be used with caution, since it can cause data corruption with certain cache configurations. Not the vibe!
  • -mprefergot โ€” when generating position-independent code, emits function calls using the Global Offset Table instead of the Procedure Linkage Table ๐ŸŒธ
  • -musermode, -mno-usermode โ€” -musermode means don't let the compiler generate privileged mode code ๐Ÿ™…โ€โ™€๏ธ -mno-usermode means go ahead and allow it ๐Ÿ™Œ Specifying -musermode also implies -mno-inline-ic_invalidate if the inlined code wouldn't work in user mode. -musermode is the default when the target is sh*-*-linux*. If the target is SH1* or SH2*, -musermode has no effect, since there's no user mode there ๐Ÿคทโ€โ™€๏ธ
  • -multcost=number โ€” sets the cost to assume for a multiply insn ๐Ÿงฎ
  • -mdiv=strategy โ€” sets the division strategy used for integer division operations ๐Ÿฐ strategy can be one of:
    • call-div1 โ€” calls a library function that uses the single-step division instruction div1 to do the operation ๐Ÿซถ Division by zero calculates an unspecified result and does not trap. This is the default except for SH4, SH2A and SHcompact.
    • call-fp โ€” calls a library function that does the operation in double precision floating point ๐Ÿ’ฅ Division by zero causes a floating-point exception. This is the default for SHcompact with FPU. Specifying this for targets that don't have a double precision FPU defaults to call-div1.
    • call-table โ€” calls a library function that uses a lookup table for small divisors and the div1 instruction with case distinction for larger divisors ๐Ÿ“š Division by zero calculates an unspecified result and does not trap. This is the default for SH4. Specifying this for targets that don't have dynamic shift instructions defaults to call-div1.

When a division strategy hasn't been specified, the default gets picked based on the current target ๐ŸŽฏ For SH2A, the default strategy is to use the divs and divu instructions instead of library function calls โœจ

  • -maccumulate-outgoing-args โ€” reserves space once for outgoing arguments in the function prologue instead of around each call ๐Ÿ“ฆ This is generally beneficial for performance and size. It's also needed for unwinding, so the stack frame doesn't change 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/clobbered registers as if this option weren't there.
  • -mfixed-range=register-range โ€” makes the compiler treat the given register range as fixed registers, which means the register allocator can't use them ๐Ÿ” This is useful when compiling kernel code. A register range is two registers separated by a dash, and you can specify multiple ranges separated by a comma.
  • -mbranch-cost=num โ€” assumes num is the cost for a branch instruction ๐ŸŒฟ Higher numbers make the compiler try to generate more branch-free code if possible. If you don't specify it, the value is picked based on the processor type being compiled for.
  • -mzdcbranch, -mno-zdcbranch โ€” -mzdcbranch assumes that zero displacement conditional branch instructions bt and bf are fast โšก With it, the compiler prefers zero displacement branch code sequences. This is enabled by default when generating code for SH4 and SH4A. You can explicitly turn it off with -mno-zdcbranch ๐Ÿ™…โ€โ™€๏ธ (-mno-zdcbranch means do not assume they're fast.)
  • -mcbranch-force-delay-slot โ€” forces the use of delay slots for conditional branches, which stuffs the delay slot with a nop if a suitable instruction can't be found ๐Ÿ˜ด This is disabled by default. You can enable it to work around hardware bugs like the ones found in the original SH7055 ๐Ÿ› ๏ธ
  • -mfused-madd, -mno-fused-madd โ€” -mfused-madd generates code that uses the floating-point multiply and accumulate instructions ๐Ÿง -mno-fused-madd generates code that does not use them ๐Ÿ™…โ€โ™€๏ธ These instructions are generated by default if hardware floating point is used. The machine-dependent -mfused-madd option is now mapped to the machine-independent -ffp-contract=fast option, and -mno-fused-madd is mapped to -ffp-contract=off ๐Ÿ”„
  • -mfsca, -mno-fsca โ€” allows (-mfsca) or disallows (-mno-fsca) the compiler from emitting the fsca instruction for sine and cosine approximations ๐Ÿ“ The option -mfsca must be used in combination with -funsafe-math-optimizations. It's enabled by default when generating code for SH4A. Using -mno-fsca disables sine and cosine approximations even if -funsafe-math-optimizations is in effect.
  • -mfsrra, -mno-fsrra โ€” allows (-mfsrra) or disallows (-mno-fsrra) the compiler from emitting the fsrra instruction for reciprocal square root approximations ๐ŸŒŸ The option -mfsrra must be used with -funsafe-math-optimizations and -ffinite-math-only. It's enabled by default when generating code for SH4A. Using -mno-fsrra disables reciprocal square root approximations even if -funsafe-math-optimizations and -ffinite-math-only are in effect.
  • -mpretend-cmove โ€” prefers zero-displacement conditional branches for conditional move instruction patterns ๐Ÿƒโ€โ™€๏ธ This can result in faster code on the SH4 processor.
  • -mfdpic โ€” generates code using the FDPIC ABI ๐Ÿงš

โœจ Solaris 2 Options โœจ

These -m options are supported on Solaris 2 ๐ŸŒž

  • -mclear-hwcap โ€” tells the compiler to remove the hardware capabilities generated by the Solaris assembler ๐Ÿงน This is only necessary when object files use ISA extensions that the current machine doesn't support, but check at runtime whether or not to use them.
  • -mimpure-text โ€” used in addition to -shared, this tells the compiler to not pass -z text to the linker when linking a shared object ๐Ÿฆ„ With this option, you can link position-dependent code into a shared object. Iconic, honestly.

bestie, okay so -mimpure-text silences the "relocations remain against allocatable but non-writable sections" linker error ๐Ÿ™ˆ but ngl it's a total trap ๐Ÿ’€. The necessary relocations trigger copy-on-write, and the shared object is NOT actually shared across processes ๐Ÿ˜ญ. So instead of reaching for -mimpure-text, compile all your source code with -fpic or -fPIC ๐Ÿซถโœจ.

On Solaris 2, you also get this one in addition to the above:

  • -pthreads โ€” literally just a synonym for -pthread ๐Ÿ’œ

๐ŸŒธ SPARC Options ๐ŸŒธ

These -m options are supported on the SPARC ๐Ÿฆ‹

  • -mno-app-regs, -mapp-regs โ€” Okay, -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 2 through 4 is then treated as an allocable register that gets clobbered by function calls. This is the default โœจ. If you want to be fully SVR4 ABI-compliant (with a bit of a performance hit, sadly ๐Ÿฅฒ), use -mno-app-regs. You should compile libraries and system software with this one ๐Ÿซถ.
  • -mflat, -mno-flat โ€” With -mflat, the compiler skips the save/restore instructions and uses a "flat" or single register window model ๐Ÿงš This model is compatible with the regular register window model. The local registers and the input registers (0--5) are still treated as "call-saved" registers and get saved on the stack as needed. With -mno-flat (the default ๐Ÿ‘‘), the compiler generates save/restore instructions, except for leaf functions. This is the normal operating mode.
  • -mfpu, -mhard-float โ€” Generates output with floating-point instructions. This is the default, obviously ๐Ÿ’–.
  • -mno-fpu, -msoft-float โ€” Generates output with 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 are 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 with 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, it's MUCH slower than calling the ABI library routines. Which is exactly why -msoft-quad-float is the default ๐Ÿ™ˆ.

  • -mno-unaligned-doubles, -munaligned-doubles โ€” -mno-unaligned-doubles assumes doubles have 8-byte alignment. This is the default โœจ.

With -munaligned-doubles, GCC only assumes doubles have 8-byte alignment if they're contained in another type, or if they have an absolute address. Otherwise, it assumes 4-byte alignment ๐Ÿฆ‹. Using this option avoids some rare compatibility problems with code generated by other compilers. It's not the default though, because it costs performance, especially for floating-point code ๐Ÿฅฒ.

  • -muser-mode, -mno-user-mode โ€” -mno-user-mode is the default ๐Ÿ‘‘. It means no code that can only run in supervisor mode gets generated. This is only relevant for the casa instruction emitted for the LEON3 processor ๐Ÿงš.
  • -mfaster-structs, -mno-faster-structs โ€” With -mfaster-structs, the compiler assumes structures should have 8-byte alignment. That lets it use pairs of ldd and std instructions for copies in structure assignment, instead of twice as many ld and st pairs ๐Ÿš€. BUT this changed alignment directly violates the SPARC ABI ๐Ÿ’€. So it's only meant for targets where the developer acknowledges their 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 that return structures or unions. It 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 are v7, cypress, v8, supersparc, hypersparc, leon, leon3, leon3v7, leon5, sparclite, f930, f934, sparclite86x, sparclet, tsc701, v9, ultrasparc, ultrasparc3, niagara, niagara2, niagara3, niagara4, niagara7 and m8.

Native Solaris and GNU/Linux toolchains also support the value native, which picks the best architecture option for the host processor โœจ. -mcpu=native has no effect if GCC doesn't recognize the processor ๐Ÿ’€.

Default instruction scheduling parameters get used for values that select an architecture rather than an 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 SPARC ๐ŸŒˆ. With -mcpu=cypress, the compiler also 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, it's additionally optimized 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 also optimizes for the Fujitsu MB86930 chip, which is the original SPARClite, with no FPU. With -mcpu=f934, it's optimized for the Fujitsu MB86934, 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, it's additionally optimized 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. Then the chip-specific extras stack up: -mcpu=ultrasparc optimizes for the Sun UltraSPARC I/II/IIi chips, -mcpu=ultrasparc3 for the Sun UltraSPARC III/III+/IIIi/IIIi+/IV/IV+ chips, -mcpu=niagara for Sun UltraSPARC T1 chips, -mcpu=niagara2 for Sun UltraSPARC T2 chips, -mcpu=niagara3 for Sun UltraSPARC T3 chips, and -mcpu=niagara4 for Sun UltraSPARC T4 chips ๐Ÿ˜ญ. -mcpu=niagara7 optimizes for Oracle SPARC M7 chips, and -mcpu=m8 optimizes for Oracle M8 chips ๐Ÿ‘‘.

  • -mtune=cpu_type โ€” Sets the instruction scheduling parameters for machine type cpu_type, but does NOT set the instruction set or register set the way -mcpu=cpu_type does ๐ŸŽ€.

The same values work for -mtune=cpu_type as for -mcpu=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 be used too โœจ.

  • -mv8plus, -mno-v8plus โ€” With -mv8plus, GCC generates code for the SPARC-V8+ ABI ๐Ÿฆ‹. The difference from the V8 ABI is that the global and out registers are considered 64 bits wide. This is enabled by default on Solaris in 32-bit mode for all SPARC-V9 processors ๐Ÿ’….
  • -mvis, -mno-vis โ€” With -mvis, GCC generates code that takes advantage of the UltraSPARC Visual Instruction Set extensions ๐Ÿ”ฅ. The default is -mno-vis.
  • -mvis2, -mno-vis2 โ€” With -mvis2, GCC generates code that takes advantage of version 2.0 of the UltraSPARC Visual Instruction Set extensions ๐ŸŒˆ. The default is -mvis2 when targeting a CPU that supports such instructions, like UltraSPARC-III and later. Setting -mvis2 also sets -mvis.
  • -mvis3, -mno-vis3 โ€” With -mvis3, GCC generates code that takes advantage of version 3.0 of the UltraSPARC Visual Instruction Set extensions ๐Ÿงš. The default is -mvis3 when targeting a CPU that supports such instructions, like niagara-3 and later. Setting -mvis3 also sets -mvis2 and -mvis ๐Ÿ’–.
  • -mvis4, -mno-vis4 โ€” okay so -mvis4 makes GCC write code that uses version 4.0 of the UltraSPARC Visual Instruction Set extensions ๐Ÿ’– It's on by default when you target a cpu that has them, like niagara-7 and later โœจ Turning on -mvis4 also turns on -mvis3, -mvis2 and -mvis ๐Ÿฆ‹
  • -mvis4b, -mno-vis4b โ€” with -mvis4b, GCC uses version 4.0 of the UltraSPARC VIS extensions plus the extra VIS instructions added in the Oracle SPARC Architecture 2017 ๐Ÿ”ฅ The default is -mvis4b for cpus that support them, like m8 and later ๐Ÿ’… Setting -mvis4b also sets -mvis4, -mvis3, -mvis2 and -mvis ๐Ÿซถ
  • -mcbcond, -mno-cbcond โ€” with -mcbcond, GCC uses the UltraSPARC Compare-and-Branch-on-Condition instructions ๐ŸŒธ It's the default when targeting a CPU that has them, like Niagara-4 and later ๐Ÿ’œ
  • -mfmaf, -mno-fmaf โ€” with -mfmaf, GCC uses the UltraSPARC Fused Multiply-Add Floating-point instructions ๐Ÿงš Default when targeting a CPU that supports them, like Niagara-3 and later โญ
  • -mfsmuld, -mno-fsmuld โ€” with -mfsmuld, GCC uses the Floating-point Multiply Single to Double (FsMULd) instruction ๐Ÿฆ‹ The default is -mfsmuld when targeting a CPU that supports the architecture versions V8 or V9 with FPU, except -mcpu=leon ๐Ÿ™ˆ
  • -mpopc, -mno-popc โ€” with -mpopc, GCC uses the UltraSPARC Population Count instruction ๐Ÿ“ Default when targeting a CPU that has it, like Niagara-2 and later ๐Ÿ‘‘
  • -msubxc, -mno-subxc โ€” with -msubxc, GCC uses the UltraSPARC Subtract-Extended-with-Carry instruction ๐Ÿ’… It's the default for a CPU that has 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 โœจ

  • -m32, -m64 โ€” generate code for a 32-bit or 64-bit environment ๐Ÿ”ฅ The 32-bit one sets int, long and pointer to 32 bits. The 64-bit one sets int to 32 bits and long and pointer to 64 bits ๐Ÿ’…
  • -mcmodel=which โ€” set the code model to one of these ๐Ÿซถ
    • medlow โ€” the Medium/Low code model: 64-bit addresses, and programs must be linked in the low 32 bits of memory ๐ŸŒธ Programs can be statically or dynamically linked ๐Ÿ’œ
    • medmid โ€” the Medium/Middle code model: 64-bit addresses, and programs must be linked in the low 44 bits of memory ๐Ÿฆ‹ The text and data segments must each be less than 2GB in size, and the data segment must be located within 2GB of the text segment โญ
    • medany โ€” the Medium/Anywhere code model: 64-bit addresses, and programs can be linked anywhere in memory ๐ŸŒˆ The text and data segments must be less than 2GB in size, and the data segment must be located within 2GB of the text segment ๐ŸŽ€
    • embmedany โ€” the Medium/Anywhere code model for embedded systems: 64-bit addresses, and the text and data segments must be less than 2GB in size ๐Ÿงš Both can start anywhere in memory, which gets decided at link time ๐Ÿ™ˆ The global register %g4 points to the base of the data segment ๐Ÿ‘‘ Programs are statically linked, and PIC is not supported ๐Ÿ’€
  • -mmemory-model=mem-model โ€” set the memory model the processor runs with, 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 the stack pointer (and the frame pointer, if there is one) is offset by -2047, which has to 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's recommended to use -symbolic or -shared 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 ๐Ÿซถ

โœจ V850 Options โœจ

These -m options are defined for V850 implementations ๐ŸŒธ

  • -mlong-calls, -mno-long-calls โ€” treats all calls as being far away (near) ๐Ÿ’œ If calls are assumed to be far away, the compiler always loads the function's address into a register, and calls indirect through the pointer ๐Ÿฆ‹
  • -mno-ep, -mep โ€” 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 they use less code space if more than one function saves the same number of registers ๐Ÿงš The -mprolog-function option is on by default if you optimize ๐Ÿ’–
  • -mspace โ€” tries to make the code as small as possible ๐Ÿ”ฅ At present, this just turns on the -mep and -mprolog-function options ๐Ÿ’…
  • -mtda=n โ€” puts static or global variables whose size is n bytes or less into the tiny data area that the ep register points to ๐Ÿซถ The tiny data area can hold up to 256 bytes in total (128 bytes for byte references) ๐ŸŒธ
  • -msda=n โ€” puts static or global variables whose size is n bytes or less into the small data area that the gp register points to ๐Ÿ’œ The small data area can hold up to 64 kilobytes ๐Ÿฆ‹
  • -mzda=n โ€” puts static or global variables whose size is n bytes or less into the first 32 kilobytes of memory โญ
  • -mv850 โ€” specifies that the target processor is the V850 ๐ŸŒˆ
  • -mv850e3v5 โ€” specifies that the target processor is the V850E3V5 ๐ŸŽ€ The preprocessor constant __v850e3v5__ is defined if this option is used ๐Ÿงš
  • -mv850e2v4 โ€” specifies that the target processor is the V850E3V5 ๐Ÿ’– This is an alias for the -mv850e3v5 option โœจ
  • -mv850e2v3 โ€” specifies that the target processor is the V850E2V3 ๐Ÿ”ฅ The preprocessor constant __v850e2v3__ is defined if this option is used ๐Ÿ’…
  • -mv850e2 โ€” specifies that the target processor is the V850E2 ๐Ÿซถ The preprocessor constant __v850e2__ is defined if this option is used ๐ŸŒธ
  • -mv850e1 โ€” specifies that the target processor is the V850E1 ๐Ÿ’œ The preprocessor constants __v850e1__ and __v850e__ are defined if this option is used ๐Ÿฆ‹
  • -mv850es โ€” specifies that the target processor is the V850ES โญ This is an alias for the -mv850e1 option ๐ŸŒˆ
  • -mv850e โ€” 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, no matter which processor variant is the target ๐Ÿ”ฅ

  • -mdisable-callt, -mno-disable-callt โ€” 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 โ€” disables (or re-enables) the generation of hardware floating point instructions โญ This option only matters when the target architecture is V850E2V3 or higher ๐ŸŒˆ If hardware floating point instructions are being generated, then the C preprocessor symbol __FPU_OK__ is defined; otherwise, the symbol __NO_FPU__ is defined ๐ŸŽ€
  • -mloop โ€” enables the use of the e3v5 LOOP instruction ๐Ÿงš This instruction is not enabled by default when the e3v5 architecture is selected, because its use is still experimental ๐Ÿ’–
  • -mrh850-abi, -mghs โ€” enables support for the RH850 version of the V850 ABI ๐Ÿ”ฅ This is the default ๐Ÿ’… With this version of the ABI, the following rules apply ๐Ÿซถ
    • Integer sized structures and unions are returned via a memory pointer rather than a register ๐ŸŒธ
    • Large structures and unions (more than 8 bytes in size) are passed by value ๐Ÿ’œ
    • Functions are aligned to 16-bit boundaries ๐Ÿฆ‹
    • The -m8byte-align command-line option is supported โญ
    • The -mdisable-callt command-line option is enabled by default. The -mno-disable-callt command-line option is not supported ๐ŸŒˆ

When this version of the ABI is enabled, the C preprocessor symbol __V850_RH850_ABI__ is defined ๐ŸŽ€

  • -mgcc-abi โ€” okay so this one turns on the old GCC flavour of the V850 ABI ๐Ÿ’… With this version, the rules are:
    • Integer sized structures and unions get returned in register r10 ๐ŸŽ€
    • Large structures and unions (more than 8 bytes in size) get passed by reference ๐Ÿฆ‹
    • Functions get aligned to 32-bit boundaries, unless you're optimizing for size ๐ŸŒธ
    • The -m8byte-align command-line option is not supported ๐Ÿ’€
    • The -mdisable-callt command-line option is supported, but it's not enabled by default ๐Ÿ™ˆ

When this version of the ABI is on, the C preprocessor symbol __V850_GCC_ABI__ gets defined โœจ

  • -m8byte-align, -mno-8byte-align โ€” this lets double and long long get aligned on 8-byte boundaries ๐Ÿ“ By default, everything gets capped at 4-byte alignment, so this is the glow-up option. When -m8byte-align is in effect, the C preprocessor symbol __V850_8BYTE_ALIGN__ is defined ๐Ÿ’–
  • -mbig-switch โ€” generates code that's suitable for big switch tables ๐Ÿงš Only use this if the assembler or linker is yelling about out of range branches inside a switch table ๐Ÿ˜ญ
  • -mapp-regs โ€” this makes the compiler use r2 and r5 in its generated code. This is the default, so you're already set ๐Ÿซถ
  • -mno-app-regs โ€” this one treats r2 and r5 as fixed registers instead ๐Ÿ”’

โœจ VAX Options โœจ

These -m options are defined for the VAX ๐Ÿฆ‹

  • -munix โ€” don't output certain jump instructions (aobleq and so on) that the Unix assembler for the VAX can't handle across long ranges ๐Ÿ™…โ€โ™€๏ธ
  • -mgnu โ€” do output those jump instructions, on the assumption that the GNU assembler is being used ๐Ÿ’œ
  • -mg โ€” outputs code for G-format floating-point numbers instead of D-format ๐ŸŒˆ
  • -mlra, -mno-lra โ€” these enable Local Register Allocation. It's still experimental for the VAX, so by default the compiler uses standard reload ๐Ÿงช

โœจ Visium Options โœจ

These -m options are defined for the Visium ๐Ÿ›ธ

  • -mdebug โ€” if your program does file I/O and is headed for an MCM target, link it with this option ๐Ÿ”ง It causes the libraries libc.a and libdebug.a to be linked. The program should be run on the target under the control of the GDB remote debugging stub ๐Ÿ›
  • -msim โ€” if your program does file I/O and is destined for the simulator, link it with this option ๐Ÿ–ฅ๏ธ It causes the libraries libc.a and libsim.a to be linked โœจ
  • -mfpu, -mhard-float โ€” generates code containing floating-point instructions. This is the default ๐Ÿ”ฅ
  • -mno-fpu, -msoft-float โ€” generates code containing library calls for floating-point instead ๐Ÿงฎ
-msoft-float changes the calling convention in the output file, so it's only useful if you compile all of a program with this option ๐Ÿšจ In particular, you need to compile libgcc.a, the library that comes with GCC, with -msoft-float in order for this to work.
  • -mcpu=cpu_type โ€” sets the instruction set, register set, and instruction scheduling parameters for machine type cpu_type. 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 machine type cpu_type, but doesn't set the instruction set or register set that -mcpu=cpu_type would ๐ŸŽฏ
  • -msv-mode โ€” generates code for supervisor mode, where there are no restrictions on access to general registers. This is the default ๐Ÿ‘‘
  • -muser-mode โ€” generates code for user mode, where access to some general registers is forbidden. On the GR5, registers r24 to r31 can't be accessed in this mode. On the GR6, only registers r29 to r31 are affected ๐Ÿšซ

โœจ VMS Options โœจ

These -m options are defined for the VMS implementations ๐Ÿ’ป

  • -mvms-return-codes โ€” returns VMS condition codes from main. The default is to return POSIX-style condition (e.g. error) codes ๐Ÿ”
  • -mdebug-main=prefix โ€” flags the first routine whose name starts with prefix as the main routine for the debugger ๐Ÿ”
  • -mmalloc64 โ€” defaults to 64-bit memory allocation routines ๐Ÿง 
  • -mpointer-size=size โ€” sets the default size of pointers. 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__ ๐Ÿงš
  • -msmp โ€” selects SMP runtimes for linking. This isn't available on architectures other than PowerPC, nor on VxWorks version 7 or later, where the selection is part of the VxWorks build configuration and the library paths are the same for either choice ๐Ÿ™…โ€โ™€๏ธ
  • -non-static โ€” links an RTP executable against shared libraries rather than static libraries ๐Ÿ”— The options -static and -shared can also be used for RTPs, and -static is the default ๐Ÿ’œ
  • -Bstatic, -Bdynamic โ€” these options are passed down to the linker. They're defined for compatibility with Diab ๐Ÿค
  • -Xbind-lazy โ€” enables lazy binding of function calls. This option is equivalent to -Wl,-z,now and is defined for compatibility with Diab ๐Ÿฆฅ
  • -Xbind-now โ€” disables lazy binding of function calls. This option is the default, and it's defined for compatibility with Diab โšก

โœจ x86 Options โœจ

These -m options are defined for the x86 family of computers ๐Ÿ’–

  • -march=cpu-type โ€” generates instructions for the machine type cpu-type. Unlike -mtune=cpu-type, which merely tunes the generated code for the specified cpu-type, -march=cpu-type lets GCC generate code that may not run at all on processors other than the one indicated ๐Ÿ˜ฌ Specifying -march=cpu-type implies -mtune=cpu-type, except where noted otherwise.

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, so the result might not run on different machines. Using -mtune=native produces code optimized for the local machine under the constraints of the selected instruction set.
  • x86-64 โ€” a generic CPU with 64-bit extensions ๐ŸŒ
  • x86-64-v2, x86-64-v3, x86-64-v4 โ€” these choices select the 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 micro-architecture level ๐Ÿ“œ Since these cpu-type values don't have a corresponding -mtune setting, using -march with them enables generic tuning. Specific tuning can be enabled using the -mtune=other-cpu-type option with an appropriate other-cpu-type value ๐ŸŽ›๏ธ
  • i386 โ€” the original Intel i386 CPU ๐Ÿฆ•
  • i486 โ€” the Intel i486 CPU. (No scheduling is implemented for this chip ๐Ÿคทโ€โ™€๏ธ)
  • i586, pentium โ€” the Intel Pentium CPU with no MMX support ๐Ÿญ
  • lakemont โ€” the Intel Lakemont MCU, based on the Intel Pentium CPU ๐Ÿ”ง
  • pentium-mmx โ€” the Intel Pentium MMX CPU, based on the Pentium core with MMX instruction set support ๐ŸŽถ
  • pentiumpro โ€” the Intel Pentium Pro CPU ๐ŸŒŸ
  • i686 โ€” when used with -march, the Pentium Pro instruction set is used, so the code runs on all i686 family chips ๐Ÿ’œ When used with -mtune, it has the same meaning as generic.
  • pentium2 โ€” the Intel Pentium II CPU, based on the Pentium Pro core with MMX and FXSR instruction set support โœจ
  • pentium3, pentium3m โ€” the Intel Pentium III CPU, based on the Pentium Pro core with MMX, FXSR and SSE instruction set support ๐ŸŒท
  • pentium-m โ€” the Intel Pentium M, a low-power version of the Intel Pentium III CPU with MMX, SSE, SSE2 and FXSR instruction set support. It's used by Centrino notebooks ๐Ÿ’ป
  • pentium4, pentium4m โ€” the Intel Pentium 4 CPU with MMX, SSE, SSE2 and FXSR instruction set support ๐ŸŒ€
  • prescott โ€” an improved version of the Intel Pentium 4 CPU with MMX, SSE, SSE2, SSE3 and FXSR instruction set support ๐Ÿ“ˆ
  • nocona โ€” an improved version of the Intel Pentium 4 CPU with 64-bit extensions, MMX, SSE, SSE2, SSE3 and FXSR instruction set support ๐ŸŒ™
  • core2 โ€” the Intel Core 2 CPU with 64-bit extensions, MMX, SSE, SSE2, SSE3, SSSE3, CX16, SAHF and FXSR instruction set support โ˜•
  • nehalem โ€” the Intel Nehalem CPU with 64-bit extensions, MMX, SSE, SSE2, SSE3, SSSE3, SSE4.1, SSE4.2, POPCNT, CX16, SAHF and FXSR instruction set support ๐ŸŒฟ
  • westmere โ€” the Intel Westmere CPU with 64-bit extensions, MMX, SSE, SSE2, SSE3, SSSE3, SSE4.1, SSE4.2, POPCNT, CX16, SAHF, FXSR and PCLMUL instruction set support ๐Ÿ’
  • sandybridge โ€” the Intel Sandy Bridge CPU with 64-bit extensions, MMX, SSE, SSE2, SSE3, SSSE3, SSE4.1, SSE4.2, POPCNT, CX16, SAHF, FXSR, AVX, XSAVE and PCLMUL instruction set support ๐ŸŒ…
  • ivybridge โ€” the Intel Ivy Bridge CPU with 64-bit extensions, MMX, SSE, SSE2, SSE3, SSSE3, SSE4.1, SSE4.2, POPCNT, CX16, SAHF, FXSR, AVX, XSAVE, PCLMUL, FSGSBASE, RDRND and F16C instruction set support ๐Ÿƒ
  • haswell โ€” the Intel Haswell CPU with 64-bit extensions, MOVBE, MMX, SSE, SSE2, SSE3, SSSE3, SSE4.1, SSE4.2, POPCNT, CX16, SAHF, FXSR, AVX, XSAVE, PCLMUL, FSGSBASE, RDRND, F16C, AVX2, BMI, BMI2, LZCNT, FMA, MOVBE and HLE instruction set support ๐ŸŒˆ
  • broadwell ๐ŸŒธ: Intel Broadwell CPU is giving 64-bit extensions plus MOVBE, MMX, SSE, SSE2, SSE3, SSSE3, SSE4.1, SSE4.2, POPCNT, CX16, SAHF, FXSR, AVX, XSAVE, PCLMUL, FSGSBASE, RDRND, F16C, AVX2, BMI, BMI2, LZCNT, FMA, MOVBE, HLE, RDSEED, ADCX and PREFETCHW instruction set support ๐Ÿ’…
  • skylake ๐Ÿฆ‹: Intel Skylake CPU brings 64-bit extensions plus MOVBE, MMX, SSE, SSE2, SSE3, SSSE3, SSE4.1, SSE4.2, POPCNT, CX16, SAHF, FXSR, AVX, XSAVE, PCLMUL, FSGSBASE, RDRND, F16C, AVX2, BMI, BMI2, LZCNT, FMA, MOVBE, HLE, RDSEED, ADCX, PREFETCHW, AES, CLFLUSHOPT, XSAVEC, XSAVES and SGX instruction set support โœจ
  • bonnell ๐Ÿงš: Intel Bonnell CPU has 64-bit extensions plus MOVBE, MMX, SSE, SSE2, SSE3 and SSSE3 instruction set support, and that's the whole vibe ๐Ÿ“
  • silvermont ๐Ÿ’œ: Intel Silvermont CPU comes with 64-bit extensions plus MOVBE, MMX, SSE, SSE2, SSE3, SSSE3, SSE4.1, SSE4.2, POPCNT, CX16, SAHF, FXSR, PCLMUL, PREFETCHW and RDRND instruction set support ๐ŸŒˆ
  • goldmont ๐Ÿ‘‘: Intel Goldmont CPU is so extra with 64-bit extensions plus MOVBE, MMX, SSE, SSE2, SSE3, SSSE3, SSE4.1, SSE4.2, POPCNT, CX16, SAHF, FXSR, PCLMUL, PREFETCHW, RDRND, AES, SHA, RDSEED, XSAVE, XSAVEC, XSAVES, XSAVEOPT, CLFLUSHOPT and FSGSBASE instruction set support ๐Ÿ”ฅ
  • goldmont-plus โญ: Intel Goldmont Plus CPU keeps the glow up going with 64-bit extensions plus MOVBE, MMX, SSE, SSE2, SSE3, SSSE3, SSE4.1, SSE4.2, POPCNT, CX16, SAHF, FXSR, PCLMUL, PREFETCHW, RDRND, AES, SHA, RDSEED, XSAVE, XSAVEC, XSAVES, XSAVEOPT, CLFLUSHOPT, FSGSBASE, PTWRITE, RDPID and SGX instruction set support ๐Ÿ’…
  • tremont ๐ŸŽ€: Intel Tremont CPU has 64-bit extensions plus MOVBE, MMX, SSE, SSE2, SSE3, SSSE3, SSE4.1, SSE4.2, POPCNT, CX16, SAHF, FXSR, PCLMUL, PREFETCHW, RDRND, AES, SHA, RDSEED, XSAVE, XSAVEC, XSAVES, XSAVEOPT, CLFLUSHOPT, FSGSBASE, PTWRITE, RDPID, SGX, CLWB, GFNI-SSE, MOVDIRI, MOVDIR64B, CLDEMOTE and WAITPKG instruction set support ๐Ÿซถ
  • sierraforest ๐ŸŒˆ: Intel Sierra Forest CPU is literally a whole forest of features, with 64-bit extensions plus MOVBE, MMX, SSE, SSE2, SSE3, SSSE3, SSE4.1, SSE4.2, POPCNT, AES, PREFETCHW, PCLMUL, RDRND, XSAVE, XSAVEC, XSAVES, XSAVEOPT, FSGSBASE, PTWRITE, RDPID, SGX, GFNI-SSE, CLWB, MOVDIRI, MOVDIR64B, CLDEMOTE, WAITPKG, ADCX, AVX, AVX2, BMI, BMI2, F16C, FMA, LZCNT, PCONFIG, PKU, VAES, VPCLMULQDQ, SERIALIZE, HRESET, KL, WIDEKL, AVX-VNNI, AVXIFMA, AVXVNNIINT8, AVXNECONVERT, CMPCCXADD, ENQCMD and UINTR instruction set support ๐Ÿฆ‹
  • grandridge ๐Ÿงš: Intel Grand Ridge CPU has the exact same feature set as Sierra Forest, so 64-bit extensions plus MOVBE, MMX, SSE, SSE2, SSE3, SSSE3, SSE4.1, SSE4.2, POPCNT, AES, PREFETCHW, PCLMUL, RDRND, XSAVE, XSAVEC, XSAVES, XSAVEOPT, FSGSBASE, PTWRITE, RDPID, SGX, GFNI-SSE, CLWB, MOVDIRI, MOVDIR64B, CLDEMOTE, WAITPKG, ADCX, AVX, AVX2, BMI, BMI2, F16C, FMA, LZCNT, PCONFIG, PKU, VAES, VPCLMULQDQ, SERIALIZE, HRESET, KL, WIDEKL, AVX-VNNI, AVXIFMA, AVXVNNIINT8, AVXNECONVERT, CMPCCXADD, ENQCMD and UINTR instruction set support ๐Ÿ’–
  • clearwaterforest ๐Ÿ’…: Intel Clearwater Forest CPU is the newest glow up on this list, with 64-bit extensions plus MOVBE, MMX, SSE, SSE2, SSE3, SSSE3, SSE4.1, SSE4.2, POPCNT, AES, PREFETCHW, PCLMUL, RDRND, XSAVE, XSAVEC, XSAVES, XSAVEOPT, FSGSBASE, PTWRITE, RDPID, SGX, GFNI-SSE, CLWB, MOVDIRI, MOVDIR64B, CLDEMOTE, WAITPKG, ADCX, AVX, AVX2, BMI, BMI2, F16C, FMA, LZCNT, PCONFIG, PKU, VAES, VPCLMULQDQ, SERIALIZE, HRESET, KL, WIDEKL, AVX-VNNI, ENQCMD, UINTR, AVXIFMA, AVXVNNIINT8, AVXNECONVERT, CMPCCXADD, AVXVNNIINT16, SHA512, SM3, SM4, USER_MSR and PREFETCHI instruction set support ๐Ÿ‘‘
  • knl ๐ŸŒธ: Intel Knight's Landing CPU brings 64-bit extensions plus MOVBE, MMX, SSE, SSE2, SSE3, SSSE3, SSE4.1, SSE4.2, POPCNT, CX16, SAHF, FXSR, AVX, XSAVE, PCLMUL, FSGSBASE, RDRND, F16C, AVX2, BMI, BMI2, LZCNT, FMA, MOVBE, HLE, RDSEED, ADCX, PREFETCHW, AVX512PF, AVX512ER, AVX512F, AVX512CD and PREFETCHWT1 instruction set support ๐Ÿ”ฅ
  • knm ๐Ÿฆ‹: Intel Knights Mill CPU has 64-bit extensions plus MOVBE, MMX, SSE, SSE2, SSE3, SSSE3, SSE4.1, SSE4.2, POPCNT, CX16, SAHF, FXSR, AVX, XSAVE, PCLMUL, FSGSBASE, RDRND, F16C, AVX2, BMI, BMI2, LZCNT, FMA, MOVBE, HLE, RDSEED, ADCX, PREFETCHW, AVX512PF, AVX512ER, AVX512F, AVX512CD and PREFETCHWT1, AVX5124VNNIW, AVX5124FMAPS and AVX512VPOPCNTDQ instruction set support โœจ
  • skylake-avx512 ๐Ÿงš: Intel Skylake Server CPU comes with 64-bit extensions plus MOVBE, MMX, SSE, SSE2, SSE3, SSSE3, SSE4.1, SSE4.2, POPCNT, CX16, SAHF, FXSR, AVX, XSAVE, PCLMUL, FSGSBASE, RDRND, F16C, AVX2, BMI, BMI2, LZCNT, FMA, MOVBE, HLE, RDSEED, ADCX, PREFETCHW, AES, CLFLUSHOPT, XSAVEC, XSAVES, SGX, AVX512F, CLWB, AVX512VL, AVX512BW, AVX512DQ and AVX512CD instruction set support ๐Ÿ’œ
  • cannonlake ๐Ÿ’€: Intel Cannonlake Server CPU has 64-bit extensions plus MOVBE, MMX, SSE, SSE2, SSE3, SSSE3, SSE4.1, SSE4.2, POPCNT, CX16, SAHF, FXSR, AVX, XSAVE, PCLMUL, FSGSBASE, RDRND, F16C, AVX2, BMI, BMI2, LZCNT, FMA, MOVBE, HLE, RDSEED, ADCX, PREFETCHW, AES, CLFLUSHOPT, XSAVEC, XSAVES, SGX, AVX512F, AVX512VL, AVX512BW, AVX512DQ, AVX512CD, PKU, AVX512VBMI, AVX512IFMA and SHA instruction set support ๐ŸŒˆ
  • icelake-client ๐ŸŽ€: Intel Icelake Client CPU is serving 64-bit extensions plus MOVBE, MMX, SSE, SSE2, SSE3, SSSE3, SSE4.1, SSE4.2, POPCNT, CX16, SAHF, FXSR, AVX, XSAVE, PCLMUL, FSGSBASE, RDRND, F16C, AVX2, BMI, BMI2, LZCNT, FMA, MOVBE, HLE, RDSEED, ADCX, PREFETCHW, AES, CLFLUSHOPT, XSAVEC, XSAVES, SGX, AVX512F, AVX512VL, AVX512BW, AVX512DQ, AVX512CD, PKU, AVX512VBMI, AVX512IFMA, SHA, AVX512VNNI, GFNI, VAES, AVX512VBMI2, VPCLMULQDQ, AVX512BITALG, RDPID and AVX512VPOPCNTDQ instruction set support ๐Ÿซถ
  • icelake-server ๐Ÿ’–: Intel Icelake Server CPU has 64-bit extensions plus MOVBE, MMX, SSE, SSE2, SSE3, SSSE3, SSE4.1, SSE4.2, POPCNT, CX16, SAHF, FXSR, AVX, XSAVE, PCLMUL, FSGSBASE, RDRND, F16C, AVX2, BMI, BMI2, LZCNT, FMA, MOVBE, HLE, RDSEED, ADCX, PREFETCHW, AES, CLFLUSHOPT, XSAVEC, XSAVES, SGX, AVX512F, AVX512VL, AVX512BW, AVX512DQ, AVX512CD, PKU, AVX512VBMI, AVX512IFMA, SHA, AVX512VNNI, GFNI, VAES, AVX512VBMI2, VPCLMULQDQ, AVX512BITALG, RDPID, AVX512VPOPCNTDQ, PCONFIG, WBNOINVD and CLWB instruction set support ๐ŸŒธ
  • cascadelake ๐Ÿ“: Intel Cascadelake CPU comes with 64-bit extensions plus MOVBE, MMX, SSE, SSE2, SSE3, SSSE3, SSE4.1, SSE4.2, POPCNT, CX16, SAHF, FXSR, AVX, XSAVE, PCLMUL, FSGSBASE, RDRND, F16C, AVX2, BMI, BMI2, LZCNT, FMA, MOVBE, HLE, RDSEED, ADCX, PREFETCHW, AES, CLFLUSHOPT, XSAVEC, XSAVES, SGX, AVX512F, CLWB, AVX512VL, AVX512BW, AVX512DQ, AVX512CD and AVX512VNNI instruction set support ๐Ÿ‘‘
  • cooperlake ๐Ÿ”ฅ: Intel cooperlake CPU is serving 64-bit extensions plus MOVBE, MMX, SSE, SSE2, SSE3, SSSE3, SSE4.1, SSE4.2, POPCNT, CX16, SAHF, FXSR, AVX, XSAVE, PCLMUL, FSGSBASE, RDRND, F16C, AVX2, BMI, BMI2, LZCNT, FMA, MOVBE, HLE, RDSEED, ADCX, PREFETCHW, AES, CLFLUSHOPT, XSAVEC, XSAVES, SGX, AVX512F, CLWB, AVX512VL, AVX512BW, AVX512DQ, AVX512CD, AVX512VNNI and AVX512BF16 instruction set support โญ
  • tigerlake ๐Ÿงš: Intel Tigerlake CPU has 64-bit extensions plus MOVBE, MMX, SSE, SSE2, SSE3, SSSE3, SSE4.1, SSE4.2, POPCNT, CX16, SAHF, FXSR, AVX, XSAVE, PCLMUL, FSGSBASE, RDRND, F16C, AVX2, BMI, BMI2, LZCNT, FMA, MOVBE, HLE, RDSEED, ADCX, PREFETCHW, AES, CLFLUSHOPT, XSAVEC, XSAVES, SGX, AVX512F, AVX512VL, AVX512BW, AVX512DQ, AVX512CD, PKU, AVX512VBMI, AVX512IFMA, SHA, AVX512VNNI, GFNI, VAES, AVX512VBMI2, VPCLMULQDQ, AVX512BITALG, RDPID, AVX512VPOPCNTDQ, MOVDIRI, MOVDIR64B, CLWB, AVX512VP2INTERSECT and KEYLOCKER instruction set support ๐Ÿ’œ
  • sapphirerapids ๐Ÿ’…: Intel sapphirerapids CPU is the main character with 64-bit extensions plus MOVBE, MMX, SSE, SSE2, SSE3, SSSE3, SSE4.1, SSE4.2, POPCNT, CX16, SAHF, FXSR, AVX, XSAVE, PCLMUL, FSGSBASE, RDRND, F16C, AVX2, BMI, BMI2, LZCNT, FMA, MOVBE, HLE, RDSEED, ADCX, PREFETCHW, AES, CLFLUSHOPT, XSAVEC, XSAVES, SGX, AVX512F, AVX512VL, AVX512BW, AVX512DQ, AVX512CD, PKU, AVX512VBMI, AVX512IFMA, SHA, AVX512VNNI, GFNI, VAES, AVX512VBMI2, VPCLMULQDQ, AVX512BITALG, RDPID, AVX512VPOPCNTDQ, PCONFIG, WBNOINVD, CLWB, MOVDIRI, MOVDIR64B, ENQCMD, CLDEMOTE, PTWRITE, WAITPKG, SERIALIZE, TSXLDTRK, UINTR, AMX-BF16, AMX-TILE, AMX-INT8, AVX-VNNI, AVX512-FP16 and AVX512BF16 instruction set support ๐Ÿซถ
  • alderlake ๐ŸŒˆ: Intel Alderlake CPU has 64-bit extensions plus MOVBE, MMX, SSE, SSE2, SSE3, SSSE3, SSE4.1, SSE4.2, POPCNT, AES, PREFETCHW, PCLMUL, RDRND, XSAVE, XSAVEC, XSAVES, XSAVEOPT, FSGSBASE, PTWRITE, RDPID, SGX, GFNI-SSE, CLWB, MOVDIRI, MOVDIR64B, CLDEMOTE, WAITPKG, ADCX, AVX, AVX2, BMI, BMI2, F16C, FMA, LZCNT, PCONFIG, PKU, VAES, VPCLMULQDQ, SERIALIZE, HRESET, KL, WIDEKL and AVX-VNNI instruction set support ๐Ÿฆ‹
  • rocketlake ๐ŸŒธ: Intel Rocketlake CPU comes with 64-bit extensions plus MOVBE, MMX, SSE, SSE2, SSE3, SSSE3, SSE4.1, SSE4.2, POPCNT, CX16, SAHF, FXSR, AVX, XSAVE, PCLMUL, FSGSBASE, RDRND, F16C, AVX2, BMI, BMI2, LZCNT, FMA, MOVBE, HLE, RDSEED, ADCX, PREFETCHW, AES, CLFLUSHOPT, XSAVEC, XSAVES, AVX512F, AVX512VL, AVX512BW, AVX512DQ, AVX512CD, PKU, AVX512VBMI, AVX512IFMA, SHA, AVX512VNNI, GFNI, VAES, AVX512VBMI2, VPCLMULQDQ, AVX512BITALG, RDPID and AVX512VPOPCNTDQ instruction set support โœจ
  • graniterapids ๐Ÿ‘‘: Intel graniterapids CPU is the newest queen on the list, with 64-bit extensions plus MOVBE, MMX, SSE, SSE2, SSE3, SSSE3, SSE4.1, SSE4.2, POPCNT, CX16, SAHF, FXSR, AVX, XSAVE, PCLMUL, FSGSBASE, RDRND, F16C, AVX2, BMI, BMI2, LZCNT, FMA, MOVBE, HLE, RDSEED, ADCX, PREFETCHW, AES, CLFLUSHOPT, XSAVEC, XSAVES, SGX, AVX512F, AVX512VL, AVX512BW, AVX512DQ, AVX512CD, PKU, AVX512VBMI, AVX512IFMA, SHA, AVX512VNNI, GFNI, VAES, AVX512VBMI2, VPCLMULQDQ, AVX512BITALG, RDPID, AVX512VPOPCNTDQ, PCONFIG, WBNOINVD, CLWB, MOVDIRI, MOVDIR64B, ENQCMD, CLDEMOTE, PTWRITE, WAITPKG, SERIALIZE, TSXLDTRK, UINTR, AMX-BF16, AMX-TILE, AMX-INT8, AVX-VNNI, AVX512-FP16, AVX512BF16, AMX-FP16 and PREFETCHI instruction set support ๐Ÿ’–
  • graniterapids-d โ€” ๐ŸŒธ okay bestie, this is the Intel graniterapids D CPU and it is loaded. You get 64-bit extensions plus MOVBE, MMX, SSE, SSE2, SSE3, SSSE3, SSE4.1, SSE4.2, POPCNT, CX16, SAHF, FXSR, AVX, XSAVE, PCLMUL, FSGSBASE, RDRND, F16C, AVX2, BMI, BMI2, LZCNT, FMA, MOVBE, HLE, RDSEED, ADCX, PREFETCHW, AES, CLFLUSHOPT, XSAVEC, XSAVES, SGX, AVX512F, AVX512VL, AVX512BW, AVX512DQ, AVX512CD, PKU, AVX512VBMI, AVX512IFMA, SHA, AVX512VNNI, GFNI, VAES, AVX512VBMI2, VPCLMULQDQ, AVX512BITALG, RDPID, AVX512VPOPCNTDQ, PCONFIG, WBNOINVD, CLWB, MOVDIRI, MOVDIR64B, ENQCMD, CLDEMOTE, PTWRITE, WAITPKG, SERIALIZE, TSXLDTRK, UINTR, AMX-BF16, AMX-TILE, AMX-INT8, AVX-VNNI, AVX512FP16, AVX512BF16, AMX-FP16, PREFETCHI and AMX-COMPLEX instruction set support. ๐Ÿ’…โœจ
  • arrowlake โ€” ๐Ÿฆ‹ the Intel Arrow Lake CPU, also giving main character energy. It has 64-bit extensions plus MOVBE, MMX, SSE, SSE2, SSE3, SSSE3, SSE4.1, SSE4.2, POPCNT, AES, PREFETCHW, PCLMUL, RDRND, XSAVE, XSAVEC, XSAVES, XSAVEOPT, FSGSBASE, PTWRITE, RDPID, SGX, GFNI-SSE, CLWB, MOVDIRI, MOVDIR64B, CLDEMOTE, WAITPKG, ADCX, AVX, AVX2, BMI, BMI2, F16C, FMA, LZCNT, PCONFIG, PKU, VAES, VPCLMULQDQ, SERIALIZE, HRESET, KL, WIDEKL, AVX-VNNI, UINTR, AVXIFMA, AVXVNNIINT8, AVXNECONVERT and CMPCCXADD instruction set support. ๐ŸŽ€
  • arrowlake-s โ€” ๐Ÿ’– the Intel Arrow Lake S CPU, which is basically arrowlake's glow-up. It has 64-bit extensions plus MOVBE, MMX, SSE, SSE2, SSE3, SSSE3, SSE4.1, SSE4.2, POPCNT, AES, PREFETCHW, PCLMUL, RDRND, XSAVE, XSAVEC, XSAVES, XSAVEOPT, FSGSBASE, PTWRITE, RDPID, SGX, GFNI-SSE, CLWB, MOVDIRI, MOVDIR64B, CLDEMOTE, WAITPKG, ADCX, AVX, AVX2, BMI, BMI2, F16C, FMA, LZCNT, PCONFIG, PKU, VAES, VPCLMULQDQ, SERIALIZE, HRESET, KL, WIDEKL, AVX-VNNI, UINTR, AVXIFMA, AVXVNNIINT8, AVXNECONVERT, CMPCCXADD, AVXVNNIINT16, SHA512, SM3 and SM4 instruction set support. ๐Ÿงš
  • pantherlake โ€” ๐Ÿ‘‘ the Intel Panther Lake CPU, and it's giving a lot. It has 64-bit extensions plus MOVBE, MMX, SSE, SSE2, SSE3, SSSE3, SSE4.1, SSE4.2, POPCNT, AES, PREFETCHW, PCLMUL, RDRND, XSAVE, XSAVEC, XSAVES, XSAVEOPT, FSGSBASE, PTWRITE, RDPID, SGX, GFNI-SSE, CLWB, MOVDIRI, MOVDIR64B, CLDEMOTE, WAITPKG, ADCX, AVX, AVX2, BMI, BMI2, F16C, FMA, LZCNT, PCONFIG, PKU, VAES, VPCLMULQDQ, SERIALIZE, HRESET, KL, WIDEKL, AVX-VNNI, UINTR, AVXIFMA, AVXVNNIINT8, AVXNECONVERT, CMPCCXADD, AVXVNNIINT16, SHA512, SM3, SM4 and PREFETCHI instruction set support. ๐Ÿ”ฅ
  • k6 โ€” ๐ŸŒˆ the AMD K6 CPU, a classic with MMX instruction set support. Vintage queen. ๐Ÿ“
  • k6-2, k6-3 โ€” ๐Ÿง improved versions of the AMD K6 CPU, with MMX and 3DNow! instruction set support.
  • athlon, athlon-tbird โ€” โญ the AMD Athlon CPU with MMX, 3dNOW!, enhanced 3DNow! and SSE prefetch instructions support. Iconic.
  • athlon-4, athlon-xp, athlon-mp โ€” ๐Ÿ”ฅ upgraded AMD Athlon CPUs with MMX, 3DNow!, enhanced 3DNow! and full SSE instruction set support. Level up, no cap.
  • k8, opteron, athlon64, athlon-fx โ€” ๐Ÿ‘‘ processors based on the AMD K8 core with x86-64 instruction set support, including the AMD Opteron, Athlon 64, and Athlon 64 FX processors. (This one supersets MMX, SSE, SSE2, 3DNow!, enhanced 3DNow! and 64-bit instruction set extensions.) ๐Ÿซถ
  • k8-sse3, opteron-sse3, athlon64-sse3 โ€” ๐Ÿ’œ improved versions of the AMD K8 cores with SSE3 instruction set support.
  • amdfam10, barcelona โ€” ๐ŸŒธ CPUs based on AMD Family 10h cores with x86-64 instruction set support. (This supersets MMX, SSE, SSE2, SSE3, SSE4A, 3DNow!, enhanced 3DNow!, ABM and 64-bit instruction set extensions.) โœจ
  • bdver1 โ€” ๐Ÿฆ‹ CPUs based on AMD Family 15h cores with x86-64 instruction set support. (This supersets FMA4, AVX, XOP, LWP, AES, 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.) โœจ
  • znver4 โ€” ๐Ÿ”ฅ 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, AVX512F, AVX512DQ, AVX512IFMA, AVX512CD, AVX512BW, AVX512VL, AVX512BF16, AVX512VBMI, AVX512VBMI2, AVX512VNNI, AVX512BITALG, AVX512VPOPCNTDQ, GFNI and 64-bit instruction set extensions.) ๐Ÿ‘‘
  • znver5 โ€” ๐Ÿฆ‹ AMD Family 1ah 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, AVX512F, AVX512DQ, AVX512IFMA, AVX512CD, AVX512BW, AVX512VL, AVX512BF16, AVX512VBMI, AVX512VBMI2, AVX512VNNI, AVX512BITALG, AVX512VPOPCNTDQ, GFNI, AVXVNNI, MOVDIRI, MOVDIR64B, AVX512VP2INTERSECT, PREFETCHI 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 โ€” ๐Ÿง the IDT WinChip C6 CPU, which gets treated the same way as an i486 but with extra MMX instruction set support. ๐Ÿ“
  • winchip2 โ€” ๐ŸŽ€ the IDT WinChip 2 CPU, also handled the same way as an i486, plus extra MMX and 3DNow! instruction set support. ๐Ÿ’œ
  • c3 โ€” ๐ŸŒˆ the VIA C3 CPU with MMX and 3DNow! instruction set support. (No scheduling is implemented for this chip.) ๐Ÿ˜ญ
  • c3-2 โ€” ๐Ÿฆ‹ the VIA C3-2 (Nehemiah/C5XL) CPU with MMX and SSE instruction set support. (No scheduling is implemented for this chip.) ๐ŸŒธ
  • c7 โ€” โœจ the VIA C7 (Esther) CPU with MMX, SSE, SSE2 and SSE3 instruction set support. (No scheduling is implemented for this chip.) ๐Ÿซถ
  • samuel-2 โ€” ๐Ÿ’– the VIA Eden Samuel 2 CPU with MMX and 3DNow! instruction set support. (No scheduling is implemented for this chip.) ๐Ÿงš
  • nehemiah โ€” ๐Ÿ”ฅ the VIA Eden Nehemiah CPU with MMX and SSE instruction set support. (No scheduling is implemented for this chip.) ๐Ÿ‘‘
  • esther โ€” ๐Ÿ’œ the VIA Eden Esther CPU with MMX, SSE, SSE2 and SSE3 instruction set support. (No scheduling is implemented for this chip.) ๐Ÿ“
  • eden-x2 โ€” ๐ŸŒธ the VIA Eden X2 CPU with x86-64, MMX, SSE, SSE2 and SSE3 instruction set support. (No scheduling is implemented for this chip.) โœจ
  • eden-x4 โ€” ๐ŸŽ€ the VIA Eden X4 CPU with x86-64, MMX, SSE, SSE2, SSE3, SSSE3, SSE4.1, SSE4.2, AVX and AVX2 instruction set support. (No scheduling is implemented for this chip.) ๐Ÿ”ฅ
  • nano โ€” ๐Ÿ’… the generic VIA Nano CPU with x86-64, MMX, SSE, SSE2, SSE3 and SSSE3 instruction set support. (No scheduling is implemented for this chip.) ๐ŸŒˆ
  • nano-1000 โ€” ๐Ÿฆ‹ the VIA Nano 1xxx CPU with x86-64, MMX, SSE, SSE2, SSE3 and SSSE3 instruction set support. (No scheduling is implemented for this chip.) ๐Ÿซถ
  • nano-2000 โ€” ๐Ÿงš the VIA Nano 2xxx CPU with x86-64, MMX, SSE, SSE2, SSE3 and SSSE3 instruction set support. (No scheduling is implemented for this chip.) ๐Ÿ’–
  • nano-3000 โ€” โญ the VIA Nano 3xxx CPU with x86-64, MMX, SSE, SSE2, SSE3, SSSE3 and SSE4.1 instruction set support. (No scheduling is implemented for this chip.) ๐Ÿ‘‘
  • nano-x2 โ€” ๐ŸŒธ the VIA Nano Dual Core CPU with x86-64, MMX, SSE, SSE2, SSE3, SSSE3 and SSE4.1 instruction set support. (No scheduling is implemented for this chip.) ๐Ÿ’œ
  • nano-x4 โ€” ๐Ÿ“ the VIA Nano Quad Core CPU with x86-64, MMX, SSE, SSE2, SSE3, SSSE3 and SSE4.1 instruction set support. (No scheduling is implemented for this chip.) ๐ŸŽ€
  • lujiazui โ€” ๐ŸŒˆ the ZHAOXIN lujiazui CPU with x86-64, MOVBE, MMX, SSE, SSE2, SSE3, SSSE3, SSE4.1, SSE4.2, AVX, POPCNT, AES, PCLMUL, RDRND, XSAVE, XSAVEOPT, FSGSBASE, CX16, ABM, BMI, BMI2, F16C, FXSR, RDSEED instruction set support. ๐Ÿซถโœจ
  • yongfeng โ€” okay this one is a ZHAOXIN yongfeng CPU ๐Ÿ’– It supports the x86-64, MOVBE, MMX, SSE, SSE2, SSE3, SSSE3, SSE4.1, SSE4.2, AVX, POPCNT, AES, PCLMUL, RDRND, XSAVE, XSAVEOPT, FSGSBASE, CX16, ABM, BMI, BMI2, F16C, FXSR, RDSEED, AVX2, FMA, SHA, LZCNT instruction sets, so it's giving full loadout โœจ
  • geode โ€” AMD Geode embedded processor with MMX and 3DNow! instruction set support ๐ŸŒธ

๐ŸŽ€ -mtune=cpu-type

  • -mtune=cpu-type โ€” tune everything applicable in the generated code to cpu-type, but leave the ABI and the set of available instructions alone ๐Ÿฆ‹ Picking a specific cpu-type schedules things properly for that exact chip. The compiler still won't generate code that can't run on the default machine type, unless you also use a -march=cpu-type option. For example, if GCC is configured for i686-pc-linux-gnu, then -mtune=pentium4 gives you code tuned for Pentium 4 that still runs on i686 machines. Slay ๐Ÿ’…

The choices for cpu-type are the same as for -march. On top of that, -mtune has 2 extra choices:

  • 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 pick.
    • As new processors hit the market, this option's behavior changes. So if you upgrade to a newer GCC, the code generation controlled by this option shifts to match whichever processors are most common when that GCC version gets released ๐Ÿ“
    • There's no -march=generic because -march is about the instruction set the compiler can use, and there's no generic instruction set that works on every processor. -mtune, on the other hand, is about the processor (or, in this case, the collection of processors) the code is optimized for.
  • intel โ€” produces code optimized for the most current Intel processors, which for this version of GCC are Haswell and Silvermont ๐Ÿงš If you know the CPU your code will run on, use the matching -mtune or -march option instead of -mtune=intel. But if you want your app to perform well on both Haswell and Silvermont, this is your option.
    • As new Intel processors get deployed, this option's behavior changes. So if you upgrade GCC, the code generation controlled by it will reflect the most current Intel processors at the time that GCC version is released ๐Ÿ‘‘
    • There's no -march=intel option because -march is about the instruction set the compiler can use, and there's no common instruction set that works on all processors. -mtune is about the processor (or collection of processors) the code is optimized for.
  • -mcpu=cpu-type โ€” a deprecated synonym for -mtune ๐Ÿ’€ Old habit, new vibes, so maybe switch to -mtune.

๐ŸŒธ -mfpmath=unit

  • -mfpmath=unit โ€” 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 on the rest ๐Ÿซถ Code compiled this way runs almost everywhere. The temporary results are computed in 80-bit precision instead of the precision the type specifies, so you can get slightly different results compared to most other chips. Check -ffloat-store for the more detailed rundown.
      • This is the default choice for non-Darwin x86-32 targets ๐Ÿ’œ
    • sse โ€” uses scalar floating-point instructions from the SSE instruction set ๐Ÿ”ฅ This set is supported by Pentium III and newer chips, and on the AMD side by Athlon-4, Athlon XP and Athlon MP chips. The earlier version of the SSE instruction set only does single-precision arithmetic, so double and extended-precision arithmetic still go through 387. A later version, found only in Pentium 4 and AMD x86-64 chips, supports double-precision arithmetic too.
      • For the x86-32 compiler, you must use -march=cpu-type, -msse or -msse2 switches to enable 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. Heads up though: it may break some existing code that expects temporaries to be 80 bits ๐Ÿ˜ญ
      • This is the default choice for the x86-64 compiler and Darwin x86-32 targets. It's also the default choice for x86-32 targets with the SSE2 instruction set when -ffast-math is enabled ๐Ÿ‘‘
    • sse,387, sse+387, both โ€” these try to use both instruction sets at once ๐Ÿฆ‹ That effectively doubles the amount of available registers and, on chips with separate execution units for 387 and SSE, the execution resources too. Use this one with care, because it's still experimental. The GCC register allocator doesn't model separate functional units well, which can lead to unstable performance ๐Ÿ’€

๐Ÿง Assembly, IEEE, and 80387 vibes

  • -masm=dialect โ€” outputs assembly instructions in the selected dialect, and also decides which dialect is used for basic asm and extended asm ๐Ÿ’… Supported choices (in dialect order) are att or intel. The default is att. Darwin doesn't support intel ๐Ÿ™ˆ
  • -mieee-fp, -mno-ieee-fp โ€” control whether or not the compiler uses IEEE floating-point comparisons ๐Ÿ“ These handle the case where the result of a comparison is unordered correctly.
  • -m80387, -mhard-float โ€” generate output containing 80387 instructions for floating point โญ
  • -mno-80387, -msoft-float โ€” generate output that uses library calls for floating point instead ๐ŸŒธ
Warning: the requisite libraries are NOT part of GCC, bestie ๐Ÿ˜ญ Normally the facilities of the machine's usual C compiler get used, but that can't be done directly in cross-compilation. You have to make your own arrangements to provide suitable library functions for cross-compilation.

On machines where a function returns floating-point results in the 80387 register stack, some floating-point opcodes may still get emitted even if -msoft-float is used. Plot twist ๐Ÿ™ˆ

  • -mno-fp-ret-in-387 โ€” don't use the FPU registers for return values of functions ๐Ÿฆ‹ The usual calling convention has functions return float and double values in an FPU register, even when there's no FPU. The idea is that the operating system should emulate an FPU. Using -mno-fp-ret-in-387 makes those values come back in ordinary CPU registers instead ๐Ÿงš
  • -mno-fancy-math-387 โ€” some 387 emulators don't support the sin, cos and sqrt instructions for the 387, so this option tells GCC to avoid generating those instructions ๐Ÿซถ It gets overridden when -march says the target CPU always has an FPU, since then the instruction doesn't need emulation. These instructions also aren't generated unless you use the -funsafe-math-optimizations switch too.

๐ŸŽ€ Alignment and long double drama

  • -malign-double, -mno-align-double โ€” 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 gives 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 -malign-double, structures containing the above types get aligned differently than the published application binary interface specs for x86-32. They won't be binary compatible with structures in code compiled without that switch ๐Ÿ’€
  • -m96bit-long-double, -m128bit-long-double โ€” these control the size of the long double type ๐ŸŒˆ The x86-32 application binary interface specifies the size as 96 bits, so -m96bit-long-double is the default in 32-bit mode.
    • Modern architectures (Pentium and newer) prefer long double to be aligned to an 8- or 16-byte boundary. In arrays or structures that conform to the ABI, that isn't possible. So -m128bit-long-double aligns long double to a 16-byte boundary by padding it with an additional 32-bit zero ๐Ÿ“
    • In the x86-64 compiler, -m128bit-long-double is the default, since its ABI says long double is aligned on a 16-byte boundary ๐Ÿ‘‘
    • Heads up: neither of these options gives you any extra precision over the x87 standard of 80 bits for a long double ๐Ÿ™ˆ
Warning: if you override the default value for your target ABI, this changes the size of structures and arrays containing long double variables. It also modifies the function calling convention for functions taking long double. So they aren't binary-compatible with code compiled without that switch ๐Ÿ˜ญ
  • -mlong-double-64, -mlong-double-80, -mlong-double-128 โ€” these also control the size of the long double type ๐Ÿ’œ A size of 64 bits makes long double equivalent to double. That's the default for the 32-bit Bionic C library. A size of 128 bits makes long double equivalent to __float128, which is the default for the 64-bit Bionic C library ๐Ÿ”ฅ
Warning: if you override the default value for your target ABI, this changes the size of structures and arrays containing long double variables. It also modifies the function calling convention for functions taking long double. So they aren't binary-compatible with code compiled without that switch ๐Ÿ’€
  • -malign-data=type โ€” controls how GCC aligns variables ๐Ÿง The supported values for type are:
    • compat โ€” uses an increased alignment value that's compatible with GCC 4.8 and earlier ๐ŸŒธ This is the default.
    • abi โ€” uses the alignment value specified by the psABI ๐Ÿฆ‹
    • cacheline โ€” uses an increased alignment value to match the cache line size โœจ
  • -mlarge-data-threshold=threshold โ€” when -mcmodel=medium or -mcmodel=large is specified, data objects larger than threshold get placed in large data sections ๐Ÿซถ The default is 65535 ๐Ÿ’…
  • -mrtd โ€” okay bestie, this one switches to a whole different function-calling convention ๐Ÿ’… Functions with a fixed number of arguments return using the ret num instruction, which pops their arguments on the way out โœจ That saves the caller one instruction, since it doesn't have to pop them itself ๐Ÿงš

You can make one specific function use this calling sequence with the function attribute "stdcall" ๐ŸŽ€ And if -mrtd is on but you want a function to go back to normal, the function attribute "cdecl" overrides it ๐Ÿซถ

โš ๏ธ Warning: this calling convention is incompatible with the one normally used on Unix, so don't use it if you need to call libraries compiled with the Unix compiler ๐Ÿ’€

You also must provide function prototypes for all functions that take variable numbers of arguments (including printf), or incorrect code gets generated for calls to those functions ๐Ÿ˜ญ

And honestly, seriously incorrect code results if you call a function with too many arguments ๐Ÿ™ˆ Normally the extra arguments are just harmlessly ignored, but not here.

  • -mregparm=num โ€” controls how many registers get used to pass integer arguments ๐Ÿ‘‘ By default no registers are used for this, and at most 3 registers can be used. You can control this for a specific function with the function attribute regparm ๐ŸŒธ
Warning: if you use this switch and num is nonzero, then you must build all modules with the same value, including any libraries. That includes the system libraries and startup modules too ๐Ÿ˜ญ
  • -msseregparm โ€” uses SSE register passing conventions for float and double arguments and return values ๐Ÿฆ‹ You can control this for a specific function with the function attribute sseregparm.
Warning: same energy here. If you use this switch, you must build all modules with the same value, including any libraries, 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 if you need to stay compatible with existing code made by those older compiler versions or older versions of GCC ๐Ÿงธ
  • -mpc32, -mpc64, -mpc80 โ€” set the 80387 floating-point precision to 32, 64 or 80 bits ๐Ÿ”ฅ With -mpc32, the significands of floating-point results get rounded to 24 bits (single precision). -mpc64 rounds them to 53 bits (double precision), and -mpc80 rounds them to 64 bits (extended double precision), which is the default. When you use this option, higher-precision floating-point operations aren't available to the programmer unless you set the FPU control word explicitly.

Dropping the rounding below the default 80 bits can speed some programs up by 2% or more โšก But ngl, some mathematical libraries assume extended-precision (80-bit) floating-point operations are enabled by default. Routines in those libraries could lose a ton of accuracy, typically through so-called "catastrophic cancellation" ๐Ÿ’€ when this option sets the precision below extended precision.

  • -mdaz-ftz โ€” the flush-to-zero (FTZ) and denormals-are-zero (DAZ) flags in the MXCSR register control floating-point calculations ๐ŸŒˆ SSE and AVX instructions, including scalar and vector ones, could benefit from turning on FTZ and DAZ when you specify -mdaz-ftz. Just know that FTZ/DAZ won't get set when -mno-daz-ftz or -shared is specified, except that -mdaz-ftz will set them even with -shared. Plot twist ๐Ÿ™ƒ
  • -mstackrealign โ€” realigns the stack at entry ๐Ÿงš On the x86, this generates an alternate prologue and epilogue that realigns the run-time stack if necessary. It lets legacy code that keeps 4-byte stack alignment mix with modern code that keeps 16-byte stack alignment for SSE compatibility ๐Ÿซถ See also the attribute force_align_arg_pointer, which applies to individual functions.
  • -mpreferred-stack-boundary=num โ€” tries to keep the stack boundary aligned to a 2 raised to num byte boundary ๐Ÿ“ If you don't specify -mpreferred-stack-boundary, the default is 4 (16 bytes or 128 bits).
Warning: when generating code for the x86-64 architecture with SSE extensions disabled, -mpreferred-stack-boundary=3 can keep the stack boundary aligned to an 8 byte boundary. But the x86-64 ABI requires 16 byte stack alignment, so this is ABI incompatible and only meant for a controlled environment where stack space is a seriously important limitation ๐Ÿšจ This option leads to wrong code when functions compiled with 16 byte stack alignment (like functions from a standard library) get called with a misaligned stack. In that case, SSE instructions may lead to misaligned memory access traps. Variable arguments also get 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, the system libraries and startup modules.
  • -mincoming-stack-boundary=num โ€” assumes the incoming stack is aligned to a 2 raised to num byte boundary ๐Ÿ›ฌ If you don't specify -mincoming-stack-boundary, the one specified by -mpreferred-stack-boundary is used.

On Pentium and Pentium Pro, double and long double values should be aligned to an 8-byte boundary (see -malign-double), or you'll take significant run time performance penalties ๐ŸŒ On Pentium III, the SSE data type __m128 may not work properly if it isn't 16-byte aligned.

To make sure these values are aligned on the stack, the stack boundary has to be as aligned as whatever value needs the most alignment on the stack. Every function also has to be generated so it keeps the stack aligned. So calling a function compiled with a higher preferred stack boundary from a function compiled with a lower one most likely misaligns the stack ๐Ÿ˜ตโ€๐Ÿ’ซ It's recommended that libraries that use callbacks always use the default setting ๐Ÿ’–

This extra alignment does eat extra stack space and generally increases code size. If your code is sensitive to stack usage, like embedded systems and operating system kernels, you may want to reduce the preferred alignment to -mpreferred-stack-boundary=2 ๐Ÿง 

  • -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, -mavx512fp16, -mgfni, -mvaes, -mwaitpkg, -mvpclmulqdq, -mavx512bitalg, -mmovdiri, -mmovdir64b, -menqcmd, -muintr, -mtsxldtrk, -mavx512vpopcntdq, -mavx512vp2intersect, -mavx5124fmaps, -mavx512vnni, -mavxvnni, -mavx5124vnniw, -mcldemote, -mserialize, -mamx-tile, -mamx-int8, -mamx-bf16, -mhreset, -mkl, -mwidekl, -mavxifma, -mavxvnniint8, -mavxneconvert, -mcmpccxadd, -mamx-fp16, -mprefetchi, -mraoint, -mamx-complex, -mavxvnniint16, -msm3, -msha512, -msm4, -mapxf, -musermsr, -mavx10.1, -mavx10.1-256, -mavx10.1-512 โ€” these switches turn on the instruction sets for MMX, SSE, AVX512ER, AVX512CD, AVX512VL, AVX512BW, AVX512DQ, AVX512IFMA, AVX512VBMI, SHA, AES, PCLMUL, CLFLUSHOPT, CLWB, FSGSBASE, PTWRITE, RDRND, F16C, FMA, PCONFIG, WBNOINVD, FMA4, PREFETCHW, RDPID, PREFETCHWT1, RDSEED, SGX, XOP, LWP, 3DNow!, enhanced 3DNow!, POPCNT, ABM, ADX, BMI, BMI2, LZCNT, FXSR, XSAVE, XSAVEOPT, XSAVEC, XSAVES, RTM, HLE, TBM, MWAITX, CLZERO, PKU, AVX512VBMI2, GFNI, VAES, WAITPKG, VPCLMULQDQ, AVX512BITALG, MOVDIRI, MOVDIR64B, AVX512BF16, ENQCMD, AVX512VPOPCNTDQ, AVX5124FMAPS, AVX512VNNI, AVX5124VNNIW, SERIALIZE, UINTR, HRESET, AMXTILE, AMXINT8, AMXBF16, KL, WIDEKL, AVXVNNI, AVX512-FP16, AVXIFMA, AVXVNNIINT8, AVXNECONVERT, CMPCCXADD, AMX-FP16, PREFETCHI, RAOINT, AMX-COMPLEX, AVXVNNIINT16, SM3, SHA512, SM4, APX_F, USER_MSR, AVX10.1 or CLDEMOTE extended instruction sets ๐ŸŒŸ Each one has a matching -mno- option to turn that instruction use back off ๐Ÿ™…โ€โ™€๏ธ

These extensions are also available as built-in functions, so check out x86 Built-in Functions to see which functions get enabled and disabled by these switches ๐Ÿงฉ

If you want SSE/SSE2 instructions generated automatically from floating-point code (instead of 387 instructions), look at -mfpmath=sse ๐Ÿ’œ

GCC basically ghosts the SSEx instructions when -mavx is used. Instead, it generates new AVX instructions, or AVX equivalents for all the SSEx instructions, when needed โœจ

These options let GCC use these extended instructions in generated code, even without -mfpmath=sse. If your app does run-time CPU detection, you have to compile separate files for each supported architecture using the right flags ๐Ÿซ  In particular, the file with the CPU detection code should be compiled without these options.

  • -mdump-tune-features โ€” tells GCC to dump the names of the x86 performance tuning features and their default settings ๐Ÿ“œ You can use those names in -mtune-ctrl=feature-list ๐ŸŽ€
  • -mtune-ctrl=feature-list โ€” okay so this is the fine-grain dial for x86 code generation features ๐ŸŽ›๏ธโœจ You pass in a comma separated list of feature names. A feature gets turned on when it's written plainly, but if you put a ^ in front of it, it gets turned off ๐Ÿ™…โ€โ™€๏ธ Also check out -mdump-tune-features while you're at it ๐Ÿ”
โš ๏ธ BESTIE, READ THIS โš ๏ธ -mtune-ctrl=feature-list is intended for GCC developers only ๐Ÿง‘โ€๐Ÿ’ป Using it may lead to code paths that never got covered by testing, and it can potentially result in compiler ICEs or runtime errors ๐Ÿ’€
  • -mno-default โ€” this one turns off ALL the tunable features in one go ๐Ÿงน See also -mtune-ctrl=feature-list and -mdump-tune-features.
  • -mcld โ€” okay this one's a whole story ๐Ÿšจ GCC emits a cld instruction in the prologue of functions that use string instructions. String instructions rely on the DF flag to decide between autoincrement and autodecrement mode. The ABI says DF gets cleared on function entry, but some operating systems don't clear it in their exception dispatchers ๐Ÿ˜ญ So the exception handler can run with DF set, and then string instructions go in the wrong direction. This option can be turned on by default for 32-bit x86 targets by configuring GCC with the --enable-cld configure option ๐ŸŽ€ In that case, you can suppress generation of cld instructions with the -mno-cld compiler option.
  • -mvzeroupper โ€” this instructs GCC to emit a vzeroupper instruction before control flow leaves the function ๐Ÿฆ‹ It's there to cut down the AVX to SSE transition penalty, and it also removes unnecessary zeroupper intrinsics ๐Ÿงน
  • -mprefer-avx128 โ€” this tells the auto-vectorizer to use 128-bit AVX instructions instead of 256-bit AVX instructions ๐Ÿ’œ
  • -mprefer-vector-width=opt โ€” this one makes GCC use opt-bit vector width in instructions instead of the default for the selected platform ๐ŸŒˆ
  • -mpartial-vector-fp-math โ€” this lets GCC generate floating-point operations that might affect the floating-point status flags on partial vectors ๐Ÿง  (those are the ones where vector elements live in the low part of the 128-bit SSE register). Unless -fno-trapping-math is specified, the compiler keeps things correct by sanitizing all input operands so there are zeroes in the unused upper part of the vector register โœจ Heads up though: if you use built-in functions or inline assembly with partial vector arguments, NaNs, denormal or invalid values can leak into the upper part of the vector ๐Ÿ™ˆ That can cause performance issues when -fno-trapping-math is in effect. These issues can be mitigated by manually sanitizing the upper part of the partial vector argument register, or by using -mdaz-ftz to set the denormals-are-zero (DAZ) flag in the MXCSR register ๐Ÿซถ This option is enabled by default โœ…
  • -mmove-max=bits โ€” sets the maximum number of bits that can be moved from memory to memory efficiently ๐Ÿ“ฆ to bits. The valid values are 128, 256 and 512.
  • -mstore-max=bits โ€” same energy, but for storing: this sets the maximum number of bits that can be stored to memory efficiently to bits ๐Ÿ’พ The valid values are 128, 256 and 512.
    • Here's the rundown on the possible values ๐Ÿ“‹:
    • none โ€” no extra limitations applied to GCC other than what's defined by the selected platform.
    • 128 โ€” prefer 128-bit vector width for instructions.
    • 256 โ€” prefer 256-bit vector width for instructions.
    • 512 โ€” prefer 512-bit vector width for instructions.

  • -mnoreturn-no-callee-saved-registers โ€” this optimizes functions with the noreturn attribute or the _Noreturn specifier ๐Ÿชฆ by not saving callee-saved registers in the function prologue, as long as the function uses them (except for the BP register). Just know it can interfere with debugging the caller of the noreturn function, or any function further up in the call stack ๐Ÿ™ƒ so it is not enabled by default.
  • -mcx16 โ€” this lets GCC generate CMPXCHG16B instructions in 64-bit code ๐Ÿ’œ to implement compare-and-exchange operations on 16-byte aligned 128-bit objects. It's super useful for atomic updates of data structures that are bigger than one machine word ๐Ÿซง GCC uses this instruction to implement __sync Builtins. For __atomic Builtins operating on 128-bit integers, though, a library call is always used ๐Ÿ“ž
  • -msahf โ€” this enables generation of SAHF instructions in 64-bit code ๐Ÿงช History tea: early Intel Pentium 4 CPUs with Intel 64 support, before the Pentium 4 G1 step in December 2005, didn't have the LAHF and SAHF instructions that AMD64 supports ๐Ÿ™ˆ These are load and store instructions, respectively, for certain status flags. In 64-bit mode, the SAHF instruction is used to optimize the fmod, drem, and remainder built-in functions; see Other Builtins for details ๐Ÿ”
  • -mmovbe โ€” enables use of the movbe instruction to optimize byte swapping of four and eight byte entities ๐Ÿ”„
  • -mshstk โ€” this one enables shadow stack built-in functions from x86 Control-flow Enforcement Technology (CET) ๐Ÿ›ก๏ธ
  • -mcrc32 โ€” this enables the built-in functions __builtin_ia32_crc32qi, __builtin_ia32_crc32hi, __builtin_ia32_crc32si and __builtin_ia32_crc32di to generate the crc32 machine instruction ๐Ÿ”ข
  • -mmwait โ€” this enables the built-in functions __builtin_ia32_monitor and __builtin_ia32_mwait to generate the monitor and mwait machine instructions โณ
  • -mrecip โ€” this enables RCPSS and RSQRTSS (plus their vectorized buddies RCPPS and RSQRTPS) ๐Ÿงฎ with an extra Newton-Raphson step to boost precision. They get used 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. Warning, bestie ๐Ÿ™ˆ while the throughput of the sequence is higher than the non-reciprocal instruction, the precision can drop by up to 2 ulp (i.e. the inverse of 1.0 equals 0.99999994).

๐Ÿ’ก Note that GCC implements 1.0f/sqrtf(x) in terms of RSQRTSS (or RSQRTPS) already with -ffast-math (or the above option combination), so it doesn't need -mrecip.

๐Ÿ’ก Also, GCC emits the above sequence with the additional Newton-Raphson step for vectorized single-float division and vectorized sqrtf(x) already with -ffast-math (or the above option combination), so it doesn't need -mrecip either.

  • -mrecip=opt โ€” this controls which reciprocal estimate instructions are allowed to be used ๐ŸŽฏ opt is a comma-separated list of options, and any option can be preceded by a ! to invert it:
    • all โ€” enable all estimate instructions.
    • default โ€” enable the default instructions, equivalent to -mrecip.
    • none โ€” disable all estimate instructions, equivalent to -mno-recip.
    • div โ€” enable the approximation for scalar division.
    • vec-div โ€” enable the approximation for vectorized division.
    • sqrt โ€” enable the approximation for scalar square root.
    • vec-sqrt โ€” enable the approximation for vectorized square root.

So, for example, -mrecip=all,!sqrt enables all of the reciprocal approximations, except for square root โœจ

  • -mveclibabi=type โ€” this specifies the ABI type to use when vectorizing intrinsics with an external library ๐Ÿ“š For type, the supported values are svml for the Intel short vector math library and acml for the AMD math core library. To use it, both -ftree-vectorize and -funsafe-math-optimizations have to be enabled, and an SVML or ACML ABI-compatible library 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 ๐ŸŒธ It also emits calls to __vrd2_sin, __vrd2_cos, __vrd2_exp, __vrd2_log, __vrd2_log2, __vrd2_log10, __vrs4_sinf, __vrs4_cosf, __vrs4_expf, __vrs4_logf, __vrs4_log2f, __vrs4_log10f and __vrs4_powf for the corresponding function type when -mveclibabi=acml is used ๐Ÿฆ‹

  • -mabi=name โ€” this 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 โ€” this forces all calls to functions to be indirect ๐Ÿ” It's handy when you're using Intel Processor Trace, since that gives more precise timing information for function calls โฑ๏ธ
  • -mmanual-endbr โ€” this inserts an ENDBR instruction at function entry only via the cf_check function attribute ๐Ÿšช It's useful when you pair it with -fcf-protection=branch, so you can control ENDBR insertion at the function entry ๐Ÿงš
  • -mcet-switch โ€” by default, CET instrumentation is turned off on switch statements that use a jump table, and indirect branch track is disabled ๐Ÿ”€ Since jump tables live in read-only memory, this doesn't cause a direct loss of hardening. But if the jump table index is attacker-controlled, the indirect jump may not be constrained by CET ๐Ÿ˜ฑ This option turns CET instrumentation on, so indirect branch track is enabled for switch statements with jump tables, which leads to the jump targets being reachable via any indirect jumps ๐Ÿ›ก๏ธ๐Ÿ’–
  • -mcall-ms2sysv-xlogues โ€” okay so 64-bit ABIs don't agree on everything, which means any Microsoft ABI function that calls a System V ABI function has to treat RSI, RDI and XMM6-15 as clobbered ๐Ÿ’€. By default the code that saves and restores those registers gets dumped inline, making prologues and epilogues pretty lengthy. Turn this on and they use stubs in the static portion of libgcc instead, so your functions get smaller ๐Ÿ“‰ for the price of a few extra instructions โœจ
  • -mtls-dialect=type โ€” generates thread-local storage access code using the gnu or gnu2 conventions. gnu is the conservative default ๐Ÿ›ก๏ธ, while gnu2 is more efficient ๐Ÿš€ but may add compile- and run-time requirements that can't be satisfied on every system ๐Ÿ˜ฌ
  • -mpush-args, -mno-push-args โ€” uses PUSH operations to store outgoing parameters ๐Ÿ“ฆ. It's shorter and usually just as fast as the SUB/MOV method, and it's on by default. Sometimes turning it off actually helps performance thanks to better scheduling and fewer dependencies ๐Ÿงš
  • -maccumulate-outgoing-args โ€” if enabled, the maximum space needed for outgoing arguments gets computed in the function prologue ๐Ÿงฎ. This is faster on most modern CPUs because of reduced dependencies, improved scheduling and reduced stack usage when the preferred stack boundary isn't equal to 2. The catch is a notable jump in code size ๐Ÿ“ˆ. This switch implies -mno-push-args ๐Ÿซถ
  • -mthreads โ€” supports thread-safe exception handling on MinGW ๐Ÿงต. Programs that rely on it have to compile and link all their code with -mthreads. When compiling, it defines -D_MT, and when linking, it pulls in the special thread helper library -lmingwthrd, which cleans up per-thread exception-handling data ๐Ÿงน
  • -mms-bitfields, -mno-ms-bitfields โ€” turns bit-field layout that's compatible with the native Microsoft Windows compiler on or off ๐ŸŽ€

If packed is used on a structure, or if bit-fields are used, the Microsoft ABI might lay the structure out differently from how GCC normally does it ๐Ÿ‘€. This gets especially messy when you're moving packed data between GCC-compiled functions and the native Microsoft compiler, whether through a function call or as data in a file, so you may need to access either format ๐Ÿ’…

This option is enabled by default for Microsoft Windows targets ๐ŸชŸ. You can also control this locally with variable or type attributes. For more information, check out x86 Variable Attributes and x86 Type Attributes ๐Ÿฆ‹

The Microsoft structure layout algorithm is pretty simple, except for the bit-field packing ๐Ÿค“. The padding and alignment of structure members, and whether a bit-field can straddle a storage-unit boundary, are determined by these rules:

  1. Structure members are stored sequentially in the order they're declared. The first member has the lowest memory address and the last member has the highest.
  2. Every data object has an alignment requirement. For everything except structures, unions, and arrays, that requirement is either the size of the object or the current packing size (set with the aligned attribute or the pack pragma), whichever is less. For structures, unions, and arrays, the alignment requirement is 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 the integral types are the same size, and the next bit-field fits into the current allocation unit without crossing the boundary set 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, the bit-fields are not coalesced.

For example:

struct
 {
   unsigned long bf_1 : 12;
   unsigned long : 0;
   unsigned long bf_2 : 12;
 } t1;

The size of t1 is 8 bytes with the zero-length bit-field. If the zero-length bit-field were removed, t1's size would be 4 bytes ๐Ÿ’€

  1. If a zero-length bit-field is inserted after a bit-field, foo, and the alignment of the zero-length bit-field is greater than that of the member that follows it, bar, then bar is aligned as the type of the zero-length bit-field ๐ŸŒˆ

For example:

struct
 {
   char foo : 4;
   short : 0;
   char bar;
 } t2;

struct
 {
   char foo : 4;
   short : 0;
   double bar;
 } t3;

For t2, bar is placed at offset 2 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 structure โœจ

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 the zero-length bit-field may affect the alignment of the structure as a whole. For example, t2 has a size of 4 bytes, since the zero-length bit-field follows a normal bit-field and is of type short ๐ŸŽฏ
  2. Even if a zero-length bit-field isn't followed by a normal bit-field, it may still affect the alignment of the structure:
struct
 {
   char foo : 6;
   long : 0;
 } t4;

Here, t4 takes up 4 bytes ๐Ÿง 

  1. Zero-length bit-fields that follow non-bit-field members are ignored:
struct
 {
   char foo;
   long : 0;
   char bar;
 } t5;

Here, t5 takes up 2 bytes ๐ŸŒธ


  • -mno-align-stringops โ€” doesn't align the destination of inlined string operations ๐Ÿซง. This shrinks code size and speeds things up when the destination is already aligned but GCC doesn't know it
  • -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 option allows more inlining ๐Ÿ”ฅ and increases code size, but it may boost performance for code that depends on fast memcpy and memset on short lengths. It also enables inline expansion of strlen for all pointer alignments ๐Ÿ’œ
  • -minline-stringops-dynamically โ€” for string operations of unknown size, it uses run-time checks with inline code for small blocks and a library call for large blocks ๐Ÿงšโ€โ™€๏ธ
  • -mstringop-strategy=alg โ€” overrides GCC's internal decision heuristic for which algorithm gets used to inline string operations ๐ŸŽ›๏ธ. The allowed values for alg are:
    • rep_byte, rep_4byte, rep_8byte โ€” expand using the i386 rep prefix of the specified size ๐Ÿ”
    • byte_loop, loop, unrolled_loop โ€” expand into an inline loop ๐ŸŒ€
    • libcall โ€” always use a library call ๐Ÿ“ž
  • -mmemcpy-strategy=strategy โ€” overrides the internal heuristic that decides whether __builtin_memcpy should be inlined and which inline algorithm to use when the expected size of the copy is known ๐Ÿช„. strategy is a comma-separated list of alg:max_size:dest_align triplets. alg is specified in -mstringop-strategy, and max_size is the max byte size that the inline algorithm alg is allowed to handle. For the last triplet, max_size must be -1. The max_size values in the list must be given in increasing order. The minimal byte size for alg is 0 for the first triplet, and max_size + 1 of the preceding range for every triplet after that ๐Ÿ“
  • -mmemset-strategy=strategy โ€” pretty much the same as -mmemcpy-strategy= except it controls __builtin_memset expansion ๐Ÿงธ
  • -momit-leaf-frame-pointer โ€” stops keeping the frame pointer in a register for leaf functions ๐Ÿƒ. This skips the instructions for saving, setting up and restoring frame pointers, and frees up an extra register in leaf functions. The option -fomit-leaf-frame-pointer drops the frame pointer for leaf functions too, but that might make debugging harder ๐Ÿ›
  • -mtls-direct-seg-refs, -mno-tls-direct-seg-refs โ€” controls whether TLS variables can be accessed with offsets from the TLS segment register (%gs for 32-bit, %fs for 64-bit), or whether the thread base pointer has to be added ๐Ÿงต. Whether 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 a VEX prefix ๐ŸŒŠ. The option -mavx turns this on by default ๐Ÿ’ซ
  • -mfentry, -mno-fentry โ€” if profiling is active (-pg), puts the profiling counter call before the prologue ๐Ÿ“Š. Heads up: on x86 architectures the attribute "ms_hook_prologue" isn't possible at the moment for -mfentry and -pg โš ๏ธ
  • -mrecord-mcount, -mno-record-mcount โ€” if profiling is active (-pg), generates a __mcount_loc section that holds pointers to each profiling call ๐Ÿ—‚๏ธ. This is handy for automatically patching calls in and out ๐Ÿฉน
  • -mnop-mcount, -mno-nop-mcount โ€” if profiling is active (-pg), generates the calls to the profiling functions as NOPs ๐Ÿ˜ด. This is useful when they should be patched in later, dynamically. It's likely only useful together with -mrecord-mcount ๐Ÿซถ
  • -minstrument-return=type โ€” instruments function exit in -pg -mfentry instrumented functions by calling the specified function ๐Ÿšช. This only instruments true returns that end with ret, not sibling calls that end with a jump. Valid types are none to not instrument, call to generate a call to __return__, or nop5 to generate a 5-byte NOP ๐ŸŒŸ

okay so this part is a whole buffet of -m switches, and we're going through every single one ๐Ÿ’…๐ŸŽ€

  • -mrecord-return, -mno-record-return โ€” this one makes a __return_loc section that points at all the return instrumentation code ๐Ÿงš
  • -mfentry-name=name โ€” picks the name of the __fentry__ symbol that gets called at function entry for -pg -mfentry functions โœจ
  • -mfentry-section=name โ€” sets the section name where -mrecord-mcount calls get recorded. The default is __mcount_loc ๐ŸŒธ
  • -mskip-rax-setup, -mno-skip-rax-setup โ€” bestie, this is for x86-64 code with SSE extensions turned off. -mskip-rax-setup lets you skip setting up the RAX register when no variable arguments get passed in vector registers ๐Ÿฆ‹
Warning: RAX is used to avoid saving vector registers on the stack for no reason when passing variable arguments, so the impacts here are that callees may waste some stack space, misbehave, or jump to a random location. GCC 4.4 or newer don't have those issues, regardless of the RAX register value ๐Ÿ’€
  • -m8bit-idiv, -mno-8bit-idiv โ€” on some processors like Intel Atom, 8-bit unsigned integer divide is way faster than 32-bit or 64-bit integer divide. This option adds a run-time check. If both the dividend and divisor are within 0 to 255, it uses 8-bit unsigned integer divide instead of 32-bit/64-bit integer divide ๐Ÿ”ฅ
  • -mavx256-split-unaligned-load, -mavx256-split-unaligned-store โ€” splits 32-byte AVX unaligned loads and stores into smaller pieces ๐Ÿซถ
  • -mstack-protector-guard=guard โ€” generates stack protection code using a canary at the guard location. The supported locations are global for a global canary or tls for a per-thread canary in the TLS block, and tls is the default. This option only does something when -fstack-protector or -fstack-protector-all is specified ๐Ÿ‘‘
  • -mstack-protector-guard-reg=reg, -mstack-protector-guard-offset=offset โ€” with the latter choice of guard, these two decide which segment register (%fs or %gs) gets used as the base register for reading the canary, and what offset from that base it reads from. Their defaults are whatever the relevant ABI says ๐ŸŒˆ
  • -mgeneral-regs-only โ€” only generates code that uses general-purpose registers. The compiler is blocked from touching floating-point, vector, mask, and bound registers ๐Ÿ“
  • -mrelax-cmpxchg-loop โ€” when making a compare-and-swap loop for __sync Builtins and __atomic Builtins that don't have a native instruction, this optimizes for the super contended case. It issues an atomic load before the "CMPXCHG" instruction, and uses the "PAUSE" instruction to save CPU power when restarting the loop ๐Ÿ’œ
  • -mindirect-branch=choice โ€” converts indirect calls and jumps based on the choice. The default is keep, which leaves indirect calls and jumps alone. thunk converts them into call and return thunks. thunk-inline converts them into inlined call and return thunks. thunk-extern converts them into external call and return thunks that live in a separate object file. You can control this for a specific function with the function attribute "indirect_branch" ๐Ÿฆ‹
Note: -mcmodel=large is incompatible with -mindirect-branch=thunk and -mindirect-branch=thunk-extern, since the thunk function may not be reachable in the large code model ๐Ÿ™ˆ
Note: -mindirect-branch=thunk-extern is compatible with -fcf-protection=branch, since the external thunk can be made to enable control-flow check โœจ
  • -mfunction-return=choice โ€” converts function returns based on the choice. The default is keep, which leaves function returns unmodified. thunk converts them into call and return thunks. thunk-inline converts them into inlined call and return thunks. thunk-extern converts them into external call and return thunks in a separate object file. You can control this for a specific function with the function attribute "function_return" ๐ŸŒธ
Note: -mindirect-return=thunk-extern is compatible with -fcf-protection=branch, since the external thunk can be made to enable control-flow check ๐Ÿซถ
Note: -mcmodel=large is incompatible with -mfunction-return=thunk and -mfunction-return=thunk-extern, since the thunk function may not be reachable in the large code model ๐Ÿ’€
  • -mindirect-branch-register โ€” forces indirect calls and jumps to go through a register ๐Ÿงš
  • -mharden-sls=choice โ€” generates code to mitigate straight line speculation (SLS) based on the choice. The default is none, which disables all SLS hardening. return enables it for function returns, indirect-jmp enables it for indirect jumps, and all turns on all SLS hardening ๐Ÿ”ฅ
  • -mindirect-branch-cs-prefix โ€” adds a CS prefix to call and jmp instructions going to an indirect thunk, where the branch target is in the r8-r15 registers. This makes the call and jmp instruction length 6 bytes, so they can be swapped at run-time for lfence; call *%r8-r15 or lfence; jmp *%r8-r15 ๐Ÿ‘‘
  • -mapx-inline-asm-use-gpr32 โ€” for inline asm support with APX, the EGPR feature is disabled by default to prevent a possible illegal instruction from EGPR showing up. To turn on EGPR usage in inline asm, use this option, and you need to make sure the instruction actually supports EGPR ๐Ÿ™ˆ
  • -mevex512, -mno-evex512 โ€” enables or disables 512-bit vectors. It's on by default if AVX512F is enabled ๐ŸŒˆ

These -m switches are supported in addition to the above on x86-64 processors in 64-bit environments.

  • -m32, -m64, -mx32, -m16, -miamcu โ€” generates code for a 16-bit, 32-bit, or 64-bit environment. -m32 sets "int", "long", and pointer types to 32 bits, and generates code that runs in 32-bit mode ๐ŸŽ€
  • -m64 sets "int" to 32 bits and "long" and pointer types to 64 bits, and generates code for the x86-64 architecture. For Darwin only, -m64 also turns off the -fno-pic and -mdynamic-no-pic options ๐Ÿ“
  • -mx32 sets "int", "long", and pointer types to 32 bits, and generates code for the x86-64 architecture ๐Ÿฆ‹
  • -m16 is the same as -m32, except it outputs the ".code16gcc" assembly directive at the start of the assembly output so the binary can run in 16-bit mode ๐Ÿ’œ
  • -miamcu generates code that conforms to the Intel MCU psABI. It requires -m32 to be turned on โœจ
  • -mno-red-zone โ€” don't use a so-called "red zone" for x86-64 code. The red zone is mandated by the x86-64 ABI. It's a 128-byte area beyond the stack pointer that signal or interrupt handlers don't modify, so it can be used for temporary data without adjusting the stack pointer. This flag disables that red zone ๐ŸŒธ
  • -mcmodel=small โ€” generates code for the small code model, where 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, where the program is linked in the lower 2 GB of the address space. Small symbols get placed there too. Symbols bigger than -mlarge-data-threshold go into large data or BSS sections and can live above 2GB. Programs can be statically or dynamically linked ๐Ÿซถ
  • -mcmodel=large โ€” generates code for the large model, which 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 ๐ŸŽ€
  • -mneeded, -mno-needed โ€” emits the GNU_PROPERTY_X86_ISA_1_NEEDED GNU property for Linux targets. This tells you the micro-architecture ISA level needed to run the binary ๐Ÿ’…
  • -mno-direct-extern-access โ€” without -fpic or -fPIC, always uses the GOT pointer to access external symbols. With -fpic or -fPIC, access to protected symbols is treated as local symbols. The default is -mdirect-extern-access ๐Ÿ“
Warning: shared libraries compiled with -mno-direct-extern-access and executables compiled with -mdirect-extern-access may not be binary compatible if protected symbols are used in shared libraries and executables ๐Ÿ˜ญ
  • -munroll-only-small-loops โ€” controls conservative small loop unrolling. It's enabled by default with O2, and unrolls loops with fewer than 4 insns by 1 time. Explicitly using -f[no-]unroll-[all-]loops turns this flag off, so you don't get any unrolling you didn't ask for ๐Ÿฆ‹
  • -mlam=choice โ€” LAM (linear-address masking) lets special bits in the pointer be used for metadata. The default is none. With u48, pointer bits in positions 62:48 can be used for metadata. With u57, pointer bits in positions 62:57 can be used for metadata ๐Ÿ’œ

โœจ x86 Windows Options โœจ

These additional options are available for Microsoft Windows targets:

  • -mconsole โ€” this option makes a console application, by telling the linker to set the PE header subsystem type that console applications need. It's available for Cygwin and MinGW targets and is enabled by default on those targets ๐ŸŽ€
  • -mcrtdll=library: okay bestie, this one is a whole vibe ๐Ÿ’… It lets you preprocess, compile, or link with the C RunTime DLL library you pick. It adjusts the predefined macros __CRTDLL__, __MSVCRT__ and __MSVCRT_VERSION__ for that CRT, chooses its start file, and links it in ๐ŸŽ€. The names the preprocessor recognizes are "crtdll", "msvcrt10", "msvcrt20", "msvcrt40", "msvcrt-os", "msvcr70", "msvcr80", "msvcr90", "msvcr100", "msvcr110", "msvcr120" and "ucrt" โœจ. If you skip this flag, the default MinGW import library msvcrt gets linked and the preprocessor isn't touched at all ๐Ÿ™ˆ. That msvcrt import library is just a symlink to (or a copy of) whichever MinGW CRT import library was picked when MinGW got compiled. msvcrt-os is the one for the Windows system CRT DLL msvcrt.dll, and in most cases it's the default MinGW import library ๐Ÿ‘‘.
Heads up, bestie: switching the CRT DLL usually means recompiling the entire MinGW CRT ๐Ÿ’€. This option is strictly for experimental and testing purposes. It's available for MinGW targets.
  • -mdll: this one's for Cygwin and MinGW targets ๐Ÿฆ‹. It tells GCC to generate a DLL (a dynamic link library), which lets you pick the runtime startup object and entry point you need.
  • -mnop-fun-dllimport: also for Cygwin and MinGW ๐ŸŒธ. It tells GCC to ignore the dllimport attribute. Bye, attribute ๐Ÿ‘‹.
  • -mthreads: MinGW only ๐Ÿงต. It switches on MinGW-specific thread support.
  • -municode: MinGW-w64 only ๐Ÿ’œ. It predefines the UNICODE preprocessor macro and picks Unicode-capable runtime startup code, so your strings are giving full Unicode energy ๐ŸŒˆ.
  • -mwin32: Cygwin and MinGW ๐Ÿ“. It sets up the typical Microsoft Windows predefined macros in the preprocessor, but it does not change which runtime library or startup code gets chosen.
  • -mwindows: Cygwin and MinGW again ๐ŸชŸ. It makes a GUI application by telling the linker to set the PE header subsystem type to match.
  • -fno-set-stack-executable: MinGW only ๐Ÿ”’. The executable flag doesn't get set on the stack that nested functions use. This is needed for binaries running in kernel mode of Microsoft Windows, since the User32 API (the thing used to set executable privileges) isn't available there.
  • -fwritable-relocated-rdata: MinGW and Cygwin ๐Ÿงš. 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: Cygwin and MinGW ๐Ÿ’–. It uses the GNU extension to the PE file format that lets COMMON variables be aligned correctly when code is generated. This is enabled by default if GCC detects that the target assembler found during configuration supports the feature.

See also under x86 Options for standard options. That's where the regular stuff lives, bestie ๐Ÿซถ.


โœจ Xstormy16 Options โœจ

These options are defined for Xstormy16 ๐ŸŒŸ.

  • -msim: pick startup files and a linker script that suit the simulator ๐ŸŽฎ.

โœจ Xtensa Options โœจ

These options are supported for Xtensa targets ๐Ÿฆ‹.

  • -mconst16, -mno-const16: turn the use of CONST16 instructions for loading constant values on or off ๐Ÿ”›. CONST16 isn't a standard Tensilica option right now. When it's enabled, CONST16 instructions are always used in place of the standard L32R instructions. It's only on by default when L32R isn't available ๐Ÿ™ˆ.
  • -mfused-madd, -mno-fused-madd: enable or disable fused multiply/add and multiply/subtract instructions in the floating-point option ๐Ÿ”ฅ. This does nothing if the floating-point option isn't also on. Turning fused ops off makes the compiler use separate instructions for the multiply and the add/subtract. That can be the move when you need strict IEEE 754-compliant results ๐Ÿ’…, since fused multiply add/subtract doesn't round the intermediate result, so it ends up with more bits of precision than the IEEE standard specifies. Turning them off also means your program output isn't affected by how well the compiler can combine multiply and add/subtract operations ๐Ÿง .
  • -mserialize-volatile, -mno-serialize-volatile: when this is enabled, GCC inserts MEMW instructions before volatile memory references to guarantee sequential consistency ๐Ÿ”. The default is -mserialize-volatile. Use -mno-serialize-volatile if you want to leave out the MEMW instructions.
  • -mforce-no-pic: for targets like GNU/Linux, where all user-mode Xtensa code has to be position-independent code (PIC) ๐Ÿงฉ, this disables PIC when compiling kernel code.
  • -mtext-section-literals, -mno-text-section-literals: these control how literal pools are treated ๐Ÿ—‚๏ธ. The default is -mno-text-section-literals, which puts literals in a separate section of the output file. That lets the literal pool live in data RAM/ROM, and it lets the linker merge literal pools from separate object files to kill redundant literals and shrink code size โœ‚๏ธ. With -mtext-section-literals, literals are interspersed in the text section so they sit as close as possible to where they're referenced ๐Ÿ“. This might be necessary for large assembly files. Literals for each function get placed right before that function.
  • -mauto-litpools, -mno-auto-litpools: also about literal pools, bestie ๐ŸŒŠ. The default is -mno-auto-litpools, which puts literals in a separate section of the output file unless -mtext-section-literals is used. With -mauto-litpools, the assembler interweaves the literals into the text section itself. The compiler doesn't emit explicit .literal directives and loads literals into registers with MOVI instead of L32R, so the assembler can do relaxation and place literals wherever they need to go ๐Ÿช„. This lets the assembler make several literal pools per function and assemble very big functions, which might not be possible with -mtext-section-literals.
  • -mtarget-align, -mno-target-align: when enabled, GCC tells the assembler to automatically align instructions to cut down on branch penalties, even though you lose a bit of code density ๐ŸŽฏ. The assembler tries to widen density instructions so branch targets and the instructions right after call instructions get aligned. If there aren't enough safe density instructions before a target to line it up, no widening happens. The default is -mtarget-align. These options don't change how auto-aligned instructions like LOOP get treated, since the assembler always aligns those, either by widening density instructions or by inserting NOP instructions ๐Ÿ™Œ.
  • -mlongcalls, -mno-longcalls: when enabled, GCC tells the assembler to turn direct calls into indirect calls, unless it can tell the target of the direct call is within range of the call instruction ๐Ÿ“ž. This usually happens for calls to functions in other source files. Specifically, the assembler turns a direct CALL into an L32R followed by a CALLX. The default is -mno-longcalls. Use this in programs where the call target could possibly be out of range ๐Ÿš€. Fun fact, this option is implemented in the assembler, not the compiler, so the assembly GCC generates still shows direct call instructions. If you want to see what's actually running, look at the disassembled object code ๐Ÿ”. The assembler uses an indirect call for every cross-file call, not just the ones that are really out of range.
  • -mabi=name: generate code for the ABI you specify ๐Ÿ“œ. The permissible values are call0 and windowed. The default ABI is chosen by the Xtensa core configuration.
  • -mabi=call0: when this is enabled, function parameters get passed in registers a2 through a7, registers a12 through a15 are caller-saved, and register a15 may be used as a frame pointer ๐ŸŒท. When this version of the ABI is on, the C preprocessor symbol "__XTENSA_CALL0_ABI__" is defined.
  • -mabi=windowed: when this is enabled, function parameters get passed in registers a10 through a15. The called function rotates the register window by 8 registers on entry, so its arguments show up in registers a2 through a7 ๐ŸŒ€. Register a7 may be used as a frame pointer. The register window gets rotated 8 registers back upon return. When this version of the ABI is on, the C preprocessor symbol "__XTENSA_WINDOWED_ABI__" is defined.
  • -mextra-l32r-costs=n: specify an extra cost, in clock cycles, for instruction RAM/ROM access on L32R instructions ๐Ÿข. When you're optimizing for speed, this affects whether a constant gets loaded from the literal pool using L32R or built from a small one with a couple of arithmetic instructions. The default value is 0.
  • -mstrict-align, -mno-strict-align: this controls whether GCC avoids or allows generating memory accesses that might not be aligned on a natural object boundary, as described in the architecture specification ๐Ÿ“. The default is -mno-strict-align for cores that support both unaligned loads and stores in hardware, and -mstrict-align for all other cores.

โœจ zSeries Options โœจ

These are listed under

โœจ ENVIRONMENT โœจ

okay so this section is all about environment variables that change how GCC behaves ๐Ÿ’… Some of them point it at directories or prefixes to search for files, and others tweak the compilation setup itself ๐ŸŒธ

Note that you can also specify places to search using options such as -B, -I and -L ๐Ÿงš These take precedence over places set with environment variables, which in turn beat whatever GCC's configuration says ๐Ÿ‘‘

LANG, LC_CTYPE, LC_MESSAGES, LC_ALL ๐ŸŒˆ

These environment variables control the localization info that lets GCC work with different national conventions ๐ŸŒ GCC looks at the locale categories LC_CTYPE and LC_MESSAGES if it's been configured to do so. These categories can be set to any value your installation supports. A typical value is en_GB.UTF-8, which means English in the United Kingdom, encoded in UTF-8 ๐Ÿ‡ฌ๐Ÿ‡ง

LC_CTYPE is the character classification one ๐Ÿฆ‹ GCC uses it to figure out where character boundaries are in a string. This 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 decides which language is used in diagnostic messages ๐Ÿ’ฌ

If the LC_ALL variable is set, it overrides LC_CTYPE and LC_MESSAGES ๐Ÿ‘‘ Otherwise, LC_CTYPE and LC_MESSAGES default to whatever LANG says. If none of these are set, GCC defaults to traditional C English behavior ๐Ÿ“

TMPDIR ๐Ÿ—‚๏ธ

If TMPDIR is set, it tells GCC which directory to use for temporary files ๐ŸŒธ GCC uses temp files to hold the output of one stage of compilation so the next stage can use it as input. 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 the docs for that option if you want the full tea โ˜•

GCC_EXEC_PREFIX ๐Ÿง

If GCC_EXEC_PREFIX is set, it gives a prefix to use in the names of the subprograms the compiler runs ๐ŸŽ€ No slash gets added when the prefix is combined with a subprogram name, so if you want that slash, end your prefix with one yourself ๐Ÿฆ‹

If GCC_EXEC_PREFIX isn't set, GCC tries to figure out a sensible prefix based on the pathname it was invoked with ๐Ÿ”

If GCC can't find the subprogram using the prefix you gave it, it goes looking in the usual places instead ๐Ÿƒโ€โ™€๏ธ

The default value of GCC_EXEC_PREFIX is prefix/lib/gcc/, where prefix is the prefix of the installed compiler ๐Ÿ’… In a lot of cases, prefix is whatever "prefix" was set to when you ran the configure script ๐ŸŒท

Prefixes given with -B take precedence over this one ๐Ÿ‘‘

This prefix is also used to find files like crt0.o, which are used for linking ๐Ÿ”—

The prefix also gets used in a pretty unusual way when hunting for header file directories ๐Ÿคฏ For each standard directory whose name normally starts with /usr/local/lib/gcc (or, more precisely, with the value of GCC_INCLUDE_DIR), GCC tries swapping that beginning out for your specified prefix to make an alternate directory name. So with -Bfoo/, GCC searches foo/bar just before it searches the standard directory /usr/local/lib/bar ๐ŸŒˆ If a standard directory starts with the configured prefix, then that prefix gets replaced by GCC_EXEC_PREFIX when GCC looks for header files ๐Ÿงš

COMPILER_PATH ๐Ÿ›ค๏ธ

The value of COMPILER_PATH is a colon-separated list of directories, very much like PATH ๐Ÿ’– GCC tries these directories when searching for subprograms, but only if it can't find them using GCC_EXEC_PREFIX first ๐Ÿซถ

LIBRARY_PATH ๐Ÿ“š

The value of LIBRARY_PATH is also a colon-separated list of directories, just like PATH โœจ When GCC is configured as a native compiler, it tries these directories when searching for special linker files, if it can't find them using GCC_EXEC_PREFIX ๐Ÿ”ง Linking with GCC also searches these directories for ordinary libraries when you use the -l option. The directories given with -L come first though ๐Ÿ‘‘

LANG (again, but for the compiler) ๐Ÿ‡ฏ๐Ÿ‡ต

This variable passes locale info to the compiler ๐ŸŽŒ One thing it's used for is deciding which character set to use when parsing character literals, string literals and comments in C and C++ ๐Ÿ’… When the compiler is configured to allow multibyte characters, these values for LANG are recognized:

  • C-JIS โ€” Recognize JIS characters.
  • C-SJIS โ€” Recognize SJIS characters.
  • C-EUCJP โ€” Recognize EUCJP characters.

If LANG isn't defined, or it has some other value, the compiler uses "mblen" and "mbtowc" as defined by the default locale to recognize and translate multibyte characters ๐ŸŒธ

GCC_EXTRA_DIAGNOSTIC_OUTPUT ๐Ÿฉน

If GCC_EXTRA_DIAGNOSTIC_OUTPUT is set to one of these values, extra text gets printed to stderr whenever fix-it hints are emitted ๐Ÿ’ฌ Just know that -fdiagnostics-parseable-fixits and -fno-diagnostics-parseable-fixits take precedence over this env var ๐Ÿ‘‘

  • fixits-v1 โ€” Emits parseable fix-it hints, the same as -fdiagnostics-parseable-fixits. Columns are counted in bytes, starting at byte 1 for the first column ๐Ÿงฎ
  • fixits-v2 โ€” Same as fixits-v1, except the columns are expressed as display columns, like -fdiagnostics-column-unit=display does ๐Ÿ“

Some additional environment variables affect how the preprocessor behaves ๐Ÿงšโ€โ™€๏ธ

CPATH, C_INCLUDE_PATH, CPLUS_INCLUDE_PATH, OBJC_INCLUDE_PATH ๐Ÿ—บ๏ธ

Each of these variables holds a list of directories, separated by a special character (much like PATH), where GCC looks for header files ๐Ÿฆ‹ That special character, PATH_SEPARATOR, depends on the target and gets set when GCC is built. For Microsoft Windows-based targets it's a semicolon, and for almost every other target it's a colon ๐ŸชŸ

CPATH specifies directories to search as if you'd used -I, but they come after any paths given with -I on the command line ๐Ÿ’– This variable gets used no matter which language is being preprocessed ๐ŸŒˆ

The other three only apply when preprocessing the particular language they name ๐ŸŽฏ Each one lists directories to search as if you'd used -isystem, again placed after any -isystem paths on the command line ๐Ÿง

In all of these variables, an empty element tells the compiler to search its current working directory ๐Ÿ“‚ Empty elements can show up at the beginning or end of a path. For instance, if the value of CPATH is :/special/include, that's the same as -I. -I/special/include ๐Ÿซถ

DEPENDENCIES_OUTPUT ๐Ÿ•ธ๏ธ

If this variable is set, its value says how to output Make dependencies based on the non-system header files the compiler processes ๐Ÿ”จ System header files get ignored in the dependency output ๐Ÿ™…โ€โ™€๏ธ

The value of DEPENDENCIES_OUTPUT can just be a file name, in which case the Make rules get written to that file, with the target name guessed from the source file name ๐Ÿ“ Or the value can look like file target, in which case the rules are written to file using target as the target name ๐ŸŽฏ

Put simply, this env var is equivalent to combining the options -MM and -MF, with an optional -MT switch too โœจ

SUNPRO_DEPENDENCIES โ˜€๏ธ

This one is the same as DEPENDENCIES_OUTPUT (see above), 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 variable is set, its value is a UNIX timestamp used in place of the current date and time in the "__DATE__" and "__TIME__" macros ๐Ÿ•ฐ๏ธ That way embedded timestamps stay reproducible ๐Ÿ”

The value of SOURCE_DATE_EPOCH has to be a UNIX timestamp, which means the number of seconds (not counting leap seconds) since 01 Jan 1970 00:00:00, written in ASCII ๐Ÿ”ข It's the same output you'd get from date +%s on GNU/Linux and other systems that support the %s extension in the date command ๐Ÿง

The value should be a known timestamp, like the last modification time of the source or package, and the build process should set it ๐Ÿ› ๏ธ


๐Ÿ› BUGS ๐Ÿ›

For instructions on reporting bugs, see <file:///usr/share/doc/gcc-14/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 has to 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. -shared suppresses the addition of startup code that alters the floating-point environment, as done with -ffast-math, -Ofast or -funsafe-math-optimizations on some targets. โš ๏ธ

๐Ÿ”— SEE ALSO ๐Ÿ”—

gpl(7), gfdl(7), fsf-funding(7), cpp(1), gcov(1), as(1), ld(1), gdb(1) and the Info entries for gcc, cpp, as, ld, binutils and gdb ๐Ÿ“–๐Ÿ’•


๐Ÿ‘ฉโ€๐Ÿ’ป AUTHOR ๐Ÿ‘ฉโ€๐Ÿ’ป

See the Info entry for gcc, or <https://gcc.gnu.org/onlinedocs/gcc/Contributors.html>, for contributors to GCC ๐Ÿซถ The whole squad that made this happen deserves a standing ovation ๐Ÿ‘


Copyright (c) 1988-2024 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. ๐Ÿ’–


And that's the whole page, bestie ๐ŸŽ€ GCC 14, dated April 12, 2024, and we are DONE with this one โœจ๐Ÿ’…๐Ÿฆ‹

๐Ÿ“ฆ where this page comes from