GCC(1)

โœจ GCC(1) โ€” GNU โœจ

Part 1 of 116. More parts are coming, so stay tuned, bestie ๐Ÿ’–

๐Ÿ‘‘ NAME ๐Ÿ‘‘

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

๐Ÿฆ‹ SYNOPSIS ๐Ÿฆ‹

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

Okay so only the most useful options are listed up there, and you'll find the rest further down. ๐Ÿงš g++ takes mostly the same options as gcc, so no stress.

๐Ÿ’– DESCRIPTION ๐Ÿ’–

When you invoke GCC, it normally does preprocessing, compilation, assembly and linking, the whole glow-up ๐Ÿ’…. The "overall options" let you stop that process at an intermediate stage. For example, the -c option says not to run the linker, so the output is just object files spit out by the assembler. It's giving stop-early energy โœจ.

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

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

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

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

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

Many options have long names starting with -f or with -W, like -fmove-loop-invariants, -Wformat and so on. Most of these come in both positive and negative forms, and the negative form of -ffoo is -fno-foo. This manual only documents one of those two forms, whichever one isn't the default. Main character energy, the default is the one you get without asking ๐Ÿ‘‘.

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 must typically be small unsigned decimal or hexadecimal integers. Hexadecimal arguments must begin with the 0x prefix ๐Ÿ”ฅ.

Arguments to options that specify a size threshold of some sort can be arbitrarily large decimal or hexadecimal integers, followed by a byte size suffix that designates a multiple of bytes. That includes kB and KiB for kilobyte and kibibyte, MB and MiB for megabyte and mebibyte, GB and GiB for gigabyte and gigibyte, and so on ๐Ÿฆ‹. Those arguments are designated by byte-size in the rest of the text. If you want the full lore on the binary and decimal byte size prefixes, check the NIST, IEC, and other relevant national and international standards, because they've got the whole list and explanation ๐Ÿค“.

๐ŸŽ€ OPTIONS ๐ŸŽ€

๐Ÿ’… Option Summary

Here is a summary of all the options, grouped by type. The explanations live in the following sections, so keep scrolling, bestie โœจ.

๐ŸŒธ Overall Options

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

๐Ÿงš C Language Options

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

๐Ÿ’œ C++ Language Options

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

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

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

๐Ÿ“ Diagnostic Message Formatting Options

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

โš ๏ธ Warning Options

okay so this is the big warning squad ๐Ÿšจ bestie, there's a LOT of them and no explanations on this part of the page, so I'm serving them straight up ๐Ÿ’…

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

๐Ÿ” Static Analyzer Options

the analyzer crew is up next ๐Ÿงš same deal, no descriptions here, just the full lineup

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

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

these ones are C and Objective-C only, so they're a little picky about who they hang out with ๐Ÿ’œ

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

๐Ÿ› Debugging Options

last but not least, the debugging options ๐Ÿฆ‹ the list is LONG so grab a snack ๐Ÿ“

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

๐ŸŒธ Optimization Options ๐ŸŒธ

okay bestie, the optimization drawer is LOADED ๐Ÿ’…โœจ here's the whole stash:

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

๐Ÿฆ‹ Program Instrumentation Options ๐Ÿฆ‹

next up, the instrumentation squad ๐Ÿซถ profiling, sanitizing, and hardening flags, all in one spot:

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

๐ŸŽ€ Preprocessor Options ๐ŸŽ€

the preprocessor crew is giving very organized energy ๐Ÿงš

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

only two of these, but they're iconic ๐Ÿ’–

  • -Wa,option
  • -Xassembler option

๐Ÿ’œ Linker Options ๐Ÿ’œ

the linking section is bringing the main character energy ๐Ÿ‘‘

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

๐Ÿ“ Directory Options ๐Ÿ“

ngl the directory options are a whole vibe ๐Ÿ“‚

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

๐Ÿ’– Code Generation Options ๐Ÿ’–

this section is where the real craft happens ๐ŸŒธ

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

๐Ÿ‘‘ Developer Options ๐Ÿ‘‘

ok this one is for the nerds, and we love them ๐Ÿค“๐Ÿ”ฅ

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

๐ŸŒˆ Machine-Dependent Options ๐ŸŒˆ

last stop, the machine-specific flags, and every target has its own little personality ๐Ÿฆ‹

โญ AArch64 Options โญ

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

โœจ Adapteva Epiphany Options โœจ

Okay bestie, the Epiphany flags are up next ๐Ÿฆ‹ Here's the full lineup:

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

Now the AMD GCN crew ๐Ÿ’… Three flags, all iconic:

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

โœจ ARC Options โœจ

The ARC section is giving main character energy ๐Ÿ‘‘ It's a long one, so grab a snack ๐Ÿ“

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

Next up is ARM ๐ŸŒˆ Lots of flags, but they're all serving looks:

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

โœจ AVR Options โœจ

AVR time ๐Ÿฆ‹ These are a whole vibe:

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

โœจ Blackfin Options โœจ

Moving on to Blackfin ๐Ÿ”ฅ Keep scrolling, it's worth it:

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

The C6X flags are short and sweet ๐Ÿ“

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

โœจ CRIS Options โœจ

CRIS is serving retro vibes ๐Ÿ’œ Lots of options, let's go:

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

โœจ CR16 Options โœจ

Now the CR16 flags ๐ŸŒธ

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

โœจ C-SKY Options โœจ

C-SKY is up next, and it's a big one ๐Ÿซถ

  • -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 in this batch, so settle in ๐Ÿ’…โœจ

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

โœจ DEC Alpha Options โœจ

DEC Alpha is a certified classic ๐Ÿงš

  • -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 flags, bestie, they're giving tech-girl energy ๐Ÿ’€โœจ

  • -mbig-endian
  • -mlittle-endian
  • -mkernel=version
  • -mframe-limit=bytes
  • -mxbpf
  • -mco-re
  • -mno-co-re
  • -mjmpext
  • -mjmp32
  • -malu32
  • -mcpu=version

โœจ FR30 Options โœจ

Just two for FR30, and they're both pretty ๐ŸŽ€

  • -msmall-model
  • -mno-lsim

โœจ FT32 Options โœจ

FT32 keeps it short and iconic ๐Ÿฆ‹

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

โœจ FRV Options โœจ

FRV has a whole lineup, periodt ๐Ÿ’…

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

The GNU/Linux flags are next, and they're so relatable ๐Ÿซถ

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

โœจ H8/300 Options โœจ

H8/300 time, and it's a cute little set ๐ŸŒธ

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

โœจ HPPA Options โœจ

HPPA is up next, and it has a lot going on โœจ

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

โœจ IA-64 Options โœจ

IA-64 is a big, dramatic moment ๐Ÿ”ฅ Buckle up, bestie:

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

LM32 is short and sweet ๐Ÿงš

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

โœจ M32R/D Options โœจ

M32R/D flags coming through ๐Ÿ’œ

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

โœจ M32C Options โœจ

Just three for M32C ๐Ÿ“

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

โœจ M680x0 Options โœจ

M680x0 is a whole throwback era, and it's so iconic ๐Ÿ‘‘

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

โœจ MCore Options โœจ

MCore is the last stretch of this part, and it's a fun one ๐ŸŽ€

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

โœจ MeP Options โœจ

And we close out with MeP ๐ŸŒˆ A big finish, bestie:

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

๐Ÿฆ‹ MicroBlaze Options ๐Ÿฆ‹

Okay bestie, the MicroBlaze squad is up first and they're all giving main character energy ๐Ÿ’–

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

๐ŸŒธ MIPS Options ๐ŸŒธ

The MIPS section is literally huge, so grab a snack ๐Ÿ“ Every flag is here, no skipping ๐Ÿ’…

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

๐Ÿงš MMIX Options ๐Ÿงš

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

๐Ÿ’œ MN10300 Options ๐Ÿ’œ

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

๐ŸŽ€ Moxie Options ๐ŸŽ€

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

๐Ÿซถ MSP430 Options ๐Ÿซถ

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

๐ŸŒˆ NDS32 Options ๐ŸŒˆ

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

โญ Nios II Options โญ

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

๐Ÿ”ฅ Nvidia PTX Options ๐Ÿ”ฅ

  • -m64
  • -mmainkernel
  • -moptimize

๐Ÿ“ OpenRISC Options ๐Ÿ“

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

๐Ÿ’… PDP-11 Options ๐Ÿ’…

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

๐Ÿฆ‹ picoChip Options ๐Ÿฆ‹

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

๐ŸŒธ PowerPC Options ๐ŸŒธ

Quick heads-up, these live with the next squad, so just peek at RS/6000 and PowerPC Options below ๐Ÿ’–


โœจ PRU Options โœจ

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

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

  • -mbranch-cost=N-instruction
  • -mplt
  • -mno-plt
  • -mabi=ABI-string
  • -mfdiv
  • -mno-fdiv
  • -mdiv
  • -mno-div
  • -misa-spec=ISA-spec-string
  • -march=ISA-string
  • -mtune=processor-string
  • -mpreferred-stack-boundary=num
  • -msmall-data-limit=N-bytes
  • -msave-restore
  • -mno-save-restore
  • -mshorten-memrefs
  • -mno-shorten-memrefs
  • -mstrict-align
  • -mno-strict-align
  • -mcmodel=medlow
  • -mcmodel=medany
  • -mexplicit-relocs
  • -mno-explicit-relocs
  • -mrelax
  • -mno-relax
  • -mriscv-attribute
  • -mmo-riscv-attribute
  • -malign-data=type
  • -mbig-endian
  • -mlittle-endian
  • -mstack-protector-guard=guard
  • -mstack-protector-guard-reg=reg
  • -mstack-protector-guard-offset=offset

๐ŸŽ€ RL78 Options ๐ŸŽ€

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

๐ŸŒธ RS/6000 and PowerPC Options ๐ŸŒธ

This is the big one, bestie, the whole PowerPC family is in here ๐Ÿงš๐Ÿ’–

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

๐Ÿฆ‹ RX Options ๐Ÿฆ‹

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

๐Ÿ’– S/390 and zSeries Options ๐Ÿ’–

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

๐Ÿงš Score Options ๐Ÿงš

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

โญ SH Options โญ

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

๐Ÿ‘‘ Solaris 2 Options ๐Ÿ‘‘

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

๐ŸŒธ SPARC Options ๐ŸŒธ

Okay bestie, first up is the SPARC crew ๐Ÿ’… yes it's a LOT of flags, but every single one is here, no cap โœจ

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

the old-school System V flags, lowkey iconic ๐Ÿ‘‘

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

๐Ÿฆ‹ TILE-Gx Options ๐Ÿฆ‹

the TILE-Gx set, serving endianness realness ๐ŸŒˆ

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

๐Ÿงš TILEPro Options ๐Ÿงš

small but mighty, the TILEPro flags ๐Ÿ’–

-mcpu=cpu -m32

๐Ÿ’œ V850 Options ๐Ÿ’œ

the V850 list is giving main character energy, no cap ๐Ÿ”ฅ

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

๐ŸŒท VAX Options ๐ŸŒท

the VAX flags, short and sweet ๐Ÿ“

-mg -mgnu -munix -mlra

๐Ÿซง Visium Options ๐Ÿซง

the Visium set, ngl it's a vibe โœจ

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

๐ŸŒˆ VMS Options ๐ŸŒˆ

the VMS crew, lowkey dramatic about return codes and pointers ๐Ÿ’€

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

๐ŸŽ€ VxWorks Options ๐ŸŽ€

VxWorks has its own little squad ๐Ÿฆ‹

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

๐Ÿ‘‘ x86 Options ๐Ÿ‘‘

okay the x86 list is HUGE and it's also the most iconic one, so buckle up ๐Ÿ˜ญ every flag is here, just the way it's written in the page:

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

๐ŸชŸ x86 Windows Options ๐ŸชŸ

the Windows x86 crew, bringing the drama ๐Ÿซถ

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

๐ŸŒธ Xstormy16 Options ๐ŸŒธ

just one flag for the Xstormy16 lol, simple is slay ๐Ÿ’…

-msim

๐Ÿงš Xtensa Options ๐Ÿงš

the Xtensa list is long and honestly kind of a whole personality ๐Ÿ”ฎ

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

๐Ÿ’– zSeries Options ๐Ÿ’–

  • zSeries Options โ€” no list here, just go check out 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, and they always happen in that order ๐ŸŽ€ gcc can preprocess and compile a bunch of files into several assembler input files, or into one assembler input file. Then each assembler input file makes an object file, and linking mashes 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 ๐ŸŒธ

๐Ÿ“ Input file suffixes

  • file.c โ€” C source code that has to 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. Heads up, you have to 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. Same deal, you must link with the libobjc library for an Objective-C++ program to work. Also, .M means 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 that gets turned into a precompiled header (that's the default), or a C or C++ header file that gets turned into an Ada spec (via the -fdump-ada-spec switch) ๐Ÿงš
  • file.cc, file.cp, file.cxx, file.cpp, file.CPP, file.c++, file.C โ€” C++ source code that must be preprocessed. Careful with .cxx, the last two letters must both be literally x. And .C means a literal capital C ๐Ÿ’–
  • file.mm, file.M โ€” Objective-C++ source code that must be preprocessed (yep, it's listed again) ๐ŸŽ€
  • file.mii โ€” Objective-C++ source code that should not be preprocessed (also listed again, iykyk) ๐Ÿฆ‹
  • file.hh, file.H, file.hp, file.hxx, file.hpp, file.HPP, file.h++, file.tcc โ€” C++ header file that gets turned into a precompiled header or an Ada spec ๐Ÿ‘‘
  • file.f, file.for, file.ftn โ€” Fixed form Fortran source code that should not be preprocessed ๐ŸŒธ
  • file.F, file.FOR, file.fpp, file.FPP, file.FTN โ€” Fixed form Fortran source code that must be preprocessed (with the traditional preprocessor) ๐Ÿซถ
  • file.f90, file.f95, file.f03, file.f08 โ€” Free form Fortran source code that should not be preprocessed ๐Ÿ“
  • file.F90, file.F95, file.F03, file.F08 โ€” Free form Fortran source code that must be preprocessed (with the traditional preprocessor) ๐Ÿ’œ
  • file.go โ€” Go source code ๐Ÿน
  • file.d โ€” D source code ๐Ÿ”ฎ
  • file.di โ€” D interface file ๐ŸŒˆ
  • file.dd โ€” D documentation code (Ddoc) ๐Ÿ“
  • file.ads โ€” Ada source code file that holds a library unit declaration (a declaration of a package, subprogram, or generic, or a generic instantiation), or a library unit renaming declaration (a package, generic, or subprogram renaming declaration). These are also called specs ๐Ÿงš
  • file.adb โ€” Ada source code file with a library unit body (a subprogram or package body). These are also called bodies ๐ŸŽ€
  • file.s โ€” Assembler code ๐Ÿซง
  • file.S, file.sx โ€” Assembler code that must be preprocessed ๐Ÿ’…
  • other โ€” An object file that gets fed straight into linking. Any file name with no recognized suffix gets treated this way ๐Ÿฆ‹

You can tell the input language yourself with the -x option ๐Ÿ‘‘

๐Ÿ’– Picking a language with -x

  • -x language โ€” Explicitly sets the language for the input files that come after it, instead of letting the compiler guess a default from the file name suffix. It sticks for every following input file until the next -x shows up. The possible values for language are:
c  c-header  cpp-output
c++  c++-header  c++-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 โ€” Turns off any language setting, so the files that follow are handled by their file name suffixes, exactly like if -x had never been used at all ๐ŸŒท

If you only want some of the stages, use -x (or filename suffixes) to tell gcc where to start, and one of -c, -S, or -E to say where gcc should stop ๐Ÿฆ‹

Heads up bestie โš ๏ธ some combinations, for example -x cpp-output -E, tell gcc to do absolutely nothing at all ๐Ÿ’€

๐Ÿงš Stopping early with -c, -S, or -E

  • -c โ€” Compiles or assembles the source files, but does not link ๐ŸŽ€ The linking stage just doesn't happen, and the ultimate output is an object file for each source file.
    • By default, the object file name for a source file is made by replacing the suffix .c, .i, .s, etc., with .o.
    • Unrecognized input files, which don't need compilation or assembly, are ignored.
  • -S โ€” Stops after the compilation proper and does not assemble ๐Ÿซง The output is an assembler code file for each non-assembler input file you specified.
    • By default, the assembler file name for a source file is made by replacing the suffix .c, .i, etc., with .s.
    • Input files that don't need compilation are ignored.
  • -E โ€” Stops after the preprocessing stage and doesn't run the compiler proper ๐Ÿ’– The output is preprocessed source code, which gets sent to the standard output.
    • Input files that don't need preprocessing are ignored.

-o file ๐ŸŽ€

Okay bestie, -o is how you tell GCC where the primary output goes ๐Ÿ’– That could be an executable, an object file, an assembler file, or preprocessed C code. It's all the same to -o โœจ

If you skip -o, GCC picks the spots itself ๐ŸŒธ An executable lands in a.out, the object file for source.suffix goes in source.o, its assembler file goes in source.s, a precompiled header goes in source.suffix.gch, and all preprocessed C source gets dumped on standard output. ๐Ÿ’…

Here's the lowkey twist: even though -o only names the primary output, it also changes what your auxiliary and dump outputs are called ๐Ÿฆ‹ (see the examples below, they're giving clarity). Unless you override it, those extra files land in the same directory as the primary output ๐Ÿงš For auxiliary outputs, the input file's suffix gets swapped for the suffix of the aux file type. For dump outputs, the dump file's suffix gets tacked onto the input file's suffix ๐Ÿซถ

In compile-only commands, the base name of both aux and dump outputs is the base name of the primary output. In compile and link commands, it's the primary output name minus the executable suffix, combined with the input file name. If both sides share the same base name (ignoring the suffix), the result is just that base name. Otherwise they get smooshed together with a dash between them โœจ

Example:

gcc -c foo.c ...

This one uses foo.o as the primary output and puts aux outputs and dumps right next to it. For instance, the aux file foo.dwo shows up for -gsplit-dwarf, and the dump file foo.c.???r.final shows up for -fdump-rtl-final ๐ŸŒˆ

If you explicitly give a non-linker output file, aux and dump files take the same base name by default, which is very main character of them ๐Ÿ‘‘

Example:

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

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

A linker output works differently, though ๐Ÿ™ˆ It prefixes the aux and dump outputs instead:

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

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

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

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

Here, aux outputs are named dir/foo.* and dump outputs are named dir/foo.c.* ๐Ÿ’œ

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


-dumpbase dumpbase ๐Ÿ’–

This sets the base name for aux and dump files, but it does not change the name of the primary output file ๐ŸŽ€ Intermediate outputs that get preserved aren't primary outputs anymore. They count as auxiliary outputs instead โœจ

Check this out:

gcc -save-temps -S foo.c

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

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

This preprocesses into save-foo.i, compiles to save-foo.s (now an intermediate, so it's auxiliary), 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 named one. Dump output files, like the ones requested by -fdump-* options, keep the input name's suffix. Aux output files, the ones requested by other non-dump options like "-save-temps", "-gsplit-dwarf", and "-fcallgraph-info", drop it ๐Ÿซถ

If you want that same suffix differentiation for an explicit -dumpbase basename.suf, just also add -dumpbase-ext .suf ๐Ÿ’…

If dumpbase is explicitly given with any directory component, then any dumppfx specification (like -dumpdir or -save-temps=*) gets ignored. dumpbase doesn't append to it, it fully overrides it ๐Ÿ™…โ€โ™€๏ธ

Example:

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.*, and it completely ignores 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 one that compiles and then links, it can be combined with a dumppfx, just like 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 ๐ŸŒˆ

Example:

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 you get aux and dump outputs named main-foo.* and main-bar.* โœจ

An empty string given as dumpbase stops the output basename from affecting how aux and dump outputs are named during compilation. The default values get computed instead ๐Ÿ“

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

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

An empty-string dumpbase does not stop the output basename from being used during linking, though ๐Ÿงš

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

The compilation of the source files names aux outputs dir/foo.* and dir/bar.*, and 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 GCC forms the name of an auxiliary output file (not a dump file), it drops the trailing auxdropsuf from dumpbase before adding any suffixes ๐Ÿ’– If you don't specify it, it defaults to the suffix of a default dumpbase. That means the suffix of the input file when -dumpbase isn't on the command line, or when the dumpbase is combined with a dumppfx โœจ

Example:

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 puts auxiliary outputs in dir/x-foo.*. It takes the location from the primary output and drops the .c suffix from the dumpbase. Dump outputs keep the suffix, so they end up as 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 aux and dump outputs, it uses the executable name minus auxdropsuf as a prefix, so you get aux outputs main-foo.* and main-bar.*, and dump outputs main-foo.c.* and main-bar.c.* ๐Ÿฆ‹


-dumpdir dumppfx ๐Ÿ‘‘

When 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 auxiliary outputs named pfx-foo.*. It combines the given dumppfx with the default dumpbase, which comes from the default primary output, which in turn comes from the input name. Dump outputs also take the input name suffix, so they're pfx-foo.c.* โœจ

If you want dumppfx to act 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 auxiliary outputs named dir/bar.*. It combines the given dumppfx with the default dumpbase derived from the primary output name. Dump outputs also take the input name suffix, so they're dir/bar.c.* ๐Ÿ“

By default, dumppfx is the location of the output file, unless the output file is a special file like "/dev/null". The options -save-temps=cwd and -save-temps=obj override this default, just like an explicit -dumpdir does. If more than one of these shows up, the last one wins ๐Ÿซถ

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

This outputs foo.o, with 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. Dump outputs are named foo.c.* ๐Ÿฆ‹

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

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

This sends auxiliary dumps to dir/pfx-main-foo.* and dir/pfx-main-bar.*, appending dumpbase- to dumppfx. Dump outputs keep the input file suffix: dir/pfx-main-foo.c.* and dir/pfx-main-bar.c.*, respectively ๐Ÿงš

Now contrast that with single-input compilation:

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

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

When you compile and then link from multiple input files, a defaulted or explicitly specified dumppfx also gets the dumpbase- transformation above. The compilation of foo.c and bar.c above is an example, just without -c. If you give neither -dumpdir nor -dumpbase, then the linker output base name, minus auxdropsuf if you specified it (or the executable suffix otherwise), plus a dash, gets appended to the default dumppfx instead ๐Ÿ’œ Heads up, though, this is different from the earlier linking cases:

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

This does not append the output name main to dumppfx, because -dumpdir was explicitly specified. The idea is that an explicit dumppfx can contain the output name as part of the prefix, if that's what you want. Only an explicitly specified -dumpbase would get combined with it, so that a meaningful option doesn't just get thrown away ๐Ÿ‘‘

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

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

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

Here's the big-picture version (a little fuzzy, but the vibe is 100% right ๐Ÿ’…). The primary output name gets split into a directory part and a basename part. dumppfx gets set to the directory part, unless you override it with -dumpdir or -save-temps=*. dumpbase gets set to the basename part, unless you override it with -dumpbase. If there are multiple inputs or you're linking, this dumpbase can get combined with dumppfx and pulled from each input file ๐Ÿงฉ. Auxiliary output names for each input are formed by smooshing together dumppfx, dumpbase minus its suffix, and the auxiliary output suffix. Dump output names are only different in that they keep the suffix from dumpbase ๐ŸŒธ

Now for LTO recompilation ๐Ÿฆ‹: a combo of dumppfx and dumpbase gets passed down to lto-wrapper as a -dumpdir option. That combo can be whatever you gave, or something derived from the linker output name (but never from the inputs), even in cases where it wouldn't otherwise get used that way. A trailing period takes the place of the compiler-added dash, if there is one. Since gcc is involved in linking, it doesn't normally get any -dumpbase or -dumpbase-ext, and it ignores them ๐Ÿ™ˆ

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

  • -v โ€” Prints (on standard error) the commands run for each stage of compilation. It also prints the version number of the compiler driver program, plus the preprocessor and the compiler proper ๐Ÿ“ฃ
  • -### โ€” Like -v, except nothing actually runs, and arguments only get quoted unless they're made of alphanumeric characters or "./-_". Super handy for shell scripts that want to snag the command lines the driver generates ๐Ÿค“
  • --help โ€” Prints (on standard output) a description of the command-line options gcc understands. If -v is also specified, --help gets passed on to the various processes gcc invokes too, so they can show the options they accept. If -Wextra was specified too (before --help), then options with no documentation get displayed as well ๐Ÿ“–
  • --target-help โ€” Prints (on standard output) a description of the target-specific command-line options for each tool. For some targets, extra target-specific info may get printed too ๐ŸŽฏ
  • --help={class|[^]qualifier}[,...] โ€” Prints (on standard output) a description of the command-line options the compiler understands that fit into all the classes and qualifiers you specify. These are the supported classes:
    • optimizers โ€” Shows all the optimization options the compiler supports โšก
    • warnings โ€” Shows all the options that control the warning messages the compiler produces โš ๏ธ
    • target โ€” Shows target-specific options. Unlike --target-help, target-specific options of the linker and assembler are not shown, because those tools don't currently support the extended --help= syntax ๐Ÿ™…โ€โ™€๏ธ
    • params โ€” Shows the values recognized by --param ๐Ÿง
    • language โ€” Shows the options supported for language, where language is the name of one of the languages supported in this version of GCC. If an option is supported by all languages, you need to pick the common class ๐Ÿ—ฃ๏ธ
    • common โ€” Shows the options that are common to all languages ๐ŸŒ

And here are the qualifiers, bestie:

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

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 putting the ^ character in front of it. So, for example, to display all the binary warning options (the ones that are either on or off and don't take an argument) that have a description, use:

--help=warnings,^joined,^undocumented
Heads up: the argument to --help= should not consist solely of inverted qualifiers ๐Ÿšซ

Combining several classes is possible, although it usually narrows 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 have already been displayed ๐Ÿ”. If --help is also specified anywhere on the command line, then it takes precedence over any --help= option ๐Ÿ‘‘

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

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

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

The output is sensitive to the effects of previous command-line options, so it's possible to find out which optimizations are enabled at -O2 by using:

-Q -O2 --help=optimizers

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

  • -ffile-prefix-map=old=new โ€” When compiling files living in directory old, records any references to them in the result of the compilation as if the files lived in directory new instead. Specifying this option is equivalent to specifying all the individual -f*-prefix-map options. This is great for reproducible builds that are location independent ๐Ÿ—บ๏ธ. See also -fmacro-prefix-map, -fdebug-prefix-map and -fprofile-prefix-map.
  • -fplugin=name.so โ€” Loads the plugin code in file name.so, which is assumed to be a shared object to be dlopen'd by the compiler ๐Ÿงฉ. The base name of the shared object file is used to identify the plugin for argument parsing (see -fplugin-arg-name-key=value below). Each plugin should define the callback functions specified in the Plugins API.
  • -fplugin-arg-name-key=value โ€” Defines an argument called key with a value of value for the plugin called name ๐Ÿ”‘
  • -fdump-ada-spec[-slim] โ€” For C and C++ source and include files, generates corresponding Ada specs ๐Ÿฆ…
  • -fada-spec-parent=unit โ€” Used together with -fdump-ada-spec[-slim] above, this generates Ada specs as child units of parent unit ๐Ÿ‘ถ
  • -fdump-go-spec=file โ€” For input files in any language, generates corresponding Go declarations in file. This generates Go "const", "type", "var", and "func" declarations, which can be a useful way to start writing a Go interface to code written in some other language ๐Ÿน
  • @file โ€” Reads command-line options from file. The options read get inserted in place of the original @file option. If file doesn't exist or can't be read, then the option is treated literally and not removed ๐Ÿซฃ

Options in file are separated by whitespace. A whitespace character can be included in an option by wrapping the entire option in either single or double quotes. Any character (including a backslash) can be included by putting a backslash in front of it. 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, and preprocessed C++ files use the suffix .ii ๐ŸŒˆ. GCC recognizes files with these names and compiles them as C++ programs, even if you call the compiler the same way you would for C programs (usually with the name gcc) ๐Ÿ’…

However, the use of gcc does not add the C++ library. Bestie, this is where g++ comes in โœจ. It's a program that calls GCC and automatically specifies linking against the C++ library, so you don't have to think about it ๐Ÿ’–. It also treats .c, .h and .i files as C++ source files instead of C source files, unless you use -x ๐Ÿ’…. It's super handy for precompiling a C header file with a .h extension for use in C++ compilations ๐Ÿงš. On lots of systems, g++ is also installed under the name c++ ๐ŸŒธ.

When you compile C++ programs, you can use a lot of the same command-line options you'd use for any language ๐ŸŽ€, or options meant for C and related languages ๐Ÿฆ‹, or options that only matter for C++ ๐Ÿ‘‘. Mix and match, it's giving versatile.


๐Ÿ’… 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 the same as -std=c90, and in C++ mode it's the same as -std=c++98. It turns off GCC features that clash with ISO C90 (for C code) or standard C++ (for C++ code), like the asm and typeof keywords, and predefined macros such as unix and vax that identify what kind of system you're on. It also turns on the undesirable and rarely used ISO trigraph feature ๐Ÿ’€. For the C compiler, it also disables recognition of C++ style // comments as well as the inline keyword.

The alternate keywords __asm__, __extension__, __inline__ and __typeof__ keep working even with -ansi. You wouldn't want them in an ISO C program, obviously ๐Ÿ™ƒ, but they're useful in header files that might get included in -ansi builds. Alternate predefined macros like __unix__ and __vax__ are available too, with or without -ansi.

-ansi doesn't reject non-ISO programs gratuitously. For that, you need -Wpedantic in addition to -ansi ๐Ÿง.

The macro __STRICT_ANSI__ is predefined when -ansi is used. Some header files notice it and skip declaring certain functions or defining certain macros that ISO doesn't ask for, so they don't interfere with programs using those names for other things ๐Ÿซถ.

Functions that are normally built in but have no semantics defined by ISO C (like alloca and ffs) are not built-in functions when -ansi is used.

  • -std= โ€” Determines the language standard. This option is only supported when compiling C or C++ ๐Ÿ“š.

The compiler can accept several base standards, like c90 or c++98, plus GNU dialects of those, like gnu90 or gnu++98. With a base standard, the compiler accepts all programs following that standard plus GNU extensions that don't contradict it. For example, -std=c90 turns off GCC features that clash with ISO C90, like the asm and typeof keywords, but keeps other GNU extensions that don't mean anything in ISO C90, like leaving out the middle term of a ?: expression. With a GNU dialect, though, every feature the compiler supports gets enabled, even when those features change the meaning of the base standard. So some strictly conforming programs may get rejected ๐Ÿ˜ฌ. -Wpedantic uses the chosen standard to figure out which features are GNU extensions for that version. For example, -std=gnu90 -Wpedantic warns about C++ style // comments, while -std=gnu99 -Wpedantic does not.

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

  • c90, c89, iso9899:1990 โ€” Supports all ISO C90 programs (certain GNU extensions that conflict with ISO C90 are disabled). Same as -ansi for C code.
  • iso9899:199409 โ€” ISO C90 as modified in amendment 1.
  • c99, c9x, iso9899:1999, iso9899:199x โ€” ISO C99. 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, floating-point issues (mainly but not entirely relating to optional C11 features from Annexes F and G) and the optional Annexes K (Bounds-checking interfaces) and L (Analyzability). The name c1x is deprecated.
  • c17, c18, iso9899:2017, iso9899:2018 โ€” ISO C17, the 2017 revision of the ISO C standard (published in 2018). This standard is the same as C11 except for corrections of defects (all of which are also applied with -std=c11) and a new value of __STDC_VERSION__, so it's supported to the same extent as C11.
  • c2x โ€” The next version of the ISO C standard, still under development. Support for this version is experimental and incomplete.
  • gnu90, gnu89 โ€” GNU dialect of ISO C90 (including some C99 features).
  • gnu99, gnu9x โ€” GNU dialect of ISO C99. The name gnu9x is deprecated.
  • gnu11, gnu1x โ€” GNU dialect of ISO C11. The name gnu1x is deprecated.
  • gnu17, gnu18 โ€” GNU dialect of ISO C17. This is the default for C code ๐Ÿ‘‘.
  • gnu2x โ€” The next version of the ISO C standard, still under development, plus GNU extensions. Support for this version is experimental and incomplete.
  • c++98, c++03 โ€” The 1998 ISO C++ standard plus the 2003 technical corrigendum and some additional defect reports. Same as -ansi for C++ code.
  • gnu++98, gnu++03 โ€” GNU dialect of -std=c++98.
  • c++11, c++0x โ€” The 2011 ISO C++ standard plus amendments. The name c++0x is deprecated.
  • gnu++11, gnu++0x โ€” GNU dialect of -std=c++11. The name gnu++0x is deprecated.
  • c++14, c++1y โ€” The 2014 ISO C++ standard plus amendments. The name c++1y is deprecated.
  • gnu++14, gnu++1y โ€” GNU dialect of -std=c++14. The name gnu++1y is deprecated.
  • c++17, c++1z โ€” The 2017 ISO C++ standard plus amendments. The name c++1z is deprecated.
  • gnu++17, gnu++1z โ€” GNU dialect of -std=c++17. This is the default for C++ code ๐Ÿ‘‘. The name gnu++1z is deprecated.
  • c++20, c++2a โ€” The 2020 ISO C++ standard plus amendments. Support is experimental, and could change in incompatible ways in future releases. The name c++2a is deprecated.
  • gnu++20, gnu++2a โ€” GNU dialect of -std=c++20. Support is experimental, and could change in incompatible ways in future releases. The name gnu++2a is deprecated.
  • c++2b, c++23 โ€” The next revision of the ISO C++ standard, planned for 2023. Support is highly experimental, and will almost certainly change in incompatible ways in future releases.
  • gnu++2b, gnu++23 โ€” GNU dialect of -std=c++2b. Support is highly experimental, and will almost certainly change in incompatible ways in future releases.
  • -aux-info filename โ€” Outputs prototyped declarations for all functions declared and/or defined in a translation unit, including those in header files, to the given filename ๐Ÿ“. This option is silently ignored in any language other than C.

Besides declarations, the file notes in comments the origin of each declaration (source file and line). It also shows whether each declaration was implicit, prototyped or unprototyped (I, N for new or O for old, respectively, in the first character after the line number and the colon), and whether it came from a declaration or a definition (C or F, respectively, in the following character). For function definitions, a K&R-style list of arguments followed by their declarations is also provided, inside comments, after the declaration.

  • -fallow-parameterless-variadic-functions โ€” Accepts variadic functions without named parameters.

Although it's possible to define such a function, it isn't very useful, since it's not possible to read the arguments. This is only supported for C, as this construct is allowed by C++.

  • -fno-asm โ€” Doesn't recognize asm, inline or typeof as keywords, so code can use these words as identifiers. You can use the keywords __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. You may want to use the -fno-gnu-keywords flag instead, which disables typeof but not asm and inline. In C99 mode (-std=c99 or -std=gnu99), this switch only affects the asm and typeof keywords, since inline is a standard keyword in ISO C99.

  • -fno-builtin, -fno-builtin-function โ€” Doesn't recognize built-in functions whose names don't start with the __builtin_ prefix ๐Ÿ™ˆ.

GCC normally generates special code to handle certain built-in functions more efficiently โœจ. For instance, 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 both smaller and faster, but since the function calls no longer appear as such, you can't set a breakpoint on those calls, nor can you change the behavior of the functions by linking with a different library ๐Ÿ˜ญ. In addition, when a function is recognized as a built-in function, GCC may use information about that function to warn about problems with calls to it, or to generate more efficient code, even if the resulting code still contains calls to that function. For example, warnings are given with -Wformat for bad calls to printf when printf is built in and strlen is known not to modify global memory.

Okay so with -fno-builtin-function, only the built-in version of function gets switched off ๐Ÿ™ˆ function can't begin with __builtin_ ๐Ÿšซ. If the function isn't built-in in your GCC version, the option just gets ignored, no drama ๐Ÿ’…. There's no matching -fbuiltin-function option, though. If you want to turn built-ins back on one at a time while using -fno-builtin or -ffreestanding, you can define your own macros like this ๐ŸŽ€:

#define abs(n)          __builtin_abs ((n))
#define strcpy(d, s)    __builtin_strcpy ((d), (s))
  • -fcond-mismatch โ€” This lets conditional expressions have mismatched types in the second and third arguments ๐Ÿฆ‹. The value of that kind of expression is void. ngl, this one is not supported for C++ ๐Ÿ’€.
  • -ffreestanding โ€” Tells GCC that compilation targets a freestanding environment ๐Ÿงš. This implies -fno-builtin. Freestanding means the standard library might not exist, and program startup might not be at "main" ๐Ÿ˜ญ. The most obvious example is an OS kernel ๐Ÿ‘‘. This is equivalent to -fno-hosted.
  • -fgimple โ€” Enables parsing of function definitions marked with "__GIMPLE" ๐Ÿงช. It's experimental, and it exists so you can unit test GIMPLE passes โœจ.
  • -fgnu-tm โ€” When you pass this, GCC generates code for the Linux variant of Intel's current Transactional Memory ABI specification document (Revision 1.1, May 6 2009) ๐Ÿ’œ. It's experimental, so the interface may change in future GCC versions as the official spec changes โš ๏ธ. Also, not all architectures are supported for this feature ๐Ÿ™.

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

Heads up: the transactional memory feature is not supported with non-call exceptions (-fnon-call-exceptions) ๐Ÿšซ.
  • -fgnu89-inline โ€” Tells GCC to use the traditional GNU semantics for inline functions when in C99 mode ๐ŸŒธ. Using this is roughly equivalent to adding the gnu_inline function attribute to all inline functions.
  • -fno-gnu89-inline โ€” Explicitly tells GCC to use the C99 semantics for inline when in C99 or gnu99 mode, which is the default behavior ๐Ÿ’…. This option is not supported in -std=c90 or -std=gnu90 mode.

To check which inline semantics are in effect, you can use the preprocessor macros "__GNUC_GNU_INLINE__" and "__GNUC_STDC_INLINE__" ๐Ÿ”.

  • -fhosted โ€” Tells GCC that compilation targets a hosted environment ๐Ÿ . This implies -fbuiltin. A hosted environment has the entire standard library available, and main has a return type of int ๐Ÿ’–. Examples are nearly everything except a kernel. This is equivalent to -fno-freestanding.
  • -flax-vector-conversions โ€” Allows implicit conversions between vectors with differing numbers of elements and/or incompatible element types ๐ŸŒˆ. Honestly? Don't use this for new code ๐Ÿ™….
  • -fms-extensions โ€” Accepts some non-standard constructs used in Microsoft header files ๐ŸชŸ. In C++ code, this lets member names in structures be similar to previous type declarations. Like this:
typedef int UOW;
struct ABC {
  UOW UOW;
};

Also, 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 โ€” These specify which OpenMP and OpenACC offload targets get code generated ๐ŸŽฏ. The default, which is equivalent to -foffload=default, generates 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 written in GCC's internal target-triplet format ๐Ÿ“. Run the compiler with -v to see the list of configured offload targets under "OFFLOAD_TARGET_NAMES" ๐Ÿ‘€.

  • -foffload-options=options, -foffload-options=target-triplet-list=options โ€” With -foffload-options=options, GCC passes 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 the -foffload= option.

Typical command lines are:

-foffload-options=-lgfortran -foffload-options=-lm
-foffload-options="-lgfortran -lm" -foffload-options=nvptx-none=-latomic
-foffload-options=amdgcn-amdhsa=-march=gfx906 -foffload-options=-lm
  • -fopenacc โ€” Enables handling of OpenACC directives "#pragma acc" in C/C++ and "!$acc" in Fortran ๐Ÿง‘โ€๐Ÿ’ป. When this is on, the compiler generates accelerated code according to the OpenACC Application Programming Interface v2.6, which you can look up at https://www.openacc.org โœจ. This option implies -pthread, so it's only supported on targets that have support for -pthread โš ๏ธ.
  • -fopenacc-dim=geom โ€” 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 the order 'gang', 'worker' and 'vector' ๐Ÿงฎ. You can omit a size to use a target-specific default value.
  • -fopenmp โ€” Enables handling of OpenMP directives "#pragma omp" in C/C++ and "!$omp" in Fortran ๐ŸŒท. When this is on, the compiler generates parallel code according to the OpenMP Application Program Interface v4.5, found at 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 โ€” Enables handling of OpenMP's SIMD directives with "#pragma omp" in C/C++ and "!$omp" in Fortran ๐ŸŽถ. Other OpenMP directives are ignored.
  • -fpermitted-flt-eval-methods=style โ€” ISO/IEC TS 18661-3 defines new permissible values for FLT_EVAL_METHOD ๐Ÿง . These say operations and constants with a semantic type that's an interchange or extended format should be evaluated to the precision and range of that type. The new values are a superset of the ones permitted under C99/C11, which doesn't specify the meaning of other positive values of FLT_EVAL_METHOD. So, code that conforms to C11 may not have been written expecting the new values ๐Ÿซ .

This option decides whether the compiler allows only the FLT_EVAL_METHOD values from C99/C11, or the extended set from ISO/IEC TS 18661-3 ๐Ÿ’…. style is either "c11" or "ts-18661-3", as appropriate. The default in a standards-compliant mode (-std=c11 or similar) is -fpermitted-flt-eval-methods=c11. The default in a GNU dialect (-std=gnu11 or similar) is -fpermitted-flt-eval-methods=ts-18661-3.

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

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

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

  • -fsso-struct=endianness โ€” Sets the default scalar storage order of structures and unions to the specified endianness ๐Ÿงฑ. The accepted values are big-endian, little-endian and native, which is the native endianness of the target and the default. This option is not supported for C++.
Warning: the -fsso-struct switch causes GCC to generate code that is not binary compatible with code generated without it if the specified endianness is not the native endianness of the target ๐Ÿšจ.

๐ŸŒˆ Options Controlling C++ Dialect ๐ŸŒˆ

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

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

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

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

Here is a list of options that are only for compiling C++ programs:

  • -fabi-version=n โ€” Uses version n of the C++ ABI ๐Ÿงพ. The default is version 0.
    • Version 0 refers to the version conforming most closely to the C++ ABI specification. Therefore, the ABI obtained using version 0 will change in different versions of G++ as ABI bugs are fixed.
    • Version 1 is the version of the C++ ABI that first appeared in G++ 3.2.
    • Version 2 is the version of the C++ ABI that first appeared in G++ 3.4, and was the default through G++ 4.9.
    • Version 3 corrects an error in mangling a constant address as a template argument.

Version 4 is where G++ 4.5 dropped a standard mangling for vector types ๐Ÿฆ‹ Version 5 showed up with G++ 4.6 and fixed the mangling of attribute const/volatile on function pointer types, decltype of a plain decl, and using a function parameter in the declaration of another parameter ๐Ÿ’…

Version 6 came with G++ 4.7 and fixed the promotion behavior of C++11 scoped enums, plus the mangling of template argument packs, const/static_cast, prefix ++ and --, and a class scope function used as a template argument โœจ

Version 7 is G++ 4.8's glow-up ๐ŸŒธ It treats nullptr_t as a builtin type and fixes the mangling of lambdas in default argument scope.

Version 8 landed with G++ 4.9 and corrected the substitution behavior of function types with function-cv-qualifiers ๐ŸŽ€

Version 9 came in with G++ 5.2 and fixed the alignment of "nullptr_t" ๐Ÿ’–

Version 10 is from G++ 6.1 and adds mangling for attributes that affect type identity, like ia32 calling convention attributes (e.g. stdcall) ๐Ÿงš

Version 11 is from G++ 7 and fixed the mangling of sizeof... expressions and operator names ๐Ÿฆ‹ For multiple entities with the same name inside a function that are declared in different scopes, the mangling changes starting with the twelfth occurrence. It also implies -fnew-inheriting-ctors.

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

Version 13 arrived with G++ 8.2 and fixed that accidental change from version 12 ๐Ÿซถ

Version 14 is G++ 10's contribution and corrects the mangling of the nullptr expression ๐ŸŒˆ

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

See also -Wabi. ๐Ÿ“


  • -fabi-compat-version=n โ€” okay so on targets that support strong aliases, G++ works around mangling changes by making an alias with the correct mangled name whenever you define a symbol with an incorrect one ๐Ÿ”ง This switch picks which ABI version that alias uses. With -fabi-version=0 (the default), it defaults to 11 (GCC 7 compatibility). If you explicitly select another ABI version, it defaults to 0. For compatibility with GCC versions 3.2 through 4.9, use -fabi-compat-version=2. If you skip this option but do give -Wabi=n, that version gets used for the compatibility aliases. If you give this option along with -Wabi (without a version), the version from this option gets used for the warning ๐Ÿ’…
  • -fno-access-control โ€” turns off all access checking ๐Ÿ™ˆ It's mainly useful for working around bugs in the access control code.
  • -faligned-new โ€” enables C++17 new for types that need more alignment than void* ::operator new(std::size_t) provides โœจ You can pass a number like -faligned-new=32 to say how much alignment (in bytes) that function provides, but honestly few users will need to override the default of alignof(std::max_align_t). This flag is enabled by default for -std=c++17 ๐ŸŽ€
  • -fchar8_t, -fno-char8_t โ€” enables support for char8_t as adopted for C++20 ๐Ÿ’œ This adds a brand new char8_t fundamental type, changes the types of UTF-8 string and character literals, adds new signatures for user-defined literals, comes with associated standard library updates, and adds the new __cpp_char8_t and __cpp_lib_char8_t feature test macros.

This option lets you overload functions for ordinary and UTF-8 strings ๐Ÿฆ‹

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

It also introduces new signatures for user-defined literals ๐ŸŒธ

int operator""_udl1(char8_t);
int v3 = u8'x'_udl1;
int operator""_udl2(const char8_t*, std::size_t);
int v4 = u8"text"_udl2;
template<typename T, T...> int operator""_udl3();
int v5 = u8"text"_udl3;
โš ๏ธ bestie, the change to the types of UTF-8 string and character literals breaks compatibility with ISO C++11 and later. For example, this code is well-formed under ISO C++11, but it's ill-formed when -fchar8_t is specified ๐Ÿ˜ญ
char ca[] = u8"xx";     // error: char-array initialized from wide
                        //        string
const char *cp = u8"xx";// error: invalid conversion from
                        //        `const char8_t*' to `const char*'
int f(const char*);
auto v = f(u8"xx");     // error: invalid conversion from
                        //        `const char8_t*' to `const char*'
std::string s{u8"xx"};  // error: no matching function for call to
                        //        `std::basic_string<char>::basic_string()'
using namespace std::literals;
s = u8"xx"s;            // error: conversion from
                        //        `basic_string<char8_t>' to non-scalar
                        //        type `basic_string<char>' requested
  • -fcheck-new โ€” checks that the pointer returned by operator new is non-null before it tries to modify the storage it allocated ๐Ÿ” Normally this check is unnecessary, since the C++ standard says operator new only returns 0 if it's declared throw(). In that case the compiler always checks the return value, even without this option. In all other cases, when operator new has a non-empty exception specification, memory exhaustion is signalled by throwing std::bad_alloc. See also new (nothrow).
  • -fconcepts, -fconcepts-ts โ€” below -std=c++20, -fconcepts enables support for the C++ Extensions for Concepts Technical Specification, ISO 19217 (2015) ๐Ÿง 

With -std=c++20 and above, Concepts are part of the language standard, so -fconcepts defaults to on ๐Ÿ‘‘ But the standard spec for Concepts is pretty different from the TS, so some constructs that were allowed in the TS but didn't make it into the standard can still be enabled with -fconcepts-ts ๐Ÿ’…

  • -fconstexpr-depth=n โ€” sets the maximum nested evaluation depth for C++11 constexpr functions to n ๐ŸŒ€ A limit is needed to catch endless recursion during constant expression evaluation. The minimum the standard specifies is 512.
  • -fconstexpr-cache-depth=n โ€” sets the maximum nesting level of evaluation depth for C++11 constexpr functions that will be cached to n ๐Ÿงš It's a heuristic that trades compilation speed (when the cache avoids repeated calculations) against memory consumption (when the cache grows huge from highly recursive evaluations). The default is 8. Very few users will want to change it, but if your code does heavy constexpr calculations, you might want to experiment to find which value works best for you ๐ŸŽ€
  • -fconstexpr-fp-except โ€” okay so Annex F of the C standard says IEC559 floating point exceptions hit at compile time shouldn't stop compilation โœจ C++ compilers have historically not followed this, 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 that say a particular operation is undefined.
constexpr float inf = 1./0.; // OK with -fconstexpr-fp-except
  • -fconstexpr-loop-limit=n โ€” sets the maximum number of iterations for a loop in C++14 constexpr functions to n ๐Ÿ” A limit is needed to catch infinite loops during constant expression evaluation. The default is 262144 (1<<18).
  • -fconstexpr-ops-limit=n โ€” sets the maximum number of operations during a single constexpr evaluation ๐Ÿ’ฅ Even when the number of iterations in a single loop is limited by the loop limit above, you can still get trouble. If there are several nested loops that each have lots of iterations (but are still under that loop limit), or if too many expressions need evaluating in a loop body (or even outside a loop), the constexpr evaluation might take way too long. The default is 33554432 (1<<25).
  • -fcoroutines โ€” enables support for the C++ coroutines extension ๐Ÿงช This one is still experimental, so proceed with a little caution, bestie.
  • -fno-elide-constructors โ€” the C++ standard lets an implementation skip creating a temporary that's only used to initialize another object of the same type ๐Ÿ™ƒ Using this option turns that optimization off and forces G++ to call the copy constructor in all cases. It also makes G++ call trivial member functions that would otherwise be expanded inline.

In C++17, the compiler is required to omit these temporaries, but this option still affects trivial member functions ๐Ÿซถ

  • -fno-enforce-eh-specs โ€” this one is spicy ๐ŸŒถ๏ธ It tells G++ not to generate code that checks for violations of exception specifications at run time. This option violates the C++ standard, but it can be useful for shrinking code size in production builds, kind of like defining NDEBUG. It does NOT give your code permission to throw exceptions that break the exception specifications ๐Ÿ’€ The compiler still optimizes based on those specifications, so if you throw an unexpected exception, the result is undefined behavior at run time.
  • -fextern-tls-init, -fno-extern-tls-init โ€” okay so the C++11 and OpenMP standards 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 does any initialization needed. If the use and the definition are in the same translation unit, that overhead can get optimized away ๐Ÿ’…. But if the use is in a different translation unit, there's real overhead even when the variable doesn't need dynamic initialization at all ๐Ÿ˜ญ. If you can be sure that no use in a non-defining TU needs to trigger dynamic initialization (because the variable is statically initialized, or a use in the defining TU runs before any use 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, the default is -fno-extern-tls-init.
  • -fno-gnu-keywords โ€” typeof stops being a keyword, so you can use it as a regular identifier ๐ŸŒธ. If you still want the keyword, __typeof__ is there for you ๐Ÿ’–. This is already implied by the strict ISO C++ dialects, like -ansi, -std=c++98, -std=c++11, etc.
  • -fimplicit-constexpr โ€” inline functions become implicitly constexpr ๐Ÿ”ฅ, as long as they meet the requirements for a constexpr function. This works in C++14 mode or later, and it can switch initialization from dynamic to static, plus other optimizations โœจ.
  • -fno-implicit-templates โ€” never emit code for non-inline templates that get instantiated implicitly (aka just by using them) ๐Ÿ™ˆ. Only explicit instantiations get code emitted.
Heads up, bestie: if you use this, you have to structure your code so every necessary explicit instantiation is included, or you'll get undefined symbols at link time ๐Ÿ˜ฌ.
  • -fno-implicit-inline-templates โ€” don't emit code for implicit instantiations of inline templates either ๐Ÿฆ‹. The default handles inlines differently, so 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 ๐Ÿ’€. Just know this causes linker errors if those functions aren't inlined everywhere they're called.
  • -fmodules-ts, -fno-modules-ts โ€” enables support for C++20 modules ๐Ÿงš. -fno-modules-ts is usually not needed, since that's already the default. Even though modules are a C++20 feature, picking that standard version doesn't implicitly turn them on.
  • -fmodule-header, -fmodule-header=user, -fmodule-header=system โ€” compiles a header file into an importable header unit ๐ŸŽ€.
  • -fmodule-implicit-inline โ€” member functions defined inside their class definitions aren't implicitly inline for modular code ๐Ÿค”. That's different from traditional C++ behavior, and it's different for good reasons, but it can be a headache when porting code. This option makes those function definitions implicitly inline. It does create an ABI incompatibility, so you must use it everywhere or nowhere. (Definitions outside of a named module stay implicitly inline regardless.)
  • -fno-module-lazy โ€” disables lazy module importing and module mapper creation ๐Ÿ’ค.
  • -fmodule-mapper=... โ€” basically 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 too, an in-process default is provided. The forms are:
    • -fmodule-mapper=[hostname]:port[?ident]
    • -fmodule-mapper=|program[?ident] args...
    • -fmodule-mapper==socket[?ident]
    • -fmodule-mapper=<>[inout][?ident]
    • -fmodule-mapper=<in>out[?ident]
    • -fmodule-mapper=file[?ident]
  • -fmodule-only โ€” only emits the Compiled Module Interface, and skips the object file ๐Ÿ’œ.
  • -fms-extensions โ€” disables Wpedantic warnings about constructs used in MFC, like implicit int and getting a pointer to a member function via non-standard syntax ๐ŸŒˆ.
  • -fnew-inheriting-ctors โ€” enables the P0136 adjustment to C++11 constructor inheritance semantics โœจ. It's part of C++17, but it's also considered a Defect Report against C++11 and C++14. This flag is on by default unless -fabi-version=10 or lower is specified.
  • -fnew-ttp-matching โ€” enables the P0522 resolution to Core issue 150 (template template parameters and default arguments) ๐Ÿฆ‹. Basically, a template with default template arguments can 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 โ€” disables built-in declarations of functions that aren't mandated by ANSI/ISO C ๐Ÿ™…โ€โ™€๏ธ. That includes ffs, alloca, _exit, index, bzero, conjf, and other related functions.
  • -fnothrow-opt โ€” treats a throw() exception specification as if it were a noexcept specification ๐Ÿ“, to reduce or eliminate the text size overhead compared to a function with no exception specification. If the function has local variables with non-trivial destructors, the exception specification 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 that spec results in a call to terminate rather than unexpected.
Watch out: that terminate vs unexpected swap is a real behavior change, so don't flip this on without thinking it through ๐Ÿ’€.
  • -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 โ€” disables diagnostics that the standard says a compiler doesn't need to issue ๐Ÿ™ˆ. Right now, the only one G++ issues like that is the one for a name having multiple meanings within a class.
  • -fpermissive โ€” downgrades some diagnostics about nonconformant code from errors to warnings ๐Ÿ˜ค. So using -fpermissive lets some nonconforming code compile.
  • -fno-pretty-templates โ€” okay so when an error message points at a specialization of a function template, the compiler normally prints the template signature, followed by the template arguments and any typedefs or typenames in the signature. You'll see something like void f(T) [with T = int] instead of void f(int), so you can tell which template is involved ๐Ÿ”. For a specialization of a class template, it leaves out any template arguments that match the defaults. If either of those behaviors makes the error harder to read, you can turn them off with -fno-pretty-templates ๐Ÿ’….
  • -fno-rtti โ€” disables generation of run-time type information for every class with virtual functions, which is what the C++ run-time type identification features (dynamic_cast and typeid) use ๐Ÿง . If you don't use those parts of the language, you can save some space with this flag. Exception handling uses the same info, but G++ generates it as needed. The dynamic_cast operator still works for casts that don't need run-time type information, i.e. casts to void * or to unambiguous base classes.
Mixing code compiled with -frtti with code compiled with -fno-rtti may not work. For example, programs may fail to link if a class compiled with -fno-rtti is used as a base for a class compiled with -frtti ๐Ÿ˜ต.
  • -fsized-deallocation โ€” enables the built-in global declarations below, which were introduced in C++14 ๐ŸŒธ. They're useful for user-defined replacement deallocation functions that, for example, use the size of the object to make deallocation faster.
void operator delete (void *, std::size_t) noexcept;
void operator delete[] (void *, std::size_t) noexcept;

This is 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 of the enumeration ๐ŸŽฏ. (As defined in the C++ standard, basically a value that fits in the minimum number of bits needed to represent all the enumerators.)
This assumption may not hold if your program uses a cast to convert an arbitrary integer value to the enumerated type ๐Ÿ™ƒ.
  • -fstrong-eval-order โ€” evaluates member access, array subscripting, and shift expressions left-to-right, and evaluates assignment right-to-left, as adopted for C++17 ๐Ÿ‘‘. Enabled by default with -std=c++17. -fstrong-eval-order=some enables just the ordering of member access and shift expressions, and it's the default without -std=c++17.
  • -ftemplate-backtrace-limit=n โ€” sets the maximum number of template instantiation notes for a single warning or error to n ๐Ÿ“œ. The default is 10.
  • -ftemplate-depth=n โ€” sets the maximum instantiation depth for template classes to n ๐ŸŒ€. A limit is needed to catch endless recursions during template class instantiation. ANSI/ISO C++ conforming programs must not rely on a maximum depth greater than 17 (changed to 1024 in C++11). The default is 900, because the compiler can run out of stack space before hitting 1024 in some situations.
  • -fno-threadsafe-statics โ€” doesn't emit the extra code that uses the routines from the C++ ABI for thread-safe initialization of local statics ๐Ÿงต. You can use this to shave a bit of code size off code that doesn't need to be thread-safe.
  • -fuse-cxa-atexit โ€” registers destructors for objects with static storage duration with the __cxa_atexit function, instead of 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 โ€” declares that you won't compare pointers to inline functions or methods where the addresses of the two functions are taken in different shared objects ๐Ÿฆ‹.

Okay so GCC can basically slap __attribute__ ((visibility ("hidden"))) on inline methods ๐Ÿซถ, which means they stay out of a DSO's export table and skip the PLT indirection when they're used inside that same DSO โœจ. Turning this on can have a dramatic effect on load and link times for a DSO ๐Ÿ˜ญ, because it massively shrinks the dynamic export table when the library leans hard on templates ๐Ÿ’….

The behavior is not quite the same as marking methods hidden directly ๐Ÿ™ˆ. This switch doesn't touch static variables local to the function, and it doesn't make the compiler deduce that the function is defined in only one shared object ๐Ÿงš.

You can give a method an explicit visibility to negate the switch for that method ๐ŸŽ€. Like, if you do want to compare pointers to a particular inline method, mark it as default visibility ๐Ÿฆ‹. Marking the enclosing class with explicit visibility does nothing though ๐Ÿ’€.

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 three changes to GCC's linkage model:
  1. It sets the default visibility to "hidden", like -fvisibility=hidden.
  2. Types, but not their members, are not hidden by default.
  3. The One Definition Rule is relaxed for types without explicit visibility specifications that are defined in more than one shared object: those declarations are permitted if they're permitted when this option isn't used.

In new code, it's better to use -fvisibility=hidden and export only the classes that are meant to be externally visible ๐ŸŒˆ. Unfortunately, code can rely (maybe accidentally) on the Visual Studio behavior ๐Ÿ˜ฌ.

Among the consequences: static data members of the same type, with the same name, defined in different shared objects are different, so changing one doesn't change the other ๐Ÿ’”. Pointers to function members defined in different shared objects may also not compare equal. With this flag on, defining types with the same name differently is a violation of the ODR ๐Ÿšจ.

  • -fno-weak โ€” don't use weak symbol support, even if the linker provides it ๐Ÿ™…. By default G++ uses weak symbols when they're available. This option exists only for testing, so end-users should steer clear ๐Ÿšซ. It results in inferior code and has no benefits, and it may be removed in a future release of G++ ๐Ÿ‘‹.
  • -fext-numeric-literals (C++ and Objective-C++ only) โ€” accepts imaginary, fixed-point, or machine-defined literal number suffixes as GNU extensions โœจ. When this option is turned off, those suffixes get treated as C++11 user-defined literal numeric suffixes instead. It's on by default for all pre-C++11 dialects and all GNU dialects: -std=c++98, -std=gnu++98, -std=gnu++11, -std=gnu++14. It's off by default for ISO C++11 onwards (-std=c++11, ...) ๐Ÿง.
  • -nostdinc++ โ€” doesn't search for header files in the standard directories specific to C++, but still searches the other standard directories ๐Ÿ“š. (This one gets used when building the C++ library ๐Ÿ› ๏ธ.)
  • -flang-info-include-translate, -flang-info-include-translate-not, -flang-info-include-translate=header โ€” these inform you about include translation events ๐Ÿ”. The first notes accepted include translations, and the second notes declined ones ๐Ÿ™…โ€โ™€๏ธ. The header form tells 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 โ€” inform you about Compiled Module Interface pathnames ๐Ÿงพ. The first one notes all the read CMI pathnames ๐Ÿ“–. The module form covers a specific module's CMI. The module value can be a named module or a header-unit, and a header-unit is indicated either by 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, and the native C++ runtime for G++) and libc++, which is the C++ runtime installed on some operating systems (for example, Darwin versions from Darwin11 onwards) ๐ŸŽ. Picking one switches G++ to use the headers from that library, and it emits -lstdc++ or -lc++ respectively when a C++ runtime is needed 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 ๐Ÿท๏ธ. Peep C++ Attributes for the full scoop on ABI tags ๐Ÿ“.
  • -Wcomma-subscript (C++ and Objective-C++ only) โ€” warns about uses of a comma expression within a subscripting expression ๐Ÿ™ˆ. This usage was deprecated in C++20 and is going to be removed in C++23 ๐Ÿ’€. However, a comma expression wrapped in ( ) is not deprecated โœจ. Example:
void f(int *a, int b, int c) {
    a[b,c];     // deprecated in C++20, invalid in C++23
    a[(b,c)];   // OK
}

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

It's enabled by default with -std=c++20 unless -Wno-deprecated is given, and with -std=c++23 regardless of -Wno-deprecated ๐Ÿ””.

  • -Wctad-maybe-unsupported (C++ and Objective-C++ only) โ€” warns when you perform class template argument deduction (CTAD) on a type with no explicitly written deduction guides ๐Ÿ•ต๏ธ. This warning points out cases where CTAD only succeeded because the compiler synthesized the implicit deduction guides, which might not be what you intended ๐Ÿค”. Certain style guides only allow CTAD on types that specifically "opt-in", meaning types that are designed to support CTAD ๐Ÿ™‹. You can suppress this warning with the following pattern:
struct allow_ctad_t; // any name works
template <typename T> struct S {
  S(T) { }
};
S(allow_ctad_t) -> S<void>; // guide with incomplete parameter type will never be considered
  • -Wctor-dtor-privacy (C++ and Objective-C++ only) โ€” warns when a class seems unusable because all its constructors or destructors are private, and it has neither friends nor public static member functions ๐Ÿ”’. It also warns if there are no non-private methods and there's at least one private member function that isn't a constructor or destructor ๐Ÿšง.
  • -Wdelete-non-virtual-dtor (C++ and Objective-C++ only) โ€” warns when delete is used to destroy an instance of a class that has virtual functions and a non-virtual destructor ๐Ÿ’ฅ. It's unsafe to delete an instance of a derived class through a pointer to a base class if the base class doesn't have a virtual destructor โš ๏ธ. This warning is enabled by -Wall ๐ŸŽ€.
  • -Wdeprecated-copy (C++ and Objective-C++ only) โ€” warns that the implicit declaration of a copy constructor or copy assignment operator is deprecated if the class has a user-provided copy constructor or copy assignment operator, in C++11 and up ๐Ÿ“ข. This warning is enabled by -Wextra ๐Ÿงƒ. With -Wdeprecated-copy-dtor, it also deprecates the implicit declaration if the class has a user-provided destructor ๐Ÿซถ.
  • -Wno-deprecated-enum-enum-conversion (C++ and Objective-C++ only) โ€” disables the warning about the case where the usual arithmetic conversions are applied to operands where one is of enumeration type and the other is of a different enumeration type ๐Ÿ™…. This conversion was deprecated in C++20 ๐Ÿ“œ. For example:
enum E1 { e };
enum E2 { f };
int k = f - e;

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

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

-Wdeprecated-enum-float-conversion is enabled by default with -std=c++20 ๐Ÿ”ฅ. In pre-C++20 dialects, this warning can be enabled by -Wenum-conversion ๐Ÿ“.

  • -Wno-init-list-lifetime (C++ and Objective-C++ only) โ€” don't warn about uses of std::initializer_list that are likely to result in dangling pointers ๐Ÿงจ. The underlying array for an initializer_list is handled like a normal C++ temporary object, so it's super easy to accidentally keep a pointer to the array past the end of the array's lifetime ๐Ÿ˜ญ. Some examples of that:
  • If a function returns a temporary initializer_list, or a local initializer_list variable, the array's lifetime ends at the end of the return statement, so the value returned has a dangling pointer ๐Ÿ’€.
  • If a new-expression creates an initializer_list, the array only lives until the end of the enclosing full-expression, so the initializer_list in the heap has a dangling pointer ๐Ÿซ .
  • When an initializer_list variable is assigned from a brace-enclosed initializer list, the temporary array created for the right side of the assignment only lives until the end of the full-expression, so at the next statement the initializer_list variable has a dangling pointer ๐Ÿ™ˆ.
// li's initial underlying array lives as long as li
std::initializer_list<int> li = { 1,2,3 };
// assignment changes li to point to a temporary array
li = { 4, 5 };
// now the temporary is gone and li has a dangling pointer
int i = li.begin()[0] // undefined behavior
Heads up bestie: that last line is undefined behavior ๐Ÿ’€, so don't go poking at dangling pointers like that ๐Ÿ™.
  • ๐Ÿซฃ When a list constructor stores the begin pointer from the initializer_list argument, that does not extend the lifetime of the array. So if a class variable gets built from a temporary initializer_list, the pointer is left dangling by the end of the variable declaration statement. ๐Ÿ’€

  • -Winvalid-imported-macros โ€” okay so this one checks that every imported macro definition is still valid at the end of compilation ๐Ÿ”. It's not enabled by default because it needs extra processing to figure that out. It's super handy when you're putting together sets of header-units and want your macros to stay consistent โœจ.
  • -Wno-literal-suffix (C++ and Objective-C++ only) โ€” bestie, don't warn when a string or character literal gets 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, and it keeps older code working when it uses formatting macros from <inttypes.h> ๐ŸŽ€. For example:
#define __STDC_FORMAT_MACROS
#include <inttypes.h>
#include <stdio.h>

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

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

This option also controls warnings for a user-defined literal operator declared with a literal suffix identifier that doesn't begin with an underscore ๐Ÿ‘€. Those identifiers are reserved for future standardization, so the warning is a heads up.

These warnings are enabled by default. ๐Ÿ’–


  • -Wno-narrowing (C++ and Objective-C++ only) โ€” for C++11 and later, narrowing conversions get diagnosed by default, as the standard requires ๐Ÿ“. A narrowing conversion from a constant gives an error, and a narrowing conversion from a non-constant gives a warning. -Wno-narrowing silences that diagnostic ๐Ÿ™ˆ.

Just so you know, it doesn't change what well-formed code means, since narrowing conversions are still ill-formed in SFINAE contexts.

With -Wnarrowing in C++98, it warns when a narrowing conversion that C++11 prohibits happens inside { }, e.g.

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

This flag is included in -Wall and -Wc++11-compat ๐Ÿ”ฅ.

  • -Wnoexcept (C++ and Objective-C++ only) โ€” it warns when a noexcept-expression evaluates to false because of a call to a function that doesn't have a non-throwing exception specification (so, throw() or noexcept) but that the compiler knows will never actually throw ๐Ÿง.
  • -Wnoexcept-type (C++ and Objective-C++ only) โ€” this one's about the C++17 feature that makes noexcept part of a function type. It warns if that changes the mangled name of a symbol compared to C++14 ๐Ÿฆ‹. 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) โ€” it warns when the destination of a call to a raw memory function like memset or memcpy is an object of class type ๐Ÿšจ. It also warns when writing into that object might bypass the class's non-trivial or deleted constructor or copy assignment, break const-correctness or encapsulation, or corrupt virtual table pointers. Messing with the representation of these objects can violate invariants that the class's member functions rely on.
๐Ÿ’€ For example, the call to memset below is undefined because it modifies a non-trivial class object, so it gets diagnosed:
std::string str = "abc";
memset (&str, 0, sizeof str);

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

The -Wclass-memaccess option is enabled by -Wall. Explicitly casting the pointer to the class object to void *, or to a type that the raw memory function can safely access, suppresses the warning โœจ.

  • -Wnon-virtual-dtor (C++ and Objective-C++ only) โ€” it warns when a class has virtual functions but an accessible non-virtual destructor, either on itself or in an accessible polymorphic base class ๐Ÿ˜ฌ. That makes it possible, but unsafe, to delete a derived-class instance through a pointer to the class itself or its base class. This warning is automatically enabled if -Weffc++ is specified.
  • -Wregister (C++ and Objective-C++ only) โ€” it warns on uses of the register storage class specifier, except when it's part of the GNU Explicit Register Variables extension ๐Ÿ™…โ€โ™€๏ธ. The register keyword as a storage class specifier was deprecated in C++11 and removed in C++17. Enabled by default with -std=c++17.
  • -Wreorder (C++ and Objective-C++ only) โ€” it warns when the member initializers in your code aren't in the order they actually have to run ๐Ÿงฉ. For instance:
struct A {
  int i;
  int j;
  A(): j (0), i (1) { }
};

The compiler rearranges the member initializers for i and j to match the declaration order of the members, and it emits a warning to say so. This warning is enabled by -Wall.


  • -Wno-pessimizing-move (C++ and Objective-C++ only) โ€” this warning goes off when a call to std::move prevents copy elision ๐Ÿ™ˆ. A typical scenario where copy elision can happen is returning from a function with a class return type, when the returned expression is the name of a non-volatile automatic object that isn't a function parameter and has the same type as the function's return type.
struct T {
...
};
T fn()
{
  T t;
  ...
  return std::move (t);
}

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

  • -Wno-redundant-move (C++ and Objective-C++ only) โ€” this one flags redundant calls to std::move, meaning cases where a move would have happened even without the std::move call ๐Ÿ”. That happens because the compiler is forced to treat the object as an rvalue in certain situations, like returning a local variable where copy elision isn't applicable. Look:
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. Still, G++ 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) โ€” it warns when a C++ range-based for-loop is making an unnecessary copy ๐Ÿ“‹. That can happen when the range declaration isn't a reference but probably should be. For example:
struct S { char arr[128]; };
void fn () {
  S arr[5];
  for (const auto x : arr) { ... }
}

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

This warning also fires when a loop variable in a range-based for-loop is initialized with a value of a different type, which 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, and the reference const double & is bound to that temporary ๐Ÿ˜ต. This warning is enabled by -Wall.

  • -Wredundant-tags (C++ and Objective-C++ only) โ€” it warns about redundant class-key and enum-key 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's no warning, because the keyword is 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) โ€” don't warn if a class type has a base or a field whose type uses the anonymous namespace or depends on a type with no linkage ๐ŸŒธ. If a type A depends on a type B with no 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) โ€” it warns about violations of these style guidelines from Scott Meyers' Effective C++ series of books ๐Ÿ“š:
    • Write a copy constructor and an assignment operator for any class holding 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 have to return an object ๐Ÿ™….
    • Tell the prefix and postfix forms of the increment and decrement operators apart ๐Ÿ‘ฏ.
    • Never overload &&, ||, or , ๐Ÿšซ.

This option also enables -Wnon-virtual-dtor, which is also one of the effective C++ recommendations. The check is extended, though, so it also warns about a missing virtual destructor in accessible non-polymorphic base classes ๐Ÿซถ.

Okay bestie, heads up before you flip these on ๐Ÿ™ˆ the standard library headers don't follow all of these guidelines, so use grep -v to filter out those warnings ๐Ÿ’…

  • -Wno-exceptions (C++ and Objective-C++ only) โ€” no more warnings when one exception handler gets shadowed by another one ๐Ÿ™ˆ This can point out a wrong ordering of your exception handlers, but you can turn it off here.
  • -Wstrict-null-sentinel (C++ and Objective-C++ only) โ€” warns about using an uncasted NULL as a sentinel ๐Ÿ“ When you compile only with GCC, it's a valid sentinel, since NULL is defined to __null. It's a null pointer constant rather than a null pointer, but it's guaranteed to be the same size as a pointer. Still, this use isn't portable across different compilers, so be careful ๐Ÿซถ
  • -Wno-non-template-friend (C++ and Objective-C++ only) โ€” turns off warnings for non-template friend functions declared inside a template โœจ In very old GCC versions that came before the ISO standard was implemented, declarations like friend int foo(int), where the friend's name is an unqualified-id, could be read as a particular specialization of a template function. The warning exists to catch 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 shows up in a C++ program ๐Ÿ’… The new-style casts (dynamic_cast, static_cast, reinterpret_cast, and const_cast) are less vulnerable to unintended effects and much easier to search for ๐Ÿ”
  • -Woverloaded-virtual (C++ and Objective-C++ only) โ€” warns when a function declaration hides virtual functions from a base class ๐Ÿ‘€ For example:
struct A {
  virtual void f();
};

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

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

B* b;
b->f();

fails to compile ๐Ÿ’€

  • -Wno-pmf-conversions (C++ and Objective-C++ only) โ€” disables the diagnostic for converting a bound pointer to a member function into a plain pointer ๐Ÿฆ‹
  • -Wsign-promo (C++ and Objective-C++ only) โ€” warns when overload resolution picks a promotion from an unsigned or enumerated type to a signed type, instead of a conversion to an unsigned type of the same size ๐Ÿงš Older versions of G++ tried to preserve unsignedness, but the standard mandates the current behavior, so that's the vibe now.
  • -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 can 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 allocation or deallocation function ๐Ÿ”ฅ That includes C++ operator delete being called with pointers returned from 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 where that 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 was returned from. The call to free gets diagnosed too ๐Ÿ˜ญ

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

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

The related option -Wmismatched-dealloc diagnoses mismatches involving allocation and deallocation functions other than operator new and operator delete ๐Ÿง 

-Wmismatched-new-delete is included in -Wall โœจ

  • -Wmismatched-tags (C++ and Objective-C++ only) โ€” warns for declarations of structs, classes, and class templates, plus their specializations, that use a class-key which doesn't match either the definition or the first declaration when no definition is provided ๐ŸŽ€

For example, the declaration of struct Object in the argument list of draw triggers the warning. To avoid it, either remove the redundant class-key struct or replace it with class to match its definition.

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

It's not wrong to declare a class with the class-key struct, as the example above shows ๐Ÿ™‚โ€โ†•๏ธ The -Wmismatched-tags option is meant to help you keep a consistent style of class declarations. In code that's intended to be portable to Windows-based compilers, the warning helps prevent unresolved references caused by the difference in the mangling of symbols declared with different class-keys. The option can be used on its own or together with -Wredundant-tags.

  • -Wmultiple-inheritance (C++ and Objective-C++ only) โ€” warns when a class is defined with multiple direct base classes ๐ŸŒธ Some coding rules disallow multiple inheritance, so this can be used to enforce that rule. The warning is inactive inside a system header file, like the STL, so you can still use the STL. You can also define classes that indirectly use multiple inheritance.
  • -Wvirtual-inheritance โ€” warns when a class is defined with a virtual direct base class ๐Ÿฆ„ Some coding rules disallow multiple inheritance, and this can be used to enforce that rule. The warning is inactive inside a system header file, like the STL, so you can still use the STL. You can also define classes that indirectly use virtual inheritance.
  • -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 mean both objects end up in the moved-from state ๐Ÿ˜ฑ

If the move assignment operator is written to avoid moving from a moved-from object, you can disable this warning.

  • -Wnamespaces โ€” warns when a namespace definition is opened ๐Ÿ“ฆ Some coding rules disallow namespaces, 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 can also use using directives and qualified names.
  • -Wno-terminate (C++ and Objective-C++ only) โ€” disables the warning about a throw-expression that will immediately result in a call to terminate ๐Ÿ›‘
  • -Wno-vexing-parse (C++ and Objective-C++ only) โ€” warns about the most vexing parse syntactic ambiguity ๐ŸŒ€ This is when a declaration looks like a variable definition, but C++ requires it to be read as a function declaration. For instance:
void f(double a) {
  int i();        // extern int i (void);
  int n(int(a));  // extern int n (int);
}

Another example:

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

The warning will suggest options for dealing with the ambiguity, e.g., it can suggest removing the parentheses or using braces instead ๐Ÿง

This warning is enabled by default โœ…

  • -Wno-class-conversion (C++ and Objective-C++ only) โ€” don't warn when a conversion function converts an object to the same type, to a base class of that type, or to void ๐Ÿ™… Such a conversion function will never be called, so the warning is just noise ๐Ÿ™„
  • -Wvolatile (C++ and Objective-C++ only) โ€” warns about deprecated uses of the volatile qualifier ๐Ÿ“œ This includes:
    • postfix and prefix ++ and -- expressions of volatile-qualified types
    • simple assignments where the left operand is a volatile-qualified non-class type, for their value
    • compound assignments where the left operand is a volatile-qualified non-class type
    • a volatile-qualified function return type
    • a volatile-qualified parameter type
    • structured bindings of a volatile-qualified type

This usage was deprecated in C++20 ๐Ÿ’€

Enabled by default with -std=c++20 ๐Ÿ’œ

  • -Wzero-as-null-pointer-constant (C++ and Objective-C++ only) โ€” warns when a literal 0 is used as a null pointer constant ๐Ÿผ This can be useful for making the switch to nullptr in C++11 โœจ
  • -Waligned-new โ€” warns about a new-expression of a type that requires greater alignment than alignof(std::max_align_t), but uses an allocation function without an explicit alignment parameter ๐Ÿ“ This option is enabled by -Wall.

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

  • -Wno-placement-new, -Wplacement-new=n โ€” warns about placement new expressions with undefined behavior, like constructing an object in a buffer that's smaller than the type of the object ๐Ÿงธ For example, the placement new expression below is diagnosed, because it tries to construct an array of 64 integers in a buffer that's only 64 bytes large.
char buf [64];
new (buf) int[64];

This warning is enabled by default ๐Ÿ’–

  • -Wplacement-new=1 โ€” this is the default warning level of -Wplacement-new ๐ŸŒท At this level, the warning isn't issued for some strictly undefined constructs that GCC allows as extensions for compatibility with legacy code. For example, the following new expression isn't diagnosed at this level, even though it has undefined behavior according to the C++ standard, because it writes past the end of the one-element array ๐Ÿ™ˆ
struct S { int n, a[1]; };
S *s = (S *)malloc (sizeof *s + 31 * sizeof s->a[0]);
new (s->a)int [32]();

Cranking it up to -Wplacement-new=2 ๐Ÿ’… gets you everything level 1 catches, plus a warning for placement new expressions that build an object inside the last member of a struct when that member is a single-element array and the object being built is bigger than the array. ๐Ÿ˜ญ The previous example would get flagged, but the flexible member array extension lets you dodge the warning at level 2 ๐Ÿฆ‹

struct S { int n, a[]; };
S *s = (S *)malloc (sizeof *s + 32 * sizeof s->a[0]);
new (s->a)int [32]();
  • -Wcatch-value, -Wcatch-value=n (C++ and Objective-C++ only) โ€” bestie, this one roasts catch handlers that don't catch by reference ๐Ÿ™ˆ
    • -Wcatch-value=1 (or -Wcatch-value for short) โ€” flags polymorphic class types that get caught by value
    • -Wcatch-value=2 โ€” flags all class types caught by value
    • -Wcatch-value=3 โ€” flags all types that aren't caught by reference
    • -Wcatch-value is enabled by -Wall, so you're basically getting it for free โœจ
  • -Wconditionally-supported (C++ and Objective-C++ only) โ€” warns about conditionally-supported constructs (C++11 [intro.defs]) ๐ŸŒธ
  • -Wno-delete-incomplete (C++ and Objective-C++ only) โ€” turns off the warning for deleting a pointer to an incomplete type. Heads up, that can cause undefined behavior at runtime ๐Ÿ’€ This warning is on by default.
  • -Wextra-semi (C++, Objective-C++ only) โ€” catches redundant semicolons after in-class function definitions ๐Ÿงš
  • -Wno-inaccessible-base (C++, Objective-C++ only) โ€” controls the warnings you get when a base class is inaccessible in a derived class because of ambiguity. It's on by default, and the warning for ambiguous virtual bases comes along with -Wextra. Check out this drama:
struct A { int a; };

struct B : A { };

struct C : B, A { };
  • -Wno-inherited-variadic-ctor โ€” silences the warnings about C++11 inheriting constructors when the base class has a C variadic constructor. That warning is on by default, since the ellipsis doesn't get inherited, so this is you saying "I know, I know" ๐Ÿ™„
  • -Wno-invalid-offsetof (C++ and Objective-C++ only) โ€” shushes the warnings for using the offsetof macro on a non-POD type. The 2014 ISO C++ standard says applying offsetof to a non-standard-layout type is undefined, but existing C++ implementations usually give meaningful results anyway. This flag is for the girlies who know their code is nonportable and chose to ignore the warning on purpose ๐Ÿ’…

The restrictions on offsetof may be relaxed in a future version of the C++ standard, so keep your eyes open ๐Ÿ‘€

  • -Wsized-deallocation (C++ and Objective-C++ only) โ€” warns when you define an unsized deallocation function like this:
void operator delete (void *) noexcept;
void operator delete[] (void *) noexcept;

...without also defining the matching sized deallocation function like this:

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

...or the other way around. It's enabled by -Wextra along with -fsized-deallocation ๐Ÿ”ฅ

  • -Wsuggest-final-types โ€” suggests when a type with virtual methods would look better with the C++11 final specifier or, if possible, living in an anonymous namespace. This lets GCC devirtualize polymorphic calls more aggressively ๐Ÿš€ It's way more useful with link-time optimization, since that gives the full class hierarchy graph.
  • -Wsuggest-final-methods โ€” suggests when a virtual method would be better off with the final specifier, or if possible, when its type lives in an anonymous namespace or uses final. Same deal, it's more effective with link-time optimization. Pro tip: look at -Wsuggest-final-types suggestions first, then rebuild with the new annotations ๐ŸŽ€
  • -Wsuggest-override โ€” warns when you override virtual functions without the override keyword ๐Ÿซถ
  • -Wuse-after-free, -Wuse-after-free=n โ€” warns about using pointers to dynamically allocated objects that a deallocation function has made indeterminate. It's enabled at every optimization level, but the results can change depending on whether optimization is on ๐ŸŒˆ
    • -Wuse-after-free=1 โ€” only diagnoses unconditional uses of pointers made indeterminate by a deallocation call, or by a successful realloc call (whether or not it actually moved the memory). That includes double free calls and uses in arithmetic and relational expressions. Uses in equality or inequality expressions aren't diagnosed at this level, even though they're still undefined.
    • -Wuse-after-free=2 โ€” adds conditional uses of pointers made indeterminate by a deallocation call. Just like level 1, equality and inequality uses don't get flagged here. In this example, the second free call is the one that gets caught:
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 โ€” also diagnoses equality expressions that use indeterminate pointers. All uses of indeterminate pointers are undefined, but equality tests sometimes show up after realloc calls to check whether the object moved to a new address. This level is separate so legacy code can slowly move to safer alternatives ๐Ÿฆ‹ In this function, the equality test is what gets flagged:
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 the allocated memory instead of pointers. That way you never have to fix up stored pointers after reallocation, which is so much cleaner ๐Ÿงš

-Wuse-after-free=2 is included in -Wall.

  • -Wuseless-cast (C++ and Objective-C++ only) โ€” warns when an expression gets cast to its own type. Why are we doing that ๐Ÿ’€
  • -Wno-conversion-null (C++ and Objective-C++ only) โ€” stops the warnings for conversions between NULL and non-pointer types. -Wconversion-null is enabled by default, so this is the opt-out ๐Ÿ™ˆ

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

NOTE: This manual does not describe the Objective-C and Objective-C++ languages themselves. Okay, this section is only about the command-line options that matter for Objective-C and Objective-C++ programs ๐Ÿ’–

You can also use most of the language-independent GNU compiler options. For example, you might compile a file called some_class.m like this:

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

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

Objective-C is an extension of the C language, so Objective-C compilations can also use options specific to the C front-end (for example, -Wtraditional). In the same way, Objective-C++ compilations can use C++-specific options (for example, -Wabi) ๐Ÿ‘‘

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

  • -fconstant-string-class=class-name โ€” picks the class to instantiate for each literal string written with the "@"..."" syntax. The default is "NXConstantString" if the GNU runtime is in use, and "NSConstantString" if the NeXT runtime is in use (see below). If -fconstant-cfstrings is also present, it overrides -fconstant-string-class and makes "@"..."" literals get laid out as constant CoreFoundation strings โœจ
  • -fgnu-runtime โ€” generates object code that 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. This is the default on NeXT-based systems, including Darwin and Mac OS X. The macro "__NEXT_RUNTIME__" is predefined if, and only if, this option is used ๐Ÿ“
  • -fno-nil-receivers โ€” assumes every Objective-C message dispatch ("[receiver message:arg]") in this translation unit makes sure the receiver is not "nil". That lets the runtime use faster entry points. This option 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 it's only supported for the NeXT runtime ๐Ÿ’œ
    • Version 0 is the traditional (32-bit) ABI, with no support for properties or the other Objective-C 2.0 additions.
    • Version 1 is the traditional (32-bit) ABI with support for properties and the other Objective-C 2.0 additions.
    • Version 2 is the modern (64-bit) ABI.
    • If you don't specify anything, the default is Version 0 on 32-bit target machines and Version 2 on 64-bit target machines.
  • -fobjc-call-cxx-cdtors โ€” okay so for every Objective-C class, GCC peeks at its instance variables ๐Ÿ‘€. If any of them is a C++ object with a non-trivial default constructor, GCC quietly synthesizes a special - (id) .cxx_construct instance method โœจ. That method runs those constructors on the instance variables, in order, and then returns self ๐Ÿ’–. Same energy for destructors: if any instance variable is a C++ object with a non-trivial destructor, GCC synthesizes a - (void) .cxx_destruct method that runs all of those default destructors in reverse order ๐Ÿ”„.
    • The generated methods only work on instance variables declared in the current Objective-C class, not the ones inherited from superclasses ๐Ÿ™…โ€โ™€๏ธ. Making sure every method in an object's inheritance hierarchy gets invoked is the Objective-C runtime's job ๐Ÿซถ.
    • The runtime calls - (id) .cxx_construct right after a new object instance is allocated โฐ. It calls - (void) .cxx_destruct right before deallocating an object instance ๐Ÿ—‘๏ธ.
    • As of this writing, only the NeXT runtime on Mac OS X 10.4 and later has support for invoking - (id) .cxx_construct and - (void) .cxx_destruct ๐Ÿ’€.
  • -fobjc-direct-dispatch โ€” allows fast jumps to the message dispatcher โšก. On Darwin, this is done via the comm page ๐Ÿ“.
  • -fobjc-exceptions โ€” turns on syntactic support for structured exception handling in Objective-C, kinda like what C++ offers ๐Ÿงš. You need this flag 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 a different GC implementation that doesn't need any special compiler flags โœจ.
  • -fobjc-nilcheck โ€” for the NeXT runtime with version 2 of the ABI, this checks for a nil receiver in method invocations before the actual method call ๐Ÿ”. It's the default, and you can switch it off with -fno-objc-nilcheck ๐Ÿ™…. Class methods and super calls are never checked for nil this way, no matter what this flag is set to ๐Ÿคท. Right now this flag does nothing when the GNU runtime, or an older version of the NeXT runtime ABI, is in use ๐Ÿ’ค.
  • -fobjc-std=objc1 โ€” conforms to the language syntax of Objective-C 1.0, the language recognized by GCC 4.0 ๐Ÿ•ฐ๏ธ. It only affects the Objective-C additions to C/C++, and doesn't change conformance to C/C++ standards, which is controlled by the separate C/C++ dialect option flags ๐Ÿ™ƒ. With the Objective-C or Objective-C++ compiler, any Objective-C syntax that GCC 4.0 doesn't recognize gets rejected โŒ. This is super useful if you need to make sure your Objective-C code compiles with older versions of GCC ๐Ÿ‘ต.
  • -freplace-objc-classes โ€” emits a special marker telling ld(1) not to statically link the resulting object file, and lets dyld(1) load it in at run time instead ๐Ÿฆ‹. This is used with the Fix-and-Continue debugging mode, where the object file can be recompiled and dynamically reloaded during execution, no restart needed ๐Ÿ”. Right now, Fix-and-Continue is only available with the NeXT runtime on Mac OS X 10.3 and later ๐ŸŽ.
  • -fzero-link โ€” when compiling for the NeXT runtime, GCC 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 improves run-time performance ๐ŸŽ๏ธ. This flag suppresses that behavior and keeps the calls to objc_getClass("...") ๐Ÿ™Œ. It's useful in Zero-Link debugging mode, since it lets you modify individual class implementations while the program is running ๐Ÿ› ๏ธ. The GNU runtime always keeps calls to objc_get_class("..."), no matter what command-line options you pass ๐Ÿ’….
  • -fno-local-ivars โ€” by default, instance variables can be accessed as if they were local variables from within the methods of the class they're declared in ๐Ÿง. That can cause shadowing between instance variables and other variables, whether those are declared locally inside a class method or globally with the same name ๐Ÿ‘ฏ. This flag disables that behavior, so you avoid the variable shadowing issues ๐Ÿšซ.
  • -fivar-visibility=[public|protected|private|package] โ€” sets the default instance variable visibility to whatever option you pick ๐Ÿ”. Instance variables declared outside the scope of any access modifier directive will default to that visibility.
  • -gen-decls โ€” dumps interface declarations for all classes seen in the source file into a file named sourcename.decl ๐Ÿ“„.
  • -Wassign-intercept (Objective-C and Objective-C++ only) โ€” warns whenever an Objective-C assignment is being intercepted by the garbage collector ๐Ÿšจ.
  • -Wno-property-assign-default (Objective-C and Objective-C++ only) โ€” no warning if a property for an Objective-C object has no assign semantics specified ๐Ÿคซ.
  • -Wno-protocol (Objective-C and Objective-C++ only) โ€” if a class says it implements a protocol, you normally get a warning for every protocol method the class doesn't implement ๐Ÿ“ฃ. By default, that includes methods the class doesn't explicitly implement even when the superclass has them, which is lowkey extra ๐Ÿ™„. With -Wno-protocol, inherited methods count as implemented, so no warning gets issued for them ๐Ÿ’–.
  • -Wobjc-root-class (Objective-C and Objective-C++ only) โ€” warns if a class interface lacks a superclass ๐ŸŒณ. Most classes inherit from "NSObject" (or "Object"), for example ๐Ÿงธ. When you're declaring classes that are meant to be root classes, you can suppress the warning by marking their interfaces with __attribute__((objc_root_class)) ๐Ÿคซ.
  • -Wselector (Objective-C and Objective-C++ only) โ€” warns if multiple methods of different types for the same selector are found during compilation ๐Ÿ•ต๏ธ. The check runs on the list of methods in the final stage of compilation ๐Ÿ. It also checks each selector appearing in a @selector(...) expression, if a corresponding method for that selector was found during compilation ๐Ÿ”Ž. Because these checks only scan the method table at the end, these warnings won't be produced if the final stage isn't reached ๐Ÿ˜ญ. That happens if an error is found during compilation, or if the -fsyntax-only option is being used.
  • -Wstrict-selector-match (Objective-C and Objective-C++ only) โ€” warns if multiple methods with differing argument and/or return types are found for a given selector when you try to send a message with it to a receiver of type id or Class ๐Ÿ“จ. When this flag is off (which is the default), the compiler skips these warnings if the differences are confined to types that share the same size and alignment ๐Ÿซ .
  • -Wundeclared-selector (Objective-C and Objective-C++ only) โ€” warns if a @selector(...) expression referring to an undeclared selector is found ๐Ÿ™ˆ. A selector counts as undeclared if no method with that name has been declared before the @selector(...) expression, either explicitly in an @interface or @protocol declaration, or implicitly in an @implementation section ๐Ÿ“œ. This option checks as soon as a @selector(...) expression is found, while -Wselector only checks in the final stage of compilation โฑ๏ธ. It also enforces the coding style convention that methods and selectors must be declared before they're used ๐Ÿ’….
  • -print-objc-runtime-info โ€” generates a C header describing the largest structure that gets passed by value, if any ๐Ÿงพ.

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

Traditionally, diagnostic messages have been formatted without caring about the output device's aspect (like its width, etc.) ๐Ÿ–ฅ๏ธ. The options here let you control the formatting algorithm, like how many characters go on a line, or how often source location info gets reported ๐Ÿ“. Heads up: some language front ends may not honor these options ๐Ÿซฃ.

  • -fmessage-length=n โ€” tries to format error messages so they fit on lines of about n characters ๐Ÿ“. If n is zero, no line-wrapping gets done, and each error message appears 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 diagnostic output that looks as plain as possible ๐Ÿงผ. This can be useful when running dejagnu or other utilities that parse diagnostics output and prefer it stay more stable over time ๐Ÿงช. It's currently equivalent to the following options:
-fno-diagnostics-show-caret -fno-diagnostics-show-line-numbers -fdiagnostics-color=never -fdiagnostics-urls=never -fdiagnostics-path-format=separate-events

Looking ahead ๐Ÿ”ฎ, if GCC ever changes the default appearance of its diagnostics, the matching option to disable the new behavior will be added to this list ๐Ÿ’–.

  • -fdiagnostics-show-location=once โ€” only meaningful in line-wrapping mode ๐Ÿ“. It tells the diagnostic messages reporter to emit source location info once. If a message is too long to fit on one physical line and has to be wrapped, the source location won't be emitted again as a prefix on each continuation line ๐Ÿ™…. This is the default behavior ๐Ÿ’….
  • -fdiagnostics-show-location=every-line โ€” also only meaningful in line-wrapping mode ๐Ÿ“. It tells the reporter to emit the same source location info (as a prefix) for each physical line that results from breaking up a message that's too long to fit on a single line ๐Ÿ”.
  • -fdiagnostics-color[=WHEN], -fno-diagnostics-color โ€” slap color on your diagnostics (or take it right off) ๐Ÿ’…

This one decides whether GCC's messages come out in color ๐ŸŒˆ. WHEN can be never, always, or auto. The default depends on how the compiler was configured ๐Ÿ”ง. It can be any of those WHEN options too, 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 GCC isn't 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 themselves come from the GCC_COLORS environment variable โœจ. Its value is a colon-separated list of capabilities and Select Graphic Rendition (SGR) substrings. SGR commands are interpreted by your terminal or terminal emulator, so check your text terminal's docs for the permitted values and what they mean as character attributes ๐Ÿ“–. These substring values are decimal integers, and they can be stuck together with semicolons ๐Ÿซถ.

Here are some common values you can concatenate:

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

The default GCC_COLORS is ๐ŸŽจ

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

So 01;31 is bold red, 01;35 is bold magenta, 01;36 is bold cyan, 32 is green, 34 is blue, 01 is bold, and 31 is red ๐ŸŽ€. Setting GCC_COLORS to the empty string disables colors entirely ๐Ÿ™…. These are the capabilities you can customize:

  • "error=" โ€” the SGR substring for error: markers ๐Ÿ”ด
  • "warning=" โ€” the SGR substring for warning: markers ๐ŸŸฃ
  • "note=" โ€” the SGR substring for note: markers ๐Ÿฉต
  • "path=" โ€” the SGR substring for colorizing paths of control-flow events printed via -fdiagnostics-path-format=, like the identifiers of individual events and the lines showing interprocedural calls and returns ๐Ÿ—บ๏ธ
  • "range1=" โ€” the SGR substring for the first additional range
  • "range2=" โ€” the SGR substring for the second additional range
  • "locus=" โ€” the SGR substring for location info, like file:line or file:line:column etc. ๐Ÿ“
  • "quote=" โ€” the SGR substring for info printed within quotes ๐Ÿ’ฌ
  • "fixit-insert=" โ€” the SGR substring for fix-it hints suggesting text to be inserted or replaced โž•
  • "fixit-delete=" โ€” the SGR substring for fix-it hints suggesting text to be deleted โž–
  • "diff-filename=" โ€” the SGR substring for filename headers within generated patches ๐Ÿ“„
  • "diff-hunk=" โ€” the SGR substring for the starts of hunks within generated patches ๐Ÿงฉ
  • "diff-delete=" โ€” the SGR substring for deleted lines within generated patches โŒ
  • "diff-insert=" โ€” the SGR substring for inserted lines within generated patches โœ…
  • "type-diff=" โ€” the SGR substring for highlighting mismatching types within template arguments in the C++ frontend ๐ŸŒธ
  • -fdiagnostics-urls[=WHEN] โ€” sneak clickable-vibe URLs into your diagnostics ๐Ÿฆ‹

This uses escape sequences to embed URLs in diagnostics. For example, when -fdiagnostics-show-option prints the command-line option controlling a diagnostic, it can embed a URL pointing to the documentation for that option ๐Ÿ“š.

WHEN is never, always, or auto. auto makes GCC use URL escape sequences only when standard error is a terminal, and when GCC isn't running in an emacs shell or in any graphical terminal known to be incompatible with this feature (see below) ๐Ÿ™ˆ.

The default depends on how the compiler was configured, and it can be any of the above WHEN options ๐Ÿ”ง.

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

Even with -fdiagnostics-urls=always, the behavior still depends on those environment variables ๐Ÿงš:

  • If GCC_URLS is set to empty or no, URLs are not embedded in diagnostics.
  • If it's set to st, URLs use ST escape sequences.
  • If it's set to bel, which is the default, URLs use BEL escape sequences.
  • Any other non-empty value enables the feature.

If GCC_URLS isn't set, TERM_URLS is used as a fallback.

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

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

Heads up, bestie: on those terminals the URL escapes are likely to misbehave, i.e. print garbage on the screen ๐Ÿ™ˆ.
  • -fno-diagnostics-show-option โ€” stop naming the controlling option ๐Ÿ™ˆ

By default, each diagnostic includes text indicating the command-line option that directly controls it (if that option is known to the diagnostic machinery). Specifying -fno-diagnostics-show-option suppresses that behavior ๐Ÿšซ.

  • -fno-diagnostics-show-caret โ€” no source line, no caret ๐Ÿ’…

By default, each diagnostic includes the original source line and a caret ^ pointing at the column. This option suppresses that info ๐Ÿ™…. The source line is truncated to n characters if the -fmessage-length=n option is given. When the output goes to the terminal, the width is limited to the width given by the COLUMNS environment variable or, if that isn't set, to the terminal width ๐Ÿ“.

  • -fno-diagnostics-show-labels โ€” skip the little labels ๐Ÿท๏ธ

By default, when printing source code (via -fdiagnostics-show-caret), diagnostics can label ranges of source code with pertinent information, such as the types of expressions:

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

This option suppresses the printing of these labels. In the example above, that means the vertical bars and the "char *" and "long int" text disappear ๐Ÿ™ˆ.

  • -fno-diagnostics-show-cwe โ€” hide the CWE metadata ๐Ÿ”’

Diagnostic messages can optionally have an associated CWE (https://cwe.mitre.org/index.html) identifier. GCC itself only provides this metadata for some of the -fanalyzer diagnostics. GCC plugins may also provide diagnostics with this metadata. By default, if the information is present, it gets printed with the diagnostic. This option suppresses printing that metadata ๐Ÿšซ.

  • -fno-diagnostics-show-line-numbers โ€” no line-number 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 โ€” machine-readable fix-its, made for IDEs ๐Ÿค–

This emits fix-it hints in a machine-parseable format, which is suitable for IDEs to consume ๐Ÿซถ. 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", and double quotes as "\"". Non-printable characters get written as octal, so vertical tab shows up as "\013" ๐Ÿงฉ.

An empty replacement string means that range is to be removed ๐Ÿ—‘๏ธ. An empty range, like "45:3-45:3", means the string is to be inserted at the given position โž•.

  • -fdiagnostics-generate-patch โ€” fix-its served up as a diff ๐Ÿฉน

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 โ€” template mismatches as a tree ๐ŸŒณ

In the C++ frontend, when printing diagnostics that show mismatching template types, you get messages like this:

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

The -fdiagnostics-show-template-tree flag turns on a tree-like structure that shows the common and differing parts of the types, like this:

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

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

  • -fno-elide-type โ€” stop squishing the matching bits into [...] ๐Ÿ™…

By default, when the C++ frontend prints diagnostics showing mismatching template types, the common parts get printed as "[...]" to keep the error message simpler ๐Ÿ’…. 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 โ€” okay so this one decides how control-flow paths get shown ๐Ÿ›ค๏ธ for diagnostics that actually have one attached โœจ

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

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

separate-events prints a separate "note" diagnostic for every event in the diagnostic ๐Ÿ“ Here's how that looks:

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

inline-events prints the events right inside the source code ๐Ÿ–ผ๏ธ It tries to group events that sit close together into runs and shows them as labelled ranges. Same events as above, but the vibe is totally different:

'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 gets shown by grouping the events by stack frame ๐Ÿ“š Indentation shows how stack frames nest, get pushed, and get popped, and it's giving organized ๐Ÿงƒ Like this:

  '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 โ€” bonus info ๐Ÿ” for when GCC prints control-flow paths attached to a diagnostic

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

This one is mainly for GCC developers and plugin developers who are debugging diagnostics that report interprocedural control flow ๐Ÿ”ง

  • -fno-show-column โ€” no column numbers in diagnostics, periodt ๐Ÿ™…

Do not print column numbers in diagnostics. This might be necessary if a program that doesn't understand column numbers is scanning your diagnostics, like dejagnu ๐Ÿซถ

  • -fdiagnostics-column-unit=UNIT โ€” pick the units used for column numbers ๐Ÿ“ This affects traditional diagnostics (when -fno-show-column isn't set), plus JSON diagnostics if you ask for them

The default, display, counts the number of display columns each character takes up ๐Ÿ–ฅ๏ธ 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, "GREEK SMALL LETTER PI (U+03C0)" takes up one display column but needs two bytes in UTF-8. Meanwhile "SLIGHTLY SMILING FACE (U+1F642)" takes up two display columns and needs four bytes in UTF-8 ๐Ÿ™‚

Setting UNIT to byte changes the column number to the raw byte count in all cases ๐Ÿงฎ That's how GCC did it before version 11.1.0, so it's giving throwback ๐Ÿ•ฐ๏ธ

  • -fdiagnostics-column-origin=ORIGIN โ€” choose what number the first column starts at ๐Ÿ”ข

The default value of 1 matches traditional GCC behavior and the GNU style guide, so it's the safe pick โœจ Some utilities might work better with an origin of 0, and any non-negative value can be specified ๐ŸŒธ

  • -fdiagnostics-escape-format=FORMAT โ€” how weird bytes in source lines get escaped ๐Ÿ”ค

Normally, when GCC prints the relevant source lines for a diagnostic, it tries to print the source bytes directly ๐Ÿ“œ But some diagnostics are about encoding issues in the source file, like malformed UTF-8 or Unicode normalization problems. Those get flagged, so GCC escapes any bytes that aren't printable ASCII when it prints those source lines ๐Ÿ’€

This option controls how those bytes get escaped ๐Ÿ’…

The default, unicode, displays non-printable-ASCII Unicode characters as <U+XXXX>, and bytes that aren't validly encoded UTF-8 as hexadecimal in the form <XX> ๐Ÿฆ‹ For example, say a source line has the string before, then the Unicode character U+03C0 ("GREEK SMALL LETTER PI", which is UTF-8 encoded as 0xCF 0x80), then the byte 0xBF (a stray UTF-8 trailing byte), then the string after. For that diagnostic it would be printed as:

before<U+03C0><BF>after

Setting FORMAT to bytes displays all non-printable-ASCII bytes as <XX>, which shows the underlying encoding of non-ASCII Unicode characters ๐Ÿง  For the same example above, this is what gets printed:

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

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

The JSON gets emitted as one line with no formatting, so the examples below were formatted just so they're readable ๐Ÿ‘€

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

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

might 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 kind is "warning", then there's an "option" key describing the command-line option that controls the warning โš ๏ธ

A diagnostic can have zero or more locations ๐Ÿ“โœจ and each one can carry an optional "label" string plus up to three positions: a "caret" position, and optional "start" and "finish" positions. Each position is described by a "file" name, a "line" number, and three numbers that tell you the column:

  • display-column โ€” counts display columns, accounting for tabs and multibyte characters ๐Ÿ‘€
  • byte-column โ€” counts raw bytes ๐Ÿงฎ
  • column โ€” is equal to one of the two above, depending on -fdiagnostics-column-unit ๐ŸŽ€

All three columns are relative to the origin set by -fdiagnostics-column-origin. That's usually 1, but you can set it to 0 for compatibility with other tools that count columns from 0 ๐ŸŒธ The column origin gets recorded in the JSON output under the "column-origin" tag. In the examples below I've left out the extra column number outputs to keep things short, bestie ๐Ÿซถ

Okay so, 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, one for the left and one for the right-hand side of the expression, and both of 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 has fix-it hints, it gets a "fixits" array ๐Ÿ”ง The array is made of half-open intervals, kind of like the output of -fdiagnostics-parseable-fixits. For example, this diagnostic with a replacement fix-it hint:

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

might be printed in JSON form as:

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

So the fix-it hint basically says to swap out the text from "start" up to but not including "next" with the value of "string" โœจ Deletions are written as an empty value for "string", and insertions are written by having "start" equal "next" ๐Ÿ™ˆ

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

For example, the intraprocedural example 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 hints whether non-ASCII bytes should be escaped when the relevant lines of source code get printed. It's "true" for diagnostics involving source encoding issues ๐ŸŒธ


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

Warnings are diagnostic messages about constructions that aren't inherently wrong, but are risky or suggest there might have been an error ๐Ÿ‘€โš ๏ธ

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

  • -fsyntax-only โ€” Checks the code for syntax errors, and that's it. It won't do anything beyond that ๐Ÿ™…โ€โ™€๏ธ
  • -fmax-errors=n โ€” Limits the maximum number of error messages to n. When that limit is hit, GCC bails out instead of trying to keep processing the source code ๐Ÿ›‘ If n is 0 (the default), there's no limit on how many error messages get produced. If -Wfatal-errors is also specified, then -Wfatal-errors takes precedence over this option ๐Ÿ‘‘
  • -w โ€” Inhibits all warning messages. Total silence ๐Ÿคซ
  • -Werror โ€” Turns all warnings into errors ๐Ÿ’€
  • -Werror= โ€” Turns the specified warning into an error. You append the warning's specifier to the end, so for example -Werror=switch turns the warnings controlled by -Wswitch into errors ๐Ÿ”ฅ This switch also has a negative form, which negates -Werror for specific warnings. For example, -Wno-error=switch makes -Wswitch warnings not be errors, even when -Werror is in effect ๐Ÿซถ
    • The warning message for each controllable warning includes the option that controls it. You can then use that option with -Werror= and -Wno-error= as described above. (Printing the option in the warning message can be turned off with the -fno-diagnostics-show-option flag ๐Ÿ™ˆ)
    • Note that specifying -Werror=foo automatically implies -Wfoo. However, -Wno-error=foo does not imply anything ๐Ÿง
  • -Wfatal-errors โ€” Makes the compiler abort compilation on the first error it hits, instead of trying to keep going and printing more error messages ๐Ÿ›‘

You can request lots of specific warnings with options that start with -W. For example, -Wimplicit requests warnings on implicit declarations ๐ŸŽ€ Each of these specific warning options also has a negative form that starts with -Wno- to turn the warnings off. For example, -Wno-implicit. This manual only lists one of the two forms, whichever one isn't the default ๐Ÿ“– For 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, like -Wall and -Wextra, turn on other options, such as -Wunused, which may then turn on even more options, like -Wunused-value ๐ŸŒˆ When you combine positive and negative forms, the more specific option wins over the less specific one, no matter where it sits on the command-line. For options of the same specificity, the last one takes effect. Options enabled or disabled via pragmas act as if they appeared at the end of the command-line ๐Ÿ’œ

When you request an unrecognized warning option (e.g., -Wunknown-warning), GCC emits a diagnostic saying the option isn't recognized ๐Ÿ˜ญ The -Wno- form is a little different, though. No diagnostic is produced for -Wno-unknown-warning unless other diagnostics are being produced too. This lets you use new -Wno- options with old compilers, but if something goes wrong, the compiler warns that an unrecognized option is present ๐Ÿฆ‹

The effectiveness of some warnings depends on optimizations also being enabled, bestie ๐Ÿ”ฅ. For example, -Wsuggest-final-types hits way harder with link-time optimization โœจ, and some instances of other warnings won't get issued at all unless optimization is turned on. Optimization in general makes the control and data flow sensitive warnings more powerful ๐Ÿ’…, but in some cases it can also cause false positives ๐Ÿ™ˆ.


๐ŸŽ€ -Wpedantic, -pedantic

Okay so these two are the strict-rules besties ๐Ÿ‘‘. They make GCC issue all the warnings that strict ISO C and ISO C++ demand, and they reject any program using forbidden extensions, plus some other programs that don't follow ISO C and ISO C++. For ISO C, it follows whichever version of the standard you asked for with any -std option.

Valid ISO C and ISO C++ programs should compile just fine with or without this option ๐Ÿ’– (though a rare few need -ansi or a -std option that names the version of ISO C they require). Without this option, though, certain GNU extensions and traditional C and C++ features still get supported. With this option on, they get rejected ๐Ÿ˜ญ.

-Wpedantic doesn't warn about the alternate keywords whose names begin and end with __. That alternate format can also turn off warnings for non-ISO __intN types, meaning __intN__ โœจ. Pedantic warnings are also disabled in the expression that follows "__extension__". Real talk though: only system header files should use these escape routes, so application programs should steer clear of them ๐Ÿซถ.

Some users try to use -Wpedantic to check their programs for strict ISO C conformance, and they quickly find it doesn't do exactly what they want ๐Ÿ™ƒ. It does find some non-ISO practices, but not all of them. It only catches the ones ISO C requires a diagnostic for, plus some others that diagnostics have been added for.

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

Where the standard set with -std is a GNU extended dialect of C, like gnu90 or gnu99, there's a corresponding base standard, which is the version of ISO C that the GNU dialect is built on. -Wpedantic gives warnings wherever the base standard requires them. (It wouldn't make sense to only warn about features outside the specified GNU C dialect, since by definition the GNU dialects include every feature the compiler supports with that option, so there'd be nothing to warn about ๐Ÿคทโ€โ™€๏ธ.)

๐ŸŒธ -pedantic-errors

Think of this one as -Wpedantic but with the drama turned all the way up ๐Ÿ˜ค. It gives an error whenever the base standard (see -Wpedantic) requires a diagnostic. It also errors in some cases where there's undefined behavior at compile time, and in some other cases that don't stop compilation of programs that are valid according to the standard.

This is not the same as -Werror=pedantic ๐Ÿ™…โ€โ™€๏ธ. There are errors this option enables that -Werror=pedantic doesn't, and vice versa. Don't mix them up, bestie!

๐ŸŒˆ -Wall

This one turns on all the warnings about constructions that some users consider questionable and that are easy to avoid (or easy to modify to prevent the warning), even when macros are involved ๐Ÿงš. It also enables some language-specific warnings described in C++ Dialect Options and Objective-C and Objective-C++ Dialect Options.

-Wall turns on the following warning flags:

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

Note that some warning flags are not implied by -Wall ๐Ÿ‘€. Some of them warn about constructions that users generally don't consider questionable, but that you might occasionally want to check for. Others warn about constructions that are necessary or hard to avoid in some cases, and there's no simple way to change the code to suppress the warning. Some of them are enabled by -Wextra, but many of them must be enabled individually.

๐Ÿ’– -Wextra

This enables some extra warning flags that -Wall doesn't โœจ. (This option used to be called -W. The older name is still supported, but -Wextra is more descriptive, so use that one ๐Ÿ’….)

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

The option -Wextra also prints warning messages for the following cases ๐Ÿง:

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

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

This one warns about code affected by ABI changes ๐Ÿฆ‹. That includes code that may not be compatible with the vendor-neutral C++ ABI, as well as the psABI for the particular target.

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

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

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

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

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

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

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

This was fixed in -fabi-version=3.

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

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

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

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

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

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

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

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

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

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

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

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

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

  • Target-specific attributes ๐ŸŽ€ โ€” Stuff that changes what a type is, like the ia32 calling conventions on a function type (stdcall, regparm, etc.), was NOT showing up in the mangled name. So you could get name collisions when function pointers were used as template arguments. Literal chaos ๐Ÿ˜ญ

This was fixed in -fabi-version=10, which is the default for GCC 6.1. ๐Ÿ’…

Okay so this option also turns on warnings about psABI-related changes โœจ The known psABI changes at this point include:

  • SysV/x86-64 unions with long double members ๐Ÿ‘‘ โ€” these get passed in memory as the psABI specifies. Before GCC 4.4 that wasn't the case. Here's an example:
union U {
  long double ld;
  int i;
};

So union U is now always passed in memory. No cap, that's a big deal ๐Ÿซถ

  • -Wchar-subscripts ๐ŸŒธ โ€” Warns if an array subscript has type char. This is a super common mistake, because programmers forget that this type 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 fail to match the source, and GCC can't use the profile feedback info. By default this warning is on and treated as an error. -Wno-coverage-mismatch turns the warning off, and -Wno-error=coverage-mismatch turns off the error. Skipping the error can lead to poorly optimized code, so it's only useful for super minor changes, like bug fixes to an existing codebase. Fully disabling the warning is not recommended ๐Ÿ™ˆ
  • -Wno-coverage-invalid-line-number ๐Ÿ“ โ€” Warns in case a function ends earlier than it begins because of an invalid linenum macro. This warning is only emitted when --coverage is enabled.

By default this warning is on and treated as an error. -Wno-coverage-invalid-line-number can be used to turn the warning off, or -Wno-error=coverage-invalid-line-number can be used to turn off the error.

  • -Wno-cpp (C, Objective-C, C++, Objective-C++ and Fortran only) ๐Ÿงš โ€” Suppresses the warning messages emitted by #warning directives.
  • -Wdouble-promotion (C, C++, Objective-C and Objective-C++ only) โœจ โ€” Gives a warning when a value of type float is implicitly promoted to double. CPUs with a 32-bit single-precision floating-point unit implement float in hardware but emulate double in software. On a machine like that, doing math with double values is way more expensive because of the software emulation overhead.

It's super easy to accidentally do double math, because floating-point literals are implicitly of type double. For example:

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

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

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

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

  • -Wformat=1, -Wformat ๐Ÿฆ‹ โ€” -Wformat is the same as -Wformat=1, and -Wno-format is the same as -Wformat=0. Since -Wformat also checks for null format arguments for several functions, -Wformat also implies -Wnonnull. Some parts of this level of format checking can be turned off with -Wno-format-contains-nul, -Wno-format-extra-args, and -Wno-format-zero-length. -Wformat is enabled by -Wall.
  • -Wformat=2 ๐Ÿ”ฅ โ€” Enables -Wformat plus additional format checks. Right now it's equivalent to -Wformat -Wformat-nonliteral -Wformat-security -Wformat-y2k.
  • -Wno-format-contains-nul ๐Ÿ™ˆ โ€” If -Wformat is specified, don't warn about format strings that contain NUL bytes.
  • -Wno-format-extra-args ๐Ÿ’… โ€” If -Wformat is specified, don't warn about excess arguments to a printf or scanf format function. The C standard says those extra arguments are ignored.

If the unused arguments sit between used arguments that are specified with $ operand number specifications, warnings still happen by default, since the implementation couldn't know what type to pass to va_arg to skip the unused arguments. But for scanf formats, this option suppresses the warning if the unused arguments are all pointers, because the Single Unix Specification says those unused arguments are allowed.

  • -Wformat-overflow, -Wformat-overflow=level ๐Ÿ’– โ€” Warns about calls to formatted input/output functions, like sprintf and vsprintf, that might overflow the destination buffer. When the exact number of bytes written by a format directive can't be determined at compile time, it's estimated using heuristics that depend on the level argument and on optimization. Turning on optimization will usually make the warning more accurate, but it can also cause false positives.
    • -Wformat-overflow, -Wformat-overflow=1 ๐ŸŒธ โ€” Level 1 of -Wformat-overflow is enabled by -Wformat and takes a conservative approach, only warning about calls that most likely overflow the buffer. At this level, numeric arguments to format directives with unknown values are assumed to have the value of 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 either by their directive's precision or by a finite set of string literals, are assumed to take on the value within the range that produces the most bytes of output. For example, the sprintf call below gets diagnosed, because even with both a and b equal to zero, the terminating NUL character ('\0') appended to the destination buffer is written past its end. Making the buffer one byte bigger is enough to avoid the warning, though it may not be enough to 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 given an argument of sufficient length or magnitude. At level 2, unknown numeric arguments are assumed to have the minimum representable value for signed types with a precision greater than 1, and the maximum representable value otherwise. Unknown string arguments whose length can't be assumed to be bounded, either by the directive's precision or by a finite set of string literals they may evaluate to, or by the character array they may point to, are assumed to be 1 character long.

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

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

void f (int a, int b)
{
  char buf [23];
  sprintf (buf, "a = %hi, b = %i\n", a, (short)b);
}
  • -Wno-format-zero-length ๐Ÿงธ โ€” If -Wformat is specified, don't warn about zero-length formats. The C standard says zero-length formats are allowed.
  • -Wformat-nonliteral ๐Ÿซง โ€” If -Wformat is specified, also warn if the format string is not a string literal and so can't be checked, unless the format function takes its format arguments as a va_list.
  • -Wformat-security โ€” okay so if you've got -Wformat on, this one also goes hunting for format calls that could be a security problem ๐Ÿ˜ญ๐Ÿ”’. Right now it side-eyes printf and scanf calls where the format string isn't a string literal and there aren't any format arguments, like printf (foo);. That can be a real security hole if the format string came from untrusted input and has %n in it ๐Ÿ’€. (ngl this is currently just a subset of what -Wformat-nonliteral catches, but future -Wformat-security warnings might cover stuff that -Wformat-nonliteral doesn't ๐Ÿ”ฎ.)
  • -Wformat-signedness โ€” if -Wformat is specified, this one also warns when the format string wants an unsigned argument but you gave it a signed one, and vice versa ๐Ÿงฎโœจ.
  • -Wformat-truncation, -Wformat-truncation=level โ€” warns about formatted input/output calls like snprintf and vsnprintf that might chop your output short โœ‚๏ธ. When the exact number of bytes a format directive writes can't be figured out at compile time, GCC 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, -Wformat-truncation=1 โ€” level 1 (enabled by -Wformat) is the chill, conservative option ๐Ÿง˜. It only warns about bounded function calls whose return value is unused and that will most likely end up truncating the output.
    • -Wformat-truncation=2 โ€” level 2 goes further and also warns about bounded function calls whose return value is used and that might truncate given an argument of sufficient length or magnitude ๐Ÿ“.
  • -Wformat-y2k โ€” if -Wformat is specified, also warn about strftime formats that may yield only a two-digit year ๐Ÿ“….
  • -Wnonnull โ€” warns when you pass a null pointer for arguments the nonnull function attribute says must be non-null ๐Ÿšซ. It's included in -Wall and -Wformat, and you can turn it off with -Wno-nonnull.
  • -Wnonnull-compare โ€” warns when you compare an argument marked with the nonnull function attribute against null inside the function ๐Ÿ‘€. It's included in -Wall and can be disabled with -Wno-nonnull-compare.
  • -Wnull-dereference โ€” warns if GCC detects paths that trigger erroneous or undefined behavior from dereferencing a null pointer ๐Ÿ’ฅ. This one is only active when -fdelete-null-pointer-checks is active, which optimizations enable on most targets. How precise the warnings are depends on the optimization options you used ๐ŸŽฏ.
  • -Winfinite-recursion โ€” warns about infinitely recursive calls ๐Ÿ”โ™พ๏ธ. It's effective at all optimization levels, but you need optimization to catch infinite recursion in calls between two or more functions. It's included in -Wall.
  • -Winit-self (C, C++, Objective-C and Objective-C++ only) โ€” warns about uninitialized variables that get initialized with themselves ๐Ÿคก. Note this option can only be used with -Wuninitialized.

For example, GCC warns about "i" being uninitialized in the following snippet only when -Winit-self has been specified:

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

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

  • -Wno-implicit-int (C and Objective-C only) โ€” controls warnings when a declaration doesn't specify a type ๐Ÿค”. This warning is enabled by default in C99 and later dialects of C, and also by -Wall.
  • -Wno-implicit-function-declaration (C and Objective-C only) โ€” controls warnings when a function is used before being declared ๐Ÿ“ฃ. This warning is enabled by default in C99 and later dialects of C, and also by -Wall. It gets turned into an error by -pedantic-errors ๐Ÿšจ.
  • -Wimplicit (C and Objective-C only) โ€” same as -Wimplicit-int and -Wimplicit-function-declaration ๐Ÿ‘ฏ. This warning is enabled by -Wall.
  • -Wimplicit-fallthrough โ€” 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, e.g. when there's a return statement or a call to a function declared with the noreturn attribute ๐Ÿ™Œ. -Wimplicit-fallthrough= also takes control flow statements, such as ifs, into account and only warns when appropriate. For example:

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

Since there are occasions where a switch case fall through is desirable, GCC provides an attribute, __attribute__ ((fallthrough)), that is to be used along with a null statement to suppress this warning that would normally occur ๐Ÿซถ:

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

C++17 provides a standard way to suppress the -Wimplicit-fallthrough warning using [[fallthrough]]; instead of the GNU attribute โœจ. In C++11 or C++14, users can use [[gnu::fallthrough]];, which is a GNU extension. Instead of these attributes, it's also possible to add a fallthrough comment to silence the warning ๐Ÿ’ฌ. The whole body of the C or C++ style comment should match the given regular expressions listed below. The option argument n specifies what kind of comments are accepted:

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

The comment needs to be followed, after optional whitespace and other comments, by "case" or "default" keywords, or by a user label that precedes some "case" or "default" label ๐Ÿท๏ธ:

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

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

  • -Wno-if-not-aligned (C, C++, Objective-C and Objective-C++ only) โ€” controls whether warnings triggered by the warn_if_not_aligned attribute should be issued ๐Ÿ“. These warnings are enabled by default.
  • -Wignored-qualifiers (C and C++ only) โ€” warns if the return type of a function has a type qualifier such as const ๐ŸŽ€. For ISO C, a qualifier like that has no effect, since the value returned by a function isn't an lvalue. For C++, the warning is only emitted for scalar types or void. ISO C prohibits qualified void return types on function definitions, so those always get a warning, even without this option. This warning is also enabled by -Wextra.
  • -Wno-ignored-attributes (C and C++ only) โ€” controls warnings when an attribute is ignored ๐Ÿ™ˆ. This is different from the -Wattributes option, because it warns whenever the compiler decides to drop an attribute, not when the attribute is unknown, used in a wrong place, etc. This warning is enabled by default.
  • -Wmain โ€” warns if the type of main is suspicious ๐Ÿ‘‘. main should be a function with external linkage, returning int, taking either zero arguments, two, or three arguments of appropriate types. This warning is enabled by default in C++ and is enabled by either -Wall or -Wpedantic.
  • -Wmisleading-indentation (C and C++ only) โ€” warns when the indentation of the code doesn't reflect the block structure ๐Ÿซฃ. Specifically, a warning is issued for if, else, while, and for clauses with a guarded statement that doesn't use braces, followed by an unguarded statement with the same indentation.

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

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

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

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

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

This one goes quiet after a #line directive ๐Ÿ™ˆ because that usually means autogenerated code, and nobody can assume anything about the layout of the file the directive points to. โœจ

This warning is enabled by -Wall in C and C++. ๐Ÿ’–


โœจ -Wmissing-attributes โœจ

okay so this one checks if a function declaration is missing an attribute that a related function has, and that absence could mess with the correctness or efficiency of the generated code ๐Ÿ’… For example, it fires on alias declarations that use attributes to ask for less restrictive stuff than their targets. That usually means you've got a potential optimization just sitting there, bestie ๐Ÿงš

By contrast, -Wattribute-alias=2 is the one that warns when the alias is more restrictive than the target, which could lead to incorrect code generation ๐Ÿ˜ญ Attributes this warning considers are "alloc_align", "alloc_size", "cold", "const", "hot", "leaf", "malloc", "nonnull", "noreturn", "nothrow", "pure", "returns_nonnull", and "returns_twice". ๐ŸŒธ

In C++, the warning kicks in when an explicit specialization of a primary template is declared without one of these attributes, if the primary template had "alloc_align", "alloc_size", "assume_aligned", "format", "format_arg", "malloc", or "nonnull". 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 explicitly listing them all. ๐Ÿฆ‹ This attribute works on declarations of functions, variables, or types.

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

Here's the vibe: the primary function template below uses both "malloc" and "alloc_size", so the explicit specialization of the template gets flagged for missing one of them ๐Ÿ‘‘

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

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

โœจ -Wmissing-braces โœจ

This one warns if an aggregate or union initializer isn't fully bracketed ๐ŸŽ€ In the example below, the initializer for a isn't fully bracketed, but the one for b is. Iykyk, the second one is the slay ๐Ÿ’…

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

This warning is enabled by -Wall. ๐Ÿ“


โœจ -Wmissing-include-dirs (C, C++, Objective-C, Objective-C++ and Fortran only) โœจ

Warns if a user-supplied include directory doesn't exist ๐Ÿ“ This option is disabled by default for C, C++, Objective-C, and Objective-C++. For Fortran, it's partially enabled by default, but only for -I and -J ๐ŸŒˆ


โœจ -Wno-missing-profile โœจ

ngl this one's about profile feedback ๐Ÿ“ˆ It controls warnings when feedback profiles are missing while you're using -fprofile-use. It's looking for cases where a new function or a new file got added between compiling with -fprofile-generate and compiling with -fprofile-use, without regenerating the profiles ๐Ÿ™ˆ In those cases, the profile feedback data files don't contain any profile info for the new function or file.

Also, if profile count data (.gcda) files get removed, GCC can't use any profile feedback info at all ๐Ÿ’€ In all of these situations, you get warnings telling you a profile generation step is due. Ignoring them can result in poorly optimized code, so be careful, bestie ๐Ÿ˜ญ

-Wno-missing-profile can be used to turn the warning off, but that is not recommended and should only be done when the non-existent profile data is justified ๐Ÿซถ


โœจ -Wmismatched-dealloc โœจ

Okay this one is so good. It warns for calls to deallocation functions that get pointer arguments returned from allocation functions where the former isn't a suitable deallocator for the latter ๐Ÿ”ฅ A pair of functions can be linked up as matching allocator and deallocator using the malloc attribute.

Unless you turn it off with -fno-builtin, the standard functions "calloc", "malloc", "realloc", and "free", plus the matching forms of C++ "operator new" and "operator delete", are implicitly associated as matching allocators and deallocators ๐Ÿ‘‘ In the example below, mydealloc is the deallocator for pointers returned from myalloc.

void mydealloc (void*);

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

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

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

Option -Wmismatched-dealloc is included in -Wall. ๐Ÿ’œ


โœจ -Wmultistatement-macros โœจ

This one warns about unsafe multi-statement macros that look guarded by a clause like if, else, for, switch, or while, but where only the first statement is actually guarded after the macro gets expanded ๐Ÿ˜ญ

Here's the trap: the macro below will increment y unconditionally, not just when c holds ๐Ÿ’€

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

This can usually be fixed by wrapping the macro in a do-while loop ๐ŸŽ€

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

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


โœจ -Wparentheses โœจ

This one warns when parentheses are left out in certain contexts, like when there's an assignment where a truth value is expected, or when operators are nested in ways people often get confused about ๐Ÿง

It also warns if a comparison like x<=y<=z shows up. That's equivalent to (x<=y ? 1 : 0) <= z, which is a different interpretation from ordinary math notation, so it's a whole vibe check ๐Ÿ™…โ€โ™€๏ธ

It also warns about dangerous uses of the GNU extension to ?: with an omitted middle operand. When the condition in the ?: operator is a boolean expression, the omitted value is always 1. Programmers often expect it to be a value computed inside the conditional expression instead, which is not it ๐Ÿ’€

For C++, this also warns about some cases of unnecessary parentheses in declarations, which can indicate an attempt at a function call instead of a declaration ๐Ÿ™ˆ

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

This warning is enabled by -Wall. ๐Ÿ’…


โœจ -Wsequence-point โœจ

Let's talk about sequence points, the chaotic little rules that decide when stuff in an expression gets evaluated ๐ŸŒ€ This warning flags code that may have undefined semantics because it breaks those rules in C and C++.

Basically, sequence points are a partial ordering between parts of the program: the stuff before a sequence point and the stuff after it. They happen after a full expression is evaluated, after the first operand of &&, ||, ? :, or , (comma) is evaluated, before a function is called (but after its arguments and the expression denoting the called function are evaluated), and in certain other places. Other than that, the order of evaluating subexpressions isn't specified. Even so, the standards committee has ruled that function calls don't overlap โœจ

It's not specified when between sequence points changes to object values take effect. Programs that depend on this have undefined behavior. The standards say that "Between the previous and next sequence point an object shall have its stored value modified at most once by the evaluation of an expression. Furthermore, the prior value shall be read only to determine the value to be stored." If a program breaks these rules, the results on any particular implementation are entirely unpredictable ๐Ÿ˜ญ๐Ÿ”ฅ

Examples of undefined behavior 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 the occasional false positive, but overall it's been found pretty effective at catching this kind of problem in programs ๐Ÿซถ

The C++17 standard will define the order of evaluation for 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 โœจ

Do not warn about returning a pointer (or, in C++, a reference) to a variable that goes out of scope after the function returns ๐Ÿฆ‹


โœจ -Wreturn-type โœจ

This one warns whenever a function is defined with a return type that defaults to int ๐Ÿ‘€ It also warns about any return statement with no return value in a function whose return type isn't void. Falling off the end of the function body counts as returning without a value, so yep, that's flagged too ๐Ÿ’…

Okay bestie, this one is C only ๐Ÿ’… It warns you when a return has an expression in a function whose return type is void, unless that expression is also void โœจ As a GNU extension, that last case gets a pass with no warning unless you use -Wpedantic ๐Ÿซถ

๐Ÿ˜ญ Undefined alert: trying to use the return value of a non-void function (other than main) that just flows off the end by reaching the closing curly brace is undefined. Do not do this bestie.

Unlike in C, in C++ flowing off the end of a non-void function (other than main) is undefined behavior even if you never use the return value ๐Ÿ™ˆ

This warning is on by default in C++, and in C it comes along with -Wall ๐Ÿ’–

  • -Wno-shift-count-negative โ€” Warns if a shift count is negative. This one is on by default, so you get it for free ๐ŸŒธ
  • -Wno-shift-count-overflow โ€” Warns if a shift count is greater than or equal to the bit width of the type. Also on by default ๐Ÿ“
  • -Wshift-negative-value โ€” Warns when you left shift a negative value. It's turned on by -Wextra in C99 and C++11 modes (and newer) ๐Ÿฆ‹
  • -Wno-shift-overflow, -Wshift-overflow=n โ€” These two control warnings about left shift overflows ๐ŸŒˆ
    • -Wshift-overflow=1 โ€” This is the level -Wshift-overflow uses, and it's on by default in C99 and C++11 modes (and newer). It does not warn about left-shifting 1 into the sign bit. (In C, that overflow still gets 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 in that mode โœจ
    • -Wshift-overflow=2 โ€” This level also warns about left-shifting 1 into the sign bit, unless C++14 mode (or newer) is active ๐Ÿ‘‘
  • -Wswitch โ€” Warns whenever a switch statement has an index of enumerated type and is missing a case for one or more of the named codes in that enum. (A default label stops this warning from happening ๐Ÿ™…โ€โ™€๏ธ) case labels outside the enum range also get flagged with this option, even if there's a default label. Enabled by -Wall ๐Ÿ’œ
  • -Wswitch-default โ€” Warns whenever a switch statement doesn't have a default case ๐Ÿงš
  • -Wswitch-enum โ€” Same vibe as -Wswitch, with case labels outside the enum range flagged too. The only real difference is that this one warns about an omitted enum code even if there's a default label. Main character energy ๐Ÿ‘‘
  • -Wno-switch-bool โ€” Doesn't warn when a switch has a boolean index and the case values are outside the range of a boolean. You can shush this warning by casting the controlling expression to a type other than bool. For example:
switch ((int) (a == 4))
  {
  ...
  }

This warning is on by default for C and C++ programs ๐ŸŽ€

  • -Wno-switch-outside-range โ€” Controls warnings when a switch case has a value outside of its type's range. Enabled by default for C and C++ programs ๐Ÿซง
  • -Wno-switch-unreachable โ€” Doesn't warn when a switch has statements between the controlling expression and the first case label that will never run. For example:
switch (cond)
  {
   i = 15;
  ...
   case 5:
  ...
  }

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

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

This warning is on 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. Heads up, these functions changed semantics in GCC 4.4 ๐Ÿ˜ฌ
  • -Wunused-but-set-parameter โ€” Warns whenever a function parameter gets assigned to but is otherwise unused (aside from its declaration) ๐Ÿซถ

To shush this one, use the unused attribute.

This warning is also turned on by -Wunused together with -Wextra โœจ

  • -Wunused-but-set-variable โ€” Warns whenever a local variable gets assigned to but is otherwise unused (aside from its declaration). Enabled by -Wall ๐Ÿฆ‹

To shush this one, use the unused attribute.

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

  • -Wunused-function โ€” Warns whenever a static function is declared but not defined, or a non-inline static function is unused. Enabled by -Wall ๐Ÿ“
  • -Wunused-label โ€” Warns whenever a label is declared but never used. Enabled by -Wall ๐Ÿงš

To shush this one, use the unused attribute.

  • -Wunused-local-typedefs (C, Objective-C, C++ and Objective-C++ only) โ€” Warns when a typedef defined locally inside a function isn't used. Enabled by -Wall ๐Ÿ’œ
  • -Wunused-parameter โ€” Warns whenever a function parameter is unused aside from its declaration ๐ŸŒˆ

To shush this one, use the unused attribute.

  • -Wno-unused-result โ€” Doesn't warn if a caller of a function marked with the attribute warn_unused_result doesn't use its return value. The default is -Wunused-result ๐ŸŽ€
  • -Wunused-variable โ€” Warns whenever a local or static variable is unused aside from its declaration. This option implies -Wunused-const-variable=1 for C, but not for C++. Enabled by -Wall โœจ

To shush this one, use the unused attribute.

  • -Wunused-const-variable, -Wunused-const-variable=n โ€” Warns whenever a constant static variable is unused aside from its declaration. -Wunused-const-variable=1 is enabled by -Wunused-variable for C, but not for C++. In C this declares variable storage, but in C++ it's not an error, since const variables take the place of #defines ๐Ÿ™ƒ

To shush this one, use the unused attribute.

  • -Wunused-const-variable=1 โ€” This is the level that -Wunused-variable enables for C. It only warns about unused static const variables defined in the main compilation unit, not about static const variables declared in any header that's included ๐Ÿ’–
  • -Wunused-const-variable=2 โ€” This level also warns about unused constant static variables in headers (excluding system headers). It's the level of -Wunused-const-variable and must be explicitly requested, since in C++ it isn't an error and in C it might be harder to clean up every header that's included ๐Ÿงน
  • -Wunused-value โ€” Warns whenever a statement computes a result that is explicitly not used. To shush it, cast the unused expression to void. This covers an expression-statement or the left-hand side of a comma expression that has no side effects. For example, an expression like x[i,j] causes a warning, while x[(void)i,j] does not. Enabled by -Wall ๐Ÿ”ฅ
  • -Wunused โ€” All the above -Wunused options combined. ๐Ÿซง

To get a warning about an unused function parameter, you must either specify -Wextra -Wunused (note that -Wall implies -Wunused), or separately specify -Wunused-parameter.

  • -Wuninitialized โ€” Warns if an object with automatic or allocated storage duration is used without having been initialized. In C++, it also warns if a non-static reference or non-static const member appears in a class without constructors ๐Ÿ˜ญ

Passing a pointer (or, in C++, a reference) to an uninitialized object into a const-qualified argument of a built-in function that's known to read the object 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 a variable in its own initializer, use the -Winit-self option ๐Ÿซถ

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

There may be no warning about a variable that's only used to compute a value that itself is never used, because those computations may be deleted by data flow analysis before the warnings are printed ๐Ÿ™ˆ

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

struct A {
  int a;
  int b;
  A() : a(b) { }
};
  • -Wno-invalid-memory-model โ€” Controls warnings for invocations of __atomic built-ins, __sync built-ins, and the C11 atomic generic functions with a memory consistency argument that's either invalid for the operation or outside the range of values of the memory_order enumeration. For example, since __atomic_store and __atomic_store_n are only defined for the relaxed, release, and sequentially consistent memory orders, the following code 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 there are other paths where it isn't, the compiler emits a warning if it can't prove those uninitialized paths never run at runtime ๐Ÿฆ‹

Passing a pointer (or in C++, a reference) to an uninitialized object into a const-qualified function argument also gets flagged by this warning ๐Ÿ‘€. (-Wuninitialized fires for built-in functions known to read the object.) If you annotate the function with the attribute access (none), you're telling GCC the argument doesn't access the object, and the warning goes poof โœจ.

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

They're optional because GCC sometimes can't tell that code is correct even when it looks like an error ๐Ÿฅบ. Here's a classic example:

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

If the value of y is always 1, 2 or 3, then x is always initialized, but GCC doesn't know that ๐Ÿ™ƒ. To shush the warning, add a default case with assert(0) or similar code ๐Ÿ’….

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

Some spurious warnings can be avoided if you declare every function you use that never returns as noreturn ๐Ÿซถ.

This warning is enabled by -Wall or -Wextra โœจ.


  • -Wunknown-pragmas โ€” Warns when GCC runs into a #pragma directive it doesn't understand ๐Ÿ”. If you turn this on from the command line, you'll even get warnings for unknown pragmas hiding in system header files. That doesn't happen if it's only enabled by the -Wall command-line option.
  • -Wno-pragmas โ€” Chill, GCC, no warnings about pragma misuse ๐ŸŒธ. That covers incorrect parameters, invalid syntax, or pragmas clashing with each other. See also -Wunknown-pragmas.
  • -Wno-prio-ctor-dtor โ€” Don't warn if a priority from 0 to 100 is used for a constructor or destructor ๐ŸŽ€. Constructor and destructor attributes let you set a priority to control their order of execution before main is called or after it returns. Priority values have to be greater than 100, because the compiler reserves 0--100 for its own implementation โญ.
  • -Wstrict-aliasing โ€” This one only works when -fstrict-aliasing is active ๐Ÿฆ‹. It warns about code that might break the strict aliasing rules the compiler uses for optimization. It doesn't catch every case, but it does try to catch the more common pitfalls. It's included in -Wall, and it's equivalent to -Wstrict-aliasing=3.
  • -Wstrict-aliasing=n โ€” Also only active when -fstrict-aliasing is active ๐Ÿ’œ. It warns about code that might break the strict aliasing rules used for optimization. Higher levels mean higher accuracy (fewer false positives), but also more effort, kind of like how -O works. -Wstrict-aliasing is equivalent to -Wstrict-aliasing=3.
    • Level 1 โ€” Most aggressive, quick, and least accurate ๐Ÿ˜ต. It's possibly useful when higher levels don't warn but -fstrict-aliasing still breaks the code, since it has very few false negatives. The catch 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 and quick, but 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. It runs in the front end only.
    • Level 3 (default for -Wstrict-aliasing) โ€” The main character of levels ๏ฟฝรซ๏ฟฝ. It should have very few false positives and few false negatives. It's slightly slower than levels 1 or 2 when optimization is enabled. It handles the common pun+dereference pattern in the front end, like *(int*)&some_float. If optimization is enabled, it also runs in the back end, where it deals with multiple statement cases using flow-sensitive points-to information. It only warns when the converted pointer is dereferenced, and it doesn't warn about incomplete types.
  • -Wstrict-overflow, -Wstrict-overflow=n โ€” 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 place the code might overflow, only where the compiler actually implements some optimization, so this warning depends on the optimization level.

An optimization that assumes signed overflow doesn't occur is perfectly safe if the values involved never actually overflow. That means this warning can easily give a false positive, which is a warning about code that isn't really a problem ๐Ÿ™„. To help you focus on the important stuff, several warning levels are defined. No warnings are issued for undefined signed overflow when estimating how many iterations a loop needs, particularly when figuring out whether a loop runs at all.

  • -Wstrict-overflow=1 โ€” Warns about cases that are both questionable and easy to avoid ๐Ÿงน. For example, the compiler simplifies x + 1 > x to 1. This level is enabled by -Wall. 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 ๐Ÿง . For example: 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 ๐Ÿ‘€. For example: x + 1 > 1 is simplified to x > 0.
  • -Wstrict-overflow=4 โ€” Also warns about other simplifications that aren't covered by the cases above ๐Ÿ“. For example: (x * 10) / 5 is simplified to x * 2.
  • -Wstrict-overflow=5 โ€” Also warns about cases where the compiler reduces the magnitude of a constant involved in a comparison ๐Ÿ˜ญ. For example: x + 2 > y is simplified to x + 1 >= y. This is only reported at the highest warning level, because this simplification applies to 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 gets determined to be always zero or always non-zero in equality tests. That happens because the length of one argument is greater than the size of the array the other argument is stored in (or the bound, in the case of strncmp) ๐Ÿงต. Such calls could be mistakes. Here's an example:
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");
}

The strcmp call in that example gets diagnosed, because its result is necessarily non-zero no matter what the contents of the array a are ๐Ÿšซ. -Wstring-compare is enabled by -Wextra.

  • -Wno-stringop-overflow, -Wstringop-overflow, -Wstringop-overflow=type โ€” Warns for calls to string manipulation functions like memcpy and strcpy that would overflow the destination buffer ๐Ÿ’ฅ. The optional argument is one greater than the type of Object Size Checking to perform when determining the size of the destination. That argument only matters for functions that operate on character arrays, not raw memory functions like memcpy, which always use Object Size type-0. The option also warns for calls that specify a size bigger than the largest possible object, or at most SIZE_MAX / 2 bytes. It gets the best results with optimization enabled, but it can also catch a small subset of simple buffer overflows without optimization, in calls to GCC built-in functions like __builtin_memcpy that match the standard functions ๐Ÿซถ. Either way, it only warns about a subset of the buffer overflows the matching overflow-checking built-ins detect.

For example, this option warns about the strcpy call below, because it copies at least 5 characters (the string "blue" including the terminating NUL) into a buffer of size 4 ๐Ÿ’.

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

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

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

  • -Wstringop-overflow, -Wstringop-overflow=1 โ€” This one uses type-zero Object Size Checking to determine the sizes of destination objects ๐Ÿฆ„. At this setting, it doesn't warn for writes past the end of subobjects of larger objects accessed by pointers, unless the size of the largest surrounding object is known. When the destination 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 โ€” ๐ŸŽ€ okay so this level uses type-one Object Size Checking to figure out how big the destination objects are. At this setting it warns about overflows when writing to members of the largest complete objects whose exact size is known. It does not warn for excessive writes to the same members of unknown objects referenced by pointers, since those pointers might point to arrays with unknown numbers of elements ๐Ÿ™ˆ. This is the default setting of the option โœจ.
  • -Wstringop-overflow=3 โ€” ๐Ÿ’– this one switches to type-two Object Size Checking for the destination sizes. It warns about overflowing the smallest object or data member. It's the most restrictive setting that can still warn on code that's actually safe, so ngl it can be a little dramatic ๐Ÿ’….
  • -Wstringop-overflow=4 โ€” ๐Ÿฆ‹ type-three Object Size Checking is the next level up. It warns about overflowing any data members, and when the destination is one of several objects, it uses the size of the largest one to decide whether to warn. Just like -Wstringop-overflow=3, this setting may also warn about benign code ๐ŸŒธ.
  • -Wno-stringop-overread โ€” ๐Ÿงš warns for calls to string manipulation functions such as memchr or strcpy that are determined to read past the end of the source sequence.

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

  • -Wno-stringop-truncation โ€” ๐ŸŒˆ do not warn for calls to bounded string manipulation functions such as strncat, strncpy, and stpncpy that may either truncate the copied string or leave the destination unchanged.

Here's a little example. The call to strncat sets a bound that's smaller than the length of the source string, so the copy gets truncated and the call is diagnosed ๐Ÿ‘€. To avoid the warning, use bufsize - strlen (buf) - 1) as the bound.

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

Another one: this strncpy call copies just the characters before the terminating NUL, so the result never gets a NUL at the end. Assuming the result of strncpy is always NUL-terminated is a super common mistake, so the call gets diagnosed ๐Ÿ™ƒ. To avoid the warning when the result isn't supposed to be NUL-terminated, call memcpy instead.

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

And here the call to strncpy uses the size of the destination buffer as the bound. If the source string's length is equal to or greater than that size, the copy won't be NUL-terminated, so yep, it's diagnosed too ๐Ÿ’€. To avoid it, specify sizeof buf - 1 as the bound and set the last element of the buffer to NUL.

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

If a character array is meant to hold a sequence of bytes with no terminating NUL, you can annotate it with the attribute nonstring to skip this warning ๐Ÿซถ. Just know that these arrays aren't suitable for functions that expect NUL-terminated strings. To help catch accidental misuse, GCC still issues warnings for them unless it can prove the use is safe.

  • -Wsuggest-attribute=[pure|const|noreturn|format|cold|malloc] โ€” ๐Ÿ‘‘ warns for cases where adding an attribute might be beneficial. The attributes currently supported are listed below.
    • -Wsuggest-attribute=pure, -Wsuggest-attribute=const, -Wsuggest-attribute=noreturn, -Wmissing-noreturn, -Wsuggest-attribute=malloc โ€” ๐Ÿ”ฅ warns about functions that might be good candidates for the attributes pure, const, noreturn, or malloc. The compiler only warns for functions that are visible in other compilation units, or (for pure and const) if it can't prove the function returns normally. A function returns normally if it doesn't contain an infinite loop and doesn't return abnormally by throwing, calling abort, or trapping. This analysis requires option -fipa-pure-const, which is enabled by default at -O and higher. Higher optimization levels make the analysis more accurate โœจ.
    • -Wsuggest-attribute=format, -Wmissing-format-attribute โ€” ๐ŸŒธ warns about function pointers that might be candidates for format attributes. These are only possible candidates, not absolute ones. GCC guesses that function pointers with format attributes that get used in assignment, initialization, parameter passing, or return statements should 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, and again, these are only possible candidates ๐Ÿง . GCC guesses that format attributes might be appropriate for any function that calls a function like vprintf or vscanf. That's not always the case though, and some functions that really should have format attributes may not get detected.

  • -Wsuggest-attribute=cold โ€” ๐ŸงŠ warns about functions that might be candidates for the cold attribute. This is based on static detection, and it generally only warns about functions that always lead to a call to another cold function, like wrappers of C++ throw or fatal error reporting functions that lead to abort.
  • -Walloc-zero โ€” ๐Ÿ’€ warns about calls to allocation functions decorated with the attribute alloc_size that specify zero bytes. That includes the built-in forms of aligned_alloc, alloca, calloc, malloc, and realloc.
Heads up bestie: the behaviour of these functions when called with a zero size differs between implementations (and realloc has been deprecated for this). Relying on it can cause sneaky portability bugs, so it's best to avoid it ๐Ÿšซ.
  • -Walloc-size-larger-than=byte-size โ€” ๐ŸŒŠ warns about calls to functions decorated with the attribute alloc_size that try to allocate objects larger than the specified number of bytes. It also warns when the result of the size computation, done in an integer type with infinite precision, would exceed the value of PTRDIFF_MAX on the target. -Walloc-size-larger-than=PTRDIFF_MAX is enabled by default ๐Ÿ’–. You can disable the warnings controlled by this option either by specifying a byte-size of SIZE_MAX or more, or by using -Wno-alloc-size-larger-than.
  • -Wno-alloc-size-larger-than โ€” ๐Ÿ™… disables -Walloc-size-larger-than= warnings. This option is equivalent to -Walloc-size-larger-than=SIZE_MAX or larger.
  • -Walloca โ€” ๐Ÿ” warns on all uses of alloca in the source. No exceptions, no cap ๐Ÿงข.
  • -Walloca-larger-than=byte-size โ€” ๐Ÿช„ warns on calls to alloca with an integer argument whose value is either zero, or that isn't bounded by a controlling predicate limiting it to at most byte-size. It also warns for calls to alloca where the bound value is unknown. Arguments of non-integer types are treated as unbounded, even if they look like they're constrained to the expected range.

Here's a bounded use of alloca:

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

In this example, passing -Walloca-larger-than=1000 won't issue a warning, because the call to alloca is known to be at most 1000 bytes. But if -Walloca-larger-than=500 were passed, the compiler would emit a warning ๐Ÿ˜ค.

Unbounded uses are the ones where alloca has 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 code above would trigger a warning, this time because there's no bounds checking at all ๐Ÿ™ˆ.

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

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

In this example, n could be negative, which would cause a larger than expected argument to be implicitly cast into the alloca call. Rude ๐Ÿ˜ญ.

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

-Walloca-larger-than=PTRDIFF_MAX is enabled by default, but it's usually only effective when -ftree-vrp is active (the default for -O2 and above) ๐ŸŒˆ.

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

  • -Wno-alloca-larger-than โ€” ๐Ÿซ  disables -Walloca-larger-than= warnings. This option is 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 ๐Ÿ’….

- -Warray-bounds=1 โ€” okay bestie, this is the default level of -Warray-bounds, and it's already switched on by -Wall โœจ Higher levels are NOT on by default, so you have to ask for them explicitly ๐Ÿ’…

  • -Warray-bounds=2 โ€” this stricter level also catches out of bounds accesses to trailing struct members of one-element array types, plus intermediate results of pointer arithmetic that might land out of bounds ๐Ÿ‘€ It can throw a bigger pile of false positives, so it's deactivated by default ๐Ÿ™ˆ
  • -Warray-compare โ€” warns about equality and relational comparisons between two operands of array type ๐ŸŽ€ This comparison got deprecated in C++20, so be careful, babe ๐Ÿ’€ Here's the vibe:
int arr1[5];
int arr2[5];
bool same = arr1 == arr2;

-Warray-compare is enabled by -Wall ๐Ÿ’–

  • -Warray-parameter, -Warray-parameter=n โ€” this one warns about redeclarations of functions where the array or pointer arguments are inconsistent in kind or form ๐Ÿฆ‹ It also turns on detection of out-of-bounds accesses to those parameters, caught by warnings like -Warray-bounds ๐Ÿ”ฅ

If the first function declaration uses the array form, the bound in the array is treated as the minimum number of elements you must pass in, and the maximum number of elements the function touches. So passing too-small arrays or accessing more than that max might get flagged by warnings like -Warray-bounds ๐Ÿซถ At level 1, the warning catches inconsistencies involving array parameters declared with the "T[static N]" form ๐ŸŒธ

Here's why the warning fires in this example: the first declaration lets an array of any size get passed to f, but the second one uses the keyword static to demand at least four elements ๐Ÿ˜ญ

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

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

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

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

-Warray-parameter=2 is included in -Wall โœจ And the -Wvla-parameter option does the same kind of thing, but for Variable Length Array arguments ๐ŸŒˆ

  • -Wattribute-alias=n, -Wno-attribute-alias โ€” warns about declarations using the "alias" and similar attributes whose target doesn't match the type of the alias ๐Ÿ“
    • -Wattribute-alias=1 โ€” this is the default level, and it diagnoses type incompatibilities between the alias declaration and its target ๐Ÿ’œ These are usually signs of bugs, so don't ignore them, bestie ๐Ÿ˜ค
    • -Wattribute-alias=2 โ€” at this level, it also diagnoses cases where the alias declaration's attributes are more restrictive than the ones on its target ๐Ÿ™ˆ These mismatches can lead to incorrect code generation ๐Ÿ’€ Sometimes they're harmless and you can fix them just by adding the missing attribute to the target. For comparison, check out -Wmissing-attributes, which covers the opposite situation, where the alias is less restrictive than the target ๐Ÿฆ‹

Attributes considered here include "alloc_align", "alloc_size", "cold", "const", "hot", "leaf", "malloc", "nonnull", "noreturn", "nothrow", "pure", "returns_nonnull", and "returns_twice" ๐ŸŽ€

-Wattribute-alias is the same as -Wattribute-alias=1, and that's the default ๐Ÿ’… You can turn these warnings off with either -Wno-attribute-alias or -Wattribute-alias=0 ๐Ÿซถ

  • -Wbidi-chars=[none|unpaired|any|ucn] โ€” warns about possibly misleading UTF-8 bidirectional control characters in comments, string literals, character constants, and identifiers ๐ŸŒˆ These can flip the writing direction from left-to-right to right-to-left (and back), which causes confusion between logical order and visual order ๐Ÿ˜ต This can be seriously dangerous, because it might look like a chunk of code is commented out when it actually isn't ๐Ÿ’€

GCC has three warning levels. 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 skips UCNs ๐Ÿ™ˆ If you want that checking too, use -Wbidi-chars=unpaired,ucn or -Wbidi-chars=any,ucn. Using -Wbidi-chars=ucn is valid and works the same as -Wbidi-chars=unpaired,ucn, as long as no earlier -Wbidi-chars=any was specified ๐Ÿงš

  • -Wbool-compare โ€” warns when a boolean expression gets compared with an integer value that's different from "true"/"false" ๐Ÿ“ For example, this comparison is always false, so it's a mess:
int n = 5;
...
if ((n > 1) == 2) { ... }

This warning is enabled by -Wall โœจ

  • -Wbool-operation โ€” warns about sus operations on expressions of boolean type ๐Ÿคจ For instance, bitwise negation of a boolean is very likely a bug ๐Ÿ’€ In C, this also warns about incrementing or decrementing a boolean, which almost never makes sense ๐Ÿ™…โ€โ™€๏ธ (In C++, decrementing a boolean is always invalid. Incrementing a boolean is invalid in C++17 and deprecated otherwise.)

This warning is enabled by -Wall ๐Ÿ’–

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

It won't warn when both branches contain just a null statement ๐Ÿซถ It also covers conditional operators:

int i = x ? *p : *p;
  • -Wduplicated-cond โ€” warns about duplicated conditions in an if-else-if chain ๐Ÿ™„ For example, it'll warn about this one:
if (p->q != NULL) { ... }
else if (p->q != NULL) { ... }
  • -Wframe-address โ€” warns when __builtin_frame_address or __builtin_return_address gets called with an argument greater than 0 ๐Ÿ˜ฑ These calls might return indeterminate values or crash the program ๐Ÿ’€ This warning is included in -Wall โœจ
  • -Wno-discarded-qualifiers (C and Objective-C only) โ€” stops the warning about type qualifiers on pointers being discarded ๐ŸŒธ Normally, the compiler warns if a "const char *" variable gets passed to a function that takes a "char *" parameter. This option shuts that down ๐Ÿ™ˆ
  • -Wno-discarded-array-qualifiers (C and Objective-C only) โ€” same deal, but for type qualifiers on arrays that are pointer targets ๐Ÿ“ Normally, the compiler warns if a "const int (*)[]" variable gets passed to a function taking a "int (*)[]" parameter. This option silences that warning ๐Ÿงš
  • -Wno-incompatible-pointer-types (C and Objective-C only) โ€” skips the warning when there's a conversion between pointers with incompatible types ๐Ÿฆ‹ This is for cases that -Wno-pointer-sign doesn't cover, since that one handles pointer argument passing or assignment with different signedness ๐Ÿ’…
  • -Wno-int-conversion (C and Objective-C only) โ€” no warnings about incompatible integer-to-pointer and pointer-to-integer conversions ๐Ÿ’œ This one is about implicit conversions. For explicit ones, you can use -Wno-int-to-pointer-cast and -Wno-pointer-to-int-cast ๐Ÿซถ
  • -Wzero-length-bounds โ€” warns about accesses to elements of zero-length array members that might overlap other members of the same object ๐ŸŒˆ Declaring interior zero-length arrays is discouraged, because accessing them is undefined ๐Ÿ˜ญ See

In the example below, the first two stores in function bad get flagged, because those array elements overlap the members b and c ๐Ÿ‘€ The third store is caught by -Warray-bounds because it's past the end 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
}

-Wzero-length-bounds is enabled by -Warray-bounds โœจ

  • -Wno-div-by-zero โ€” no warnings about compile-time integer division by zero ๐Ÿ™…โ€โ™€๏ธ Floating-point division by zero doesn't get warned about either, since it can be a legit way to get infinities and NaNs ๐ŸŒธ
  • -Wsystem-headers โ€” prints warning messages for constructs found in system header files ๐Ÿ”ฅ Warnings from system headers are normally hidden, on the assumption that they usually aren't real problems and would just make the compiler output harder to read ๐Ÿ˜ค This flag tells GCC to show warnings from system headers as if they came from user code ๐Ÿ’… Heads up, though: using -Wall with this option still won't warn about unknown pragmas in system headers. For that, -Wunknown-pragmas must also be used ๐Ÿซถ
  • -Wtautological-compare โ€” warns if a self-comparison always evaluates to true or false ๐Ÿง  This catches mistakes like:
int i = 1;
...
if (i > i) { ... }

It also warns about bitwise comparisons that always evaluate to true or false, like this one:

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

That will always be false, so it's a no-go ๐Ÿ’€ This warning is enabled by -Wall ๐Ÿ’–

  • -Wtrampolines โ€” okay bestie, this one is a heads-up about trampolines ๐Ÿคธ that get 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. For some targets it's only data, so no special treatment is needed โœจ. For most targets, though, it's code, which means the stack has to be made executable for the program to work properly ๐Ÿ’€.
Heads up, bestie: on most targets the stack has to be made executable, so don't sleep on this warning ๐Ÿ™ˆ
  • -Wfloat-equal โ€” warns if floating-point values are used in equality comparisons ๐Ÿงฎ

The vibe here is that sometimes it's convenient for you as the programmer to treat floating-point values as approximations to infinitely precise real numbers. If that's your move, you need to figure out (by analyzing the code, or some other way) the maximum or likely maximum error the computation introduces, and allow for it when doing comparisons (and when producing output, but that's a different problem ๐Ÿ’…).

In particular, instead of testing for equality, you should check whether the two values have ranges that overlap. That's done with the relational operators, so equality comparisons are probably mistaken ๐Ÿ™…

  • -Wtraditional (C and Objective-C only) โ€” warns about certain constructs that behave differently in traditional C and ISO C. It also warns about ISO C constructs that have no traditional C equivalent, and/or problematic constructs you should avoid ๐Ÿง
    • Macro parameters that show up inside string literals in the macro body. In traditional C, macro replacement happens inside string literals, but in ISO C it doesn't ๐Ÿ™ƒ
    • In traditional C, some preprocessor directives didn't exist. Traditional preprocessors only treated a line as a directive if the # 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 you hide directives like "#pragma" that traditional C doesn't understand by indenting them. Some traditional implementations don't recognize "#elif", so this option suggests avoiding it altogether.
    • A function-like macro that appears without arguments.
    • The unary plus operator.
    • The U integer constant suffix, or the F or L floating-point constant suffixes. (Traditional C does support the L suffix on integer constants.) Note, these suffixes appear in macros defined in the system headers of most modern systems, e.g. the _MIN/_MAX macros in "<limits.h>". Use of these macros in user code might normally lead to spurious warnings, however 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 has an operand of type "long".
    • A non-"static" function declaration follows a "static" one. This construct is not accepted by some traditional C compilers.
    • 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. I.e. hexadecimal or octal values, which typically represent bit patterns, are not warned about.
    • Usage of ISO string concatenation is detected.
    • Initialization of automatic aggregates.
    • Identifier conflicts with labels. Traditional C lacks a separate namespace for labels.
    • Initialization of unions. If the initializer is zero, the warning is omitted. This is done under the assumption that the zero initializer in user code appears conditioned on e.g. "__STDC__" to avoid missing initializer warnings and relies on default initialization to zero in the traditional C case.
    • Conversions by prototypes between fixed/floating-point values and vice versa. The absence of these prototypes when compiling with traditional C causes serious problems. This is a subset of the possible conversion warnings; for the full set use -Wtraditional-conversion.
    • Use of ISO C style function definitions. This warning intentionally is not issued for prototype declarations or variadic functions, because these ISO C features appear in your code when using libiberty's traditional C compatibility macros, "PARAMS" and "VPARAMS". This warning is also bypassed for nested functions, because that feature is already a GCC extension and thus not relevant to traditional C compatibility.

  • -Wtraditional-conversion (C and Objective-C only) โ€” warns if a prototype causes a type conversion that's different from what would happen to the same argument without a prototype ๐Ÿ”„. This includes conversions of fixed point to floating and vice versa, and conversions changing the width or signedness of a fixed-point argument, except when it's the same as the default promotion.
  • -Wdeclaration-after-statement (C and Objective-C only) โ€” warns when a declaration is found after a statement in a block ๐Ÿ“. This construct is known from C++, was introduced with ISO C99, and is allowed by default in GCC. It is not supported by ISO C90.
  • -Wshadow โ€” warns whenever a local variable or type declaration shadows another variable, parameter, type, class member (in C++), or instance variable (in Objective-C), or whenever a built-in function is shadowed ๐Ÿ‘€. Note that 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. This means that -Wno-shadow=local and -Wno-shadow=compatible-local are ignored when -Wshadow is used. Same as -Wshadow=global.
  • -Wno-shadow-ivar (Objective-C only) โ€” no warnings 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 type of the shadowing variable can be converted to that of the shadowed variable. This flag (in addition to -Wshadow=local) exists because when a local variable shadows another one of incompatible type, it's most likely intentional, not a bug or typo, as shown in the following example:
for (SomeIterator i = SomeObj.begin(); i != SomeObj.end(); ++i)
{
  for (int i = 0; i < N; ++i)
  {
    ...
  }
  ...
}

Since the two variable "i" in the example above have incompatible types, enabling only -Wshadow=compatible-local does not emit a warning. 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 that shadowing "const char *i" by "char *i" does not emit a warning.

This warning is also enabled by -Wshadow=local.


  • -Wlarger-than=byte-size โ€” warns whenever an object is defined whose size 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. The option is equivalent to -Wlarger-than=SIZE_MAX or larger ๐Ÿšซ
  • -Wframe-larger-than=byte-size โ€” warns if the size of a function frame exceeds byte-size ๐Ÿ–ผ๏ธ. The computation done to determine the stack frame size is approximate and not conservative, so the actual requirements may be somewhat greater than byte-size even if you don't get a warning. Also, any space allocated via "alloca", variable-length arrays, or related constructs is not included by the compiler when deciding whether to issue a warning. -Wframe-larger-than=PTRDIFF_MAX is enabled by default. Warnings controlled by this option can be disabled either by specifying a byte-size of SIZE_MAX or more, or by -Wno-frame-larger-than.
  • -Wno-frame-larger-than โ€” disables -Wframe-larger-than= warnings. The option is equivalent to -Wframe-larger-than=SIZE_MAX or larger ๐Ÿšซ
  • -Wfree-nonheap-object โ€” warns when you try to deallocate an object that was either not allocated on the heap, or that was reached through a pointer not returned from a prior call to the matching allocation function ๐Ÿšจ. For example, because the call to "stpcpy" returns a pointer to the terminating nul character and not to the beginning of the object, the call to "free" below gets diagnosed:
void f (char *p)
{
  p = stpcpy (p, "abc");
  // ...
  free (p);   // warning
}

-Wfree-nonheap-object is included in -Wall.

  • -Wstack-usage=byte-size โ€” warns if the stack usage of a function might exceed byte-size ๐Ÿฅž. The computation done to determine stack usage is conservative. Any space allocated via "alloca", variable-length arrays, or related constructs is included by the compiler when deciding whether to issue a warning.

The message matches the output of -fstack-usage.

If the stack usage is fully static but exceeds the specified amount, it looks like this:

warning: stack usage is 1120 bytes

If the stack usage is (partly) dynamic but bounded, it looks like this:

warning: stack usage might be 1648 bytes
  • If the stack usage is (partly) dynamic and not bounded, it's:
warning: stack usage might be unbounded

okay so -Wstack-usage=PTRDIFF_MAX is on by default, bestie ๐Ÿ’… You can silence these warnings by setting a byte-size of SIZE_MAX or more, or just use -Wno-stack-usage ๐Ÿ™ˆ

  • -Wno-stack-usage โ€” No more -Wstack-usage= warnings ๐Ÿ™ˆ It's the same as -Wstack-usage=SIZE_MAX or larger, so GCC gets to chill.
  • -Wunsafe-loop-optimizations โ€” Warns if a loop can't be optimized ๐Ÿ”ฅ That happens when the compiler can't assume anything about the bounds of the loop indices. Add -funsafe-loop-optimizations and it'll warn you whenever the compiler makes those assumptions instead ๐Ÿ‘€
  • -Wno-pedantic-ms-format (MinGW targets only) โ€” When you use it with -Wformat and -pedantic (without GNU extensions), it turns off the warnings about non-ISO printf and scanf width specifiers I32, I64, and I on Windows targets. Those depend on the MS runtime, so this one's a lifesaver ๐Ÿ’–
  • -Wpointer-arith โ€” Warns about anything that depends on the "size of" a function type or of void ๐Ÿฆ‹ GNU C gives those types a size of 1, which is super handy for math with void * pointers and pointers to functions. In C++, it also warns when an arithmetic operation involves NULL. This one's also turned on by -Wpedantic โœจ
  • -Wno-pointer-compare โ€” Don't warn when a pointer gets compared with a zero character constant. That usually means the pointer was supposed to be dereferenced ๐Ÿ‘€ Check out this example:
const char *p = foo ();
if (p == '\0')
  return 42;
The code above is invalid in C++11, so be careful ๐Ÿ˜ญ

This warning is enabled by default.

  • -Wtsan โ€” Warns about unsupported features in ThreadSanitizer ๐Ÿงš ThreadSanitizer doesn't support std::atomic_thread_fence, and it can report false positives.

This warning is enabled by default.

  • -Wtype-limits โ€” Warns if a comparison is always true or always false because of the limited range of the data type ๐Ÿ’… Constant expressions don't get flagged, though. For example, it'll warn if an unsigned variable gets compared against zero with < or >=. This one's also turned on by -Wextra ๐ŸŒˆ
  • -Wabsolute-value (C and Objective-C only) โ€” Warns when you call a standard absolute-value function and there's a better one available ๐Ÿซถ For example, abs(3.14) triggers it, because a double argument should go to fabs. It also warns when the argument to one of those calls has an unsigned type. You can shut it up 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 about trigraphs that might change what your program means โœจ Trigraphs inside comments don't get flagged, except the ones that would form escaped newlines. This option is implied by -Wall. If you don't pass -Wall, it's still on unless trigraphs are enabled. Want trigraph conversion without the warnings but still all the other -Wall warnings? Use -trigraphs -Wall -Wno-trigraphs ๐ŸŽ€
  • -Wundef โ€” Warns if an undefined identifier gets evaluated in an #if directive ๐ŸŒธ Those identifiers get replaced with zero.
  • -Wexpansion-to-defined โ€” Warns whenever defined shows up in the expansion of a macro, including when the macro gets expanded by an #if directive ๐Ÿ™ˆ That kind of usage isn't portable. This warning is also enabled by -Wpedantic and -Wextra.
  • -Wunused-macros โ€” Warns about macros defined in the main file that are never used ๐Ÿ“ A macro counts as used if it gets expanded or tested for existence at least once. The preprocessor also warns if the macro hasn't been used by the time it gets redefined or undefined.

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

Note: If a macro is used, but only inside skipped conditional blocks, the preprocessor still reports it as unused ๐Ÿ˜ญ To dodge the warning, you could improve the scope of the macro's definition, for example by moving it into the first skipped block. Or you could give it a dummy use, something like:

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

The second and third FOO should be in comments. This warning is on by default.

  • -Wbad-function-cast (C and Objective-C only) โ€” Warns when a function call gets cast to a non-matching type ๐Ÿฆ‹ For example, it warns if a call to a function that returns an integer type gets cast to a pointer type.
  • -Wc90-c99-compat (C and Objective-C only) โ€” Warns about features that exist in ISO C99 but not in ISO C90 ๐ŸŒˆ Think variable length arrays, the long long type, the bool type, compound literals, designated initializers, and so on. This option doesn't depend on the standards mode. Warnings are turned off in the expression that follows __extension__.
  • -Wc99-c11-compat (C and Objective-C only) โ€” Warns about features that exist in ISO C11 but not in ISO C99 โœจ That includes 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 either. Warnings are turned off in the expression that follows __extension__.
  • -Wc11-c2x-compat (C and Objective-C only) โ€” Warns about features that exist in ISO C2X but not in ISO C11 ๐Ÿงš That includes leaving out the string in _Static_assert, using [[]] attribute syntax, using decimal floating-point types, and so on. Once again, this option doesn't depend on the standards mode, and warnings are turned off in the expression that follows __extension__.
  • -Wc++-compat (C and Objective-C only) โ€” Warns about ISO C constructs that sit outside the common subset of ISO C and ISO C++ ๐Ÿซถ For example, it'll flag 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 diagnosed 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 diagnosed 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 diagnosed if you use -Wpedantic.
  • -Wno-c++20-extensions (C++ and Objective-C++ only) โ€” Don't warn about C++20 constructs when you're compiling with an older C++ standard ๐Ÿฆ‹ Even without this option, some C++20 constructs only get diagnosed if you use -Wpedantic.
  • -Wno-c++23-extensions (C++ and Objective-C++ only) โ€” Don't warn about C++23 constructs when you're compiling with an older C++ standard โœจ Even without this option, some C++23 constructs only get diagnosed if you use -Wpedantic.

  • -Wcast-qual โ€” Warns whenever a pointer gets cast in a way that removes a type qualifier from the target type ๐Ÿ’– For example, it warns if a const char * gets cast to an ordinary char *.

It also warns when a cast introduces a type qualifier in an unsafe way. Casting char ** to const char ** is unsafe, as in this example:

/* p is char ** value.  */
const char **q = (const char **) p;
/* Assignment of readonly string to const char * is OK.  */
*q = "string";
/* Now char** pointer points to read-only memory.  */
**p = 'b';
  • -Wcast-align โ€” Warns whenever a pointer gets cast so the required alignment of the target goes up ๐Ÿงš For example, it warns if a char * gets cast to an int * on machines where integers can only be accessed at two- or four-byte boundaries.
  • -Wcast-align=strict โ€” Same idea as -Wcast-align, but stricter ๐Ÿ’… It warns whenever a pointer gets cast so the required alignment of the target goes up, no matter what the target machine is. For example, it warns if a char * gets cast to an int * regardless of the target machine.
  • -Wcast-function-type โ€” Warns when a function pointer gets cast to an incompatible function pointer ๐Ÿ”ฅ When it comes to function types with a variable argument list, only the types of the initial arguments that are actually provided get considered. Any parameter of pointer-type matches any other pointer-type. Harmless differences in integral types are ignored, like int vs. long on ILP32 targets, and type qualifiers are ignored too. The function type void (*) (void) is special and matches everything, so you can use it to suppress this warning ๐Ÿ™ˆ For pointer to member types, this warning fires whenever the cast changes the pointer to member type. This warning is enabled by -Wextra ๐ŸŒธ
  • -Wwrite-strings โ€” okay bestie, when you're compiling C, this gives string constants the type const char[length], so copying one into a non-const char * pointer gets you a warning ๐Ÿซถ These are super helpful for catching code that might try to write into a string constant at compile time, but only if you've been really careful with const in your declarations and prototypes. Otherwise they're just a nuisance ๐Ÿ’€ which is exactly why -Wall doesn't ask for them ๐Ÿ™ˆ

When you're compiling C++, it warns about the deprecated conversion from string literals to char *, and this one is switched on by default for C++ programs โœจ

  • -Wclobbered โ€” warns about variables that longjmp or vfork might change behind your back ๐Ÿ‘€ It's also turned on by -Wextra.
  • -Wconversion โ€” warns about implicit conversions that might mess with a value ๐Ÿ”ฅ That includes real โ†” integer swaps, like abs (x) when x is double; signed โ†” unsigned swaps, like unsigned ui = -1; and squishing into smaller types, like sqrtf (M_PI). It won't nag you about explicit casts like abs ((int) x) or ui = (unsigned) -1, or about conversions that don't actually change the value, like abs (2.0). If the signed/unsigned stuff is too much, you can silence it with -Wno-sign-conversion ๐Ÿ’…

For C++, it also warns about confusing overload resolution for user-defined conversions, plus conversions that never use a type conversion operator: conversions to void, to the same type, to a base class, or to a reference to any of those. In C++, the signed/unsigned warnings are off by default unless you explicitly turn on -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 code where it's unclear which if an else belongs to ๐Ÿ™ƒ Here's a sneaky example:
{
  if (a)
    if (b)
      foo ();
  else
    bar ();
}

In C and C++, every else attaches to the innermost possible if, which here is if (b). That's often not what you meant, especially when your indentation says otherwise ๐Ÿ˜ญ When this confusion is possible, GCC warns you if this flag is on. To kill the warning, wrap the innermost if in explicit braces so the else can't possibly belong to the outer one โœจ Like this:

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

This warning is enabled by -Wparentheses ๐ŸŽ€

  • -Wdangling-pointer, -Wdangling-pointer=n โ€” okay this one is lowkey iconic ๐Ÿ’– It warns about using pointers (or C++ references) to objects with automatic storage duration after their lifetime has already ended. That covers locals declared in nested blocks, compound literals, and other unnamed temporary objects. It also warns about stashing the address of those objects in escaped pointers ๐Ÿซฃ It's on at every optimization level, but the results might look different with optimization than without.
    • -Wdangling-pointer=1 โ€” at level 1, you only get warnings for unconditional uses of dangling pointers ๐Ÿ“ For example:
int f (int c1, int c2, x)
{
  char *p = strchr ((char[]){ c1, c2 }, c3);
  return p ? *p : 'x';   // warning: dangling pointer to a compound literal
}

In the next function, storing the address of the local variable x into the escaped pointer *p also triggers the warning ๐Ÿ‘‘

void g (int **p)
{
  int x = 7;
  *p = &x;   // warning: storing the address of a local variable in *p
}
  • -Wdangling-pointer=2 โ€” level 2 does everything level 1 does, plus conditional uses of dangling pointers ๐Ÿงš In this function, the array a is out of scope by the time the pointer s gets used, so this level catches it:
void f (char *s)
{
  if (!s)
    {
      char a[12] = "tmpname";
      s = a;
    }
  strcat (s, ".tmp");   // warning: dangling pointer to a may be used
  ...
}
-Wdangling-pointer=2 is already included in -Wall, so you get it for free ๐Ÿ’…
  • -Wdate-time โ€” warns whenever the __TIME__, __DATE__ or __TIMESTAMP__ macros show up, since they can stop your builds from being bit-wise identical and reproducible โฐ
  • -Wempty-body โ€” warns if there's an empty body in an if, else or do while statement ๐Ÿซฅ It's also enabled by -Wextra.
  • -Wno-endif-labels โ€” don't warn about stray tokens after #else and #endif ๐ŸŒˆ
  • -Wenum-compare โ€” warns about comparing values from different enumerated types ๐Ÿ” In C++, enum mismatches in conditional expressions are also flagged, and this one is on by default there. In C, it's turned on by -Wall.
  • -Wenum-conversion โ€” warns when a value of one enumerated type gets implicitly converted into a different enumerated type ๐Ÿ’œ In C, it's enabled by -Wextra.
  • -Wjump-misses-init (C, Objective-C only) โ€” warns if a goto or switch statement jumps forward across the initialization of a variable, or jumps backward to a label that comes after the variable was already initialized ๐Ÿš€ It only cares about variables that get initialized right when they're declared. This warning is only supported for C and Objective-C, because in C++ this kind of jump is already an error anyway ๐Ÿ™…โ€โ™€๏ธ

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

  • -Wsign-compare โ€” warns when comparing signed and unsigned values could give you a wrong answer, because the signed value gets converted to unsigned first ๐Ÿ˜ฌ In C++, it's also enabled by -Wall. In C, it's enabled by -Wextra.
  • -Wsign-conversion โ€” warns about implicit conversions that might change the sign of an integer value, like assigning a signed integer expression to an unsigned integer variable ๐Ÿ”„ An explicit cast will shut it up. In C, this option is also turned on by -Wconversion.
  • -Wfloat-conversion โ€” warns about implicit conversions that lose precision in a real value โœ‚๏ธ That includes real-to-integer conversions, and conversions from a higher-precision real to a lower-precision one. This option is also turned on by -Wconversion.
  • -Wno-scalar-storage-order โ€” don't warn about suspicious constructs involving reverse scalar storage order ๐Ÿคทโ€โ™€๏ธ
  • -Wsizeof-array-div โ€” warns about dividing two sizeof operators when the first one is applied to an array and the divisor isn't the size of an array element ๐Ÿงฎ In that case, the math won't give you the number of elements in the array, which is probably not what you wanted. This warning catches stuff like this:
int fn ()
{
  int arr[10];
  return sizeof (arr) / sizeof (short);
}

This warning is enabled by -Wall โœจ

  • -Wsizeof-pointer-div โ€” warns about suspicious divisions of two sizeof expressions that divide the pointer size by the element size ๐Ÿ™ˆ That's the usual trick for computing an array's size, but it won't work correctly with pointers. For example, it warns about sizeof (ptr) / sizeof (ptr[0]) if ptr is a pointer and not an array. This warning is enabled by -Wall ๐Ÿ’–
  • -Wsizeof-pointer-memaccess โ€” warns about suspicious length parameters passed to certain string and memory built-in functions when the argument uses sizeof ๐Ÿง It triggers for things like memset (ptr, 0, sizeof (ptr)); when ptr is a pointer and not an array, and it even suggests a possible fix. It also triggers for stuff like memcpy (&foo, ptr, sizeof (&foo));.

-Wsizeof-pointer-memaccess also warns about calls to bounded string copy functions like strncat or strncpy that use the sizeof of the source array as the bound. In this function, the strncat call uses the size of the source string as its bound, which is almost certainly a mistake, so it gets flagged:

void make_file (const char *name)
{
  char path[PATH_MAX];
  strncpy (path, name, sizeof path - 1);
  strncat (path, ".text", sizeof ".text");
  ...
}

The -Wsizeof-pointer-memaccess option is enabled by -Wall ๐Ÿ”ฅ

  • -Wno-sizeof-array-argument โ€” don't warn when sizeof is applied to a parameter that's declared as an array in a function definition ๐Ÿซถ This warning is enabled by default for C and C++ programs.
  • -Wmemset-elt-size โ€” warns about suspicious calls to the memset built-in function ๐Ÿง  It fires when the first argument references an array, and the third argument is a number equal to the number of elements, but not equal to the size of the array in memory. That usually means you forgot to multiply by the element size. This warning is enabled by -Wall.
  • -Wmemset-transposed-args โ€” warns about suspicious memset calls where the second argument isn't zero and the third argument is zero ๐Ÿ”€ For example, memset (buf, sizeof buf, 0) gets 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 much less likely to have been swapped by mistake, so no warning is emitted. This warning is enabled by -Wall ๐ŸŒธ
  • -Waddress โ€” warns about suspicious uses of address expressions ๐Ÿ‘€ These include comparing the address of a function or a declared object against the null pointer constant, such as in

Okay so the rest of -Waddress is giving sneaky ๐Ÿซฃ Checking whether a function is "there" in a condition gets flagged, bestie:

void f (void);
void g (void)
{
  if (!func)   // warning: expression evaluates to false
    abort ();
}

Comparing a pointer to a string literal gets flagged too ๐Ÿ™ˆ

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

And testing the result of pointer addition or subtraction against null for equality is flagged as well:

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

Honestly these almost always mean a programmer error ๐Ÿ’€ The address of most functions and objects is basically always true (except weak symbols ๐Ÿฆ‹), so putting one in a condition might mean you forgot parentheses in a function call, or you're missing a dereference in an array expression.

The object-pointer part of the warning can be silenced by casting the pointer operand to an integer type like inptr_t or uinptr_t. String literal comparisons give unspecified behavior and aren't portable, and they're a hint you meant to call strcmp. The warning also gets suppressed if the sus expression came from macro expansion. -Waddress is enabled by -Wall โœจ

  • -Wno-address-of-packed-member โ€” don't warn when you take the address of a packed member of a struct or union, since that usually gives you an unaligned pointer value ๐ŸŽ€ This one is on by default.
  • -Wlogical-op โ€” warns about suspicious logical operators in expressions, especially when a bitwise operator is 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 on the left side of a comparison ๐Ÿง It won't warn if the right operand is a boolean expression. It's there to catch stuff like this:
int a;
...
if (!a > 1) { ... }

You can shut it up by wrapping the LHS in parentheses:

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

This warning is enabled by -Wall.

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

Also, using -Wno-attributes= lets you suppress warnings about unknown scoped attributes (in C++11 and C2X) โœจ For example, -Wno-attributes=vendor::attr disables the warning for this declaration:

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

You can disable warnings about all attributes in a namespace with -Wno-attributes=vendor::, which stops warnings for both of these:

[[vendor::safe]] void f();
[[vendor::unsafe]] void f2();

Note that -Wno-attributes= does not imply -Wno-attributes.

  • -Wno-builtin-declaration-mismatch โ€” warns if a built-in function is declared with an incompatible signature or as a non-function, or when a built-in function declared with a type that has no prototype is called with arguments whose promoted types don't match what it expects ๐Ÿ”ฅ With -Wextra, it also warns when a built-in function that takes arguments is declared without a prototype. The -Wbuiltin-declaration-mismatch warning is enabled by default. To avoid it, include the right header to bring the built-in prototypes into scope.

For example, the memset call below gets diagnosed because the function expects a size_t argument but 32 is an int. With -Wextra, the declaration itself gets diagnosed too:

extern void* memset ();
void f (void *d)
{
  memset (d, '\0', 32);
}
  • -Wno-builtin-macro-redefined โ€” don't warn if certain built-in macros get redefined. This suppresses warnings for redefinitions of __TIMESTAMP__, __TIME__, __DATE__, __FILE__, and __BASE_FILE__ ๐Ÿ•ฐ๏ธ
  • -Wstrict-prototypes (C and Objective-C only) โ€” warns if a function is declared or defined without specifying its argument types. (An old-style function definition is allowed without a warning if it's preceded by a declaration that specifies the argument types.)
  • -Wold-style-declaration (C and Objective-C only) โ€” warns about obsolescent usages in a declaration, according to the C Standard ๐Ÿ™„ For example, it warns if storage-class specifiers like static aren't the first things in a declaration. This warning is also enabled by -Wextra.
  • -Wold-style-definition (C and Objective-C only) โ€” warns if an old-style function definition is used, even if there's a previous prototype. A definition using () is not considered old-style in C2X mode, because it's equivalent to (void) there, but it is considered old-style for older standards.
  • -Wmissing-parameter-type (C and Objective-C only) โ€” warns when a function parameter is declared without a type specifier in K&R-style functions:
void foo(bar) { }

This warning is also enabled by -Wextra.

  • -Wmissing-prototypes (C and Objective-C only) โ€” warns if a global function is defined without a previous prototype declaration. It warns even if the definition itself provides a prototype ๐Ÿ‘€ Use this 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 declares an overload rather than conflicting with an earlier one. For missing declarations in C++, use -Wmissing-declarations.
  • -Wmissing-declarations โ€” warns if a global function is defined without a previous declaration, even if the definition itself provides a prototype. Use this to find global functions that aren't declared in header files. In C, no warnings are issued for functions with previous non-prototype declarations, so use -Wmissing-prototypes for those. In C++, no warnings are issued for function templates, inline functions, or functions in anonymous namespaces ๐ŸŒธ
  • -Wmissing-field-initializers โ€” warns if a struct's initializer is missing some fields. This code causes the warning, because x.h is implicitly zero:
struct s { int f, g, h; };
struct s x = { 3, 4 };

This option doesn't warn about designated initializers, so this change won't trigger it:

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

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

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

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

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

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

so satisfied is only true if concept C is satisfied for type T.

This warning can be disabled with -Wno-missing-requires.

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

In rare cases you can get false positives. To silence them, wrap the expression in parentheses. For example, the following is treated as a template, even where m and N are integers:

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

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

This warning can be disabled with -Wno-missing-template-keyword.

  • -Wno-multichar โ€” don't warn if a multicharacter constant ('FOOF') is used. These usually mean a typo in your code, since they have implementation-defined values and shouldn't be used in portable code ๐Ÿซ 
  • -Wnormalized=[none|id|nfc|nfkc] โ€” in ISO C and ISO C++, two identifiers are different if they're different sequences of characters. But when non-ASCII characters are involved, you can get two different sequences that look exactly the same ๐Ÿ˜ต To avoid that confusion, the ISO 10646 standard defines normalization rules that turn look-alike sequences into the same sequence. GCC can warn you if you use identifiers that haven't been normalized, and this option controls that warning.

Okay so bestie, GCC has FOUR levels of normalization warnings ๐Ÿ’… The default is -Wnormalized=nfc, which yells at you about any identifier that isn't in the ISO 10646 "C" normalized form, NFC ๐Ÿซถ NFC is the recommended vibe for most uses, and -Wnormalized means the exact same thing.

Unfortunately โœจ some characters that ISO C and ISO C++ let you use in identifiers stop being allowed once they get turned into NFC ๐Ÿ˜ญ So there's literally no way to write portable ISO C or C++ and keep every identifier in NFC. -Wnormalized=id silences the warning for just those characters ๐Ÿฆ‹ The standards folks are hoping future versions fix this, which is why it isn't the default.

You can switch the warning off for every character with -Wnormalized=none or -Wno-normalized. Only do this if you're using some other normalization scheme (like "D") ๐Ÿ’€ Otherwise you can super easily create bugs that are literally impossible to see.

Some ISO 10646 characters mean totally different things but look identical in some fonts or display setups, especially once formatting gets applied ๐Ÿ‘€ Like "\u207F", which is "SUPERSCRIPT LATIN SMALL LETTER N", and it looks exactly like a regular n that got bumped into a superscript. ISO 10646 also defines the NFKC normalization scheme to turn all of these into one standard form, and GCC will warn if your code isn't NFKC when you use -Wnormalized=nfkc ๐Ÿ”ฅ This is kind of like warning about every identifier with the letter O in it because it might get mixed up with the digit 0 ๐Ÿ™ˆ So it's not the default, but it can be a useful local coding convention if your programming environment can't be fixed to display these characters differently.

  • -Wno-attribute-warning โš ๏ธ โ€” Don't warn about using functions declared with the "warning" attribute. This warning is on by default. You can use -Wno-attribute-warning to turn the warning off, or -Wno-error=attribute-warning to turn off the error when you're compiling with the -Werror flag ๐ŸŽ€
  • -Wno-deprecated ๐Ÿ™…โ€โ™€๏ธ โ€” Don't warn about using 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 ๐Ÿง โ€” Warn about One Definition Rule violations during link-time optimization. This is enabled by default. ngl the name starts with -Wno- but this one actually WARNS, so read it carefully bestie ๐Ÿ’…
  • -Wopenacc-parallelism ๐Ÿงš โ€” Warn about potentially suboptimal choices related to OpenACC parallelism.
  • -Wopenmp-simd โœจ โ€” Warn if the vectorizer cost model overrides the OpenMP simd directive that the user set. You can use -fsimd-cost-model=unlimited to relax the cost model.
  • -Woverride-init (C and Objective-C only) ๐Ÿ“ โ€” Warn if an initialized field without side effects gets overridden when you're using designated initializers. This warning is included in -Wextra. If you want 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 ๐ŸŽ€ โ€” Warn if a structure gets the packed attribute but the packed attribute has no effect on the layout or size of the structure. Structures like that may end up misaligned for basically no benefit. For example, in this code the variable f.x inside 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 ignored the "packed" attribute on bit-fields of type "char". That got fixed in GCC 4.4, but the change can lead to differences in structure layout. GCC tells you when the offset of such a field has changed in GCC 4.4. For example, there's no longer a 4-bit padding between field "a" and "b" in this structure:
        struct foo
        {
          char a:4;
          char b:8;
        } __attribute__ ((packed));

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

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

This warning is enabled by -Wall.

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

-Wrestrict catches 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) ๐Ÿšจ โ€” Warn if an "extern" declaration shows up inside a function.
  • -Winline ๐Ÿ” โ€” Warn if a function declared as inline can't be inlined. Even with this option on, the compiler won't warn about failures to inline functions declared in system headers.

The compiler uses a bunch of heuristics to decide whether to inline a function ๐Ÿงฎ For example, it looks at how big the function being inlined is and how much inlining has already been done in the current function. So seemingly tiny changes in your source can make the -Winline warnings show up or disappear, lol ๐Ÿ™ƒ

  • -Winterference-size ๐Ÿ  โ€” Warn about using C++17 std::hardware_destructive_interference_size without specifying its value with --param destructive-interference-size. It also warns about questionable values for that option.

This one is for controlling class layout so you don't get false sharing in concurrent code โœจ Here's the vibe:

        struct independent_fields {
          alignas(std::hardware_destructive_interference_size) std::atomic<int> one;
          alignas(std::hardware_destructive_interference_size) std::atomic<int> two;
        };

The idea is that one and two end up far enough apart that stores to one won't force accesses to two to reload the cache line ๐ŸงŠ

By default, --param destructive-interference-size and --param constructive-interference-size are set based on the current -mtune option. That's usually the L1 cache line size for the target CPU, and 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 has to be compiled with the same -mtune (or -mcpu).

If ABI stability matters, like if the use is in a header for a library, you should probably not use the hardware interference size variables at all ๐Ÿ˜ฌ Or you can force a specific value with --param. And if you're confident your use of the variable doesn't affect ABI outside a single build of your project, you can turn off the warning with -Wno-interference-size.

  • -Wint-in-bool-context ๐Ÿง โ€” Warn about suspicious use of integer values where booleans are 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++);. Same goes for all kinds of multiplications, regardless of data type. This warning is enabled by -Wall.
  • -Wno-int-to-pointer-cast ๐Ÿ™ˆ โ€” Suppress 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) ๐Ÿญ โ€” Suppress warnings about casts from a pointer to an integer type of a different size.
  • -Winvalid-pch ๐Ÿ”Ž โ€” Warn if a precompiled header is found in the search path but can't be used.
  • -Wlong-long ๐ŸŽˆ โ€” Warn if the long long type is used. This is enabled by either -Wpedantic or -Wtraditional in ISO C90 and C++98 modes. To shush the warning messages, use -Wno-long-long.
  • -Wvariadic-macros ๐ŸŒ€ โ€” Warn if variadic macros are used in ISO C90 mode, or if the GNU alternate syntax is used in ISO C99 mode. This is enabled by either -Wpedantic or -Wtraditional. To inhibit the warning messages, use -Wno-variadic-macros.
  • -Wno-varargs ๐Ÿ’œ โ€” Don't warn about questionable usage of the macros used to handle variable arguments, like va_start. These warnings are enabled by default.
  • -Wvector-operation-performance โ€” okay so this one warns you if a vector operation isn't using the architecture's SIMD superpowers ๐Ÿš€. It's mainly for performance tuning, bestie. A vector op can get done three ways: "piecewise" runs the scalar op on every single vector element ๐Ÿงฉ, "in parallel" builds the vector op out of scalars of a wider type, which is usually way more performance efficient ๐ŸŽ๏ธ, and "as a single scalar" means the vector fits into one scalar type ๐Ÿ’Ž.
  • -Wvla โ€” warns you if a variable-length array shows up anywhere in your code ๐Ÿ™ˆ. And -Wno-vla stops the -Wpedantic warning about variable-length arrays, so you can quiet that one specifically ๐Ÿคซ.
  • -Wvla-larger-than=byte-size โ€” if you turn this on, the compiler warns about VLA declarations whose size is either unbounded, or bounded by an argument that lets the array grow past byte-size bytes ๐Ÿ“. It's basically the VLA version of -Walloca-larger-than=byte-size ๐Ÿ‘ฏ.

Heads up ๐Ÿ’…: GCC might optimize small VLAs with a known value into plain arrays, so this warning might not fire for those.

-Wvla-larger-than=PTRDIFF_MAX is on by default, but it's usually only actually effective when -ftree-vrp is active, which is the default for -O2 and up โœจ.

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

  • -Wno-vla-larger-than โ€” turns off the -Wvla-larger-than= warnings ๐Ÿ™…. It's the same as -Wvla-larger-than=SIZE_MAX or anything bigger.
  • -Wvla-parameter โ€” warns about redeclarations of functions with VLA-type arguments whose kinds or forms don't match ๐Ÿคจ, and turns on detection of out-of-bounds accesses to those parameters through warnings like -Warray-bounds ๐Ÿ”.

Here's the tea โ˜•: if the first declaration uses the VLA form, the bound in the array is treated as the minimum number of elements callers have to provide, and the maximum number the function will access. Not giving enough, or accessing more than that max, might get flagged ๐Ÿšฉ.

The warning triggers for the redeclarations below, because the first one lets an array of any size get passed to f, while the second one says the array argument needs at least n elements. Calling f with the associated VLA bound parameter bigger than the actual VLA bound also triggers a warning ๐Ÿ‘€.

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

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

-Wvla-parameter is included in -Wall ๐ŸŽ€. The -Warray-parameter option handles similar problems with ordinary array arguments ๐Ÿงบ.

  • -Wvolatile-register-var โ€” warns if a register variable gets declared volatile ๐Ÿซ . Just know that volatile doesn't stop every optimization that might eliminate reads and/or writes to register variables ๐Ÿ™ƒ. This warning is enabled by -Wall ๐Ÿ’œ.
  • -Wdisabled-optimization โ€” warns if a requested optimization pass gets disabled ๐Ÿ˜ฌ. Don't spiral though, bestie, this doesn't generally mean your code is wrong ๐Ÿซถ. It just means GCC's optimizers can't handle the code effectively. Often the code is too big or too complex, and GCC refuses to optimize programs when the optimization would likely take an inordinate amount of time โณ.
  • -Wpointer-sign (C and Objective-C only) โ€” warns for pointer argument passing or assignment with different signedness ๐Ÿ”ข. It's only supported for C and Objective-C. It's implied by -Wall and by -Wpedantic, and you can disable it with -Wno-pointer-sign ๐Ÿ™….
  • -Wstack-protector โ€” only active when -fstack-protector is active ๐Ÿ›ก๏ธ. It warns about functions that aren't protected against stack smashing ๐Ÿ’ฅ.
  • -Woverlength-strings โ€” warns about string constants longer than the "minimum maximum" length the C standard specifies ๐Ÿ“œ. Modern compilers are chill and allow string constants way longer than the standard's minimum, but very portable programs should still avoid super long strings ๐ŸŒ.

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

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

  • -Wunsuffixed-float-constants (C and Objective-C only) โ€” warns for any floating constant that doesn't have a suffix ๐Ÿ”ค. Pair it with -Wsystem-headers and it also warns about those constants in system header files ๐Ÿ—‚๏ธ. This is super handy when you're prepping code to use with the FLOAT_CONST_DECIMAL64 pragma from the decimal floating-point extension to C99 ๐Ÿง .
  • -Wno-lto-type-mismatch โ€” during link-time optimization, this stops warnings about type mismatches in global declarations from different compilation units ๐Ÿค. It requires -flto to be enabled, and it's on by default โœจ.
  • -Wno-designated-init (C and Objective-C only) โ€” suppresses warnings when a positional initializer is used to initialize a struct marked with the designated_init attribute ๐Ÿงธ.

โœจ Options That Control Static Analysis โœจ

  • -fanalyzer โ€” enables static analysis of program flow ๐Ÿ”ฌ. It hunts for "interesting" interprocedural paths through your code and warns about problems it finds along them ๐Ÿ•ต๏ธโ€โ™€๏ธ. Fair warning, bestie: this analysis is way more expensive than other GCC warnings ๐Ÿ’ธ.

Turning this on effectively enables the following warnings ๐Ÿ‘‘:

-Wanalyzer-double-fclose -Wanalyzer-double-free
-Wanalyzer-exposure-through-output-file -Wanalyzer-file-leak
-Wanalyzer-free-of-non-heap -Wanalyzer-malloc-leak
-Wanalyzer-mismatching-deallocation
-Wanalyzer-possible-null-argument
-Wanalyzer-possible-null-dereference -Wanalyzer-null-argument
-Wanalyzer-null-dereference -Wanalyzer-shift-count-negative
-Wanalyzer-shift-count-overflow -Wanalyzer-stale-setjmp-buffer
-Wanalyzer-tainted-allocation-size -Wanalyzer-tainted-array-index
-Wanalyzer-tainted-divisor -Wanalyzer-tainted-offset
-Wanalyzer-tainted-size -Wanalyzer-unsafe-call-within-signal-handler
-Wanalyzer-use-after-free -Wanalyzer-use-of-uninitialized-value
-Wanalyzer-use-of-pointer-in-stale-stack-frame
-Wanalyzer-write-to-const -Wanalyzer-write-to-string-literal
This option is only available if GCC was configured with analyzer support enabled. ๐Ÿšจ
  • -Wanalyzer-too-complex โ€” if -fanalyzer is on, the analyzer uses a bunch of heuristics to explore control flow and data flow ๐Ÿงญ. Sufficiently complicated code can defeat them though ๐Ÿ˜ตโ€๐Ÿ’ซ. By default, the analysis quietly stops when code is too complicated and it hits an internal limit ๐Ÿคซ. -Wanalyzer-too-complex warns you when that happens ๐Ÿšจ.
  • -Wno-analyzer-double-fclose โ€” this one requires -fanalyzer, which turns it on, and you can switch it off with -Wno-analyzer-double-fclose ๐Ÿ™…. It flags paths where a FILE * can have fclose called on it more than once ๐Ÿ“‚.
  • -Wno-analyzer-double-free โ€” needs -fanalyzer to be enabled, and you can disable it with -Wno-analyzer-double-free ๐Ÿ™…. It flags paths where a pointer can have a deallocator called on it more than once, either free, or a deallocator referenced by attribute malloc ๐Ÿ’€.
  • -Wno-analyzer-exposure-through-output-file โ€” needs -fanalyzer, and you disable it with -Wno-analyzer-exposure-through-output-file ๐Ÿ™…. It flags paths where a security-sensitive value gets written to an output file, like dumping a password into a log file ๐Ÿ”.
  • -Wno-analyzer-file-leak โ€” needs -fanalyzer, and disable it with -Wno-analyzer-file-leak ๐Ÿ™…. It flags paths where a <stdio.h> FILE * stream object gets leaked ๐Ÿซ—.
  • -Wno-analyzer-free-of-non-heap โ€” needs -fanalyzer, and disable it with -Wno-analyzer-free-of-non-heap ๐Ÿ™…. It flags paths where free gets called on a non-heap pointer, like an on-stack buffer or a global ๐Ÿ—‘๏ธ.
  • -Wno-analyzer-malloc-leak โ€” needs -fanalyzer, and disable it with -Wno-analyzer-malloc-leak ๐Ÿ™…. It flags paths where a pointer allocated through an allocator gets leaked: either malloc, or a function marked with attribute malloc ๐Ÿ’ง.
  • -Wno-analyzer-mismatching-deallocation โ€” needs -fanalyzer, and disable it with -Wno-analyzer-mismatching-deallocation ๐Ÿ™…. It flags paths where the wrong deallocation function gets called on a pointer, based on which function allocated it ๐Ÿ™ƒ. That covers mismatches between free, scalar delete and vector delete[], plus anything marked as allocator/deallocator pairs using attribute malloc ๐Ÿ‘ฏ.
  • -Wno-analyzer-possible-null-argument โ€” needs -fanalyzer, and disable it with -Wno-analyzer-possible-null-argument ๐Ÿ™…. It flags paths where a possibly-NULL value gets passed to a function argument marked with __attribute__((nonnull)) as requiring a non-NULL value ๐Ÿšซ.
  • -Wno-analyzer-possible-null-dereference โ€” needs -fanalyzer, and disable it with -Wno-analyzer-possible-null-dereference ๐Ÿ™…. It flags paths where a possibly-NULL value gets dereferenced ๐Ÿ‘‰.
  • -Wno-analyzer-null-argument โ€” this warning requires -fanalyzer, which enables it, and you can disable it with -Wno-analyzer-null-argument ๐Ÿ™….

Okay so this one is the warning for when a value we know is NULL gets passed into a function argument that's marked __attribute__((nonnull)), which means it needs a real, non-NULL value ๐Ÿ™…โ€โ™€๏ธ๐Ÿ’– This diagnostic warns for paths through the code where that happens.

  • -Wno-analyzer-null-dereference โ€” bestie, this one needs -fanalyzer to be turned on, and you can switch it off with -Wno-analyzer-null-dereference ๐Ÿ’… It warns for paths through the code where a value known to be NULL gets dereferenced ๐Ÿ’€
  • -Wno-analyzer-shift-count-negative โ€” this one also needs -fanalyzer to run, and -Wno-analyzer-shift-count-negative turns it off ๐Ÿฆ‹ It warns for paths where a shift happens with a negative count. It's the analyzer's version of -Wshift-count-negative from the C/C++ front ends, except it looks at interprocedural paths instead of just parsing the syntax tree. The analyzer doesn't prioritize catching these, so false negatives are more likely than with other warnings ๐Ÿ™ˆ
  • -Wno-analyzer-shift-count-overflow โ€” needs -fanalyzer, and you turn it off with -Wno-analyzer-shift-count-overflow โœจ It warns for paths where a shift is attempted with a count greater than or equal to the precision of the operand's type. It's the sibling of -Wshift-count-overflow in the C/C++ front ends, but again it's built on analyzing interprocedural paths rather than the syntax tree. Same deal: the analyzer doesn't prioritize these, so false negatives are more likely relative to other warnings ๐ŸŒธ
  • -Wno-analyzer-stale-setjmp-buffer โ€” needs -fanalyzer, and -Wno-analyzer-stale-setjmp-buffer disables it ๐Ÿ˜ญ It warns 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 is called on a jmp_buf, it records the stack frame. That frame becomes invalid once the function with the setjmp call returns, so rewinding to it via longjmp would reference a stack frame that doesn't exist anymore. That's likely to lead to a crash, or worse ๐Ÿ’€๐Ÿ”ฅ
  • -Wno-analyzer-tainted-allocation-size โ€” this one needs both -fanalyzer and -fanalyzer-checker=taint to be enabled, and -Wno-analyzer-tainted-allocation-size turns it off ๐Ÿซถ It warns for paths where a value an attacker could control gets used as the size of an allocation without being sanitized. That means an attacker could inject a huge allocation and maybe cause a denial of service attack ๐Ÿšจ See CWE-789: Memory Allocation with Excessive Size Value, at https://cwe.mitre.org/data/definitions/789.html ๐Ÿ”—
  • -Wno-analyzer-tainted-array-index โ€” needs both -fanalyzer and -fanalyzer-checker=taint, and you disable it with -Wno-analyzer-tainted-array-index ๐ŸŽ€ It warns for paths where an attacker-controllable value is used as an array index without being sanitized, which could let an attacker inject an out-of-bounds access ๐Ÿ‘€ See CWE-129: Improper Validation of Array Index, at https://cwe.mitre.org/data/definitions/129.html ๐Ÿ’–
  • -Wno-analyzer-tainted-divisor โ€” needs both -fanalyzer and -fanalyzer-checker=taint, and -Wno-analyzer-tainted-divisor shuts it off ๐Ÿ™…โ€โ™€๏ธ It warns for paths where an attacker-controllable value is used as the divisor in a division or modulus operation without being sanitized, so an attacker could inject a division-by-zero ๐Ÿ’€
  • -Wno-analyzer-tainted-offset โ€” needs both -fanalyzer and -fanalyzer-checker=taint, and you can turn it off with -Wno-analyzer-tainted-offset ๐Ÿฆ‹ It warns for paths where an attacker-controllable value is used as a pointer offset without being sanitized, which could let an attacker inject an out-of-bounds access. See CWE-823: Use of Out-of-range Pointer Offset, at https://cwe.mitre.org/data/definitions/823.html ๐ŸŒˆ
  • -Wno-analyzer-tainted-size โ€” needs both -fanalyzer and -fanalyzer-checker=taint, and -Wno-analyzer-tainted-size disables it ๐Ÿ“ It warns for paths where an attacker-controllable value is used as the size of an operation like memset without being sanitized, so an attacker could inject an out-of-bounds access ๐Ÿ˜ค
  • -Wno-analyzer-unsafe-call-within-signal-handler โ€” needs -fanalyzer, and -Wno-analyzer-unsafe-call-within-signal-handler turns it off โญ It warns for paths where a function known to be async-signal-unsafe, like fprintf, gets called from inside a signal handler ๐Ÿšซ
  • -Wno-analyzer-use-after-free โ€” needs -fanalyzer, and you disable it with -Wno-analyzer-use-after-free ๐Ÿ”ฅ It warns for paths where a pointer gets used after a deallocator has been called on it. That deallocator is either free, or a deallocator referenced by attribute "malloc" ๐Ÿ’…
  • -Wno-analyzer-use-of-pointer-in-stale-stack-frame โ€” needs -fanalyzer, and -Wno-analyzer-use-of-pointer-in-stale-stack-frame switches it off ๐Ÿงš It warns for paths where a pointer gets dereferenced and it points to a variable in a stale stack frame ๐Ÿ‘‘
  • -Wno-analyzer-write-to-const โ€” needs -fanalyzer, and -Wno-analyzer-write-to-const turns it off ๐Ÿซถ It warns for paths where the analyzer detects an attempt to write through a pointer to a const object. Heads up, though: the analyzer doesn't prioritize these, so false negatives are more likely relative to other warnings ๐Ÿ™ˆ
  • -Wno-analyzer-write-to-string-literal โ€” needs -fanalyzer, and you can disable it with -Wno-analyzer-write-to-string-literal ๐Ÿ’œ It warns for paths where the analyzer detects an attempt to write through a pointer to a string literal. Same vibe as before: the analyzer doesn't prioritize these, so false negatives are more likely relative to other warnings ๐ŸŒธ
  • -Wno-analyzer-use-of-uninitialized-value โ€” needs -fanalyzer, and -Wno-analyzer-use-of-uninitialized-value shuts it down โœจ It warns for paths where an uninitialized value gets used ๐Ÿ˜ญ

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


The following options control the analyzer ๐Ÿ’–

  • -fanalyzer-call-summaries โ€” okay this one is a whole glow-up for interprocedural analysis โœจ Instead of exploring every path through the function from the callsite to each possible return, it computes the effect of certain calls and simplifies things for you. If it's enabled, call summaries only get used for functions with more than one call site, and that are sufficiently complicated (per --param analyzer-min-snodes-for-call-summary=value) ๐Ÿง 
  • -fanalyzer-checker=name โ€” this one restricts the analyzer to run just the named checker, and it also enables that checker ๐ŸŽฏ Some checkers are disabled by default, even with -fanalyzer. The "taint" checker that implements -Wanalyzer-tainted-array-index is one of them, and this option is required to turn those on ๐Ÿฆ‹
  • -fno-analyzer-feasibility โ€” this one is for analyzer developers, not us mortals ๐Ÿง‘โ€๐Ÿ’ป By default, the analyzer checks that there's a feasible control flow path for each diagnostic it emits, meaning the conditions that hold aren't mutually exclusive. Diagnostics with no feasible path get rejected. This filtering can be suppressed with -fno-analyzer-feasibility, which is handy for debugging issues in this code ๐Ÿ”
  • -fanalyzer-fine-grained โ€” another developer-only option ๐Ÿ› ๏ธ Internally, the analyzer builds an "exploded graph" that combines control flow graphs with data flow information. By default, an edge in this graph can hold the effects of a run of multiple statements within a basic block. With -fanalyzer-fine-grained, each statement gets its own edge ๐ŸŒˆ
  • -fanalyzer-show-duplicate-count โ€” developer-only, and honestly kinda iconic ๐Ÿ‘‘ If multiple diagnostics are detected as duplicates of each other, this emits a note when reporting the best diagnostic, telling you how many additional diagnostics were suppressed by the deduplication logic ๐Ÿ™ˆ
  • -fno-analyzer-state-merge โ€” developer-only ๐Ÿงช By default, the analyzer simplifies things by merging sufficiently similar states at each program point while 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 โ€” developer-only ๐Ÿงน By default, the analyzer purges aspects of state at a program point that seem no longer relevant. For example, 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 ๐Ÿ’œ
  • -fanalyzer-transitivity โ€” this one enables transitivity of constraints within the analyzer ๐Ÿ’…
  • -fanalyzer-verbose-edges โ€” developer-only, and it's all about detail ๐Ÿค“ It turns on more verbose, lower-level info in the descriptions of control flow within diagnostic paths ๐ŸŒธ
  • -fanalyzer-verbose-state-changes โ€” developer-only too ๐Ÿงš It enables more verbose, lower-level detail in the descriptions of events relating to state machines within diagnostic paths ๐Ÿฆ‹
  • -fanalyzer-verbosity=level โ€” this one controls how complex the control flow paths are that get emitted for analyzer diagnostics ๐ŸŽ€

The level can be one of these, bestie ๐Ÿ’…โœจ

  • 0 โ€” ๐Ÿฆ‹ At this level, the analyzer shows interprocedural call and return events, along with the most pertinent state-change events for a diagnostic. Like, for a double-"free" diagnostic, both calls to "free" will show up so you can see exactly what happened ๐Ÿ’€
  • 1 โ€” ๐ŸŒธ Same as level 0, but it also shows events for the entry to each function. Main character energy ๐Ÿ‘‘
  • 2 โ€” ๐Ÿ’– Same as level 1, but it also shows control flow events that matter for triggering the issue, like "true path taken" at a conditional. This is the default level, so you're already getting this one ๐Ÿซถ
  • 3 โ€” ๐Ÿงš Same as level 2, but now it shows all control flow events, not just the significant ones. It's a lot, but it's thorough ๐Ÿ˜ญ
  • 4 โ€” ๐Ÿ”ง This one is for analyzer developers. It adds a bunch of extra events meant for debugging the analyzer itself, so unless you're the analyzer dev, maybe skip it ๐Ÿ™ˆ
  • -fdump-analyzer โ€” ๐Ÿ“„ Dumps internal details about what the analyzer is doing to file.analyzer.txt. This option gets overridden by -fdump-analyzer-stderr, so keep that in mind ๐Ÿ“
  • -fdump-analyzer-stderr โ€” ๐Ÿ–ฅ๏ธ Dumps the same internal details, but to stderr instead. This one overrides -fdump-analyzer, so if you use both, this one wins ๐Ÿ‘‘
  • -fdump-analyzer-callgraph โ€” ๐Ÿ•ธ๏ธ Dumps a representation of the call graph that's suitable for viewing with GraphViz, written to file.callgraph.dot
  • -fdump-analyzer-exploded-graph โ€” ๐ŸŒˆ Dumps a representation of the "exploded graph" for GraphViz, written to file.eg.dot. The nodes are color-coded based on state-machine states so state changes really pop out ๐Ÿ’…
  • -fdump-analyzer-exploded-nodes โ€” ๐ŸŽฏ Emits diagnostics showing where the nodes in the "exploded graph" sit in relation to the program source
  • -fdump-analyzer-exploded-nodes-2 โ€” ๐Ÿ“ Dumps a textual representation of the "exploded graph" to file.eg.txt
  • -fdump-analyzer-exploded-nodes-3 โ€” ๐Ÿ—‚๏ธ Dumps a textual representation of the "exploded graph", but one dump file per node, named file.eg-id.txt. Heads up, this is typically a huge number of dump files ๐Ÿ’€
  • -fdump-analyzer-exploded-paths โ€” ๐Ÿ›ค๏ธ Dumps a textual representation of the "exploded path" for each diagnostic to file.idx.kind.epath.txt
  • -fdump-analyzer-feasibility โ€” ๐Ÿ” Dumps internal details about the analyzer's search for feasible paths. The details are written in a form suitable for GraphViz, to filenames of the form file.*.fg.dot and file.*.tg.dot
  • -fdump-analyzer-json โ€” ๐Ÿ“ฆ Dumps a compressed JSON representation of analyzer internals to file.analyzer.json.gz. Just a heads up that the precise format is subject to change, so don't build your whole life on it ๐Ÿซ 
  • -fdump-analyzer-state-purge โ€” ๐Ÿงน Same idea as -fdump-analyzer-supergraph, dumping a GraphViz-friendly "supergraph", but annotated with what state will be purged at each node. It's written to file.state-purge.dot
  • -fdump-analyzer-supergraph โ€” ๐Ÿ—บ๏ธ Dumps representations of the "supergraph" for GraphViz, to file.supergraph.dot and file.supergraph-eg.dot. These show every control flow graph in the program, with interprocedural edges for calls and returns. The second dump has annotations showing the "exploded graph" nodes and the diagnostics attached to them โœจ

๐Ÿ› Options for Debugging Your Program

To tell GCC to emit extra info for a debugger, you almost always just need to add -g to your other options ๐Ÿ’–. Some debug formats can co-exist (like DWARF with CTF) when each one is enabled explicitly by adding its own command line option alongside your other options.

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

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

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

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

  • -ggdb โ€” ๐ŸŽฏ Produces debugging info for GDB. It uses the most expressive format available (DWARF, stabs, or the native format if neither of those is supported), including GDB extensions if at all possible ๐Ÿ‘‘
  • -gdwarf, -gdwarf-version โ€” ๐Ÿงฉ Produces debugging info in DWARF format (if that's supported). The value of version may be 2, 3, 4 or 5. The default version for most targets is 5, with the exceptions of VxWorks, TPF and Darwin/Mac OS X, which default to version 2, and AIX, which defaults to version 4 ๐ŸŒˆ

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

Version 4 may require GDB 7.0 and -fvar-tracking-assignments for maximum benefit. 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 level controls how much CTF debug info gets produced. 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. This includes callsite info, but not type info.

Level 2 produces type info for entities (functions, data objects, etc.) at file scope or global scope only.

  • -gstabs โ€” ๐Ÿ“œ Produces debugging info in stabs format (if that's supported), without GDB extensions. This is the format DBX uses on most BSD systems. On MIPS, Alpha and System V Release 4 systems, this option produces stabs debugging output that DBX doesn't understand. On System V Release 4 systems, this option requires the GNU assembler ๐Ÿ™ˆ
  • -gstabs+ โ€” ๐Ÿช„ Produces debugging info in stabs format (if that's supported), using GNU extensions that only the GNU debugger (GDB) understands. Using these extensions will likely make other debuggers crash or refuse to read the program ๐Ÿ’€
  • -gxcoff โ€” ๐Ÿ›๏ธ Produces debugging info in XCOFF format (if that's supported). This is the format the DBX debugger uses on IBM RS/6000 systems.
  • -gxcoff+ โ€” ๐Ÿงจ Produces debugging info in XCOFF format (if that's supported), using GNU extensions that only GDB understands. Using these extensions will likely make other debuggers crash or refuse to read the program, and it may cause assemblers other than the GNU assembler (GAS) to fail with an error ๐Ÿ˜ญ
  • -gvms โ€” ๐Ÿ–ค Produces debugging info in Alpha/VMS debug format (if that's supported). This is the format DEBUG uses on Alpha/VMS systems.
  • -glevel, -ggdblevel, -gstabslevel, -gxcofflevel, -gvmslevel โ€” ๐ŸŽš๏ธ Requests debugging info and uses level to specify how much info you get. The default level is 2.

Level 0 produces no debug info at all, so -g0 negates -g ๐Ÿ™…โ€โ™€๏ธ

Level 1 produces minimal info, enough to make backtraces in the parts of the program you don't plan to debug. This includes descriptions of functions and external variables, and line number tables, but no info about local variables.

Level 3 includes extra info, like 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 doesn't accept a concatenated debug level, to avoid confusion with -gdwarf-level. Instead, use an additional -glevel option to change the debug level for DWARF ๐Ÿง 

  • -fno-eliminate-unused-debug-symbols โ€” ๐Ÿšซ By default, no debug info is produced for symbols that aren't actually used. Use this option if you want debug info for all symbols ๐Ÿ”
  • -femit-class-debug-always โ€” ๐Ÿชž Instead of emitting debugging info for a C++ class in only one object file, this emits it in all object files that use the class. This option should only be used with debuggers that can't handle the way GCC normally emits debugging info for classes, because it increases the size of the 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 โ€” okay so when you compile files living in old, GCC writes the debug info like they actually live in new instead ๐Ÿ—บ๏ธ Bestie, this lets you swap a build-time path for an install-time path in the debug info. You can also turn an absolute path into a relative one by using . for new. It can give more reproducible builds that don't care where they're located ๐ŸŒธ, but you might need an extra command to tell GDB where the source files are. See also -ffile-prefix-map.
  • -fvar-tracking โ€” this runs the variable tracking pass, which figures out where variables are stored at each spot in the code ๐Ÿฆ‹ The result is better debug info, as long as your debug format can handle it. It's on by default when you compile with optimization (-Os, -O, -O2, ...) and debug info (-g) and the debug info format supports it. Lowkey main character energy โœจ
  • -fvar-tracking-assignments โ€” this annotates assignments to user variables early in compilation and tries to carry those annotations all the way to the end ๐Ÿ’… The goal is better debug info while optimizing. Using -gdwarf-4 alongside it is recommended. It can be turned on even when var-tracking is off, but then the annotations get made and maintained and then tossed at the end. By default it's enabled together with -fvar-tracking, except when selective scheduling is enabled.
  • -gsplit-dwarf โ€” if DWARF debug info is enabled, this splits as much of it as possible into a separate output file ending in .dwo ๐Ÿงš This lets the build system skip linking files that have debug info. To actually be useful, you need a debugger that can read .dwo files.
  • -gdwarf32, -gdwarf64 โ€” if DWARF debug info is enabled, -gdwarf32 picks the 32-bit DWARF format and -gdwarf64 picks the 64-bit one ๐Ÿ“ The default is target specific, though on most targets it's -gdwarf32. The 32-bit format is smaller, but it can't handle more than 2GiB of debug info in any of the DWARF debug info sections. The 64-bit format allows bigger debug info, but not every consumer supports it yet ๐Ÿ™ˆ
  • -gdescribe-dies โ€” this adds description attributes to some DWARF DIEs that don't have a name attribute ๐ŸŽ€ Think artificial variables, external references and call site parameter DIEs.
  • -gpubnames โ€” generates the DWARF .debug_pubnames and .debug_pubtypes sections ๐ŸŒˆ
  • -ggnu-pubnames โ€” generates .debug_pubnames and .debug_pubtypes in a format that can be converted into a GDB index ๐Ÿซถ Heads up, this only helps if your linker can produce GDB index version 7.
  • -fdebug-types-section โ€” with DWARF Version 4 or higher, type DIEs can get their own .debug_types section instead of living in .debug_info ๐Ÿ’– It's more efficient 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 debug info bigger instead of smaller ๐Ÿ˜ญ
  • -grecord-gcc-switches, -gno-record-gcc-switches โ€” this appends the command-line options that might affect code generation to the DW_AT_producer attribute in DWARF debug info โœจ They're joined with spaces, separating them from each other and from the compiler version. It's enabled by default. See also -frecord-gcc-switches for another way of stashing 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 allowed anyway.
  • -gno-strict-dwarf โ€” allows extensions from a later DWARF standard version than the one you picked with -gdwarf-version ๐Ÿฆ„
  • -gas-loc-support โ€” tells the compiler that the assembler supports .loc directives ๐Ÿ”ฅ The compiler can then use them so the assembler generates DWARF2+ line number tables. This is usually what you want, because assembler-generated line number tables are a lot more compact than the ones the compiler makes itself. It's enabled by default if the assembler was found to support these directives at GCC configure time.
  • -gno-as-loc-support โ€” forces GCC to generate DWARF2+ line number tables internally, if those tables are supposed to be generated at all ๐Ÿ™…โ€โ™€๏ธ
  • -gas-locview-support โ€” tells the compiler that the assembler supports "view" assignment and reset assertion checking in .loc directives ๐Ÿ‘‘ It's enabled by default if the assembler was found to support them at GCC configure time.
  • -gno-as-locview-support โ€” forces GCC to assign view numbers internally, but only if -gvariable-location-views was explicitly requested ๐Ÿฅบ
  • -gcolumn-info, -gno-column-info โ€” emits location column information into DWARF debug info, instead of just file and line ๐Ÿ“ It's enabled by default.
  • -gstatement-frontiers, -gno-statement-frontiers โ€” this makes GCC drop markers in the internal representation at the start of statements ๐Ÿงญ It keeps them roughly in place throughout compilation and uses them to guide the output of "is_stmt" markers in the line number table. It's enabled by default when you compile with optimization (-Os, -O1, -O2, ...) and output DWARF 2 debug info at the normal level.
  • -gvariable-location-views, -gvariable-location-views=incompat5, -gno-variable-location-views โ€” this augments variable location lists with progressive view numbers, implied by the line number table ๐Ÿฆ‹ Debug info consumers can then 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 usually makes them a bit less compact. The augmented tables and lists are fully backward-compatible, so consumers that don't know about these augmentations can still read them, but they won't get any benefit either.

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

โš ๏ธ There's a proposed representation for view numbers that is not backward compatible with the location list format introduced in DWARF 5. You can turn it on with -gvariable-location-views=incompat5. This option may be removed in the future, and it's only provided as a reference implementation of the proposed representation. Debug info consumers aren't expected to support this extended format, and they'd be unable to decode location lists that use it ๐Ÿ’€
  • -ginternal-reset-location-views, -gno-internal-reset-location-views โ€” this attempts to figure out which location views can be left out of 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". This is only enabled on ports that define a reliable estimation function.
  • -ginline-points, -gno-inline-points โ€” generates extended debug info for inlined functions ๐ŸŒŸ Location view tracking markers get inserted at inlined entry points, so address and view numbers can be computed and output in the debug info. This can be enabled independently of location views, in which case the view numbers won't be output. It can only be enabled along with statement frontiers, and it's only enabled by default if location views are enabled.
  • -gz[=type] โ€” produces compressed debug sections in DWARF format, if that's supported ๐Ÿ—œ๏ธ If type isn't given, the default depends on what the assembler and linker can do. type may be one of:
    • none โ€” don't compress debug sections
    • zlib โ€” use zlib compression in ELF gABI format
    • zlib-gnu โ€” use zlib compression in traditional GNU format

If the linker 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 โ€” emits debug info for struct-like types only when the base name of the compilation source file matches the base name of the file where the struct is defined ๐Ÿฅน This substantially reduces the size of debug info, but there's a significant potential loss in type information for the debugger. For a less aggressive option, see -femit-struct-debug-reduced. For more detailed control, see -femit-struct-debug-detailed. This option only works with DWARF debug output.
  • -femit-struct-debug-reduced โ€” emits debug info for struct-like types only when the base name of the compilation source file matches the base name of the file where the type is defined ๐ŸŒธ The exception is if the struct is a template or is defined in a system header. This significantly reduces the size of debug info, with some potential loss in type information. For a more aggressive option, see -femit-struct-debug-baseonly. For more detailed control, see -femit-struct-debug-detailed. This only works with DWARF debug output.
  • -femit-struct-debug-detailed[=spec-list] โ€” this lets you specify which struct-like types the compiler generates debug info for ๐ŸŽฏ The whole point is to cut down on duplicate struct debug info between different object files within the same program.

This one is the glow-up of -femit-struct-debug-reduced and -femit-struct-debug-baseonly ๐Ÿ’…โœจ and honestly it covers most of what you'll need ๐ŸŽ€ Its value looks like this:

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

The first word is optional and filters by how a struct gets used ๐Ÿฆ‹ dir: means the struct is used directly, like it's the type of a variable or a member. ind: means it's used indirectly, through pointers to structs. Basically, if using an incomplete struct would be valid, that's an indirect use ๐Ÿ™ˆ For example, in struct one direct; struct two * indirect;, the first one is direct and the second one is indirect.

The second word is also optional and picks between ordinary structs (ord:) and generic structs (gen:) ๐Ÿงš Generic structs are a little tricky, ngl. In C++, they're non-explicit specializations of template classes, or non-template classes inside those. Other languages have generics too, but -femit-struct-debug-detailed doesn't implement them yet, so don't expect it to handle them ๐Ÿ˜ญ

The third word decides which source files get debug info for their structs ๐ŸŒธ none and any mean what you'd expect. base means the base name of the file where the type is declared has to match the base name of your main compilation file. So when you compile foo.c, you get debug info for types declared in foo.c and foo.h, but not other headers ๐Ÿ’œ sys covers types that match base or that are declared in system or compiler headers.

You might need to play around with settings to find what works best for your project ๐Ÿซถ

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

This option only works with DWARF debug output, so keep that in mind bestie โš ๏ธ

  • -fno-dwarf2-cfi-asm โ€” Puts DWARF unwind info into a compiler-generated .eh_frame section, instead of using GAS .cfi_* directives ๐ŸŒˆ
  • -fno-eliminate-unused-debug-types โ€” Normally, when making DWARF output, GCC skips debug info for types that never show up in the source file being compiled ๐Ÿ’… Sometimes you want debug info for every type declared in a compilation unit, even unused ones. For example, you might want to cast a value to a type that's declared but not used in your program while you're debugging ๐Ÿ” Most of the time though, this just wastes a ton of space ๐Ÿ’€

โœจ Options That Control Optimization โœจ

These options control various kinds of optimization ๐Ÿ”ฅ

Without any optimization option, the compiler's goal is to cut down on compilation cost and make debugging give you the results you expect ๐ŸŽ€ Statements are independent. So if you hit a breakpoint between statements, you can assign a new value to any variable, or jump the program counter to any other statement in the function, and get exactly the results you'd expect from the source code ๐Ÿฆ‹

Turning on optimization flags makes the compiler try to improve performance and/or code size, but it costs compilation time and might make the program harder to debug ๐ŸŒธ

The compiler optimizes based on what it knows about your program ๐Ÿง  Compiling multiple files at once into a single output file lets the compiler use info from all of those files when it compiles each one ๐Ÿ‘‘

Not every optimization has a flag ๐Ÿ’… Only the ones that do are listed in this section.

Most optimizations are completely disabled at -O0, or whenever no -O level is set on the command line, even if you add individual optimization flags ๐Ÿ™ˆ In the same way, -Og suppresses lots of optimization passes.

Depending on your 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 ๐ŸŒˆ To find the exact set for each level, run -Q --help=optimizers ๐Ÿซถ

If you use more than one -O option, with or without level numbers, the last one is the one that counts ๐Ÿ‘‘

Options that look like -fflag are machine-independent flags โœจ Most flags have both a positive and a negative form, and the negative form of -ffoo is -fno-foo. Below, only one form is listed, the one you'll usually use ๐Ÿ’– You can figure out the other one by 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 can use these flags in the rare cases when you want to "fine-tune" which optimizations get performed ๐Ÿ”ง

  • -O, -O1 โ€” Optimize ๐ŸŒธ Optimizing compilation takes somewhat more time, and a lot more memory for a large function. With -O, the compiler tries to shrink code size and cut execution time, without doing any optimization that takes a huge amount of compilation time. -O turns on the following flags:
-fauto-inc-dec -fbranch-count-reg -fcombine-stack-adjustments
-fcompare-elim -fcprop-registers -fdce -fdefer-pop -fdelayed-branch
-fdse -fforward-propagate -fguess-branch-probability -fif-conversion
-fif-conversion2 -finline-functions-called-once -fipa-modref
-fipa-profile -fipa-pure-const -fipa-reference
-fipa-reference-addressable -fmerge-constants -fmove-loop-invariants
-fmove-loop-stores -fomit-frame-pointer -freorder-blocks
-fshrink-wrap -fshrink-wrap-separate -fsplit-wide-types
-fssa-backprop -fssa-phiopt -ftree-bit-ccp -ftree-ccp -ftree-ch
-ftree-coalesce-vars -ftree-copy-prop -ftree-dce
-ftree-dominator-opts -ftree-dse -ftree-forwprop -ftree-fre
-ftree-phiprop -ftree-pta -ftree-scev-cprop -ftree-sink -ftree-slsr
-ftree-sra -ftree-ter -funit-at-a-time
  • -O2 โ€” Optimize even more ๐Ÿ”ฅ GCC does nearly every supported optimization that doesn't involve a space-speed tradeoff. Compared to -O, this increases both compilation time and the performance of the generated code. -O2 turns on every flag that -O1 does, plus these:
-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 ๐Ÿ™ˆ There's a warning under -fgcse about using -O2 on programs that use computed gotos, so go read that before you turn it on ๐Ÿ’€
  • -O3 โ€” Optimize yet more ๐Ÿ’ช -O3 turns on every optimization that -O2 does, and also these 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 โ€” Cuts down compilation time and makes debugging give the expected results ๐Ÿงš This is the default ๐ŸŽ€
  • -Os โ€” Optimize for size ๐ŸŒˆ -Os enables all -O2 optimizations except the ones that often increase code size. Those are:
-falign-functions  -falign-jumps -falign-labels  -falign-loops
-fprefetch-loop-arrays  -freorder-blocks-algorithm=stc

It also enables -finline-functions, makes the compiler tune for code size instead of execution speed, and runs further optimizations designed to shrink the code ๐Ÿฆ‹

  • -Ofast โ€” Ignores strict standards compliance ๐Ÿ˜ˆ -Ofast enables all -O3 optimizations. It also turns on 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.
This one is spicy, so only use it if you know your code can handle these looser rules โš ๏ธ
  • -Og โ€” Optimize the debugging experience ๐Ÿ” -Og should be your go-to level for the normal edit-compile-debug cycle ๐Ÿ’– It gives you a reasonable amount of optimization while keeping compilation fast and debugging smooth. It's a better pick than -O0 for producing debuggable code, because some compiler passes that collect debug info are disabled at -O0.

Like -O0, -Og completely disables a bunch of optimization passes, so the individual options that control them do nothing. Otherwise, -Og 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 โ€” Optimize aggressively for size instead of speed ๐ŸŒธ This may increase the number of instructions executed, if those instructions take fewer bytes to encode. -Oz works similarly to -Os, including turning on most -O2 optimizations.
  • -fno-defer-pop โ€” For machines that have to pop arguments after a function call, this 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 โ€” Runs 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 โœจ โ€” this one's all about floating-point expression contraction, and it comes in three flavours:
    • -ffp-contract=off ๐Ÿšซ turns contraction off entirely.
    • -ffp-contract=fast ๐Ÿ”ฅ turns it on, so things like fused multiply-add operations can get formed when the target has native support for them.
    • -ffp-contract=on ๐Ÿค” turns it on only if the language standard allows it. Bestie, this one is currently not implemented, so it's treated exactly the same as -ffp-contract=off. Not it. ๐Ÿ’€

The default is -ffp-contract=fast. ๐Ÿ’–

  • -fomit-frame-pointer ๐Ÿฆ‹ โ€” skip the frame pointer in any function that doesn't actually need one. That means no more instructions to save, set up, and restore it, and on lots of targets you also get an extra register to play with. Iconic. โœจ

On some targets this does literally nothing, because the standard calling sequence always uses a frame pointer, so it can't be left out. ๐Ÿ™ˆ

Heads up: -fno-omit-frame-pointer doesn't promise the frame pointer gets used in every function. Several targets always omit it in leaf functions anyway. ๐Ÿ’…

Enabled by default at -O1 and higher. ๐ŸŒธ

  • -foptimize-sibling-calls ๐Ÿ‘‘ โ€” optimizes sibling and tail recursive calls. Main character energy. ๐Ÿ’œ

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

  • -foptimize-strlen ๐Ÿงš โ€” speeds up standard C string functions like "strlen", "strchr" or "strcpy", plus their "_FORTIFY_SOURCE" counterparts, by swapping them for faster alternatives. Obsessed. ๐Ÿ˜ญ

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

  • -fno-inline ๐Ÿ™…โ€โ™€๏ธ โ€” don't expand any functions inline, except the ones marked with the always_inline attribute. This is the default when you're not optimizing. ๐Ÿ“

If you want to exempt just a single function from inlining, mark it with the noinline attribute. ๐Ÿซถ

  • -finline-small-functions ๐ŸŒˆ โ€” integrates functions into their callers whenever the body is smaller than the code for calling it would be, so the overall program gets smaller. The compiler makes a heuristic guess about which functions are simple enough. This applies to all functions, even the ones not declared inline. It's giving efficiency. ๐Ÿ’…

Enabled at levels -O2, -O3, -Os. โญ

  • -findirect-inlining ๐Ÿ”ฎ โ€” also inlines indirect calls that the compiler can figure out at compile time, thanks to earlier inlining. This only does anything if inlining is already turned on by -finline-functions or -finline-small-functions. ๐ŸŽ€

Enabled at levels -O2, -O3, -Os. ๐ŸŒธ

  • -finline-functions ๐Ÿฆข โ€” considers every function for inlining, even the ones not declared inline. The compiler heuristically picks which ones are worth integrating. ๐Ÿง 

If every call to a given function gets integrated and the function is declared static, it usually won't be output as assembler code in its own right. Lowkey genius. ๐Ÿ™Œ

Enabled at levels -O2, -O3, -Os. Also enabled by -fprofile-use and -fauto-profile. ๐Ÿ’–

  • -finline-functions-called-once ๐Ÿ’ โ€” considers all static functions called exactly once for inlining into their caller, even if they aren't marked inline. Once a call to one of them gets integrated, that function isn't output as assembler code in its own right. ๐Ÿฅน

Enabled at levels -O1, -O2, -O3 and -Os, but not -Og. ๐Ÿšซ

  • -fearly-inlining โšก โ€” inlines functions marked always_inline, along with any functions whose body seems smaller than the function call overhead. This happens early, before the -fprofile-generate instrumentation and the real inlining pass. It makes profiling way cheaper and usually makes inlining faster in programs with big chains of nested wrapper functions. Efficient, bestie. ๐Ÿซง

Enabled by default. โœจ

  • -fipa-sra ๐Ÿงฉ โ€” performs interprocedural scalar replacement of aggregates, removes unused parameters, and swaps parameters passed by reference for parameters passed by value. Very cleanup-core. ๐Ÿงน

Enabled at levels -O2, -O3 and -Os. ๐Ÿ’œ

  • -finline-limit=n ๐ŸŽš๏ธ โ€” GCC normally caps how big a function can be and still get inlined. This flag gives you coarse control over that cap, where n is the size of inlinable functions measured in pseudo instructions. ๐Ÿ“

Inlining is actually controlled by a bunch of parameters, which you can set one at a time with --param name=value. The -finline-limit=n option sets some of them for you:

  • max-inline-insns-single is set to n/2.
  • max-inline-insns-auto is set to n/2.

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

Note: there may be no value for -finline-limit that gives you the default behaviour. Plot twist. ๐Ÿ˜ญ
Note: "pseudo instruction" is just an abstract measurement of a function's size in this context. It is in no way a count of assembly instructions, so what it means could change from one release to another. Don't build your whole personality around it. ๐Ÿ™ˆ
  • -fno-keep-inline-dllexport ๐ŸŽฏ โ€” a more fine-grained version of -fkeep-inline-functions. It only applies to functions declared with the "dllexport" attribute or declspec. ๐ŸชŸ
  • -fkeep-inline-functions ๐Ÿ“ฆ โ€” in C, emits static functions declared inline into the object file, even if they've been inlined into all of their callers. This doesn't touch functions using the extern inline extension in GNU C90. In C++, it emits any and all inline functions into the object file. ๐Ÿง
  • -fkeep-static-functions ๐Ÿ’พ โ€” emits static functions into the object file, even if they're never used. Packed, no notes. ๐ŸŽ’
  • -fkeep-static-consts ๐Ÿ”’ โ€” emits variables declared static const when optimization isn't turned on, 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 is doing, use -fno-keep-static-consts. ๐Ÿ•ต๏ธโ€โ™€๏ธ

  • -fmerge-constants ๐Ÿค โ€” tries to merge identical constants (string constants and floating-point constants) across compilation units. ๐Ÿงท

This is the default for optimized compilation if the assembler and linker support it. Use -fno-merge-constants to shut this behaviour down. ๐Ÿ™…โ€โ™€๏ธ

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 considers things like constant initialized arrays or initialized constant variables with integral or floating-point types. ๐Ÿงฎ
Warning, bestie: C and C++ require every variable, including multiple instances of the same variable in recursive calls, to have distinct locations. Using this option therefore results in non-conforming behaviour. Proceed with caution. ๐Ÿ’€
  • -fmodulo-sched ๐ŸŽข โ€” performs swing modulo scheduling right before the first scheduling pass. It looks at the innermost loops and reorders their instructions by overlapping different iterations. Honestly, so smart. ๐Ÿง โœจ
  • -fmodulo-sched-allow-regmoves ๐Ÿƒโ€โ™€๏ธ โ€” performs more aggressive SMS-based modulo scheduling and allows register moves. Setting this flag deletes certain anti-dependence edges, which triggers generation of reg-moves based on the life-range analysis. This only works when -fmodulo-sched is also enabled. ๐Ÿ”—
  • -fno-branch-count-reg ๐Ÿ”ข โ€” disables the optimization pass that hunts for chances to use "decrement and branch" instructions on a count register. Instead of decrementing a register, comparing it against zero, and then branching based on the result, you get the count-register version. This only matters on architectures that support such instructions, which include x86, PowerPC, IA-64 and S/390. ๐Ÿ–ฅ๏ธ

Note that -fno-branch-count-reg doesn't remove the decrement and branch instructions that other optimization passes already put into the generated instruction stream. ๐Ÿซถ

The default is -fbranch-count-reg at -O1 and higher, except for -Og. ๐ŸŒธ

  • -fno-function-cse ๐Ÿ™ƒ โ€” doesn't put function addresses into registers. Instead, every instruction that calls a constant function contains that function's address explicitly. ๐Ÿ“
This gives you less efficient code, but some strange hacks that alter the assembler output may get confused by the optimizations you get when this option is not used. So, know your hacks. ๐Ÿงช

The default is -ffunction-cse. ๐Ÿ’œ

  • -fno-zero-initialized-in-bss ๐Ÿ›๏ธ โ€” if the target supports a BSS section, GCC normally puts variables that are initialized to zero into BSS, which can save space in the resulting code. This option turns that behaviour off, because some programs explicitly rely on variables going into the data section. For example, a program might want to find the beginning of that section, or make assumptions based on it. ๐Ÿงญ

The default is -fzero-initialized-in-bss. ๐Ÿ“

  • -fthread-jumps ๐Ÿงต โ€” performs optimizations that check whether a jump branches to a location where another comparison, subsumed by the first, is found. If it is, the first branch gets redirected to either the destination of the second branch or to the point right after it, depending on whether the condition is known to be true or false. ๐Ÿชก

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

  • -fsplit-wide-types ๐Ÿช“ โ€” when a type occupies multiple registers (like "long long" on a 32-bit system), this splits the registers apart and allocates them independently. This usually generates better code for those types, but it may make debugging harder. Tradeoffs, bestie. ๐Ÿฅฒ

Enabled at levels -O1, -O2, -O3, -Os. ๐Ÿซง

  • -fsplit-wide-types-early โฐ โ€” fully splits wide types early, instead of very late. This does nothing unless -fsplit-wide-types is turned on. It's the default on some targets. ๐ŸŽฏ
  • -fcse-follow-jumps ๐Ÿƒ โ€” during common subexpression elimination (CSE), it scans through jump instructions when the jump's target isn't reached by any other path. For example, when CSE meets an "if" statement with an "else" clause, it follows the jump when the tested condition is false. ๐Ÿ‘€

Enabled at levels -O2, -O3, -Os. ๐Ÿ’…

  • -fcse-skip-blocks ๐Ÿฆ˜ โ€” similar to -fcse-follow-jumps, but it makes CSE follow jumps that conditionally skip over blocks. When CSE hits a simple "if" statement with no "else" clause, -fcse-skip-blocks has CSE follow the jump around the body of the "if". Slick. ๐Ÿ’–

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

  • -frerun-cse-after-loop ๐Ÿ” โ€” re-runs common subexpression elimination after the loop optimizations have been performed. Second chances are everything. ๐Ÿฅฐ

Enabled at levels -O2, -O3, -Os. โญ

  • -fgcse โ€” ๐Ÿ” Okay so this turns on a global common subexpression elimination pass, and it also does global constant and copy propagation. It's giving "stop redoing the same work" energy โœจ. Note: if you're compiling a program that uses computed gotos (a GCC extension), you might get better run-time performance by turning this pass off with -fno-gcse on the command line ๐Ÿ’…. Enabled at levels -O2, -O3, -Os.
  • -fgcse-lm โ€” ๐ŸŒธ When this is on, global common subexpression elimination tries to move loads that only get killed by stores into themselves. So a loop with a load/store sequence can get its load moved outside the loop, with a copy/store inside the loop. Lowkey iconic ๐Ÿฆ‹. Enabled by default when -fgcse is enabled.
  • -fgcse-sm โ€” ๐Ÿงน This runs a store motion pass right after global common subexpression elimination, and it tries to move stores out of loops. If you pair it with -fgcse-lm, a loop 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 โ€” ๐Ÿ’œ This one eliminates redundant loads that happen after stores to the same memory location, covering both partial and full redundancies. Not enabled at any optimization level.
  • -fgcse-after-reload โ€” ๐Ÿงฝ This runs a redundant load elimination pass after reload, and its whole job is cleaning up redundant spilling. Enabled by -O3, -fprofile-use and -fauto-profile.
  • -faggressive-loop-optimizations โ€” ๐Ÿ” The loop optimizer uses language constraints to figure out bounds for a loop's number of iterations. This assumes loop code does not invoke undefined behavior, like signed integer overflows or out-of-bound array accesses, so be careful with that ๐Ÿ˜ฌ. The bounds guide loop unrolling, loop peeling, and loop exit test optimizations. Enabled by default.
  • -funconstrained-commons โ€” ๐Ÿ“ฆ This tells the compiler that variables declared in common blocks (like in Fortran) might later get overridden with longer trailing arrays. It stops certain optimizations that depend on knowing the array bounds ๐Ÿ™ˆ.
  • -fcrossjumping โ€” ๐Ÿ”— This does the cross-jumping transformation, which unifies equivalent code and saves code size. The result may or may not perform better than without it, so it's not a guaranteed win ๐Ÿคทโ€โ™€๏ธ. Enabled at levels -O2, -O3, -Os.
  • -fauto-inc-dec โ€” โž• This combines increments or decrements of addresses with memory accesses. It's 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 โ€” ๐Ÿ—‘๏ธ This does dead code elimination (DCE) on RTL. Enabled by default at -O1 and higher.
  • -fdse โ€” ๐Ÿงผ This does dead store elimination (DSE) on RTL. Enabled by default at -O1 and higher.
  • -fif-conversion โ€” ๐Ÿ”€ This tries to transform conditional jumps into branch-less equivalents. That includes conditional moves, min, max, set flags, abs instructions, and some tricks you can do with standard arithmetic ๐Ÿงฎ. Whether conditional execution gets used on chips that have it is controlled by -fif-conversion2. Enabled at levels -O1, -O2, -O3, -Os, but not with -Og.
  • -fif-conversion2 โ€” โšก This uses conditional execution (where the hardware has it) to transform conditional jumps into branch-less equivalents. Enabled at levels -O1, -O2, -O3, -Os, but not with -Og.
  • -fdeclone-ctor-dtor โ€” ๐Ÿ‘ฏ Okay, the C++ ABI needs multiple entry points for constructors and destructors: one for a base subobject, one for a complete object, and one for a virtual destructor that calls operator delete afterwards. With virtual bases, the base and complete variants end up as clones, which means two copies of the function. With this option, those variants become thunks that call one common implementation ๐Ÿงš. Enabled by -Os.
  • -fdelete-null-pointer-checks โ€” ๐Ÿšซ This assumes programs can't safely dereference null pointers, and that no code or data element lives at address zero. It turns on simple constant folding optimizations at all optimization levels. Other GCC passes use this flag to run global dataflow analyses that remove useless null pointer checks. Those analyses assume that touching address zero always traps, so if a pointer gets checked after it's already been dereferenced, it can't be null ๐Ÿ’€.
โš ๏ธ Heads up: in some environments this assumption isn't true. If your program depends on that behavior, use -fno-delete-null-pointer-checks to turn this optimization off.

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

  • -fdevirtualize โ€” ๐ŸŽฏ This tries to convert calls to virtual functions into direct calls. It happens both within a procedure and interprocedurally, as part of indirect inlining (-findirect-inlining) and interprocedural constant propagation (-fipa-cp). Enabled at levels -O2, -O3, -Os.
  • -fdevirtualize-speculatively โ€” ๐Ÿ”ฎ This tries to convert virtual function calls into speculative direct calls. Based on the type inheritance graph, GCC figures out the likely targets for a given call. If that set is small (ideally size 1), the call becomes a conditional that picks between a direct call and an indirect call. Those speculative calls unlock more optimizations, like inlining. If they turn out to be useless after further optimization, they get converted back to their original form ๐Ÿ”„.
  • -fdevirtualize-at-ltrans โ€” ๐Ÿšš This streams extra information needed for aggressive devirtualization when the link-time optimizer runs in local transformation mode. It enables more devirtualization, but it significantly increases the size of the streamed data, so it's disabled by default ๐Ÿ“‰.
  • -fexpensive-optimizations โ€” ๐Ÿ’ธ This performs a bunch of minor optimizations that are relatively expensive. Enabled at levels -O2, -O3, -Os.
  • -free โ€” ๐Ÿงน This attempts to remove redundant extension instructions. It's especially helpful on x86-64, which implicitly zero-extends 64-bit registers after writing to their lower 32-bit half ๐Ÿ–ฅ๏ธ. Enabled for Alpha, AArch64 and x86 at levels -O2, -O3, -Os.
  • -fno-lifetime-dse โ€” โณ In C++, an object's value is only affected by changes made during its lifetime. When the constructor begins, the object has an indeterminate value, and any changes made during its lifetime are dead once it's destroyed. Normally dead store elimination takes advantage of this. If your code relies on the object's storage value sticking around beyond the object's lifetime, use this flag to turn that optimization off ๐Ÿ™…โ€โ™€๏ธ. If you want to keep stores before the constructor starts (for example, because your operator new clears the object storage) but still treat the object as dead after the destructor, use -flifetime-dse=1. The default can be picked explicitly with -flifetime-dse=2. And -flifetime-dse=0 is the same as -fno-lifetime-dse.
  • -flive-range-shrinkage โ€” ๐Ÿ“‰ This tries to reduce register pressure through register live range shrinkage. It's helpful for fast processors with small or moderate-sized register sets ๐ŸŽ๏ธ.
  • -fira-algorithm=algorithm โ€” ๐ŸŽจ This uses the specified coloring algorithm for the integrated register allocator. algorithm 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 on the targets that do support it, it's the default because it generates better code ๐Ÿ‘‘.
  • -fira-region=region โ€” ๐Ÿ—บ๏ธ This uses the specified regions for the integrated register allocator. The region argument should be one of the following:
    • all โ€” uses all loops as register allocation regions. This can give the best results for machines with a small and/or irregular register set.
    • mixed โ€” uses all loops except loops with small register pressure as the regions. This value usually gives the best results in most cases and for most architectures, and it's enabled by default when you compile 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 โ€” ๐Ÿ—๏ธ This uses IRA to evaluate register pressure in the code hoisting pass when deciding whether to hoist expressions. It usually results in smaller code, but it can slow the compiler down ๐Ÿข. Enabled at level -Os for all targets.
  • -fira-loop-pressure โ€” ๐Ÿ”„ This uses IRA to evaluate register pressure in loops when deciding whether to move loop invariants. It usually generates faster and smaller code on machines with large register files (>= 32 registers), but it can also slow the compiler down. Enabled at level -O3 for some targets ๐ŸŒˆ.
  • -fno-ira-share-save-slots โ€” ๐Ÿšซ This 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 โ€” ๐Ÿšซ This 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 too ๐Ÿฅฒ.
  • -flra-remat โ€” โ™ป๏ธ This enables CFG-sensitive rematerialization in LRA. Instead of loading the values of spilled pseudos, LRA tries to rematerialize (recalculate) them when that's profitable. Enabled at levels -O2, -O3, -Os.
  • -fdelayed-branch โ€” ๐Ÿฆฅ If the target machine supports it, this attempts to reorder instructions so it can use the instruction slots available after delayed branch instructions. Enabled at levels -O1, -O2, -O3, -Os, but not at -Og.
  • -fschedule-insns โ€” okay so if the target machine supports it, GCC tries to shuffle instructions around so the CPU isn't just sitting there waiting on data that isn't ready yet ๐Ÿ’… This is clutch for machines with slow floating point or memory load instructions, because other instructions can get issued while the load or float op is still cooking. Enabled at levels -O2, -O3. ๐Ÿฆ‹
  • -fschedule-insns2 โ€” basically the same energy as -fschedule-insns, but it gets a second scheduling pass after register allocation is done ๐Ÿ”ฅ It's especially iconic on machines with a relatively small number of registers, where memory loads take more than one cycle. Enabled at levels -O2, -O3, -Os.

  • -fno-sched-interblock โ€” the vibe here is "no scheduling across basic blocks" ๐Ÿ™…โ€โ™€๏ธ Normally this is on when scheduling happens before register allocation, so either -fschedule-insns or -O2 or higher turns it on.
  • -fno-sched-spec โ€” this one shuts off speculative motion of non-load instructions ๐Ÿšซ Also normally on when scheduling happens before register allocation, meaning -fschedule-insns or -O2 or higher.
  • -fsched-pressure โ€” this turns on register pressure sensitive insn scheduling before register allocation ๐Ÿง โœจ It only makes sense when that pre-allocation scheduling is on (so -fschedule-insns or -O2 or higher). It can make the generated code better and smaller by keeping register pressure from climbing past the number of available hard registers, which means fewer spills in register allocation. Main character energy, honestly ๐Ÿ‘‘
  • -fsched-spec-load โ€” allows speculative motion of some load instructions ๐ŸŽ€ Only makes sense when scheduling before register allocation, so -fschedule-insns or -O2 or higher.
  • -fsched-spec-load-dangerous โ€” the bolder sister of the one above, letting speculative motion of more load instructions ๐Ÿ’€ Same deal: only makes sense when scheduling before register allocation, so -fschedule-insns or -O2 or higher.
  • -fsched-stalled-insns, -fsched-stalled-insns=n โ€” this decides how many insns (if any) can get moved early from the queue of stalled insns into the ready list during the second scheduling pass ๐Ÿ“ -fno-sched-stalled-insns means nothing gets moved early, and -fsched-stalled-insns=0 means there's no limit on how many queued insns can jump the line. 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 controls how many insn groups (cycles) get checked for a dependency on a stalled insn that's a candidate for early removal from the stalled queue ๐Ÿ” It only has an effect during the second scheduling pass, and only if -fsched-stalled-insns is being used. -fno-sched-stalled-insns-dep is equivalent to -fsched-stalled-insns-dep=0, and -fsched-stalled-insns-dep with no value is equivalent to -fsched-stalled-insns-dep=1. ๐Ÿซถ
  • -fsched2-use-superblocks โ€” when scheduling after register allocation, this uses superblock scheduling ๐ŸŒˆ That lets instructions move across basic block boundaries, which can give you faster schedules.
โš ๏ธ Heads up bestie: this one is experimental! Not every machine description GCC uses models the CPU closely enough to avoid unreliable results from the algorithm, so be careful with it ๐Ÿ˜ญ

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


  • -fsched-group-heuristic โ€” turns on the group heuristic in the scheduler, which favors the instruction that belongs to a schedule group ๐Ÿงš It's on by default whenever scheduling is enabled, so -fschedule-insns or -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, so -fschedule-insns or -fschedule-insns2 or -O2 or higher.
  • -fsched-spec-insn-heuristic โ€” enables the speculative instruction heuristic, which favors speculative instructions with greater dependency weakness ๐Ÿฆ„ On by default whenever scheduling is enabled, so -fschedule-insns or -fschedule-insns2 or -O2 or higher.
  • -fsched-rank-heuristic โ€” enables the rank heuristic, which favors the instruction living in a basic block with greater size or frequency ๐Ÿ“ˆ On by default whenever scheduling is enabled, so -fschedule-insns or -fschedule-insns2 or -O2 or higher.
  • -fsched-last-insn-heuristic โ€” enables the last-instruction heuristic, which favors the instruction that's less dependent on the last instruction scheduled ๐Ÿ’œ On by default whenever scheduling is enabled, so -fschedule-insns or -fschedule-insns2 or -O2 or higher.
  • -fsched-dep-count-heuristic โ€” enables the dependent-count heuristic, which favors the instruction that has more instructions depending on it ๐Ÿ‘ฏ On by default whenever scheduling is enabled, so -fschedule-insns or -fschedule-insns2 or -O2 or higher.

  • -freschedule-modulo-scheduled-loops โ€” modulo scheduling happens before the traditional scheduling, and if a loop got modulo scheduled, later scheduling passes might change its schedule ๐Ÿ”„ Use this option to control that behavior, bestie.
  • -fselective-scheduling โ€” schedules instructions using the selective scheduling algorithm ๐ŸŽฏ It runs instead of the first scheduler pass.
  • -fselective-scheduling2 โ€” same selective scheduling algorithm, but this one runs instead of the second scheduler pass ๐ŸŽฏ
  • -fsel-sched-pipelining โ€” enables software pipelining of the innermost loops during selective scheduling ๐ŸŒ€ This does nothing unless -fselective-scheduling or -fselective-scheduling2 is turned on.
  • -fsel-sched-pipelining-outer-loops โ€” when pipelining loops during selective scheduling, this also pipelines the outer loops too ๐Ÿช† It has no effect unless -fsel-sched-pipelining is turned on.

  • -fsemantic-interposition โ€” okay so some object formats, like ELF, let the dynamic linker swap out symbols (that's "interposing") ๐Ÿ™ˆ That means for symbols exported from the DSO, the compiler can't do interprocedural propagation, inlining, or other optimizations, because the function or variable might get changed out from under it. This is super useful for stuff like swapping in a debugging version of memory allocation functions, but it's expensive in terms of code quality ๐Ÿ˜ฉ With -fno-semantic-interposition, the compiler assumes that if interposition does happen for functions, the overwriting function will have precisely the same semantics (and side effects). Same idea for variables: the constructor of the variable will be the same. This flag has no effect on functions explicitly declared inline (where interposition is never allowed to change semantics), or on symbols explicitly declared weak.
  • -fshrink-wrap โ€” emits function prologues only before the parts of the function that actually need them, instead of at the very top ๐ŸŽ€ Enabled by default at -O and higher.
  • -fshrink-wrap-separate โ€” shrink-wraps the parts of the prologue and epilogue separately, so each part only runs when it's needed ๐Ÿงผ This is on by default, but it has no effect unless -fshrink-wrap is also turned on and the target supports this.
  • -fcaller-saves โ€” enables allocation of values to registers that get clobbered by function calls, by emitting extra instructions to save and restore those registers around the calls ๐Ÿ’พ This allocation only happens when it seems to give better code. It's always enabled by default on certain machines, usually the ones with no call-preserved registers to use instead. Enabled at levels -O2, -O3, -Os.
  • -fcombine-stack-adjustments โ€” tracks stack adjustments (pushes and pops) and stack memory references, then tries to find ways to combine them ๐Ÿฅž Enabled by default at -O1 and higher.
  • -fipa-ra โ€” lets the compiler use caller save registers for allocation if none of the called functions use those registers โœจ That means you don't have to save and restore them around calls. This is only possible if the called functions are part of the same compilation unit as the current function and get compiled before it. It's enabled at levels -O2, -O3, -Os, however it's turned 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 (this happens on targets that don't expose prologues and epilogues in RTL) ๐Ÿ™…โ€โ™€๏ธ
  • -fconserve-stack โ€” tries to minimize stack usage, even if the program ends up slower because of it ๐Ÿข This option implies setting the large-stack-frame parameter to 100 and the large-stack-frame-growth parameter to 400.

  • -ftree-reassoc โ€” performs reassociation on trees ๐ŸŒณ Enabled by default at -O1 and higher.
  • -fcode-hoisting โ€” performs code hoisting, which tries to move the evaluation of expressions that run on all paths to the function exit as early as possible ๐Ÿš€ It's especially useful as a code size optimization, but it often helps code speed too. Enabled by default at -O2 and higher.
  • -ftree-pre โ€” performs partial redundancy elimination (PRE) on trees ๐Ÿงน Enabled by default at -O2 and -O3.
  • -ftree-partial-pre โ€” makes partial redundancy elimination (PRE) more aggressive ๐Ÿ˜ค Enabled by default at -O3.
  • -ftree-forwprop โ€” performs forward propagation on trees โžก๏ธ Enabled by default at -O1 and higher.
  • -ftree-fre โ€” performs full redundancy elimination (FRE) on trees ๐Ÿ” The difference between FRE and PRE is that FRE only considers expressions that are computed on all paths leading to the redundant computation. That makes the analysis faster than PRE, though it exposes fewer redundancies. Enabled by default at -O1 and higher.
  • -ftree-phiprop โ€” performs hoisting of loads from conditional pointers on trees ๐Ÿช„ This pass is enabled by default at -O1 and higher.
  • -fhoist-adjacent-loads โ€” okay so this one speculatively hoists loads from both branches of an if-then-else, but only when the loads grab adjacent spots in the same structure and the target architecture has a conditional move instruction ๐Ÿ‘‘. It's on by default at -O2 and higher โœจ.
  • -ftree-copy-prop โ€” copy propagation on trees ๐Ÿ’…, which cleans up all the unnecessary copy operations so your code stops carrying dead weight ๐Ÿซถ. Enabled by default at -O1 and higher.
  • -fipa-pure-const โ€” finds out which functions are pure or constant ๐Ÿ”ฎ. Enabled by default at -O1 and higher.
  • -fipa-reference โ€” figures out which static variables never escape the compilation unit ๐ŸŒธ. Enabled by default at -O1 and higher.
  • -fipa-reference-addressable โ€” spots 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 whenever it can ๐Ÿงš. Enabled by default.
  • -fipa-pta โ€” does interprocedural pointer analysis and interprocedural modification and reference analysis ๐Ÿง .
๐Ÿ’€ Heads up bestie: this one can eat excessive memory and compile-time on large compilation units. It is not enabled by default at any optimization level.
  • -fipa-profile โ€” propagates profile info across functions โœจ. The functions called only from cold functions get marked as cold, and functions executed once (such as "cold", "noreturn", static constructors or destructors) get identified ๐ŸงŠ. Cold functions and loop-less parts of functions executed once then get optimized for size ๐Ÿ“. Enabled by default at -O1 and higher.
  • -fipa-modref โ€” interprocedural mod/ref analysis, which figures out the side effects of functions (the memory locations they modify or reference) so the compiler can optimize across the function call boundary ๐Ÿ’œ. This flag is enabled by default at -O1 and higher.
  • -fipa-cp โ€” interprocedural constant propagation ๐Ÿ”ฅ. It checks when values passed to functions are constants and optimizes accordingly, and it can seriously boost performance if your app passes constants into functions ๐Ÿš€. This flag is enabled by default at -O2, -Os and -O3. It is also enabled by -fprofile-use and -fauto-profile.
  • -fipa-cp-clone โ€” function cloning to make interprocedural constant propagation stronger ๐Ÿงฌ. When enabled, it clones functions when an externally visible function can be called with constant arguments. Since this can create multiple copies of functions, it may significantly increase code size (see --param ipa-cp-unit-growth=value) ๐Ÿ“ˆ. This flag is enabled by default at -O3. It is also enabled by -fprofile-use and -fauto-profile.
  • -fipa-bit-cp โ€” when enabled, does interprocedural bitwise constant propagation ๐ŸŽ€. This flag is enabled by default at -O2 and by -fprofile-use and -fauto-profile. It requires that -fipa-cp is enabled.
  • -fipa-vrp โ€” when enabled, does interprocedural propagation of value ranges ๐ŸŒˆ. This flag is 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 may disturb unwind stacks by swapping a function out for an equivalent one with a different name ๐Ÿ™ˆ. It works more effectively with link-time optimization enabled.

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

This flag is enabled by default at -O2 and -Os.

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

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

The impacted functions are determined by the compiler's interprocedural optimizations. For example, a caller is impacted when inlining a function into its caller, cloning a function and changing its caller to call this new clone, or extracting a function's pureness/constness information to optimize its direct or indirect callers, etc.

Usually, the more IPA optimizations enabled, the larger the number of impacted functions for each function. To keep that number under control and make the list of impacted functions easier to compute, IPA optimizations can be partially enabled at two different levels ๐ŸŽฏ.

The level argument should be one of the following:

  • inline-clone โ€” only enables inlining and cloning optimizations, which includes inlining, cloning, interprocedural scalar replacement of aggregates and partial inlining ๐Ÿ’–. As a result, when patching a function, all its callers and its clones' callers are impacted, so they need to be patched as well.

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

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

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

When -flive-patching is specified without any value, the default value is inline-clone โœจ. This flag is disabled by default.

Note that -flive-patching is not supported with link-time optimization (-flto) ๐Ÿ™…โ€โ™€๏ธ.

  • -fisolate-erroneous-paths-dereference โ€” 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. This flag is enabled by default at -O2 and higher, and it depends on -fdelete-null-pointer-checks also being enabled.
  • -fisolate-erroneous-paths-attribute โ€” detects paths that trigger erroneous or undefined behavior because a null value is used in a way forbidden by a "returns_nonnull" or "nonnull" attribute ๐Ÿซฃ. It isolates those paths from the main control flow and turns the statement into a trap. This is not currently enabled, but may be enabled by -O2 in the future.
  • -ftree-sink โ€” performs forward store motion on trees ๐Ÿ›ผ. This flag is enabled by default at -O1 and higher.
  • -ftree-bit-ccp โ€” performs sparse conditional bit constant propagation on trees and propagates pointer alignment information ๐Ÿ”. This pass only operates on local scalar variables and is enabled by default at -O1 and higher, except for -Og. It requires that -ftree-ccp is enabled.
  • -ftree-ccp โ€” performs sparse conditional constant propagation (CCP) on trees ๐Ÿงน. This pass only operates on local scalar variables and is enabled by default at -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. This flag is enabled by default at -O1 and higher.
  • -fssa-phiopt โ€” does pattern matching on SSA PHI nodes to optimize conditional code ๐Ÿงฉ. This pass is enabled by default at -O1 and higher, except for -Og.
  • -ftree-switch-conversion โ€” converts simple initializations in a switch into initializations from a scalar array ๐Ÿญ. This flag is enabled by default at -O2 and higher.
  • -ftree-tail-merge โ€” looks for identical code sequences, and when it finds them, replaces one with a jump to the other ๐Ÿช„. This optimization is known as tail merging or cross jumping. This flag is enabled by default at -O2 and higher. The compilation time in this pass can be limited using the max-tail-merge-comparisons parameter and the max-tail-merge-iterations parameter.
  • -ftree-dce โ€” dead code elimination (DCE) on trees ๐Ÿ’€. This flag is 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 ๐ŸŒท. This flag is enabled by default at -O2 and higher if -Os is not also specified.
  • -ffinite-loops โ€” assumes that a loop with an exit will eventually take the exit and not loop forever ๐Ÿ”„. This lets the compiler 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 โ€” runs 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). This flag is 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 by another store later without any intervening loads, so the earlier store can be deleted. This flag is enabled by default at -O1 and higher.
  • -ftree-ch โ€” loop header copying on trees ๐ŸŽถ. This is beneficial because it increases the effectiveness of code motion optimizations, and it also saves one jump. This flag is enabled by default at -O1 and higher. It is not enabled for -Os, since it usually increases code size.
  • -ftree-loop-optimize โ€” loop optimizations on trees ๐Ÿ”โœจ. This flag is enabled by default at -O1 and higher.
  • -ftree-loop-linear, -floop-strip-mine, -floop-block โ€” okay bestie, these three share one description ๐Ÿฆ‹ They all do loop nest optimizations, and it's literally the same as -floop-nest-optimize โœจ To use this code transformation, GCC has to be configured with --with-isl so the Graphite loop transformation infrastructure is switched on ๐Ÿ’…
  • -fgraphite-identity โ€” this one is giving science experiment ๐Ÿงช It enables the identity transformation for graphite. For every SCoP, GCC generates the polyhedral representation and then transforms it back to gimple. Using -fgraphite-identity lets you check the costs or benefits of the GIMPLE -> GRAPHITE -> GIMPLE transformation ๐Ÿ“Š Some minimal optimizations also happen in the code generator isl, like index splitting and dead code elimination in loops ๐Ÿงน
  • -floop-nest-optimize โ€” the isl based loop nest optimizer, and it is so iconic ๐Ÿ‘‘ 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 ๐ŸŒˆ
โš ๏ธ Heads up: this option is experimental, so it's still a little spicy ๐ŸŒถ๏ธ
  • -floop-parallelize-all โ€” uses the Graphite data dependence analysis to identify loops that can be parallelized ๐Ÿงต It parallelizes all the loops that can be analyzed to not contain loop carried dependences, but it does this without checking that it is profitable to parallelize the loops ๐Ÿ’€
  • -ftree-coalesce-vars โ€” while GCC transforms the program out of the SSA representation, this one tries to reduce copying by coalescing versions of different user-defined variables, not just compiler temporaries ๐Ÿซถ It may severely limit your ability to debug an optimized program compiled with -fno-var-tracking-assignments, so keep that in mind ๐Ÿ™ˆ In the negated form, this flag prevents SSA coalescing of user variables. It's enabled by default if optimization is enabled, and it does very little otherwise ๐ŸŒธ
  • -ftree-loop-if-convert โ€” attempts to transform conditional jumps in the innermost loops into branch-less equivalents. The goal is to remove control-flow from the innermost loops so the vectorization pass can handle them better โœจ This is enabled by default if vectorization is enabled ๐Ÿฆ‹
  • -ftree-loop-distribution โ€” performs loop distribution, which can improve cache performance on big loop bodies and lets further loop optimizations, like parallelization or vectorization, take place ๐Ÿ“ For example, this loop:
DO I = 1, N
  A(I) = B(I) + C
  D(I) = E(I) * F
ENDDO

is transformed to:

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

This flag is enabled by default at -O3. It is also enabled by -fprofile-use and -fauto-profile ๐Ÿ’œ

  • -ftree-loop-distribute-patterns โ€” performs loop distribution of patterns that can be code generated with calls to a library ๐Ÿ“š This flag is enabled by default at -O2 and higher, and by -fprofile-use and -fauto-profile ๐ŸŒˆ

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

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

is transformed to:

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

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

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

is transformed to:

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

This flag is enabled by default at -O3. It 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 ๐Ÿซถ This flag is enabled by default at -O3. It is also enabled by -fprofile-use and -fauto-profile ๐Ÿ”ฅ
  • -ftree-loop-im โ€” performs loop invariant motion on trees ๐Ÿƒโ€โ™€๏ธ This pass only moves invariants that are hard to handle at RTL level, like function calls or operations that expand to 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 is modified in a loop in such a way that its value when exiting the loop can be determined using only its initial value and the number of loop iterations, GCC replaces uses of the final value with 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, aka splits their iteration space to run in n threads ๐Ÿงต This is only possible for loops whose iterations are independent and can be arbitrarily reordered. The optimization is only profitable on multiprocessor machines, for loops that are CPU-intensive, rather than loops constrained by things like memory bandwidth ๐Ÿ–ฅ๏ธ This option implies -pthread, so it's only supported on targets that have support for -pthread ๐Ÿšซ
  • -ftree-pta โ€” performs function-local points-to analysis on trees. This flag is enabled by default at -O1 and higher, except for -Og ๐Ÿซง
  • -ftree-sra โ€” performs scalar replacement of aggregates ๐Ÿ’Ž This pass replaces structure references with scalars so structures don't get committed to memory too early. This flag is enabled by default at -O1 and higher, except for -Og ๐ŸŒท
  • -fstore-merging โ€” performs merging of narrow stores to consecutive memory addresses ๐Ÿ“ฆ It merges contiguous stores of immediate values that are 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 swapped out at their use location for 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 ๐ŸŒˆ This flag enables -ftree-loop-vectorize and -ftree-slp-vectorize if they aren't explicitly specified ๐Ÿซถ
  • -ftree-loop-vectorize โ€” performs loop vectorization on trees ๐ŸŽ€ This flag is enabled by default at -O2, and by -ftree-vectorize, -fprofile-use, and -fauto-profile ๐Ÿ‘‘
  • -ftree-slp-vectorize โ€” performs basic block vectorization on trees โญ This flag is enabled by default at -O2, and by -ftree-vectorize, -fprofile-use, and -fauto-profile ๐Ÿ”ฅ
  • -ftrivial-auto-var-init=choice โ€” initializes automatic variables with either a pattern or zeroes, to boost the security and predictability of a program by preventing uninitialized memory disclosure and use ๐Ÿ” GCC still considers an automatic variable that doesn't have an explicit initializer to be uninitialized, and -Wuninitialized and -Wanalyzer-use-of-uninitialized-value will still report warnings on those variables ๐Ÿ™ˆ With this option, GCC also initializes any padding of automatic variables that have structure or union types to zeroes ๐Ÿงธ

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, are easily recognized 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 the byte 0xFE. The values used for pattern initialization might be changed in the future โš ๏ธ
  • zero โ€” initializes automatic variables with zeroes ๐Ÿซง

The default is uninitialized ๐Ÿ’…

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 GCC uses for vectorization ๐ŸŽ€ model has to be one of unlimited, dynamic, cheap, or very-cheap โœจ
    • unlimited โ€” the vectorized code path is assumed to be profitable, no cap ๐Ÿ’–
    • 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 ๐Ÿฆ‹
    • cheap โ€” skips vectorizing loops where it would be cost prohibitive, like when it needs runtime checks for data dependence or alignment. Otherwise it's exactly the same as dynamic ๐ŸŒธ
    • very-cheap โ€” only vectorizes if the vector code would entirely replace the scalar code being vectorized. For example, if each vectorized iteration can only handle exactly four iterations of the scalar loop, this model only allows it if the scalar iteration count is known to be a multiple of four ๐Ÿ‘‘

The default cost model depends on other optimization flags and is either dynamic or cheap ๐Ÿงš

  • -fsimd-cost-model=model โ€” same energy, but for loops marked with the OpenMP simd directive ๐ŸŒˆ model should be unlimited, dynamic, or cheap. Every value means exactly what it does in -fvect-cost-model, and by default, whatever cost model you set with -fvect-cost-model is the one that gets used ๐Ÿซถ
  • -ftree-vrp โ€” turns on 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 unnecessary range checks, like array bound checks and null pointer checks ๐Ÿ”ฅ Enabled by default at -O2 and higher.

Null pointer check elimination only happens if -fdelete-null-pointer-checks is enabled ๐Ÿ’€

  • -fsplit-paths โ€” splits paths leading to loop backedges ๐Ÿฆ‹ This can improve dead code elimination and common subexpression elimination. Enabled by default at -O3 and above ๐Ÿ’œ
  • -fsplit-ivs-in-unroller โ€” lets the compiler express the values of induction variables in later iterations of an unrolled loop using the value from the first iteration. This breaks up long dependency chains, which improves the efficiency of the scheduling passes ๐ŸŒธ

A combination of -fweb and CSE is often enough to get the same effect, ngl. But it's not reliable when the loop body is more complicated than a single basic block, and it doesn't work at all on some architectures because of restrictions in the CSE pass ๐Ÿ˜ญ

This optimization is enabled by default ๐Ÿ’…

  • -fvariable-expansion-in-unroller โ€” when unrolling a loop, the compiler makes multiple copies of some local variables, which can result in superior code ๐ŸŽ€ This is enabled by default for PowerPC targets, but disabled by default everywhere else ๐ŸŒˆ
  • -fpartial-inlining โ€” inlines parts of functions ๐Ÿงš This only has an effect when inlining itself is turned on by -finline-functions or -finline-small-functions โœจ Enabled at levels -O2, -O3, -Os.
  • -fpredictive-commoning โ€” performs predictive commoning, which means reusing computations (especially memory loads and stores) from previous iterations of loops ๐Ÿ”ฅ Enabled at level -O3. It's also turned on by -fprofile-use and -fauto-profile ๐Ÿ’–
  • -fprefetch-loop-arrays โ€” if the target machine supports it, generates instructions to prefetch memory, so loops that access large arrays can run faster ๐Ÿฆ‹ Heads up, this may make the code better or worse, since the results are highly dependent on how the loops are structured in your source ๐Ÿ™ˆ Disabled at level -Os.
  • -fno-printf-return-value โ€” stops GCC from swapping in constants for the known return values of formatted output functions like sprintf, snprintf, vsprintf, and vsnprintf (but not printf or fprintf) ๐Ÿงš That swap is a whole glow-up: when the arguments are constant, or known to be in a range that pins down the exact return value, GCC can optimize or even eliminate branches based on it ๐Ÿ’… For example, when -fprintf-return-value is in effect, both the branch and the body of the if statement (but not the call to snprint) can be optimized away when i is a 32-bit or smaller integer, because the return value is guaranteed to be at most 8 ๐Ÿคฏ
char buf[9];
if (snprintf (buf, "%08x", i) >= sizeof buf)
  ...

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

  • -fno-peephole, -fno-peephole2 โ€” disables any machine-specific peephole optimizations ๐ŸŒธ The difference between the two is how they're implemented in the compiler. Some targets use one, some use the other, and a few use both ๐Ÿซถ

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

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

GCC uses heuristics to guess branch probabilities when profiling feedback (-fprofile-arcs) doesn't provide them. These heuristics are based on the control flow graph. If some branch probabilities are specified by __builtin_expect, the heuristics guess 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 complicated, so sometimes it helps to turn the heuristics off, so the effects of __builtin_expect are easier to understand ๐Ÿง 

You can also specify the expected probability of an expression with the __builtin_expect_with_probability built-in function โœจ

The default is -fguess-branch-probability at levels -O, -O2, -O3, -Os ๐ŸŽ€

  • -freorder-blocks โ€” reorders basic blocks in the compiled function to cut down on 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. algorithm can be simple, which doesn't increase code size (except sometimes through secondary effects like alignment), or stc, the "software trace cache" algorithm. stc tries to put all the often-executed code together, minimizing the number of branches executed by making extra copies of code ๐Ÿงš

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

  • -freorder-blocks-and-partition โ€” on top of reordering basic blocks to cut down on taken branches, this splits hot and cold basic blocks into separate sections of the assembly and .o files, for better paging and cache locality ๐ŸŒˆ

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

Enabled for x86 at levels -O2, -O3, -Os โœจ

  • -freorder-functions โ€” reorders functions in the object file to improve code locality ๐Ÿฆ‹ This uses special subsections: .text.hot for the most frequently executed functions, and .text.unlikely for unlikely executed ones. The linker does the reordering, so the object file format has to support named sections and the linker has to place them in a reasonable way ๐Ÿ”ง

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

Enabled at levels -O2, -O3, -Os ๐ŸŒธ


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

Pay special attention to code like this:

union a_union {
  int i;
  double d;
};

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

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

int f() {
  union a_union t;
  int* ip;
  t.d = 3.0;
  ip = &t.i;
  return *ip;
}
๐Ÿ’€ Similarly, access by taking the address, casting the resulting pointer and dereferencing the result has undefined behavior, even if the cast uses a union type, e.g.:
int f() {
  double d = 3.0;
  return ((union a_union *) &d)->i;
}

The -fstrict-aliasing option is enabled at levels -O2, -O3, -Os ๐Ÿ’œ

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

This option is enabled by default and is only effective in combination with -fstrict-aliasing โœจ

  • -falign-functions, -falign-functions=n, -falign-functions=n:m, -falign-functions=n:m:n2, -falign-functions=n:m:n2:m2 โ€” bestie, this one lines up the start of every function ๐ŸŽ€ It snaps the start to the next power-of-two that's >= n, and it's allowed to skip up to m-1 bytes to get there. The payoff is that at least the first m bytes of the function can be fetched by the CPU without crossing an n-byte alignment boundary. So cute โœจ
    • 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, and -falign-functions=32:7 aligns to the next 32-byte boundary only if that can be done by skipping 6 bytes or less.
    • The second pair, n2:m2, gives you a secondary alignment ๐Ÿ’œ For example, -falign-functions=64:7:32:3 aligns to the next 64-byte boundary if that can be done by skipping 6 bytes or less, otherwise it aligns to the next 32-byte boundary if that can be done by skipping 2 bytes or less. If m2 isn't specified, it defaults to n2.
    • Some assemblers only support this flag when n is a power of two. In that case, n gets rounded up.
    • -fno-align-functions and -falign-functions=1 are equivalent and mean functions are not aligned.
    • If n isn't specified or is zero, the compiler uses a machine-dependent default. The maximum allowed n value is 65536.
    • Enabled at levels -O2, -O3 ๐Ÿ”ฅ
  • -flimit-function-alignment โ€” okay this one is giving restraint ๐Ÿงš If it's on, the compiler tries to avoid overaligning functions for no reason. 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.
  • -falign-labels, -falign-labels=n, -falign-labels=n:m, -falign-labels=n:m:n2, -falign-labels=n:m:n2:m2 โ€” this one aligns all branch targets to a power-of-two boundary ๐ŸŒธ Its parameters work the same way as -falign-functions.
    • -fno-align-labels and -falign-labels=1 are equivalent and mean labels are not 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, you get a machine-dependent default that is very likely to be 1, which means no alignment. The maximum allowed n value is 65536.
    • Enabled at levels -O2, -O3 ๐Ÿ’–
  • -falign-loops, -falign-loops=n, -falign-loops=n:m, -falign-loops=n:m:n2, -falign-loops=n:m:n2:m2 โ€” aligns loops to a power-of-two boundary ๐Ÿฆ‹ If the loops run many times, the speed-up makes up for any execution of the dummy padding instructions. Literally worth it.
    • If -falign-labels is greater than this value, its value is used instead.
    • Parameters work the same as -falign-functions. -fno-align-loops and -falign-loops=1 are equivalent and mean loops are not aligned. The maximum allowed n value is 65536.
    • If n isn't specified or is zero, the compiler uses a machine-dependent default.
    • Enabled at levels -O2, -O3 โœจ
  • -falign-jumps, -falign-jumps=n, -falign-jumps=n:m, -falign-jumps=n:m:n2, -falign-jumps=n:m:n2:m2 โ€” aligns branch targets to a power-of-two boundary, but only for branch targets that can only be reached by jumping ๐Ÿงš In this case, no dummy operations need to run, so it's extra lowkey efficient.
    • If -falign-labels is greater than this value, its value is used instead.
    • Parameters are analogous to -falign-functions. -fno-align-jumps and -falign-jumps=1 are equivalent and mean that loops are not aligned ๐Ÿ™ˆ (yes, the page literally says loops there, even though this is the jumps flag, so keep that in mind).
    • If n isn't specified or is zero, the compiler uses a machine-dependent default. The maximum allowed n value is 65536.
    • Enabled at levels -O2, -O3 ๐Ÿ’…
  • -fno-allocation-dce โ€” do not remove unused C++ allocations during dead code elimination. Keep those allocations, babe ๐Ÿ’œ
  • -fallow-store-data-races โ€” this one is a risky flex ๐Ÿ’€ It lets the compiler do optimizations that might introduce new data races on stores, without proving that the variable can't be accessed by other threads at the same time. It doesn't touch optimization of local data.
    • It's safe to use if you already know global data won't be accessed by multiple threads.
    • Examples of optimizations it enables include hoisting or if-conversions that might cause a value already in memory to be rewritten with that same value. That rewriting is safe in a single-threaded context but may be unsafe in a multi-threaded one.
    • On some processors, if-conversions may be required to enable vectorization.
    • Enabled at level -Ofast ๐Ÿ”ฅ
  • -funit-at-a-time โ€” this one is kept around for compatibility reasons, so it has no effect ๐ŸŒˆ Meanwhile -fno-unit-at-a-time implies -fno-toplevel-reorder and -fno-section-anchors.
    • Enabled by default.
  • -fno-toplevel-reorder โ€” don't reorder top-level functions, variables, and "asm" statements. They come out in the same order they appear in the input file ๐Ÿ“ With this on, unreferenced static variables are not removed. It's mainly there to support existing code that relies on a particular ordering. For new code, it's better to use attributes when possible.
    • -ftoplevel-reorder is the default at -O1 and higher, and also at -O0 if -fsection-anchors is explicitly requested.
    • -fno-toplevel-reorder implies -fno-section-anchors.
  • -fweb โ€” this one builds webs (the way they're commonly used for register allocation) and gives each web its own individual pseudo register ๐Ÿฆ‹ That lets the register allocation pass work on pseudos directly, and it also strengthens 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 โ€” assume the current compilation unit is the whole program being compiled ๐Ÿ‘‘ All public functions and variables become static functions, except main and anything merged by the attribute "externally_visible". Because of that, the interprocedural optimizers can go harder on them.
This option should not be used together with -flto. A linker plugin should give you safer and more precise info instead.
  • -flto[=n] โ€” this is the big one, bestie ๐ŸŒˆ It runs the standard link-time optimizer. When you invoke it with source code, GCC 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 from those ELF sections and instantiated as if they were part of the same translation unit. Main character energy โœจ

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

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

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

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

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

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

The important thing to keep in mind is that you need to use the GCC driver to perform the link step. GCC automatically performs link-time optimization if any of the objects involved were compiled with the -flto command-line option. You can always override that automatic decision by passing -fno-lto to the link command ๐Ÿ’…

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

When a file is compiled with -flto and without -fuse-linker-plugin, the generated object file is larger than a regular one, because it contains GIMPLE bytecodes and the usual final code (see -ffat-lto-objects). That means object files with LTO information can be linked as normal object files. If -fno-lto is passed to the linker, no interprocedural optimizations are applied. Note that when -fno-fat-lto-objects is enabled, the compile stage is faster, but you cannot perform a regular, non-LTO link on them ๐Ÿฅฒ

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

Generally, options specified at link time override those specified at compile time, although in some cases GCC attempts to infer link-time options from the settings used to compile the input files.

If you don't pass an optimization level -O at link time, GCC uses the highest optimization level that was used when compiling the object files ๐Ÿ’… ngl, that's usually what you want. BUT ๐Ÿ™ˆ it's generally ineffective to specify -O only at link time and not at compile time, and there are two reasons. First, compiling without optimization suppresses the compiler passes that gather the info needed for good link-time optimization ๐Ÿ’€. Second, some early optimization passes can only run at compile time, not at link time. So do the optimizing at compile time, bestie ๐Ÿซถ

There are some code generation flags that GCC keeps around when it generates bytecode, because they need to be used during the final link ๐Ÿงš Right now, the following options and their settings get taken from the first object file that explicitly specifies them: -fcommon, -fexceptions, -fnon-call-exceptions, -fgnu-tm and all the -m target flags ๐ŸŒธ

The options -fPIC, -fpic, -fpie and -fPIE get combined using this scheme ๐Ÿฆ‹

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

Certain ABI-changing flags have to match in every compilation unit ๐Ÿšซ If you try to override them at link time with a conflicting value, it gets ignored ๐Ÿ™… This includes options like -freg-struct-return and -fpcc-struct-return.

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

Diagnostic options such as -Wstringop-overflow get passed through to the link stage, and their setting matches that of the compile step at function granularity ๐Ÿ‘€ This only matters for diagnostics emitted during optimization. Also, code transforms such as inlining can lead to warnings being enabled or disabled for regions of code that aren't consistent with the setting at compile time ๐Ÿ™ƒ

When you need to pass options to the assembler via -Wa or -Xassembler, make sure you either compile those translation units with -fno-lto, or consistently use the same assembler options on all translation units ๐Ÿงต You can alternatively specify assembler options at LTO link time too ๐Ÿ’ก

To enable debug info generation, you need to supply -g at compile time ๐Ÿ› If any of the input files at link time were built with debug info generation enabled, the link will enable debug info generation as well ๐Ÿ’– Any elaborate debug info settings, like the DWARF level -gdwarf-5, need to be explicitly repeated on the linker command line, and mixing different settings across translation units is discouraged ๐Ÿšฉ

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

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

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

Notice that the final link is done with g++ to get the C++ runtime libraries, and -lgfortran is added to get the Fortran runtime libraries ๐Ÿง  In general, when mixing languages in LTO mode, you should use the same link command options you'd use when mixing languages in a regular (non-LTO) compilation ๐Ÿซถ

If object files containing GIMPLE bytecode are stored in a library archive, say libfoo.a, you can extract and use them in an LTO link if you're using a linker with plugin support ๐Ÿ“ฆ To create static libraries suitable for LTO, use gcc-ar and gcc-ranlib instead of ar and ranlib. To show the symbols of object files with GIMPLE bytecode, use gcc-nm ๐Ÿ” Those commands require that ar, ranlib and nm have been compiled with plugin support. At link time, use the flag -fuse-linker-plugin to make sure the library participates in the LTO optimization process ๐Ÿฆ‹

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

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

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

Link-time optimizations don't require the presence of the whole program to operate ๐ŸŒ If the program doesn't require any symbols to be exported, you can combine -flto and -fwhole-program to let the interprocedural optimizers use more aggressive assumptions, which may lead to better optimization opportunities ๐Ÿ‘‘ Use of -fwhole-program is not needed when the linker plugin is active (see -fuse-linker-plugin).

The current implementation of LTO makes no attempt to generate bytecode that's portable between different types of hosts ๐Ÿ–ฅ๏ธ The bytecode files are versioned with a strict version check, so bytecode generated by one version of GCC does not work with an older or newer version of GCC ๐Ÿ™…

๐Ÿ› Link-time optimization does not work well with generation of debugging information on systems other than those using a combination of ELF and DWARF.

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

You can also specify -flto=jobserver to use GNU make's job server mode to determine the number of parallel jobs ๐Ÿค This is useful when the Makefile calling GCC is already executing in parallel. You must prepend a + to the command recipe in the parent Makefile for this to work. This option likely only works if MAKE is GNU make. Even without the option value, GCC tries to automatically detect a running GNU make's job server ๐Ÿ”Ž

Use -flto=auto to use GNU make's job server, if available, or otherwise fall back to autodetection of the number of CPU threads present in your system ๐Ÿงต


  • -flto-partition=alg โ€” Specify the partitioning algorithm used by the link-time optimizer ๐Ÿงฉ The value is either 1to1 to specify a partitioning mirroring the original source files, or balanced to specify partitioning into equally sized chunks (whenever possible), or max to create a new partition for every symbol where possible. Specifying none as an algorithm disables partitioning and streaming completely. The default value is balanced. While 1to1 can be used as a workaround for various code ordering issues, the max partitioning is intended for internal testing only. The value one specifies that exactly one partition should be used, while the value none bypasses partitioning and executes the link-time optimization step directly from the WPA phase.
  • -flto-compression-level=n โ€” This option sets the level of compression used for the intermediate language written to LTO object files, and it's only meaningful together with LTO mode (-flto) ๐Ÿ—œ๏ธ GCC currently supports two LTO compression algorithms. For zstd, valid values are 0 (no compression) to 19 (maximum compression), while zlib supports values from 0 to 9. Values outside this range are clamped to either the minimum or maximum of the supported values. If the option isn't given, a default balanced compression setting is used.
  • -fuse-linker-plugin โ€” Enables the use of a linker plugin during link-time optimization ๐Ÿ”Œ This option relies on plugin support in the linker, which is available in gold or in GNU ld 2.21 or newer. This option enables the extraction of object files with GIMPLE bytecode out of library archives, which improves the quality of optimization by exposing more code to the link-time optimizer. This information specifies what symbols can be accessed externally (by a non-LTO object or during dynamic linking). Resulting code quality improvements on binaries (and shared libraries that use hidden visibility) are similar to -fwhole-program. See -flto for a description of the effect of this flag and how to use it. This option is enabled by default when LTO support in GCC is enabled and GCC was configured for use with a linker supporting plugins (GNU ld 2.21 or newer or gold).
  • -ffat-lto-objects โ€” Fat LTO objects are object files that contain both the intermediate language and the object code ๐Ÿ” This makes them usable for both LTO linking and normal linking. This option is effective only when compiling with -flto and is ignored at link time. -fno-fat-lto-objects improves compilation time over plain LTO, but requires the complete toolchain to be aware of LTO. It requires a linker with linker plugin support for basic functionality. Additionally, nm, ar and ranlib need to support linker plugins to allow a full-featured build environment (capable of building static libraries etc). GCC provides the gcc-ar, gcc-nm and gcc-ranlib wrappers to pass the right options to these tools. With non-fat LTO, makefiles need to be modified to use them. Note that modern binutils provide a plugin auto-load mechanism. Installing the linker plugin into $libdir/bfd-plugins has the same effect as using the command wrappers (gcc-ar, gcc-nm and gcc-ranlib). The default is -fno-fat-lto-objects on targets with linker plugin support.

-fcompare-elim

okay so this one is a post-register-allocation glow-up ๐Ÿ’… After register allocation and post-register allocation instruction splitting, GCC hunts for arithmetic instructions that set processor flags in a way that works like a comparison. If it can, it deletes the explicit comparison operation โœจ

This pass only applies to certain targets that can't explicitly represent the comparison operation before register allocation is complete. So not every target gets this treatment ๐Ÿ™ˆ

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

-fcprop-registers

bestie, this one is giving copy-propagation energy ๐Ÿฆ‹ After register allocation and post-register allocation instruction splitting, GCC runs a copy-propagation pass. The goal is to reduce scheduling dependencies and, every once in a while, to eliminate the copy entirely ๐ŸŒธ

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

-fprofile-correction

Okay, so profiles collected from an instrumented binary for multi-threaded programs can come out inconsistent because some counter updates got missed ๐Ÿ˜ญ With this option on, GCC uses heuristics to correct or smooth out those inconsistencies. By default, GCC throws an error message when it spots an inconsistent profile.

This option is enabled by -fauto-profile.

-fprofile-partial-training

Here's the vibe: with -fprofile-use, every part of the program that didn't run during the train run gets optimized aggressively for size instead of speed ๐Ÿ“ Sometimes it's not practical to train every possible hot path. For example, a program might contain functions made for specific hardware, and the training might not cover every hardware configuration the program runs on.

With -fprofile-partial-training, profile feedback gets ignored for every function that wasn't executed during the train run. Those functions get optimized as if they were compiled without profile feedback at all. This gives better performance when the train run isn't representative, but it also leads to significantly bigger code ๐Ÿ’œ

-fprofile-use, -fprofile-use=path

main character energy alert ๐Ÿ‘‘ These turn on profile feedback-directed optimizations, plus the following optimizations. Most of them are only really worth it when profile feedback is available:

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

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

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

If you pass a path, GCC looks there for the profile feedback data files. See -fprofile-dir.

-fauto-profile, -fauto-profile=path

this one is sampling-based feedback-directed optimization, and it's obsessed with speed ๐ŸŒˆ It turns on those sampling-based optimizations along with the following ones, which are mostly only worth it when profile feedback is around:

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

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

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

Here's an example:

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

Next, use the create_gcov tool to convert the raw profile data into a format GCC can actually use. You also have to hand this tool the unstripped binary for your program. See https://github.com/google/autofdo ๐ŸŽ€

Here's that example:

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

Next up, the floating-point crew ๐Ÿงฎ These options are all about trading speed against correctness, so it's a vibe check on how precise you need your math to be. None of them turn on by themselves. You have to specifically enable each one you want ๐Ÿ’…

-ffloat-store

This one tells GCC not to keep floating-point variables in registers, and it also blocks other options that might change whether a floating-point value comes from a register or from memory ๐Ÿ™ˆ

It prevents undesirable excess precision on machines like the 68000, where the floating registers (of the 68881) keep more precision than a "double" is supposed to have. The x86 architecture has a similar issue. For most programs, that extra precision is only a good thing, but a few programs depend on the precise definition of IEEE floating point. For those, use -ffloat-store after you've modified the code to store all the important intermediate computations into variables ๐Ÿซถ

-fexcess-precision=style

this lets you have more say over excess precision on machines where floating-point operations happen in a format with more precision or range than the IEEE standard and interchange floating-point types ๐Ÿฆ‹

By default, -fexcess-precision=fast is in effect. That means operations may be carried out in a wider precision than the types in your source if that would make the code faster. It's also unpredictable when rounding to the types in your source actually happens.

When compiling C, if you specify -fexcess-precision=standard, excess precision follows the rules in ISO C99. In particular, both casts and assignments make values round to their semantic types. (-ffloat-store only affects assignments, so this one is stricter ๐Ÿ’œ) This option is enabled by default for C if a strict conformance option such as -std=c99 is used. -ffast-math enables -fexcess-precision=fast by default no matter whether a strict conformance option is used.

-fexcess-precision=standard is not implemented for languages other than 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. In the latter, rounding is unpredictable.

-ffast-math

this is the speed-at-all-costs option ๐ŸŽ๏ธ It sets -fno-math-errno, -funsafe-math-optimizations, -ffinite-math-only, -fno-rounding-math, -fno-signaling-nans, -fcx-limited-range and -fexcess-precision=fast.

It also causes the preprocessor macro __FAST_MATH__ to be defined โœจ

โš ๏ธ This option is not turned on by any -O option besides -Ofast. It can produce incorrect output for programs that depend on an exact implementation of IEEE or ISO rules and specifications for math functions. It may, however, give you 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 run as a single instruction, like sqrt. A program that relies on IEEE exceptions for math error handling might want this flag for speed while still keeping IEEE arithmetic compatibility ๐ŸŒธ

โš ๏ธ This option is not turned on by any -O option. It can produce incorrect output for programs that depend on an exact implementation of IEEE or ISO rules and specifications for math functions. It may, however, give you faster code for programs that don't need the guarantees of those specifications.

The default is -fmath-errno.

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

-funsafe-math-optimizations

this one lets the compiler do floating-point optimizations that (a) assume your arguments and results are valid and (b) might violate IEEE or ANSI standards ๐Ÿ’€ When it's used at link time, it may pull in libraries or startup files that change the default FPU control word or do other similar optimizations.

โš ๏ธ This option is not turned on by any -O option. It can produce incorrect output for programs that depend on an exact implementation of IEEE or ISO rules and specifications for math functions. It may, however, give you faster code for programs that don't need the guarantees of those specifications.

It enables -fno-signed-zeros, -fno-trapping-math, -fassociative-math and -freciprocal-math.

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

-fassociative-math

This allows re-association of operands in series of floating-point operations. It breaks the ISO C and C++ language standards because it can change the computation result ๐Ÿ™ˆ

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

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

The default is -fno-associative-math.

-freciprocal-math

This lets the compiler use the reciprocal of a value instead of dividing by that value, if doing so enables optimizations. For example, x / y can be replaced with x * (1/y), which is useful if (1/y) is subject to common subexpression elimination. Heads up though: this loses precision and increases the number of flops operating on the value ๐Ÿงฎ

The default is -fno-reciprocal-math.

-ffinite-math-only

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

โš ๏ธ This option is not turned on by any -O option. It can produce incorrect output for programs that depend on an exact implementation of IEEE or ISO rules and specifications for math functions. It may, however, give you faster code for programs that don't need the guarantees of those specifications.

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

  • -fno-signed-zeros ๐Ÿ’– โ€” okay so this one tells GCC it can do floating-point optimizations that don't care whether a zero is positive or negative. IEEE arithmetic treats +0.0 and -0.0 as distinct values, which normally stops GCC from simplifying things like x+0.0 or 0.0*x (even with -ffinite-math-only). With this flag, the sign of a zero result basically stops mattering ๐Ÿซถ
    • The default is -fsigned-zeros.
  • -fno-trapping-math ๐Ÿ”ฅ โ€” this one says "pretend floating-point operations can't cause user-visible traps." Those traps are division by zero, overflow, underflow, inexact result, and invalid operation. It only works if -fno-signaling-nans is in effect too. Turning it on can give you faster code if your program relies on "non-stop" IEEE arithmetic, for example โœจ
    • The default is -ftrapping-math.
โš ๏ธ bestie, never turn this on through any -O option! It can give incorrect output for programs that depend on an exact implementation of IEEE or ISO rules/specifications for math functions. Only use it on purpose ๐Ÿ™ˆ
  • -frounding-math ๐ŸŒˆ โ€” this one turns off transformations and optimizations that assume the default floating-point rounding behavior. That default is round-to-zero for all floating-point to integer conversions, and round-to-nearest for all other arithmetic truncations. Use it for programs that change the FP rounding mode dynamically, or that might run with a non-default rounding mode. It also disables constant folding of floating-point expressions at compile time (since rounding mode can change those results) and arithmetic transformations that are unsafe with sign-dependent rounding modes ๐Ÿ’…
    • The default is -fno-rounding-math.
๐Ÿงช this one is experimental, so it doesn't currently guarantee that every GCC optimization affected by rounding mode gets disabled. Future versions of GCC might give finer control over this using C99's FENV_ACCESS pragma. This command-line option will be used to set the default state for FENV_ACCESS.
  • -fsignaling-nans ๐Ÿฆ‹ โ€” compiles your code assuming IEEE signaling NaNs can cause user-visible traps during floating-point operations. Turning it on disables optimizations that might change the number of exceptions you can see with signaling NaNs. It also implies -ftrapping-math ๐Ÿ‘‘
    • This option causes the preprocessor macro __SUPPORT_SNAN__ to be defined.
    • The default is -fno-signaling-nans.
๐Ÿงช also experimental! It doesn't currently guarantee that every GCC optimization affecting signaling NaN behavior gets disabled.
  • -fno-fp-int-builtin-inexact ๐Ÿงš โ€” this stops the built-in functions ceil, floor, round, and trunc (plus their float and long double variants) from generating code that raises the inexact floating-point exception for noninteger arguments. ISO C99 and C11 let these functions raise inexact, but ISO/IEC TS 18661-1:2014 (the C bindings to IEEE 754-2008, as integrated into ISO C2X) doesn't allow it, so this flag is the bestie for that vibe ๐Ÿ’œ
    • The default is -ffp-int-builtin-inexact, which allows the exception to be raised, unless C2X or a later C standard is selected.
    • This option does nothing unless -ftrapping-math is in effect.
    • Even if you use -fno-fp-int-builtin-inexact, if the functions end up calling a library function, the inexact exception may still be raised if that library implementation 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 enabled, this says a range reduction step isn't needed when doing complex division. It also means there's no checking whether the result of a complex multiplication or division is NaN + I*NaN, and no attempt to rescue that situation. The default is -fno-cx-limited-range, but -ffast-math turns it on โญ
    • This option controls the default setting of the ISO C99 CX_LIMITED_RANGE pragma. Nevertheless, the option applies to all languages.
  • -fcx-fortran-rules ๐Ÿ“ โ€” complex multiplication and division follow Fortran rules. Range reduction happens as part of complex division, but there's still no checking whether the result of a complex multiplication or division is NaN + I*NaN, and no attempt to rescue it.
    • The default is -fno-cx-fortran-rules.

The following options control optimizations that may improve performance, but are not enabled by any -O options. This section includes experimental options that may produce broken code, so be careful, bestie ๐Ÿ™ˆ

  • -fbranch-probabilities ๐Ÿ“ˆ โ€” after you run a program compiled with -fprofile-arcs, you can compile it a second time using -fbranch-probabilities to improve optimizations based on how many times each branch was taken. When a program compiled with -fprofile-arcs exits, it saves arc execution counts to a file called sourcename.gcda for each source file. That data is very dependent on the structure of the generated code, so you must use the same source code and the same optimization options for both compilations. See details about the file naming in -fprofile-arcs.
    • With -fbranch-probabilities, GCC puts a REG_BR_PROB note on each JUMP_INSN and CALL_INSN, and those can be used to improve optimization. Right now they're only used in one place: in reorg.cc. Instead of guessing which path a branch is most likely to take, the REG_BR_PROB values are used to figure out exactly which path is taken more often ๐Ÿง 
    • Enabled by -fprofile-use and -fauto-profile.
  • -fprofile-values ๐Ÿ’œ โ€” if combined with -fprofile-arcs, it adds code so that some data about values of expressions in the program gets gathered.
    • With -fbranch-probabilities, it reads back the data gathered from profiling values of expressions, to use in optimizations.
    • Enabled by -fprofile-generate, -fprofile-use, and -fauto-profile.
  • -fprofile-reorder-functions ๐Ÿฆ‹ โ€” function reordering based on profile instrumentation collects the first time each function executes, then orders those functions in ascending order.
    • Enabled with -fprofile-use.
  • -fvpt โœจ โ€” if combined with -fprofile-arcs, this option tells the compiler to add code that gathers information about values of expressions. With -fbranch-probabilities, it reads back that data and actually performs the optimizations based on it. Right now those optimizations include specializing division operations using what it knows about the value of the denominator ๐Ÿ‘‘
    • Enabled with -fprofile-use and -fauto-profile.
  • -frename-registers ๐ŸŒˆ โ€” tries to avoid false dependencies in scheduled code by using registers left over after register allocation. This optimization helps the most on processors with lots of registers. Depending on the debug information format the target uses, though, it can make debugging impossible, since variables no longer stay in a "home register" ๐Ÿ’€
    • Enabled by default with -funroll-loops.
  • -fschedule-fusion ๐Ÿ”ฅ โ€” performs a target-dependent pass over the instruction stream to schedule instructions of the same type together. The target machine can run them more efficiently when they're adjacent to each other in the instruction flow.
    • Enabled at levels -O2, -O3, -Os.
  • -ftracer ๐Ÿงš โ€” performs tail duplication to enlarge superblock size. This transformation simplifies the control flow of the function, which lets other optimizations do a better job ๐Ÿ’…
    • Enabled by -fprofile-use and -fauto-profile.
  • -funroll-loops ๐ŸŽ€ โ€” unrolls loops whose number of iterations can be determined at compile time or upon entry to the loop. -funroll-loops implies -frerun-cse-after-loop, -fweb, and -frename-registers. It also turns on complete loop peeling (i.e. complete removal of loops with a small constant number of iterations). This option makes code larger, and it may or may not make it run faster ๐Ÿคท
    • Enabled by -fprofile-use and -fauto-profile.
  • -funroll-all-loops ๐Ÿ™ˆ โ€” unrolls all loops, even if their number of iterations is uncertain when the loop is entered. This usually makes programs run more slowly. -funroll-all-loops implies the same options as -funroll-loops.
  • -fpeel-loops ๐Ÿ“ โ€” peels loops that have enough information to show they don't roll much (from profile feedback or static analysis). It also turns on complete loop peeling (i.e. complete removal of loops with small constant number of iterations).
    • Enabled by -O3, -fprofile-use, and -fauto-profile.
  • -fmove-loop-invariants ๐ŸŒธ โ€” enables the loop invariant motion pass in the RTL loop optimizer.
    • Enabled at level -O1 and higher, except for -Og.
  • -fmove-loop-stores ๐Ÿ’– โ€” enables the loop store motion pass in the GIMPLE loop optimizer. This moves invariant stores to after the end of the loop, in exchange for carrying the stored value in a register across the iteration. Heads up: for this option to have an effect, -ftree-loop-im has to be enabled as well.
    • Enabled at level -O1 and higher, except for -Og.
  • -fsplit-loops โญ โ€” splits a loop into two if it contains a condition that's always true for one side of the iteration space and always false for the other.
    • Enabled by -fprofile-use and -fauto-profile.
  • -funswitch-loops ๐Ÿซถ โ€” moves branches with loop invariant conditions out of the loop, with duplicates of the loop on both branches (modified according to the result of the condition).
    • Enabled by -fprofile-use and -fauto-profile.
  • -fversion-loops-for-strides ๐Ÿ‘‘ โ€” if a loop iterates over an array with a variable stride, it creates another version of the loop that assumes the stride is always one. For example:
for (int i = 0; i < n; ++i)
  x[i * stride] = ...;

becomes:

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

This is particularly useful for assumed-shape arrays in Fortran, where (for example) it allows better vectorization assuming contiguous accesses. This flag is enabled by default at -O3. It is also enabled by -fprofile-use and -fauto-profile ๐Ÿฆ‹

โœจ OPTIONS โœจ (continued, bestie) ๐ŸŽ€

  • -ffunction-sections, -fdata-sections โ€” okay so these two put each function or data item into its own section in the output file ๐Ÿฆ‹, but only if the target supports arbitrary sections. The name of the function (or the data item) decides what the section is called in the output file ๐Ÿ’….

Use these on systems where the linker can do optimizations for locality of reference in the instruction space โœจ. Most ELF object format systems have linkers like that ๐ŸŒˆ. On AIX, the linker rearranges sections (CSECTs) based on the call graph ๐Ÿงš. The performance impact varies, so it's not guaranteed to be a glow-up ๐Ÿ™ˆ.

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

On ELF/DWARF systems, these options do not degrade the quality of the debug information ๐Ÿ’–. There could be issues with other object files/debug info formats ๐Ÿ˜ฌ.

Only use these options when there are significant benefits from doing so, bestie ๐Ÿ›‘. When you specify them, the assembler and linker create larger object and executable files and are also slower ๐Ÿข. These options affect code generation ๐Ÿง . They prevent optimizations by the compiler and assembler from using relative locations inside a translation unit, since those locations are unknown until link time ๐Ÿ’€. An example of such an optimization is relaxing calls to short call instructions.
  • -fstdarg-opt โ€” this one optimizes the prologue of variadic argument functions based on how those arguments are actually used ๐Ÿ‘‘.
  • -fsection-anchors โ€” this is giving "fewer address calculations" energy โœจ. It tries to reduce the number of symbolic address calculations by using shared "anchor" symbols to reach nearby objects ๐ŸŒธ. On some targets, this can cut down on GOT entries and GOT accesses ๐Ÿ’….

Here's the vibe. Say you compile this foo function:

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

Normally it calculates the addresses of all three variables ๐Ÿ˜ญ. But if you compile it with -fsection-anchors, it accesses the variables from a common anchor point instead ๐Ÿซถ. The effect is similar to this pseudocode (which isn't valid C, so don't copy-paste it ๐Ÿ™…โ€โ™€๏ธ):

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

Not all targets support this option, so check before you get too attached ๐Ÿฅบ.

  • -fzero-call-used-regs=choice โ€” main character security energy ๐Ÿ›ก๏ธ. This zeroes the call-used registers at function return, which helps either mitigate Return-Oriented Programming (ROP) attacks or stop information leaking out through registers ๐Ÿ”.

The possible values of choice are the same as for the zero_call_used_regs attribute ๐ŸŽ€. The default is skip ๐Ÿ’œ. You can control this for one specific function by using the function attribute zero_call_used_regs โœจ.

  • --param name=value โ€” okay this one is for the nerds who want to tweak the dials ๐ŸŽ›๏ธ. GCC uses various constants to control how much optimization happens. For example, GCC won't inline functions that have more than a certain number of instructions ๐Ÿ™ˆ. You can change some of these constants on the command line with --param ๐Ÿ“.
Heads up: the names of specific parameters, and what the values mean, are tied to the compiler's internals and can change without notice in future releases ๐Ÿšจ.

To find the minimal, maximal, and default value of a parameter, use --help=param -Q options together ๐Ÿ”. The value is always an integer ๐Ÿ”ข. These are the name choices recognized for all targets:

  • predictable-branch-outcome โ€” when a branch is predicted to be taken with a probability lower than this threshold (in percent), it counts as well predictable ๐Ÿ”ฎ.
  • max-rtl-if-conversion-insns โ€” RTL if-conversion tries to get rid of conditional branches around a block and swap them for conditionally executed instructions ๐Ÿ”€. This sets the maximum number of instructions in a block that should be considered for if-conversion. The compiler also uses other heuristics to decide whether if-conversion is actually worth it ๐Ÿง.
  • max-rtl-if-conversion-predictable-cost โ€” same if-conversion idea, but this sets the maximum permissible cost for the sequence that would be generated ๐Ÿ’ธ. The limit depends on whether the branch is statically determined to be predictable or not ๐Ÿ“ˆ. The units match the GCC internal seq_cost metric ๐Ÿ“. The compiler tries to pick a reasonable default for this using the BRANCH_COST target macro ๐ŸŽฏ.
  • max-crossjump-edges โ€” the maximum number of incoming edges to consider for cross-jumping โœ‚๏ธ. The algorithm used by -fcrossjumping is O(N^2) in the number of edges coming into each block, so higher values mean more aggressive optimization ๐Ÿ”ฅ. The catch is that compile time goes up for probably a small gain in executable size ๐ŸŒ.
  • min-crossjump-insns โ€” the minimum number of instructions that must match at the end of two blocks before cross-jumping happens on them ๐Ÿค. This value gets ignored when every instruction in the block being cross-jumped from is matched ๐Ÿ’….
  • max-grow-copy-bb-insns โ€” the maximum 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 maximum number of instructions to duplicate into a block that jumps to a computed goto ๐Ÿช„. To avoid O(N^2) behavior in a bunch of passes, GCC factors computed gotos early and unfactors them as late as possible ๐Ÿงฉ. Only computed jumps at the end of a basic block with no more than max-goto-duplication-insns get unfactored ๐Ÿ’ซ.
  • max-delay-slot-insn-search โ€” the maximum number of instructions to look at when hunting for something to fill a delay slot ๐Ÿ”Ž. Past this arbitrary number, the time saved by filling the slot is basically nothing, so GCC stops searching ๐Ÿ›‘. Higher values mean more aggressive optimization and longer compile times, for probably a small execution-time win โฑ๏ธ.
  • max-delay-slot-live-search โ€” when filling delay slots, this is the maximum number of instructions to consider while searching for a block with valid live register information ๐Ÿ•ต๏ธโ€โ™€๏ธ. Raising this arbitrary value means more aggressive optimization but longer compile times ๐Ÿข. This parameter should be removed once the delay slot code is rewritten to maintain the control-flow graph ๐Ÿšง.
  • max-gcse-memory โ€” the approximate maximum amount of memory, in "kB", that can be allocated to do 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 the expression ๐Ÿ”. That means it leaves partially redundant computations sitting in the instruction stream ๐Ÿซ .
  • max-pending-list-length โ€” the maximum number of pending dependencies the scheduler allows before it flushes the current state and starts over ๐Ÿงน. Big functions with few branches or calls can make these lists excessively large, which needlessly eats memory and resources ๐Ÿ’พ.
  • max-modulo-backtrack-attempts โ€” the maximum number of backtrack attempts the scheduler should make when modulo scheduling a loop ๐Ÿ”„. Larger values can exponentially increase compilation time, so be careful ๐Ÿ’€.
  • max-inline-functions-called-once-loop-depth โ€” the maximal loop depth of a call that the inline heuristics will consider when they try to inline all functions called once ๐ŸŒ€.
  • max-inline-functions-called-once-insns โ€” the maximal estimated size of functions produced while inlining functions called once ๐Ÿ“.
  • max-inline-insns-single โ€” several parameters control the tree inliner in GCC, and this one sets the maximum number of instructions (counted in GCC's internal representation) in a single function that the tree inliner will consider for inlining ๐Ÿชž. This only affects functions declared inline and methods implemented in a class declaration (C++) ๐Ÿ’œ.
  • max-inline-insns-auto โ€” when you use -finline-functions (included in -O3), a whole bunch of functions that the compiler would otherwise skip get looked at for inlining ๐Ÿ‘€. Those functions get a different, more restrictive limit than functions declared inline, and that limit is set with --param max-inline-insns-auto ๐Ÿ”’.
  • max-inline-insns-small โ€” this is the bound applied to calls considered relevant with -finline-small-functions ๐Ÿค.
  • max-inline-insns-size โ€” this is the bound applied to calls that are optimized for size ๐Ÿ“. A little growth may be desirable to set up optimization opportunities that inlining exposes ๐ŸŒฑ.
  • uninlined-function-insns โ€” the number of instructions the inliner counts as function overhead, like the function prologue and epilogue ๐Ÿงพ.
  • uninlined-function-time โ€” the extra time the inliner counts as function overhead, like the time needed to run the prologue and epilogue โณ.
  • inline-heuristics-hint-percent โ€” the scale (in percent) applied to inline-insns-single, inline-insns-single-O2, and inline-insns-auto when the inline heuristics hint that inlining is very profitable ๐Ÿ“ˆ. That hint means it'll enable later optimizations too ๐ŸŽ‰.
  • uninlined-thunk-insns, uninlined-thunk-time โ€” same as --param uninlined-function-insns and --param uninlined-function-time, but applied to function thunks ๐Ÿงต.
  • inline-min-speedup โ€” when the estimated performance improvement of the caller plus callee runtime goes over this threshold (in percent), the function can be inlined no matter what the --param max-inline-insns-single and --param max-inline-insns-auto limits say ๐Ÿš€. That's an absolute serve, no cap ๐Ÿ‘‘.
  • large-function-insns: okay so this is the limit for really big functions ๐Ÿ˜. Once a function is bigger than this after inlining, inlining gets reined in by --param large-function-growth. It's mainly here to stop extreme compile times caused by the non-linear algorithms the back end uses ๐Ÿ’€.
  • large-function-growth: caps how much a large function can grow from inlining, in percent ๐Ÿ“ˆ. For example, 100 limits large function growth to 2.0 times the original size ๐Ÿซถ.
  • large-unit-insns: the threshold for a large translation unit ๐Ÿงฉ. Growth from inlining in units bigger than this is limited by --param inline-unit-growth, but for small units that cap can be way too tight ๐Ÿ™ˆ. Picture a unit with an inline function A and a function B that just calls A three times ๐Ÿฆ‹. If B is tiny next to A, the unit growth is 300% and that inlining is still totally sane โœจ. For huge units full of tiny inlineable functions, though, the overall growth limit keeps code size from exploding exponentially ๐Ÿ’ฅ. So for smaller units, the size gets bumped up to --param large-unit-insns before --param inline-unit-growth gets applied ๐ŸŒธ.
  • lazy-modules: the max number of C++ module files that can be open at once when lazy loading ๐Ÿ“‚.
  • inline-unit-growth: caps the overall growth of the compilation unit from inlining ๐ŸŒฑ. For example, 20 limits unit growth to 1.2 times the original size. Cold functions (marked cold with an attribute or by profile feedback) don't count toward the unit size โ„๏ธ.
  • ipa-cp-unit-growth: the max overall growth of the compilation unit from interprocedural constant propagation ๐Ÿ”ข. For example, 10 limits unit growth to 1.1 times the original size.
  • ipa-cp-large-unit-insns: the size at which the IPA-CP pass considers a translation unit large ๐Ÿ“.
  • large-stack-frame: the limit for large stack frames ๐Ÿฅž. While inlining, the algorithm tries not to grow past this limit too much ๐Ÿ™.
  • large-stack-frame-growth: the max growth of large stack frames caused by inlining, in percent ๐Ÿ“Š. For example, 1000 limits large stack frame growth to 11 times the original size ๐Ÿ˜ญ.
  • max-inline-insns-recursive, max-inline-insns-recursive-auto: the max number of instructions an out-of-line copy of a self-recursive inline function can grow into by doing recursive inlining ๐Ÿ”. --param max-inline-insns-recursive applies to functions declared inline. For functions that aren't declared inline, recursive inlining only happens when -finline-functions (included in -O3) is enabled, and --param max-inline-insns-recursive-auto applies instead ๐Ÿ’….
  • max-inline-recursive-depth, max-inline-recursive-depth-auto: the max recursion depth used for recursive inlining ๐Ÿชž. --param max-inline-recursive-depth applies to functions declared inline. For functions that aren't declared inline, recursive inlining only happens when -finline-functions (included in -O3) is enabled, and --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 shallow recursion it can hurt, because it bloats the prologue 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 the probability that a function recurses through a given call expression ๐Ÿ”ฎ. This parameter only allows inlining for call expressions whose probability is above the threshold (in percent) ๐Ÿ“‰.
  • early-inlining-insns: the growth the early inliner is allowed to make ๐Ÿฃ. Basically, it ups the amount of inlining for code with a large abstraction penalty ๐Ÿ—๏ธ.
  • max-early-inliner-iterations: the limit on iterations of the early inliner ๐Ÿ”„. This basically bounds how many nested indirect calls the early inliner can resolve. Deeper chains still get handled by late inlining ๐Ÿ•ฐ๏ธ.
  • comdat-sharing-probability: the probability (in percent) that C++ inline functions with comdat visibility are 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 disambiguate memory locations using mod/ref information ๐Ÿ•ต๏ธ. This parameter ought to be bigger than --param modref-max-bases and --param modref-max-refs ๐Ÿ‘‘.
  • modref-max-depth: the max depth of the DFS walk used by modref escape analysis ๐Ÿ•ณ๏ธ. Setting it to 0 disables the analysis completely ๐Ÿšซ.
  • modref-max-escape-points: the max number of escape points modref tracks per SSA-name ๐Ÿ“.
  • modref-max-adjustments: the max amount the access range can be enlarged during modref dataflow analysis ๐Ÿ“.
  • profile-func-internal-id: controls whether the function internal id gets used in the profile database lookup ๐Ÿชช. If the value is 0, the compiler uses an id based on the function assembler name and filename ๐Ÿงพ. That makes old profile data more tolerant of source changes, like function reordering ๐Ÿซง.
  • min-vect-loop-bound: the min number of iterations below which loops aren't vectorized when -ftree-vectorize is used ๐Ÿšซ. The number of iterations after vectorization has to be greater than this value for vectorization to happen ๐ŸŽ€.

  • gcse-cost-distance-ratio: a scaling factor for the max distance an expression can be moved by GCSE optimizations โ†”๏ธ. Right now this is only supported in the code hoisting pass ๐Ÿƒ. The bigger the ratio, the more aggressive the hoisting of simple expressions (the ones costing less than gcse-unrestricted-cost) ๐Ÿš€. Specifying 0 disables hoisting of simple expressions ๐Ÿ™….
  • gcse-unrestricted-cost: the cost, roughly measured as a single typical machine instruction, at which GCSE stops constraining how far an expression can travel ๐Ÿ›ฃ๏ธ. This is also only supported in the code hoisting pass ๐Ÿช„. The lower the cost, the more aggressive the hoisting gets ๐Ÿ“ˆ. Specifying 0 lets all expressions travel unrestricted distances ๐Ÿฆ….
  • max-hoist-depth: the depth of the dominator tree search for expressions to hoist ๐ŸŒณ. This exists to avoid quadratic behavior in the hoisting algorithm ๐Ÿซ . A value of 0 doesn't limit the search, but it may slow compilation of huge functions ๐Ÿข.
  • max-tail-merge-comparisons: the max number of similar bbs a bb gets compared with ๐Ÿง‘โ€๐Ÿคโ€๐Ÿง‘. It's used to avoid quadratic behavior in tree tail merging ๐Ÿงต.
  • max-tail-merge-iterations: the max number of iterations of the pass over the function โฑ๏ธ. It's used to limit compilation time in tree tail merging ๐Ÿ“.
  • store-merging-allow-unaligned: lets the store merging pass introduce unaligned stores if it's legal to do so ๐Ÿงฒ.
  • max-stores-to-merge: the max number of stores the store merging pass will attempt to merge into wider stores ๐Ÿงฑ.
  • max-store-chains-to-track: the max number of store chains tracked at the same time while trying to merge them into wider stores ๐Ÿ”—.
  • max-stores-to-track: the max number of stores tracked at the same time while trying to merge them into wider stores ๐Ÿ‘€.
  • max-unrolled-insns: the max number of instructions a loop can have and still be unrolled ๐Ÿ”. If a loop gets unrolled, this parameter also decides how many times the loop code is unrolled ๐ŸŽฏ.
  • max-average-unrolled-insns: the max number of instructions, biased by how probable their execution is, that a loop can have and still be unrolled ๐ŸŽฒ. If a loop gets unrolled, this parameter also decides how many times the loop code is unrolled ๐ŸŒˆ.
  • max-unroll-times: the max number of unrollings of a single loop ๐Ÿ”‚.
  • max-peeled-insns: the max number of instructions a loop can have and still be peeled ๐ŸŠ. If a loop gets peeled, this parameter also decides how many times the loop code is peeled ๐Ÿง….
  • max-peel-times: the max number of peelings of a single loop ๐Ÿ‘.
  • max-peel-branches: the max number of branches on the hot path through the peeled sequence ๐Ÿ”ฅ.
  • max-completely-peeled-insns: the max number of insns in a completely peeled loop ๐Ÿซง.
  • max-completely-peel-times: the max number of iterations a loop can have and still be suitable for complete peeling ๐ŸŽ‚.
  • max-completely-peel-loop-nest-depth: the max depth of a loop nest that's suitable for complete peeling ๐Ÿช†.
  • max-unswitch-insns: the max number of insns in an unswitched loop ๐Ÿ”€.
  • max-unswitch-level: the max number of branches unswitched in a single loop ๐ŸŽš๏ธ.
  • lim-expensive: the min 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 min threshold for the probability of a semi-invariant condition statement triggering a loop split โœ‚๏ธ. It's the probability that makes the split worth it, so the loop gets split only when the condition is likely enough ๐Ÿ’–.
  • iv-consider-all-candidates-bound: the bound on the number of candidates for induction variables ๐Ÿงฎ. Below this bound, every candidate gets considered for each use in induction variable optimizations ๐Ÿซถ. If there are more candidates than this, only the most relevant ones get considered, so the time complexity doesn't go quadratic ๐Ÿ˜คโœจ.
  • iv-max-considered-uses ๐ŸŒธ โ€” okay so the induction variable optimizations just give up ๐Ÿ˜ญ when a loop has too many induction variable uses. Not worth the stress, bestie.
  • iv-always-prune-cand-set-bound โœจ โ€” if the candidate set is smaller than this value, GCC always tries to clean out unnecessary ivs from the set whenever it adds a new one. Very tidy behavior ๐Ÿ’….
  • avg-loop-niter ๐Ÿ”„ โ€” the average number of iterations of a loop.
  • dse-max-object-size ๐Ÿงš โ€” the max size (in bytes) of objects that dead store elimination tracks bytewise. Bigger numbers can mean longer compile times, so don't go wild ๐Ÿ™ˆ.
  • dse-max-alias-queries-per-store ๐Ÿ” โ€” the max number of queries sent to the alias oracle per store. Higher values mean longer compile times, but they can also remove more dead stores ๐Ÿฆ‹.
  • scev-max-expr-size ๐Ÿ“ โ€” a limit on how big expressions can get in the scalar evolutions analyzer. Huge expressions slow the analyzer down, lowkey a vibe killer ๐Ÿ’€.
  • scev-max-expr-complexity ๐Ÿงฉ โ€” a limit on how complex expressions can be in the scalar evolutions analyzer. Complicated expressions slow it down too ๐Ÿ˜ฉ.
  • max-tree-if-conversion-phi-args ๐ŸŒˆ โ€” the max number of arguments in a PHI that TREE if conversion supports, unless the loop is marked with a simd pragma ๐ŸŽ€.
  • vect-max-version-for-alignment-checks ๐Ÿ“ โ€” the max number of run-time checks the vectorizer can perform when doing loop versioning for alignment.
  • vect-max-version-for-alias-checks ๐Ÿซถ โ€” the max number of run-time checks the vectorizer can perform when doing loop versioning for alias.
  • vect-max-peeling-for-alignment ๐Ÿ‘ โ€” the max number of loop peels the vectorizer uses to improve access alignment. A value of -1 means no limit at all, which is very main character energy ๐Ÿ‘‘.
  • max-iterations-to-track ๐Ÿ•ต๏ธ โ€” the max number of loop iterations that the brute-force algorithm for analyzing a loop's iteration count will try to evaluate.
  • hot-bb-count-fraction ๐Ÿ”ฅ โ€” this is the denominator n of the fraction 1/n of the maximal execution count of a basic block in the entire program. A basic block has to hit at least that much to count as hot. The default is 10000, so 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 is never considered hot. This one is used in non-LTO mode ๐Ÿง .
  • hot-bb-count-ws-permille ๐ŸŒŸ โ€” the number of most-executed permilles, from 0 to 1000, of the profiled execution of the entire program. A basic block's execution count has to be part of that group to be considered hot. The default is 990, meaning a basic block is hot if its execution count contributes to the upper 990 permilles, or 99.0%, of the profiled execution of the entire program. A value of 0 means it is never considered hot. This one is used in LTO mode ๐Ÿ’œ.
  • hot-bb-frequency-fraction โญ โ€” this is the denominator n of the fraction 1/n of the execution frequency of a function's entry block. A basic block in that function needs at least that much to be considered hot. The default is 1000, so a basic block counts as hot in a function if it runs more often than 1/1000 of the entry block's frequency. A value of 0 means it is never considered hot ๐ŸŒท.
  • unlikely-bb-count-fraction ๐Ÿ™ƒ โ€” this is the denominator n of the fraction 1/n of the number of profiled runs of the entire program. A basic block's execution count has to be below that to be considered unlikely executed. The default is 20, so a basic block is unlikely executed if it runs in fewer than 1/20, or 5%, of the program's runs. A value of 0 means it is always considered unlikely executed.
  • max-predicted-iterations ๐Ÿ”ฎ โ€” the max number of loop iterations GCC predicts statically. This is handy when a function has one loop with a known bound and another with an unknown bound. The known count gets predicted correctly, while the unknown count averages out to roughly 10. That makes the loop without bounds look artificially cold compared to the other one ๐Ÿฅถ.
  • builtin-expect-probability ๐ŸŽฏ โ€” controls the probability of the expression having the specified value. This takes a percentage, so 0 through 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, used to decide whether that basic block gets aligned.
  • align-loop-iterations ๐Ÿ” โ€” a loop that's expected to iterate at least this many times gets aligned.
  • tracer-dynamic-coverage, tracer-dynamic-coverage-feedback ๐Ÿฆ„ โ€” this value limits superblock formation once the given percentage of executed instructions is covered. It keeps code size from blowing up for no reason.

The tracer-dynamic-coverage-feedback parameter is only used when profile feedback is available. Real profiles, as opposed to statically estimated ones, are way less balanced, so the threshold can be set to a larger value.

  • tracer-max-code-growth ๐ŸŒฑ โ€” stops tail duplication once code growth has reached the given percentage. Honestly this is a pretty artificial limit, since most duplicates get cleaned up later in cross jumping. So it can be set much higher than the desired code growth.
  • tracer-min-branch-ratio ๐Ÿ›‘ โ€” stops reverse growth when the reverse probability of the best edge is less than this threshold, given in percent.
  • tracer-min-branch-probability, tracer-min-branch-probability-feedback ๐Ÿšฆ โ€” stops forward growth if the best edge has a probability lower than this threshold.

Same deal as tracer-dynamic-coverage, there are two of these. tracer-min-branch-probability-feedback is used for compilation with profile feedback, and tracer-min-branch-probability is used for compilation without it. The feedback value needs to be more conservative (higher) so the tracer actually works ๐Ÿ’–.

  • stack-clash-protection-guard-size ๐Ÿ›ก๏ธ โ€” specifies the size of the operating system provided stack guard, as 2 raised to num bytes. Higher values may reduce the number of explicit probes. But a value larger than the operating system provided guard will leave code vulnerable to stack clash style attacks, which is a big no-no ๐Ÿšซ.
  • stack-clash-protection-probe-interval ๐Ÿงญ โ€” stack clash protection involves probing stack space as it gets allocated. This param controls the max distance between probes into the stack, as 2 raised to num bytes. Higher values may reduce the number of explicit probes. But a value larger than the operating system provided guard will leave code vulnerable to stack clash style attacks ๐Ÿ˜ฌ.
  • max-cse-path-length ๐Ÿ›ค๏ธ โ€” the max number of basic blocks on a path that CSE considers.
  • max-cse-insns ๐Ÿงพ โ€” the max number of instructions CSE processes before it flushes.
  • ggc-min-expand ๐Ÿงน โ€” GCC uses a garbage collector to manage its own memory allocation. This param sets the minimum percentage by which the garbage collector's heap is allowed to expand between collections. Tuning it may improve compilation speed, but it has no effect on code generation.

The default is 30% + 70% * (RAM/1GB), with an upper bound of 100% when RAM is at least 1GB. If getrlimit is available, "RAM" means the smallest of actual RAM and RLIMIT_DATA or RLIMIT_AS. If GCC can't calculate RAM on a particular platform, the lower bound of 30% is used. Setting this parameter and ggc-min-heapsize to zero causes a full collection to occur at every opportunity. This is extremely slow, but it can be useful for debugging ๐Ÿข.

  • ggc-min-heapsize ๐Ÿชฃ โ€” the minimum size of the garbage collector's heap before it bothers collecting garbage. The first collection happens after the heap expands by ggc-min-expand% beyond ggc-min-heapsize. Again, tuning this may improve compilation speed, and it has no effect on code generation.

The default is the smallest of RAM/8, RLIMIT_RSS, or a limit that tries to make sure RLIMIT_DATA or RLIMIT_AS aren't 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 particular platform, the lower bound is used. Setting this parameter very large effectively disables garbage collection. Setting this parameter and ggc-min-expand to zero causes a full collection to occur at every opportunity ๐Ÿ—‘๏ธ.

  • max-reload-search-insns ๐Ÿ”Ž โ€” the max number of instructions reload should look backward through to find an equivalent register. Higher values mean more aggressive optimization, which makes compilation take longer for probably slightly better performance.
  • max-cselib-memory-locations ๐Ÿง  โ€” the max number of memory locations cselib should take into account. Higher values mean more aggressive optimization, which makes compilation take longer for probably slightly better performance.
  • max-sched-ready-insns ๐Ÿš€ โ€” the max number of instructions ready to be issued that the scheduler should consider at any given time during the first scheduling pass. Higher values mean more thorough searches, which makes compilation take longer for probably little benefit.
  • max-sched-region-blocks ๐Ÿงฑ โ€” the max number of blocks in a region that can be considered for interblock scheduling.
  • max-pipeline-region-blocks ๐ŸŽข โ€” the max number of blocks in a region that can be considered for pipelining in the selective scheduler.
  • max-sched-region-insns ๐ŸŒบ โ€” the max number of insns in a region that can be considered for interblock scheduling.

okay so this is where the scheduler and optimizer settings get EXTRA ๐Ÿ’… bestie, you do NOT need to memorize all of these, but the vibes are immaculate โœจ

  • max-pipeline-region-insns โ€” the cap on how many insns a region can have before the selective scheduler even considers pipelining it ๐ŸŒธ
  • min-spec-prob โ€” the minimum chance (in percents) of reaching a source block that interblock speculative scheduling needs before it gets involved ๐Ÿฆ‹
  • max-sched-extend-regions-iters โ€” how many times the compiler can loop through the CFG trying to extend regions ๐Ÿ” Set it to 0 and region extensions are disabled, no cap, no debate ๐Ÿšซ
  • max-sched-insn-conflict-delay โ€” the biggest conflict delay an insn can have and still be eligible for speculative motion ๐Ÿ’œ
  • sched-spec-prob-cutoff โ€” the least probability of speculation success (in percents) that has to be there before speculative insns actually get scheduled ๐ŸŽ€
  • sched-state-edge-prob-cutoff โ€” the minimum probability an edge needs before the scheduler bothers saving its state across it ๐ŸŒˆ
  • sched-mem-true-dep-cost โ€” the minimal distance (in CPU cycles) between a store and a load that are aiming at the same memory locations ๐Ÿงš
  • selsched-max-lookahead โ€” the size of the lookahead window for selective scheduling. It's basically how deep the search goes when hunting for available instructions ๐Ÿ”
  • selsched-max-sched-times โ€” how many times one instruction can get scheduled during selective scheduling. This is the limit on how many iterations an instruction is allowed to be pipelined through ๐Ÿ”ฅ
  • selsched-insns-to-rename โ€” the number of best instructions on the ready list that get considered for renaming in the selective scheduler ๐Ÿ’…
  • sms-min-sc โ€” the smallest stage count that the swing modulo scheduler will generate ๐Ÿ“
  • max-last-value-rtl โ€” the biggest size, counted in RTLs, that the combiner can record in an expression as the last known value of a pseudo register ๐Ÿซถ
  • max-combine-insns โ€” the maximum number of instructions the RTL combiner tries to combine at once ๐Ÿ‘‘
  • integer-share-limit โ€” small integer constants can share one data structure, which saves memory and makes the compiler faster โšก This sets the biggest value a shared integer constant can have ๐Ÿ’–
  • ssp-buffer-size โ€” the minimum size of buffers (aka arrays) that get stack smashing protection when -fstack-protector is on ๐Ÿ›ก๏ธ
  • min-size-for-stack-sharing โ€” the minimum size of variables that take part in stack slot sharing when you're not optimizing ๐Ÿฆ‹
  • max-jump-thread-duplication-stmts โ€” the most statements a block can have and still be duplicated when threading jumps ๐Ÿงต
  • max-fields-for-field-sensitive โ€” the maximum number of fields in a structure that gets treated in a field sensitive way during pointer analysis ๐Ÿ”ฌ

  • prefetch-latency โ€” an estimate of how many instructions, on average, run before a prefetch finishes โณ The prefetch distance scales with this number. Crank it up and you might end up with fewer streams getting prefetched (see simultaneous-prefetches) ๐ŸŒธ
  • simultaneous-prefetches โ€” the maximum number of prefetches that can run at the same time ๐Ÿƒโ€โ™€๏ธ
  • l1-cache-line-size โ€” the size of an L1 data cache line, 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 really hard to tell when the hints actually help ๐Ÿค”
    • Set it to 1 if you want prefetch hints for non-constant strides โœ…
    • Set it to 0 if you only want hints for strides that are known to be constant and below prefetch-minimum-stride ๐Ÿšซ
  • prefetch-minimum-stride โ€” the minimum constant stride, in bytes, before prefetch hints kick in. If the stride is below this threshold, no prefetch hints get issued ๐Ÿ“‰
    • This one is super useful for processors with hardware prefetchers ๐Ÿ–ฅ๏ธ Those two can clash with the software prefetchers, so if the hardware has a max stride it can handle, put that number here to make the software prefetchers play nice ๐Ÿซถ
    • A value of -1 means there's no threshold, so prefetch hints can be issued for any constant stride โ™พ๏ธ
    • This setting only matters for strides that are known and constant ๐Ÿ’…

  • destructive-interference-size and 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 at the same time ๐Ÿ’ฅ
    • 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 typically the small end of that 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 stay stable, and on some targets it changes with -mtune. Using it somewhere ABI stability matters, like a library's public interface, is strongly discouraged ๐Ÿ˜ญ If you really have to use it there, users can pin the value with this option.
    • The constructive interference size is way less sensitive, since it's usually only used in a static_assert to check that a type fits in a cache line โœ…

See also -Winterference-size ๐Ÿ‘€


  • loop-interchange-max-num-stmts โ€” the maximum number of stmts in a loop that can be interchanged ๐Ÿ”„
  • loop-interchange-stride-ratio โ€” the minimum ratio between the strides of two loops for interchange to be profitable ๐Ÿ’ฐ
  • min-insn-to-prefetch-ratio โ€” the minimum ratio between the number of instructions and the number of prefetches needed to enable prefetching in a loop ๐Ÿงฎ
  • prefetch-min-insn-to-mem-ratio โ€” the minimum ratio between the number of instructions and the number of memory references needed to enable prefetching in a loop ๐Ÿง 
  • use-canonical-types โ€” whether the compiler should use the "canonical" type system. It should always be 1, since that uses a more efficient internal mechanism for comparing types in C++ and Objective-C++ ๐Ÿ† But if bugs in the canonical type system are causing compilation failures, set it to 0 to turn canonical types off ๐Ÿ›‘
  • switch-conversion-max-branch-ratio โ€” switch initialization conversion won't create arrays bigger than switch-conversion-max-branch-ratio times the number of branches in the switch ๐Ÿ“ฆ
  • max-partial-antic-length โ€” the maximum length of the partial antic set computed during the tree partial redundancy elimination optimization (-ftree-pre) when you're optimizing at -O3 and above ๐ŸŒ€ For some source code, the enhanced PRE can run away and eat all the memory on the host machine ๐Ÿ˜ฑ This parameter caps the length of those sets to stop the runaway behavior. Setting it to 0 allows an unlimited set length ๐Ÿ™ˆ
  • rpo-vn-max-loop-depth โ€” the maximum loop depth that gets value-numbered optimistically ๐Ÿ”ข When the limit hits, the innermost rpo-vn-max-loop-depth loops and the outermost loop in the loop nest get value-numbered optimistically, and the remaining ones don't ๐Ÿซง
  • sccvn-max-alias-queries-per-access โ€” the maximum number of alias-oracle queries performed when looking for redundancies in loads and stores ๐Ÿ”Ž If this limit is hit, the search is aborted and the load or store is not considered redundant. The number of queries is algorithmically limited to the number of stores on all paths from the load to the function entry ๐Ÿงญ

  • ira-max-loops-num โ€” IRA uses regional register allocation by default ๐Ÿ—บ๏ธ If a function has more loops than this parameter's number, only that many of the most frequently executed loops form regions for regional register allocation ๐Ÿ”ฅ
  • ira-max-conflict-table-size โ€” IRA uses a sophisticated algorithm to compress the conflict table, but huge functions can still need an excessive amount of memory for it ๐Ÿ˜ If a function's conflict table could be bigger than the size in MB given by this parameter, the register allocator switches to a faster, simpler, lower-quality algorithm that doesn't build a pseudo-register conflict table ๐Ÿƒโ€โ™€๏ธ๐Ÿ’จ
  • ira-loop-reserved-regs โ€” IRA can evaluate more accurate register pressure in loops when deciding whether to move loop invariants (see -O3) ๐ŸงŠ This is the number of available registers reserved for other purposes. The default is the best value found from numerous experiments ๐Ÿงช
  • ira-consider-dup-in-all-alts โ€” makes IRA consider matching constraints (duplicated operand numbers) heavily across all available alternatives for the preferred register class ๐ŸŽฏ
    • Set to 0 and 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 choice with an appropriate class, and respects the qualified matching constraint it found ๐Ÿง โœจ
  • lra-inheritance-ebb-probability-cutoff โ€” okay so LRA tries to reuse values it reloaded into registers in later insns ๐Ÿง โœจ. That's called inheritance ๐Ÿ’…, and the EBB is the region used for it. This parameter sets the minimal fall-through edge probability, in percentage, that decides whether a BB gets added to an inheritance EBB in LRA ๐Ÿฆ‹. The default was picked from tons of SPEC2000 runs on x86-64 ๐ŸŒธ.
  • loop-invariant-max-bbs-in-loop โ€” loop invariant motion can be super expensive ๐Ÿ˜ญ, both in compilation time and in the compile-time memory it needs, especially with massive loops ๐Ÿ’€. Any loop with more basic blocks than this value just won't get loop invariant motion ๐Ÿ™ˆ.
  • loop-max-datarefs-for-datadeps โ€” building data dependencies gets pricey for huge loops ๐Ÿ’ธ. This caps how many data references in a loop get considered for data dependence analysis ๐Ÿซถ. The really big loops over the cap aren't handled by the optimizations that use loop data dependencies ๐Ÿšซ.
  • max-vartrack-size โ€” sets a max number of hash table slots for variable tracking dataflow analysis on any function ๐Ÿ”ฅ. If you go over it with variable tracking at assignments enabled, the analysis for that function gets retried without it, after all the debug insns are removed from the function ๐Ÿ”. If it's still over the limit without debug insns, var tracking analysis is completely disabled for that function ๐Ÿ˜ญ. Setting it to zero makes it unlimited โ™พ๏ธ.
  • max-vartrack-expr-depth โ€” max recursion levels when mapping variable names or debug temporaries to value expressions ๐ŸŒ€. It's a trade-off: compile time for more complete debug information ๐ŸŽ€. Set it too low and value expressions that could be represented in debug info might end up unused ๐Ÿ’”. Set it higher and the compiler may 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 (e.g. begin stmt markers) ๐Ÿท๏ธ, so complexity doesn't explode at inlining or expanding to RTL ๐Ÿ’ฅ. If a function has more of those gimple stmts than the limit, they get dropped from the inlined copy of the function and from its RTL expansion โœ‚๏ธ.
  • min-nondebug-insn-uid โ€” nondebug insns start their uids at this value ๐Ÿ”ข. The range below it is reserved exclusively for debug insns created by -fvar-tracking-assignments ๐Ÿงš. Debug insns can still get (non-overlapping) uids above it if that reserved range runs out ๐ŸŒˆ.
  • ipa-sra-ptr-growth-factor โ€” IPA-SRA only replaces a pointer to an aggregate with one or more new parameters when their cumulative size is less than or equal to ipa-sra-ptr-growth-factor times the size of the original pointer parameter ๐Ÿ“.
  • ipa-sra-max-replacements โ€” the max pieces of an aggregate IPA-SRA tracks ๐Ÿงฉ. That also makes it the max number of replacements of a formal parameter ๐Ÿ™Œ.
  • sra-max-scalarization-size-Ospeed, sra-max-scalarization-size-Osize โ€” the two Scalar Reduction of Aggregates passes (SRA and IPA-SRA) want to swap scalar parts of aggregates for uses of independent scalar variables โœจ. These two cap the max size, in storage units, of an aggregate that's even considered for that ๐Ÿ“ฆ. The first applies when compiling for speed (sra-max-scalarization-size-Ospeed) ๐ŸŽ๏ธ, and the second applies when compiling for size (sra-max-scalarization-size-Osize) ๐Ÿค.
  • sra-max-propagations โ€” the max number of artificial accesses that Scalar Replacement of Aggregates (SRA) will track per local variable ๐Ÿ”, to help with copy propagation ๐Ÿ’–.
  • tm-max-aggregate-size โ€” when making copies of thread-local variables in a transaction ๐Ÿงต, this sets the size in bytes after which variables get saved with the logging functions instead of save/restore code sequence pairs ๐Ÿ“. It only applies when using -fgnu-tm ๐Ÿ’œ.
  • graphite-max-nb-scop-params โ€” to avoid exponential effects in the Graphite loop transforms ๐ŸŒ€๐Ÿ’ฅ, the number of parameters in a Static Control Part (SCoP) is bounded ๐Ÿšง. A value of zero lifts the bound ๐Ÿ”“. A variable whose value is unknown at compile time and is defined outside a SCoP counts as a parameter of that SCoP ๐Ÿซง.
  • loop-block-tile-size โ€” loop blocking or strip mining, enabled with -floop-block or -floop-strip-mine, strip mines each loop in the nest by a given number of iterations ๐Ÿฐ. You can change the strip length using loop-block-tile-size ๐ŸŽ€.
  • ipa-jump-function-lookups โ€” the number of statements visited during jump function offset discovery ๐Ÿ”.
  • ipa-cp-value-list-size โ€” IPA-CP tries to track all possible values and types passed to a function's parameter so it can propagate them and perform devirtualization ๐Ÿง . ipa-cp-value-list-size is the max number of values and types it stores per formal parameter of a function ๐Ÿ“š.
  • ipa-cp-eval-threshold โ€” IPA-CP calculates its own score from its cloning profitability heuristics ๐Ÿงฎ and 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 exceeds this parameter ๐ŸŽฒ.
  • ipa-cp-profile-count-base โ€” with -fprofile-use, IPA-CP looks at the measured execution count of a call graph edge at this percentage position in its histogram ๐Ÿ“Š. That's the basis it uses for its heuristics calculation ๐Ÿงช.
  • 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 receive when they're evaluated for cloning ๐Ÿ˜ฌ.
  • ipa-cp-single-call-penalty โ€” the percentage penalty functions get when they contain a single call to another function and are evaluated for cloning ๐Ÿ“‰.
  • ipa-max-agg-items โ€” IPA-CP can also propagate a number of scalar values passed in an aggregate ๐Ÿ“ฆ. This controls the max number of those values per parameter ๐Ÿ”ข.
  • ipa-cp-loop-hint-bonus โ€” when IPA-CP figures out that a cloning candidate would make the number of loop iterations known ๐Ÿ”“, it adds a bonus of ipa-cp-loop-hint-bonus to that 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 analyzing function bodies, IPA-CP uses alias analysis to track values pointed to by function parameters ๐Ÿ•ต๏ธ. So it doesn't spend forever on huge functions, it gives up and considers all memory clobbered after examining ipa-max-aa-steps statements that modify memory ๐Ÿซ .
  • ipa-max-switch-predicate-bounds โ€” the max number of boundary endpoints of case ranges in a switch statement ๐Ÿ”€. For a switch over this limit, IPA-CP won't construct the cloning cost predicate for the default case, which is used to estimate cloning benefit ๐Ÿšซ.
  • ipa-max-param-expr-ops โ€” IPA-CP analyzes conditional statements that reference a function parameter to estimate cloning benefit for a certain constant value ๐Ÿง. If the number of operations in a parameter expression goes over ipa-max-param-expr-ops, the expression is treated as complicated and isn't handled by IPA analysis ๐Ÿ™….
  • lto-partitions โ€” the desired number of partitions produced during WHOPR compilation ๐Ÿงฉ. The number should exceed the number of CPUs used for compilation ๐Ÿ’ป.
  • lto-min-partition โ€” the size of the minimal partition for WHOPR (in estimated instructions) ๐Ÿ“. This stops tiny programs from being split into too many partitions ๐Ÿ™ƒ.
  • lto-max-partition โ€” the size of the max partition for WHOPR (in estimated instructions) ๐Ÿ“. It gives an upper bound for the individual size of a partition ๐Ÿ”. It's only meant to be used with balanced partitioning โš–๏ธ.
  • lto-max-streaming-parallelism โ€” the max number of parallel processes used for LTO streaming ๐ŸŒŠ.
  • cxx-max-namespaces-for-diagnostic-help โ€” the max number of namespaces to consult for suggestions when C++ name lookup fails for an identifier ๐Ÿ”Ž.
  • sink-frequency-threshold โ€” the max relative execution frequency (in percent) of the target block, compared to a statement's original block, that still allows statement sinking ๐Ÿ›ฌ. Bigger numbers mean more aggressive statement sinking ๐Ÿ’ช. A small positive adjustment is applied to statements with memory operands, since those are even more profitable to sink ๐Ÿ’ฐ.
  • max-stores-to-sink โ€” the max number of conditional store pairs that can be sunk ๐Ÿ•ณ๏ธ. Set it to 0 if either vectorization (-ftree-vectorize) or if-conversion (-ftree-loop-if-convert) is disabled โš ๏ธ.
  • case-values-threshold โ€” the smallest number of different values for which a jump-table is better than a tree of conditional branches ๐ŸŒณ. If the value is 0, the default for the machine is used ๐Ÿค–.
  • jump-table-max-growth-ratio-for-size โ€” the max code size growth ratio when expanding into a jump table (in percent) ๐Ÿ“. This one is used when optimizing for size ๐Ÿ“ฆ.
  • jump-table-max-growth-ratio-for-speed โ€” the max code size growth ratio when expanding into a jump table (in percent) ๐Ÿ“ˆ. This one is used when optimizing for speed ๐ŸŽ๏ธ.
  • tree-reassoc-width โ€” okay so this one sets the max number of instructions that get run in parallel in a reassociated tree ๐ŸŒณ. If it's set to a non-zero value, it overrides the target-dependent heuristics that would otherwise be used by default. ๐Ÿ’…
  • sched-pressure-algorithm โ€” this lets you pick between the two available versions of -fsched-pressure ๐Ÿ”ฅ. Algorithm 1 is the original one, and it's the more likely to stop instructions from getting reordered ๐Ÿ™ˆ. Algorithm 2 was designed as a compromise between algorithm 1's pretty conservative vibe and the rather aggressive approach of the default scheduler โœจ. It leans harder on having a regular register file and accurate register pressure classes. If you want the deets, check out haifa-sched.cc in the GCC sources ๐Ÿ“š.

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

  • max-slsr-cand-scan โ€” sets the max number of existing candidates that get considered when the compiler is looking for a basis for a new straight-line strength reduction candidate ๐Ÿฆ‹.
  • asan-globals โ€” enables buffer overflow detection for global objects ๐ŸŒธ. This protection is on by default if you're using -fsanitize=address. If you want to turn global objects protection off, use --param asan-globals=0 ๐Ÿ™…โ€โ™€๏ธ.
  • asan-stack โ€” enables buffer overflow detection for stack objects ๐Ÿงš. This is on by default when using -fsanitize=address. To disable stack protection, use --param asan-stack=0 option ๐Ÿ’œ.
  • asan-instrument-reads โ€” enables 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 โ€” enables buffer overflow detection for memory writes โœ๏ธ. Again, this is on by default when using -fsanitize=address. To disable memory writes protection, use --param asan-instrument-writes=0 option ๐ŸŒˆ.
  • asan-memintrin โ€” enables detection for built-in functions ๐Ÿ› ๏ธ. This is on by default with -fsanitize=address. To turn off built-in functions protection, use --param asan-memintrin=0 ๐Ÿ’–.
  • asan-use-after-return โ€” enables detection of use-after-return, which is kind of a big deal ๐Ÿ˜ญ. It's on by default when you use the -fsanitize=address option. To disable it, use --param asan-use-after-return=0 ๐Ÿ’€.
Note: By default the check is disabled at run time ๐Ÿ™ˆ. If you want to turn it on, add "detect_stack_use_after_return=1" to the environment variable ASAN_OPTIONS โœจ.
  • asan-instrumentation-with-call-threshold โ€” if the number of memory accesses in the function being instrumented is greater than or equal to this number, the compiler uses callbacks instead of inline checks ๐Ÿ“ž. For example, to disable inline code, use --param asan-instrumentation-with-call-threshold=0 ๐Ÿ“.
  • hwasan-instrument-stack โ€” enables hwasan instrumentation of statically sized stack-allocated variables ๐ŸŽ€. This is on by default with -fsanitize=hwaddress, but it's off by default with -fsanitize=kernel-hwaddress. To turn stack instrumentation off, use --param hwasan-instrument-stack=0, and to turn it back on, use --param hwasan-instrument-stack=1 ๐Ÿ”.
  • hwasan-random-frame-tag โ€” when you're using stack instrumentation, tags for stack variables get decided using a deterministic sequence that begins at a random tag for each frame ๐ŸŽฒ. If this parameter isn't set, the tags use the same sequence but start from 1 ๐Ÿ”ข. It's enabled by default for -fsanitize=hwaddress and unavailable for -fsanitize=kernel-hwaddress ๐Ÿšซ. To disable it, use --param hwasan-random-frame-tag=0 ๐Ÿ’….
  • hwasan-instrument-allocas โ€” enables hwasan instrumentation of dynamically sized stack-allocated variables ๐ŸŒท. This is on by default with -fsanitize=hwaddress and off by default with -fsanitize=kernel-hwaddress. To turn off instrumentation of these variables, use --param hwasan-instrument-allocas=0, and to turn it on, use --param hwasan-instrument-allocas=1 ๐Ÿฆ„.
  • hwasan-instrument-reads โ€” enables hwasan checks on memory reads ๐Ÿ‘๏ธ. Read instrumentation is on by default for both -fsanitize=hwaddress and -fsanitize=kernel-hwaddress. To stop checking memory reads, use --param hwasan-instrument-reads=0 ๐Ÿ™…โ€โ™€๏ธ.
  • hwasan-instrument-writes โ€” enables hwasan checks on memory writes ๐Ÿ“. Write instrumentation is on by default for both -fsanitize=hwaddress and -fsanitize=kernel-hwaddress. To stop checking memory writes, use --param hwasan-instrument-writes=0 ๐ŸŒธ.
  • hwasan-instrument-mem-intrinsics โ€” enables hwasan instrumentation of builtin functions ๐Ÿงฐ. This is on by default for both -fsanitize=hwaddress and -fsanitize=kernel-hwaddress. To turn off instrumentation of builtin functions, use --param hwasan-instrument-mem-intrinsics=0 ๐Ÿซ .
  • use-after-scope-direct-emission-threshold โ€” if the size of a local variable in bytes is smaller than or equal to this number, the compiler directly poisons (or unpoisons) shadow memory instead of using 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() ๐Ÿšช.
  • max-fsm-thread-path-insns โ€” the max number of instructions to copy when duplicating blocks on a finite state automaton jump thread path ๐Ÿงต.
  • max-fsm-thread-length โ€” the max number of basic blocks on a jump thread path ๐Ÿงถ.
  • threader-debug โ€” threader-debug=[none|all] turns on verbose dumping of the threader solver ๐Ÿ—ฃ๏ธ.
  • parloops-chunk-size โ€” the chunk size of the omp schedule for loops parallelized by parloops ๐Ÿงฉ.
  • parloops-schedule โ€” the schedule type of the omp schedule for loops parallelized by parloops. The options are static, dynamic, guided, auto, and runtime ๐Ÿ—“๏ธ.
  • parloops-min-per-thread โ€” the minimum number of iterations per thread of an innermost parallelized loop where the parallelized version is preferred over the single threaded one ๐Ÿงต. Heads up: for a parallelized loop nest, the minimum number of iterations of the outermost loop per thread is two ๐Ÿ‘‘.
  • max-ssa-name-query-depth โ€” the max depth of recursion when querying properties of SSA names in things like fold routines ๐Ÿ”. One level of recursion corresponds to following a use-def chain ๐Ÿ”—.
  • max-speculative-devirt-maydefs โ€” the max number of may-defs analyzed when looking for a must-def that specifies the dynamic type of an object invoking a virtual call that might be devirtualized speculatively ๐Ÿ•ต๏ธโ€โ™€๏ธ.
  • max-vrp-switch-assertions โ€” the max number of assertions to add along the default edge of a switch statement during VRP ๐Ÿ”€.
  • evrp-sparse-threshold โ€” the max number of basic blocks before EVRP switches to a sparse cache ๐Ÿ—‚๏ธ.
  • evrp-mode โ€” specifies the mode Early VRP should operate in ๐ŸŽ›๏ธ.
  • vrp1-mode โ€” specifies the mode VRP pass 1 should operate in 1๏ธโƒฃ.
  • vrp2-mode โ€” specifies the mode VRP pass 2 should operate in 2๏ธโƒฃ.
  • ranger-debug โ€” specifies the type of debug output to be issued for ranges ๐Ÿ“Š.
  • evrp-switch-limit โ€” specifies the max number of switch cases before EVRP ignores a switch ๐Ÿ™ˆ.
  • unroll-jam-min-percent โ€” the minimum percentage of memory references that must be optimized away for the unroll-and-jam transformation to be considered profitable ๐Ÿ’ฐ.
  • unroll-jam-max-unroll โ€” the max number of times the outer loop should be unrolled by the unroll-and-jam transformation ๐Ÿ”.
  • max-rtl-if-conversion-unpredictable-cost โ€” the max permissible cost for the sequence that the RTL if-conversion pass would generate for a branch that's considered unpredictable ๐ŸŒ€.
  • max-variable-expansions-in-unroller โ€” if -fvariable-expansion-in-unroller is used, this is the max number of times an individual variable gets expanded during loop unrolling ๐Ÿ“ˆ.
  • partial-inlining-entry-probability โ€” the max probability of the entry BB of a split region (as a percent relative to the entry BB of the function) that still lets partial inlining happen ๐ŸŽฒ.
  • max-tracked-strlens โ€” the max number of strings the strlen optimization pass will track string lengths for ๐Ÿงต.
  • gcse-after-reload-partial-fraction โ€” the threshold ratio for performing partial redundancy elimination after reload โš–๏ธ.
  • gcse-after-reload-critical-fraction โ€” the threshold ratio of critical edges' execution count that permits performing redundancy elimination after reload ๐Ÿงฎ.
  • max-loop-header-insns โ€” the max number of insns in a loop header duplicated by the copy loop headers pass ๐Ÿ“‹.
  • vect-epilogues-nomask โ€” enables loop epilogue vectorization using a smaller vector size ๐Ÿง.
  • vect-partial-vector-usage โ€” controls when the loop vectorizer considers using partial vector loads and stores as an alternative to falling back to scalar code ๐Ÿช„. The values are:
    • 0 โ€” the vectorizer never uses partial vector loads and stores ๐Ÿšซ.
    • 1 โ€” partial vector loads and stores are allowed if vectorization removes the need for the code to iterate ๐Ÿ”„.
    • 2 โ€” partial vector loads and stores are allowed in all loops ๐Ÿ’ซ.

This parameter only has an effect on targets that 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, relative to the loop being vectorized ๐Ÿช†. The factor applied is the max of the estimated number of iterations of the inner loop and this parameter. The default value of this parameter is 50 ๐Ÿ’ฏ.
  • avoid-fma-max-bits โ€” the max number of bits for which we avoid creating FMAs ๐Ÿ™…โ€โ™€๏ธ.
  • sms-loop-average-count-threshold โ€” a threshold on the average loop count considered by the swing modulo scheduler ๐ŸŽข.
  • sms-dfa-history โ€” okay so this one sets how many cycles the swing modulo scheduler looks at when it checks for conflicts using the DFA ๐Ÿ”
  • graphite-allow-codegen-errors โ€” decides whether codegen errors should be ICEs when -fchecking is on ๐Ÿ’€
  • sms-max-ii-factor โ€” a tuning factor for the upper bound the swing modulo scheduler uses when it schedules a loop ๐ŸŽ€
  • lra-max-considered-reload-pseudos โ€” the max number of reload pseudos that get considered while spilling a non-reload pseudo ๐Ÿฆ‹
  • max-pow-sqrt-depth โ€” the max depth of sqrt chains you're allowed to use when synthesizing exponentiation by a real constant ๐ŸŒธ
  • max-dse-active-local-stores โ€” caps how many active local stores RTL dead store elimination can have at once ๐Ÿงน
  • asan-instrument-allocas โ€” turns on ASan protection for allocas and VLAs ๐Ÿ›ก๏ธ
  • max-iterations-computation-cost โ€” the bound on how expensive an expression can be when GCC computes the number of iterations ๐Ÿ’œ
  • max-isl-operations โ€” the max number of isl operations, where 0 means unlimited โ™พ๏ธ
  • graphite-max-arrays-per-scop โ€” the max number of arrays allowed per scop ๐Ÿ“ฆ
  • max-vartrack-reverse-op-size โ€” the max size of a loc list for which reverse ops should get added ๐Ÿงš
  • fsm-scale-path-stmts โ€” a scale factor applied to the number of statements in a threading path, compared against the number of (scaled) blocks ๐Ÿงต
  • uninit-control-dep-attempts โ€” the max number of nested calls used to search for control dependencies during uninitialized variable analysis ๐Ÿ”Ž
  • fsm-scale-path-blocks โ€” a scale factor applied to the number of blocks in a threading path, compared against the number of (scaled) statements ๐ŸŒˆ
  • sched-autopref-queue-depth โ€” a control flag for the hardware autoprefetcher scheduler model. It sets how many lookahead cycles the model peeks into, and at ' ' it only turns on the instruction sorting heuristic ๐Ÿซถ
  • loop-versioning-max-inner-insns โ€” the max number of instructions an inner loop can have before the loop versioning pass decides it's too big to copy ๐Ÿ“
  • loop-versioning-max-outer-insns โ€” the max number of instructions an outer loop can have before the loop versioning pass decides it's too big to copy, not counting any instructions in inner loops that directly benefit from versioning ๐ŸŒŸ
  • ssa-name-def-chain-limit โ€” the max number of SSA_NAME assignments GCC follows when figuring out a property of a variable, like its value. This limits how many iterations or recursive calls GCC makes when optimizing certain statements or checking their validity before it issues diagnostics ๐Ÿ”—
  • store-merging-max-size โ€” the max size of a single store merging region, in bytes ๐Ÿ“
  • hash-table-verification-limit โ€” the number of elements that get hash table verification done for each searched element ๐Ÿง
  • max-find-base-term-values โ€” the max number of VALUEs handled during a single find_base_term call ๐Ÿ’ซ
  • analyzer-max-enodes-per-program-point โ€” the max number of exploded nodes per program point inside the analyzer. Once it's hit, 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 bothers summarizing its effects at call sites ๐Ÿ“
  • analyzer-max-enodes-for-full-dump โ€” the max depth of exploded nodes that can show up in a dot dump before it switches to a less verbose format ๐Ÿ—‚๏ธ
  • analyzer-max-recursion-depth โ€” the max number of times a callsite can show up in a call stack inside the analyzer. Once that's reached, analysis of a call that would recurse deeper gets terminated ๐ŸŒ€
  • analyzer-max-svalue-depth โ€” the max depth of a symbolic value before the analyzer approximates it as unknown โ“
  • analyzer-max-infeasible-edges โ€” the max number of infeasible edges to reject before a diagnostic gets declared infeasible ๐Ÿšซ
  • gimple-fe-computed-hot-bb-threshold โ€” the number of executions a basic block needs before it counts as hot. This parameter is only used in the GIMPLE FE ๐Ÿ”ฅ
  • analyzer-bb-explosion-factor โ€” the max number of 'after supernode' exploded nodes per supernode inside the analyzer, before analysis gets terminated ๐Ÿ’ฅ
  • ranger-logical-depth โ€” the max depth of logical expression evaluation that ranger will look through when it evaluates outgoing edge ranges ๐Ÿง 
  • relation-block-limit โ€” the max number of relations the oracle will register in a basic block ๐Ÿค
  • openacc-kernels โ€” picks the mode for handling OpenACC kernels constructs ๐ŸŽ€
    • With --param=openacc-kernels=decompose, OpenACC kernels constructs get decomposed into parts, a sequence of compute constructs, and each one is handled individually. This is work in progress.
    • With --param=openacc-kernels=parloops, OpenACC kernels constructs are handled en bloc by the parloops pass. This is the current default.
  • openacc-privatization โ€” picks the mode for OpenACC privatization diagnostics, which show up under -fopt-info-omp-note and applicable -fdump-tree-*-details ๐Ÿ”
    • With --param=openacc-privatization=quiet, nothing gets diagnosed. This is the current default.
    • With --param=openacc-privatization=noisy, diagnostics get shown.

The following choices of name are available on AArch64 targets: ๐ŸŒˆ

  • aarch64-sve-compare-costs โ€” when vectorizing for SVE, GCC considers using "unpacked" vectors for smaller elements, and it uses the cost model to pick the cheapest approach. It also uses the cost model to choose between SVE and Advanced SIMD vectorization.

Using unpacked vectors means storing smaller elements in larger containers and accessing elements with extending loads and truncating stores. โœจ

  • aarch64-float-recp-precision โ€” the number of Newton iterations used to calculate the reciprocal for the float type. The precision of division is proportional to this param when division approximation is enabled. The default value is 1. ๐Ÿฆ‹
  • aarch64-double-recp-precision โ€” the number of Newton iterations used to calculate the reciprocal for the double type. The precision of division is proportional to this param when division approximation is enabled. The default value is 2. ๐ŸŒธ
  • aarch64-autovec-preference โ€” forces an ISA selection strategy for auto-vectorization. It accepts values from 0 to 4, inclusive. ๐Ÿ‘‘
    • 0 โ€” use the default heuristics
    • 1 โ€” use only Advanced SIMD for auto-vectorization
    • 2 โ€” use only SVE for auto-vectorization
    • 3 โ€” use both Advanced SIMD and SVE, and prefer Advanced SIMD when the costs are deemed equal
    • 4 โ€” use both Advanced SIMD and SVE, and prefer SVE when the costs are deemed equal
    • The default value is 0.
  • aarch64-loop-vect-issue-rate-niters โ€” some AArch64 CPU tuning tries to weigh both latencies and issue rates when deciding whether a loop should be vectorized with SVE, vectorized with Advanced SIMD, or not vectorized at all. If this parameter is set to n, GCC won't use this heuristic for loops known to execute in fewer than n Advanced SIMD iterations. ๐ŸŽ๏ธ

๐Ÿงš Program Instrumentation Options ๐Ÿงš

GCC supports a bunch of command-line options that tack run-time instrumentation onto the code it normally generates ๐Ÿ’…. One reason you'd instrument is to collect profiling stats so you can find program hot spots, do code coverage analysis, or run profile-guided optimizations ๐Ÿ”ฅ. Another kind of instrumentation adds run-time checks that catch programming errors like invalid pointer dereferences or out-of-bounds array accesses, plus deliberately hostile attacks like stack smashing or C++ vtable hijacking ๐Ÿ›ก๏ธ. There's also a general hook that can be used to build other forms of tracing or function-level instrumentation for debugging or program analysis ๐Ÿซถ.

  • -p, -pg โ€” generates extra code that writes profile information for the analysis program prof (with -p) or gprof (with -pg) ๐Ÿ“Š. You have to use this option when compiling the source files you want data about, and you have to use it when linking too โš ๏ธ.

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

  • -fprofile-arcs โ€” adds code so that program flow arcs get instrumented ๐ŸŒ€. While the program runs, it records how many times each branch and call gets executed, and how many times each one is taken or returns. On targets that support constructors with priority, profiling handles constructors, destructors, and C++ constructors and destructors of classes used as the type of a global variable properly ๐Ÿ’œ.

When the compiled program exits, it saves this data to a file called auxname.gcda for each source file ๐Ÿ’พ. The data can be used for profile-directed optimizations (-fbranch-probabilities) or for test coverage analysis (-ftest-coverage). Each object file's auxname comes from the name of the output file, if one is explicitly specified and it isn't the final executable. Otherwise it's the basename of the source file. In both cases, any suffix gets removed. For example, foo.gcda for input file dir/foo.c, or dir/foo.gcda for output file specified as -o dir/foo.o ๐Ÿง.

Heads up: if a command line links source files directly, the matching .gcda files get prefixed with the unsuffixed name of the output file. So "gcc a.c b.c -o binary" would generate binary-a.gcda and binary-b.gcda files ๐ŸŽฏ.

  • --coverage โ€” this is what you use to compile and link code instrumented for coverage analysis ๐Ÿงช. It's a synonym for -fprofile-arcs -ftest-coverage when compiling, and for -lgcov when linking. Check the docs for those options for more details ๐Ÿ“š.
    • Compile the source files with -fprofile-arcs plus optimization and code generation options. For test coverage analysis, add the extra -ftest-coverage option. You don't need to profile every source file in a program ๐ŸŒˆ.
  • Step 1: Compile your source files with -fprofile-abs-path too, so the .gcno files get absolute path names. That way gcov can find the right sources even when your builds run from different working directories. ๐Ÿ“‚
  • Step 2: Link your object files with -lgcov or -fprofile-arcs. The second one already brings in the first, so you're covered either way. ๐Ÿ”—
  • Step 3: Run your program on a representative workload to collect the arc profile info. You can repeat this as many times as you want ๐Ÿ”. You can even run several instances at once. As long as the file system supports locking, the data files get updated correctly ๐Ÿ”’. Unless you're using a strict ISO C dialect option, fork calls are detected and handled properly, so nothing gets double counted ๐Ÿ™Œ.

Also, you can recompile an object file multiple times and its .gcda file will merge, as long as the source file and compiler options haven't changed ๐Ÿงฉ.

  • Step 4: For profile-directed optimizations, compile your source files again with the same optimization and code generation options, plus -fbranch-probabilities ๐ŸŽฏ.
  • Step 5: For test coverage analysis, use gcov to turn the .gcno and .gcda files into human-readable info. Check the gcov documentation for the full scoop ๐Ÿ“–.

With -fprofile-arcs, GCC builds a program flow graph for each function in your program, then finds a spanning tree for that graph ๐ŸŒณ. Only the arcs not on the spanning tree need instrumenting, and GCC adds code to count how many times those arcs run ๐Ÿ”ข. If an arc is the only exit or the only entrance to a block, the counting code can go right into that block. Otherwise, GCC has to make a new basic block just to hold it ๐Ÿงฑ.

  • -ftest-coverage โ€” Okay, this one is giving coverage โœจ. It makes a notes file that the gcov code-coverage utility can use to show how much of your program is covered. Each source file's notes file is named auxname.gcno. Scroll up to -fprofile-arcs for what auxname means and how to actually generate the test coverage data ๐Ÿ“. Heads up: your coverage data matches your source files way more closely if you don't optimize ๐Ÿ™ˆ.
  • -fprofile-abs-path โ€” This one turns relative source file names into absolute path names in the .gcno files ๐Ÿ—บ๏ธ. It's the same perk as before: gcov can find the correct sources in projects where compilations happen from different working directories ๐Ÿ’–.
  • -fprofile-dir=path โ€” This sets the directory where GCC looks for profile data files, and that path can be absolute or relative ๐Ÿ“. It only affects profile data generated by -fprofile-generate, -ftest-coverage, and -fprofile-arcs, and used by -fprofile-use, -fbranch-probabilities, and their related options ๐Ÿ”—. By default the directory is the current one, so the profile data file sits right next to the object file ๐Ÿ . If the object file name isn't an absolute path, GCC mangles the absolute path of the sourcename.gcda file and uses that as the .gcda file name, so names don't clash ๐ŸŒ€. Check out -fprofile-arcs for the full file naming deets, and also see the similar option -fprofile-note ๐Ÿ‘€.

If you're running an executable in a massively parallel environment, it's smart to save profiles into different folders. You can do that by using these variables in path, which 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 need for instrumenting an app, so it can produce a profile for later recompiles with profile feedback based optimization ๐Ÿ› ๏ธ. You have to use -fprofile-generate when compiling and when linking, no skipping ๐Ÿšจ. It enables -fprofile-arcs, -fprofile-values, -finline-functions, and -fipa-bit-cp ๐Ÿ’…. If you give it a path, GCC looks there for the profile feedback data files. See -fprofile-dir for the details ๐Ÿ“‚. When you're ready to optimize based on what got collected, use -fprofile-use ๐Ÿš€.
  • -fprofile-info-section, -fprofile-info-section=name โ€” This one is a little niche ๐Ÿง. It registers the profile info in a specific section instead of using a constructor/destructor. The section is called name if you give one, and otherwise it defaults to .gcov_info ๐Ÿท๏ธ. For each translation unit, a pointer to the profile info from -fprofile-arcs gets placed in that section. This option turns off the constructor registration and the destructor processing ๐Ÿ”ง.
โš ๏ธ This option is not intended for hosted environments like GNU/Linux! It's built for free-standing environments, like embedded systems, that have limited resources and don't support constructors/destructors or C library file I/O ๐Ÿค–.

The linker can gather those input sections into one continuous memory block and define start and end symbols for it. Here's an example GNU linker script that defines a linker output section:

.gcov_info      :
{
  PROVIDE (__gcov_info_start = .);
  KEEP (*(.gcov_info))
  PROVIDE (__gcov_info_end = .);
}

Then your program can dump the profiling info registered in this linker set. It goes something like this ๐Ÿ’ป:

#include <gcov.h>
#include <stdio.h>
#include <stdlib.h>

extern const struct gcov_info *__gcov_info_start[];
extern const struct gcov_info *__gcov_info_end[];

static void
filename (const char *f, void *arg)
{
  puts (f);
}

static void
dump (const void *d, unsigned n, void *arg)
{
  const unsigned char *c = d;

  for (unsigned i = 0; i < n; ++i)
    printf ("%02x", c[i]);
}

static void *
allocate (unsigned length, void *arg)
{
  return malloc (length);
}

static void
dump_gcov_info (void)
{
  const struct gcov_info **info = __gcov_info_start;
  const struct gcov_info **end = __gcov_info_end;

  /* Obfuscate variable to prevent compiler optimizations.  */
  __asm__ ("" : "+r" (info));

  while (info != end)
  {
    void *arg = NULL;
    __gcov_info_to_gcda (*info, filename, dump, allocate, arg);
    putchar ('\n');
    ++info;
  }
}

int
main()
{
  dump_gcov_info();
  return 0;
}
  • -fprofile-note=path โ€” If you give it a path, GCC saves the .gcno file into that location ๐Ÿ“ฅ. Heads up: if you combine this with multiple source files, the .gcno file gets overwritten ๐Ÿ˜ฌ.
  • -fprofile-prefix-path=path โ€” This pairs with profile-generate=profile_dir and profile-use=profile_dir to tell GCC where the base directory of your built source tree is ๐ŸŒฒ. By default, profile_dir holds files with mangled absolute paths for every object file in the project, which is a mess ๐Ÿ™ƒ. It becomes a real problem when the directory you built the instrumented binary in is different from the one you used for the feedback-optimized build, because then the profile data won't be found during the optimized build ๐Ÿ’”. In those setups, pass -fprofile-prefix-path=path with path pointing to the build's base directory. That strips the irrelevant part and keeps every file name relative to the main build directory ๐Ÿงน.
  • -fprofile-prefix-map=old=new โ€” When you compile files living in directory old, the profiling info (recorded with --coverage) describes them as if they lived in directory new instead ๐ŸŽญ. Also check out -ffile-prefix-map ๐Ÿ‘ฏ.
  • -fprofile-update=method โ€” This changes the update method for an app that's instrumented for profile feedback based optimization ๐Ÿ”„. The method should be single, atomic, or prefer-atomic. single is great for single-threaded apps, while atomic stops profile corruption by emitting thread-safe code ๐Ÿงต.
๐Ÿšจ Warning: If your app doesn't properly join all its threads (or it creates a detached thread), the profile file can still get corrupted. Bestie, be careful!

Using prefer-atomic gets transformed into atomic when the target supports it, or into single if it doesn't ๐ŸŽ€. The GCC driver automatically picks prefer-atomic whenever -pthread is on the command line ๐Ÿงš.

  • -fprofile-filter-files=regex โ€” This instruments only the functions from files whose names match any of the regular expressions, which are 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 โ€” This is the opposite vibe: it instruments only the functions from files whose names don't match any of the regular expressions, again separated by semicolons ๐Ÿ™…โ€โ™€๏ธ. For example, -fprofile-exclude-files=/usr/.* stops instrumentation for every file in the /usr/ folder ๐Ÿšซ.
  • -fprofile-reproducible=[multithreaded|parallel-runs|serial] โ€” This controls how reproducible the profile gathered by -fprofile-generate is ๐Ÿ”. It's super useful when you want to rebuild a program with the same outcome, like for distribution packages ๐Ÿ“ฆ.

With -fprofile-reproducible=serial, the profile from -fprofile-generate is reproducible, as long as the trained program behaves the same on every invocation of the train run, isn't multi-threaded, and always streams profile data in the same order ๐Ÿง˜. Profile streaming happens at the end of the program run, but also before the fork function is invoked ๐Ÿด.

Real talk, though: lots of program execution counts depend on things like the length of temporary file names or memory space randomization, which can change hash-table collision rates ๐ŸŽฒ. That non-reproducible stuff can be annotated with the no_instrument_function function attribute ๐Ÿท๏ธ. You can use gcov-dump with -l to dump the gathered data and check that it really is reproducible ๐Ÿ”๐Ÿ’œ.

Okay so, with -fprofile-reproducible=parallel-runs ๐ŸŽ€ your collected profile stays reproducible no matter what order the data gets streamed into the gcda files โœจ. It lets you run multiple instances of your instrumented program at the same time (like with make -j) ๐Ÿƒโ€โ™€๏ธ, but it's giving a tradeoff: the quality of the gathered data takes a hit, especially for indirect call profiling ๐Ÿ˜ญ.

  • -fsanitize=address โ€” ๐Ÿ”ฅ Turns on AddressSanitizer, a fast memory error detector. Your memory access instructions get instrumented so it can catch out-of-bounds and use-after-free bugs ๐Ÿ’€. This also enables -fsanitize-address-use-after-scope. More details live at https://github.com/google/sanitizers/wiki/AddressSanitizer ๐Ÿ“š. The run-time behavior is controlled by the ASAN_OPTIONS environment variable ๐ŸŒธ. Set it to "help=1" and the available options pop up when your instrumented program starts ๐Ÿงš. For the full list of supported options, check https://github.com/google/sanitizers/wiki/AddressSanitizerFlags#run-time-flags ๐Ÿ’œ. โš ๏ธ This one cannot be combined with -fsanitize=thread or -fsanitize=hwaddress ๐Ÿ™…โ€โ™€๏ธ. Also, the only target -fsanitize=hwaddress is currently supported on is AArch64, just FYI ๐Ÿ’….
  • -fsanitize=kernel-address โ€” ๐Ÿง Enables AddressSanitizer for the Linux kernel. Deets are at https://github.com/google/kasan ๐Ÿซถ.
  • -fsanitize=hwaddress โ€” ๐Ÿฆ‹ Hardware-assisted AddressSanitizer, which is honestly iconic. It uses a hardware ability to ignore the top byte of a pointer, so it can detect memory errors with a low memory overhead ๐ŸŒˆ. Memory access instructions get instrumented to catch out-of-bounds and use-after-free bugs. This also enables -fsanitize-address-use-after-scope. See https://clang.llvm.org/docs/HardwareAssistedAddressSanitizerDesign.html for more details ๐Ÿ“–. Run-time behavior is influenced by the HWASAN_OPTIONS environment variable, and setting it to "help=1" shows the available options at startup ๐Ÿ“. โš ๏ธ It cannot be combined with -fsanitize=thread or -fsanitize=address, and it is currently only available on AArch64 ๐Ÿšซ.
  • -fsanitize=kernel-hwaddress โ€” ๐Ÿง  Hardware-assisted AddressSanitizer for compiling the Linux kernel. It's similar to -fsanitize=kernel-address but uses an alternate instrumentation method. It's also similar to -fsanitize=hwaddress, but with instrumentation differences needed for the kernel. Those differences exist to skip 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 than -fsanitize=hwaddress. Instrumenting the stack and alloca calls is not on by default, but you can still turn it on with the command-line options --param hwasan-instrument-stack=1 and --param hwasan-instrument-allocas=1 respectively ๐Ÿ™Œ. Using a random frame tag is not implemented for kernel instrumentation ๐Ÿฅฒ.
  • -fsanitize=pointer-compare โ€” ๐Ÿ‘€ Instruments comparison operations (<, <=, >, >=) with pointer operands. It must be combined with either -fsanitize=kernel-address or -fsanitize=address, and it cannot be combined with -fsanitize=thread ๐Ÿšซ.
    • ๐Ÿ’ค Note: By default the check is disabled at run time. To turn it on, add "detect_invalid_pointer_pairs=2" to the ASAN_OPTIONS environment variable. Using "detect_invalid_pointer_pairs=1" only detects invalid operations when both pointers are non-null ๐Ÿซ .
  • -fsanitize=pointer-subtract โ€” โž– Instruments subtraction with pointer operands. It must be combined with either -fsanitize=kernel-address or -fsanitize=address, and it cannot be combined with -fsanitize=thread ๐Ÿšซ.
    • ๐Ÿ’ค Note: By default the check is disabled at run time. To enable it, add "detect_invalid_pointer_pairs=2" to the ASAN_OPTIONS environment variable. Using "detect_invalid_pointer_pairs=1" only detects invalid operations 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 that shadow call stack in the function epilogue ๐Ÿชž. Instrumentation only happens in functions that need to save the return address to the stack โœจ.
    • ๐Ÿ™ƒ Right now it only supports the aarch64 platform. It's specifically designed for Linux kernels that enable the CONFIG_SHADOW_CALL_STACK option. For user space programs, runtime support is not currently provided in libc and libgcc, so users who want this in user space need to provide their 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". This 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 is no userspace runtime support, code compiled with ShadowCallStack cannot use exception handling. Use -fno-exceptions to turn off exceptions.
    • ๐Ÿ“š See https://clang.llvm.org/docs/ShadowCallStack.html for more details.
  • -fsanitize=thread โ€” ๐Ÿงต Enables ThreadSanitizer, a fast data race detector. Memory access instructions get instrumented to detect data race bugs ๐Ÿƒโ€โ™€๏ธ. See https://github.com/google/sanitizers/wiki#threadsanitizer for more details. The run-time behavior is influenced using the TSAN_OPTIONS environment variable; check https://github.com/google/sanitizers/wiki/ThreadSanitizerFlags for a list of supported options ๐Ÿ’œ. โš ๏ธ It cannot be combined with -fsanitize=address or -fsanitize=leak.
    • ๐Ÿ˜ต Note: Sanitized atomic builtins cannot throw exceptions when operating on invalid memory addresses with non-call exceptions (-fnon-call-exceptions).
  • -fsanitize=leak โ€” ๐Ÿ’ง Enables LeakSanitizer, a memory leak detector. This option only matters for linking executables, and only when the executable is linked against a library that overrides "malloc" and other allocator functions ๐Ÿซง. See https://github.com/google/sanitizers/wiki/AddressSanitizerLeakSanitizer for more details. Run-time behavior is influenced by the LSAN_OPTIONS environment variable ๐ŸŒท. โš ๏ธ It cannot be combined with -fsanitize=thread.
  • -fsanitize=undefined โ€” ๐ŸŒ€ Enables UndefinedBehaviorSanitizer, a fast undefined behavior detector. Various computations get instrumented to catch undefined behavior at runtime ๐Ÿ‘‘. See https://clang.llvm.org/docs/UndefinedBehaviorSanitizer.html for more details. Run-time behavior is influenced by the UBSAN_OPTIONS environment variable. Here are the current suboptions ๐Ÿ‘‡:
    • -fsanitize=shift โ€” ๐Ÿซจ Checks that the result of a shift operation is not undefined. What counts as undefined differs slightly between C and C++, and also between ISO C90 and C99, etc. This option has two suboptions, -fsanitize=shift-base and -fsanitize=shift-exponent.
    • -fsanitize=shift-exponent โ€” ๐Ÿ”ข Checks that the second argument of a shift operation is not negative and is smaller than the precision of the promoted first argument.
    • -fsanitize=shift-base โ€” ๐Ÿงฎ If the second argument of a shift operation is within range, checks that the result of the shift is not undefined. What counts as undefined differs slightly between C and C++, and between ISO C90 and C99, etc.
    • -fsanitize=integer-divide-by-zero โ€” ๐Ÿšซ Detects integer division by zero.
    • -fsanitize=unreachable โ€” ๐Ÿ—บ๏ธ With this option, the compiler turns the "__builtin_unreachable" call into a diagnostics message call instead. When the "__builtin_unreachable" call is reached, 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. An application built with this on will throw an error message when it tries to dereference a NULL pointer, when a reference (possibly an rvalue reference) is bound to a NULL pointer, or when a method is invoked on an object pointed to by a NULL pointer ๐Ÿ™…โ€โ™€๏ธ.
    • -fsanitize=return โ€” ๐Ÿ”™ 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 "-" does not overflow in signed arithmetic. This also detects INT_MIN / -1 signed division ๐Ÿง. Heads up, integer promotion rules have to be taken into account, so the following is not an overflow:
signed char a = SCHAR_MAX;
a++;
  • -fsanitize=bounds โ€” ๐Ÿงฑ Enables instrumentation of array bounds, so various out-of-bounds accesses get detected. Flexible array members, flexible array member-like arrays, and initializers of variables with static storage are not instrumented ๐Ÿ™ˆ.
  • -fsanitize=bounds-strict โ€” ๐Ÿงฑ Enables strict instrumentation of array bounds. Most out-of-bounds accesses get detected, including flexible array members and flexible array member-like arrays. Initializers of variables with static storage are still not instrumented ๐Ÿค.
  • -fsanitize=alignment โ€” ๐Ÿ“ Checks alignment of pointers when they are dereferenced, when a reference is bound to an insufficiently aligned target, or when a method or constructor is invoked on an insufficiently aligned object ๐ŸŽฏ.
  • -fsanitize=object-size โ€” ๐Ÿ“ฆ Instruments memory references using the "__builtin_object_size" function. Various out-of-bounds pointer accesses get detected ๐Ÿซถ.
  • -fsanitize=float-divide-by-zero โ€” okay so this one catches floating-point division by zero ๐Ÿงฎ. Unlike a lot of the other sanitizers, it is not switched on by -fsanitize=undefined, because dividing a float by zero can be a totally legit way to get infinities and NaNs โœจ. Not every spicy move is a bug, bestie ๐Ÿ’….
  • -fsanitize=float-cast-overflow โ€” this one checks floating-point to integer conversions ๐Ÿ”ข and makes sure the result doesn't overflow. Also not part of -fsanitize=undefined, and it doesn't vibe well with FE_INVALID exceptions turned on ๐Ÿ™ˆ.
  • -fsanitize=nonnull-attribute โ€” instruments calls to make sure no null values get passed into arguments that the nonnull function attribute says must never be null ๐Ÿšซ. Null in a non-null spot? Not it ๐Ÿ’€.
  • -fsanitize=returns-nonnull-attribute โ€” instruments return statements in functions marked with the returns_nonnull function attribute ๐ŸŽ€, so it can catch those functions handing back a null value.
  • -fsanitize=bool โ€” instruments loads from bool ๐Ÿงธ. If something other than 0 or 1 gets loaded, you get a run-time error. Booleans only do 0 and 1, babe ๐Ÿ˜ค.
  • -fsanitize=enum โ€” instruments loads from an enum type ๐Ÿ“. If the value being loaded is outside the range the enum allows, a run-time error gets issued.
  • -fsanitize=vptr โ€” C++ girlies, this one's for you ๐Ÿ‘‘. It instruments C++ member function calls, member accesses, and some conversions between pointers to base and derived classes, so it can verify the referenced object has the correct dynamic type ๐Ÿฆ‹.
  • -fsanitize=pointer-overflow โ€” instruments pointer arithmetic ๐Ÿงš. If that pointer math overflows, you get a run-time error.
  • -fsanitize=builtin โ€” instruments the arguments passed to selected builtin functions โœจ. If an invalid value sneaks in, a run-time error gets issued. For example, passing 0 as the argument to __builtin_ctz or __builtin_clz is undefined behavior, and this option diagnoses it ๐Ÿซถ.

While -ftrapv causes traps for signed overflows to be emitted, -fsanitize=undefined gives a diagnostic message instead ๐Ÿ“ฃ. Heads up: this currently only works for the C family of languages ๐ŸŒˆ.

  • -fno-sanitize=all โ€” disables all the sanitizers you turned on before ๐Ÿงน. Fair warning: -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 handy for experimenting with different shadow memory layouts in Kernel AddressSanitizer ๐ŸŒธ.
  • -fsanitize-sections=s1,s2,... โ€” sanitizes global variables in the user-defined sections you pick ๐Ÿ—‚๏ธ. The si entries may contain wildcards.
  • -fsanitize-recover[=opts] โ€” this one controls error recovery mode for the sanitizers listed in the comma-separated opts list ๐Ÿ”„. When recovery is on for a sanitizer, the program tries to keep running like nothing happened. That means several runtime errors can get reported in one run, and the exit code might say success even though errors were reported ๐Ÿ˜ญ. The -fno-sanitize-recover= option flips that: only the first error gets reported, and then the program exits with a non-zero exit code ๐Ÿ›‘.

Right now this only works for -fsanitize=undefined (and its suboptions, except -fsanitize=unreachable and -fsanitize=return), -fsanitize=float-cast-overflow, -fsanitize=float-divide-by-zero, -fsanitize=bounds-strict, -fsanitize=kernel-address, and -fsanitize=address. For these sanitizers, recovery is turned on by default, except for -fsanitize=address, where it's still experimental ๐Ÿงช. You can also use -fsanitize-recover=all (turns on recovery for every sanitizer that supports it) or -fno-sanitize-recover=all (turns it off for every sanitizer that supports it) ๐ŸŒˆ.

Even if recovery is turned on at the compiler side, it also has to be enabled on the runtime library side, or the failures are still fatal ๐Ÿ’€. The runtime library defaults to halt_on_error=0 for ThreadSanitizer and UndefinedBehaviorSanitizer, while AddressSanitizer defaults to halt_on_error=1. You can override that by setting the halt_on_error flag in the corresponding environment variable ๐Ÿ”ง.

Using this option without an explicit opts parameter is deprecated ๐Ÿ™…. It's the same as specifying this opts list:

undefined,float-cast-overflow,float-divide-by-zero,bounds-strict
  • -fsanitize-address-use-after-scope โ€” enables sanitization of local variables so it can catch use-after-scope bugs ๐Ÿ•ต๏ธ. This option sets -fstack-reuse to none โœจ.
  • -fsanitize-undefined-trap-on-error โ€” tells the compiler to report undefined behavior using __builtin_trap instead of a libubsan library routine ๐Ÿชค. The perk is that libubsan isn't needed and doesn't get linked in, so this works even in freestanding environments ๐Ÿ•๏ธ.
  • -fsanitize-coverage=trace-pc โ€” enables coverage-guided fuzzing code instrumentation ๐Ÿ›. It inserts a call to __sanitizer_cov_trace_pc into every basic block.
  • -fsanitize-coverage=trace-cmp โ€” enables dataflow guided fuzzing code instrumentation ๐Ÿงต. It inserts a call to __sanitizer_cov_trace_cmp1, __sanitizer_cov_trace_cmp2, __sanitizer_cov_trace_cmp4 or __sanitizer_cov_trace_cmp8 for integral comparisons where both operands are variables. For integral comparisons with one constant operand, it uses __sanitizer_cov_trace_const_cmp1, __sanitizer_cov_trace_const_cmp2, __sanitizer_cov_trace_const_cmp4 or __sanitizer_cov_trace_const_cmp8. For float or double comparisons it uses __sanitizer_cov_trace_cmpf or __sanitizer_cov_trace_cmpd, and for switch statements it uses __sanitizer_cov_trace_switch ๐ŸŽฏ.
  • -fcf-protection=[full|branch|return|none|check] โ€” turns on code instrumentation for control-flow transfers ๐Ÿ›ก๏ธ. It checks that target addresses of control-flow transfer instructions (like indirect function calls, function returns, and indirect jumps) are valid, so the flow of control can't get diverted somewhere unexpected ๐Ÿšง. This is meant to protect against threats like Return-oriented Programming (ROP), and similar call/jmp-oriented programming (COP/JOP) ๐Ÿ˜ค.
    • branch checks validity at indirect branch instructions, aka call/jmp instructions ๐Ÿ“ž.
    • return checks validity when returning from a function โ†ฉ๏ธ.
    • full is an alias for both branch and return ๐Ÿ‘‘.
    • none turns instrumentation off ๐Ÿ™….
    • check is used for the final link with link-time optimization (LTO). It issues an error if LTO object files were compiled with different -fcf-protection values. check is ignored at compile time ๐Ÿซก.

The macro __CET__ is defined when -fcf-protection is used. Its first bit is set to 1 for branch, and its second bit is set to 1 for return ๐Ÿ”. You can also use the nocf_check attribute to mark which functions and calls should be skipped from instrumentation ๐Ÿ™ˆ.

Right now, the x86 GNU/Linux target has an implementation based on Intel Control-flow Enforcement Technology (CET), which works for i686 processors or newer ๐Ÿ’ป.

  • -fharden-compares โ€” for every logical test that survives gimple optimizations and isn't the condition in a conditional branch (like conditions tested for conditional moves, or stored in boolean variables), it emits extra code to compute and verify the reversed condition ๐Ÿชž. If the results don't match, it calls __builtin_trap. Use this with -fharden-conditional-branches to cover all conditionals ๐Ÿ’–.
  • -fharden-conditional-branches โ€” for every non-vectorized conditional branch that survives gimple optimizations, it emits extra code to compute and verify the reversed condition ๐Ÿ”. If the result is unexpected, it calls __builtin_trap. Use this with -fharden-compares to cover all conditionals ๐Ÿซถ.
  • -fstack-protector โ€” emits extra code to check for buffer overflows, like stack smashing attacks ๐Ÿงฑ. It adds 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 a function is entered and then 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 allocated in registers don't ๐Ÿ™ƒ.
  • -fstack-protector-all โ€” same as -fstack-protector, except that all functions get protected ๐Ÿ›ก๏ธโœจ.
  • -fstack-protector-strong โ€” like -fstack-protector, but it also protects extra functions: ones with local array definitions, or ones that reference local frame addresses ๐Ÿ’…. Same rule applies: only variables actually allocated on the stack count, and optimized-away or register-allocated variables don't.
  • -fstack-protector-explicit โ€” like -fstack-protector, but it only protects functions that have the stack_protect attribute ๐ŸŽฏ.
  • -fstack-check โ€” generates code to verify that you don't go beyond the boundary of the stack ๐Ÿฅž. You should specify this if you're running in an environment with multiple threads. In a single-threaded environment you rarely need it, since stack overflow is automatically detected on nearly all systems when there's only one stack ๐Ÿงต.

Note that this switch doesn't actually cause checking to be done ๐Ÿ™…โ€โ™€๏ธ. The operating system or the language runtime has to do that. The switch just causes code generation that makes sure they see the stack being extended ๐ŸŒ™.

okay bestie, the string parameter is where you get to pick your vibe ๐Ÿ’… You can additionally specify a string parameter: no means no checking at all ๐Ÿ™…โ€โ™€๏ธ, generic means force the use of old-style checking, and specific means use the best checking method, which is equivalent to bare -fstack-check โœจ

Old-style checking is a generic mechanism that requires no specific target support in the compiler, but it comes with some major drawbacks ๐Ÿ˜ญ

  1. Modified allocation strategy for large objects: they are always allocated dynamically if their size exceeds a fixed threshold. ngl this may change the semantics of some code, so keep an eye out ๐Ÿ‘€
  2. Fixed limit on the size of the static frame of functions: when it's topped by a particular function, stack checking is not 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 ๐Ÿซ 

Note that old-style stack checking is also the fallback method for specific if no target support has been added in the compiler ๐Ÿงš

-fstack-check= is designed for Ada's needs to detect infinite recursion and stack overflows ๐Ÿ‘‘ specific is an excellent choice when compiling Ada code. It is not generally sufficient to protect against stack-clash attacks, though. To protect against those, you want -fstack-clash-protection ๐Ÿ›ก๏ธ

  • -fstack-clash-protection โ€” generates code to prevent stack clash style attacks ๐Ÿฆ‹ When this option is enabled, the compiler only allocates one page of stack space at a time, and each page is accessed immediately after allocation. So it stops allocations from jumping over any stack guard page provided by the operating system ๐Ÿ’–

Most targets do not fully support stack clash protection, lowkey tragic ๐Ÿ˜ญ However, on those targets, -fstack-clash-protection will protect dynamic stack allocations. It may also provide limited protection for static stack allocations if the target supports -fstack-check=specific โœจ

  • -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 required, a signal is raised at run time. For most targets the signal goes off 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. Not every setup is going to vibe with it ๐Ÿ™ˆ

You can locally override stack limit checking by using the "no_stack_limit" function attribute ๐ŸŽ€

  • -fsplit-stack โ€” generates code to automatically split the stack before it overflows ๐Ÿงš The resulting program has a discontiguous stack, which can only overflow if the program is unable to allocate any more memory. This is most useful when running threaded programs, because it's no longer necessary to calculate a good stack size to use for each thread ๐Ÿคฏ This is currently only implemented for the x86 targets running GNU/Linux ๐Ÿง

When code compiled with -fsplit-stack calls code compiled without -fsplit-stack, there may not be much stack space available for the latter code to run in ๐Ÿ˜ฌ If compiling all code, including library code, with -fsplit-stack is not an option, then the linker can fix up these calls so the code compiled without -fsplit-stack always has a large stack. Support for this is implemented in the gold linker in GNU binutils release 2.21 and later ๐Ÿ’œ

  • -fvtable-verify=[std|preinit|none] โ€” this option is only available when compiling C++ code ๐Ÿ’œ 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 the call goes through is valid for the type of the object, and hasn't been corrupted or overwritten ๐Ÿ”’ If an invalid vtable pointer is detected at run time, an error is reported and execution of the program is immediately halted ๐Ÿ›‘

This option causes run-time data structures to be built at program startup, and those are used for verifying the vtable pointers ๐Ÿงฉ The options std and preinit control the timing of when these data structures are built. In both cases, they're built before execution reaches "main". Using -fvtable-verify=std builds them after shared libraries have been loaded and initialized. -fvtable-verify=preinit builds them before shared libraries have been loaded and initialized ๐Ÿฆ‹

If this option appears multiple times on the command line with different values specified, none takes highest priority over both std and preinit, and preinit takes priority over std ๐Ÿ‘‘

  • -fvtv-debug โ€” when used alongside -fvtable-verify=std or -fvtable-verify=preinit, it causes debug versions of the runtime functions for the vtable verification feature to be called ๐Ÿ” This flag also makes the compiler log information about which vtable pointers it finds for each class. That info gets written to a file named vtv_set_ptr_data.log in the directory named by the environment variable VTV_LOGS_DIR if that's defined, or the current working directory otherwise ๐Ÿ“
Note: This feature appends data to the log file. If you want a fresh log file, be sure to delete any existing one ๐Ÿ—‘๏ธ
  • -fvtv-counts โ€” this is a debugging flag ๐Ÿ› When used alongside -fvtable-verify=std or -fvtable-verify=preinit, the compiler keeps track of the total number of virtual calls it encounters and the number of verifications it inserts. It also counts the number of calls to certain run-time library functions that it inserts, and logs this for each compilation unit ๐Ÿ“Š The compiler writes this info to a file named vtv_count_data.log in the directory named by VTV_LOGS_DIR if that's defined, or the current working directory otherwise. It also counts the size of the vtable pointer sets for each class, and writes that to vtv_class_set_sizes.log in the same directory ๐Ÿ’…
Note: This feature appends data to the log files. To get fresh log files, be sure to delete any existing ones ๐Ÿงน

  • -finstrument-functions โ€” generates instrumentation calls for entry and exit to functions ๐Ÿ”ฅ Just after function entry and just before function exit, the following profiling functions are called with the address of the current function and its call site ๐Ÿ‘€ (On some platforms, __builtin_return_address does not work beyond the current function, so the call site information may not be available to the profiling functions otherwise ๐Ÿ™ƒ)
void __cyg_profile_func_enter (void *this_fn,
                               void *call_site);
void __cyg_profile_func_exit  (void *this_fn,
                               void *call_site);

The first argument is the address of the start of the current function, which can be looked up exactly in the symbol table ๐Ÿ”Ž

This instrumentation is also done for functions expanded inline in other functions. The profiling calls indicate where, conceptually, the inline function is entered and exited. This means that addressable versions of such functions must be available. If all your uses of a function are expanded inline, this may mean an additional expansion of code size ๐Ÿ“ฆ If you use extern inline in your C code, an addressable version of such functions must be provided. (This is normally the case anyway, but if you get lucky and the optimizer always expands the functions inline, you might have gotten away without providing static copies ๐Ÿ€)

A function may be given the attribute "no_instrument_function", in which case this instrumentation is not done. This can be used for, example, the profiling functions listed above, high-priority interrupt routines, and any functions from which the profiling functions cannot safely be called (perhaps signal handlers, if the profiling routines generate output or allocate memory) ๐Ÿšซ

  • -finstrument-functions-exclude-file-list=file,file,... โ€” sets the list of functions that are excluded from instrumentation (see the description of -finstrument-functions) ๐Ÿ™…โ€โ™€๏ธ If the file that contains a function definition matches with one of the file entries, then that function is not instrumented. The match is done on substrings: if the file parameter is a substring of the file name, it's considered to be a match ๐Ÿง

For example:

-finstrument-functions-exclude-file-list=/bits/stl,include/sys

That excludes any inline function defined in files whose pathnames contain /bits/stl or include/sys ๐ŸŒˆ

If, for some reason, you want to include a comma in one of the sym values, write ,,. For example, -finstrument-functions-exclude-file-list=',,tmp' (note the single quotes surrounding the option) ๐ŸŽ€

  • -finstrument-functions-exclude-function-list=sym,sym,... โ€” this is similar to -finstrument-functions-exclude-file-list, but this one sets the list of function names to be excluded from instrumentation ๐Ÿงš The function name to be matched is its user-visible name, such as "vector<int> blah(const vector<int> &)", not the internal mangled name (e.g., "_Z4blahRSt6vectorIiSaIiEE") ๐Ÿค“ The match is done on substrings: if the sym parameter is a substring of the function name, it's considered to be a match. For C99 and C++ extended identifiers, the function name must be given in UTF-8, not using universal character names ๐Ÿ’œ
  • -fpatchable-function-entry=N[,M] โ€” generates N NOPs right at the beginning of each function, with the function entry point before the Mth NOP โœจ If M is omitted, it defaults to 0, so the function entry points to the address just at the first NOP ๐Ÿฆ‹ The NOP instructions reserve extra space that can be used to patch in any desired instrumentation at run time, provided that the code segment is writable ๐Ÿ› ๏ธ The amount of space is controllable indirectly via the number of NOPs. The NOP instruction used corresponds to the instruction emitted by the internal GCC back-end interface gen_nop. This behavior is target-specific and may also depend on the architecture variant and/or other compilation options ๐ŸŒธ

Okay so the patchable function entry stuff is giving main character energy โœจ For run-time identification ๐Ÿ”, the starting addresses of these areas (each one is its function entry minus M ๐Ÿงš) also get collected into the __patchable_function_entries section of the resulting binary.

Also, bestie, the value of __attribute__ ((patchable_function_entry (N,M))) beats the command-line option -fpatchable-function-entry=N,M ๐Ÿ‘‘. Lowkey iconic, because you can use it to make the area bigger or delete it completely on one single function ๐Ÿ’…. And if N=0, no pad location gets recorded ๐Ÿ™ˆ.

The NOP instructions go in at the function entry address, and maybe before it depending on M (even before the prologue) ๐ŸŒธ. Honestly, the maximum for N and M is 65535 ๐Ÿ’€.


โœจ 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 the -E option, nothing happens except preprocessing ๐Ÿ’–. Some of these options only make sense together with -E, because they make the preprocessor output unsuitable for actual compilation ๐Ÿ˜ญ.

Other include-file search path options are documented in Directory Options ๐Ÿฆ‹, and options that control preprocessor diagnostics are listed in Warning Options ๐Ÿซถ.

  • -D name โ€” Predefine name as a macro, with definition 1 ๐Ÿ“.
  • -D name=definition โ€” The contents of definition get tokenized and processed as if they showed up during translation phase three in a #define directive ๐Ÿงš. The definition gets cut off at embedded newline characters โœ‚๏ธ.
    • If you call the preprocessor from a shell (or something shell-like), you might need the shell's quoting syntax to protect characters like spaces, since they mean something in shell syntax ๐Ÿš.
    • If you want a function-like macro on the command line, write its argument list in parentheses before the equals sign (if there is one) ๐Ÿ’œ. Parentheses mean something to most shells, so quote the option. With sh and csh, -D'name(args...)=definition' works โœจ.
    • -D and -U options are processed in the order they appear on the command line. All -imacros file and -include file options get processed after every -D and -U option ๐Ÿ”ฅ.
  • -U name โ€” Cancel any previous definition of name, whether it was built in or came from a -D option ๐Ÿ™…โ€โ™€๏ธ.
  • -include file โ€” Process file as if #include "file" appeared as the first line of the primary source file ๐Ÿ“„. 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, as normal ๐Ÿฆ‹.
    • If you give multiple -include options, the files get included in the order they appear on the command line ๐ŸŒˆ.
  • -imacros file โ€” Exactly like -include, except any output from scanning file is thrown away ๐Ÿ—‘๏ธ. The macros it defines stay defined ๐Ÿ’…. This lets you grab all the macros from a header without also processing its declarations ๐Ÿงš.
    • All files given by -imacros get processed before all files given by -include ๐Ÿ‘‘.
  • -undef โ€” Don't predefine any system-specific or GCC-specific macros ๐Ÿ™ˆ. The standard predefined macros stay defined ๐Ÿ’–.
  • -pthread โ€” Defines additional macros needed for using the POSIX threads library ๐Ÿงต. Use this option consistently for both compilation and linking ๐Ÿ”—. It's supported on GNU/Linux targets and most other Unix derivatives, plus x86 Cygwin and MinGW targets ๐ŸŒธ.
  • -M โ€” Instead of printing the preprocessed result, output a rule for make describing the dependencies of the main source file ๐Ÿ”. You get one make rule with 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 with any leading directory parts removed ๐Ÿ“.
    • If there are lots of included files, the rule gets split across several lines using \-newline ๐Ÿ“. The rule has no commands ๐Ÿซถ.
    • This option does not suppress the preprocessor's debug output, like -dM. To keep that debug output from mixing with the dependency rules, explicitly specify the dependency output file with -MF, or use an environment variable like DEPENDENCIES_OUTPUT ๐Ÿง . Debug output still goes to the regular output stream as normal โœจ.
    • Passing -M to the driver implies -E, and suppresses warnings with an implicit -w ๐Ÿ™ˆ.
  • -MM โ€” Like -M, but don't mention header files found in system header directories, or header files included (directly or indirectly) from 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, specifies a file to write the dependencies to ๐Ÿ“. If there's no -MF, the preprocessor sends the rules to the same place it would send preprocessed output ๐Ÿ“จ.
    • When used with the driver options -MD or -MMD, -MF overrides the default dependency output file ๐Ÿ‘‘.
    • If file is -, the dependencies get written to stdout ๐Ÿ–ฅ๏ธ.
  • -MG โ€” Used along with an option like -M that requests dependency generation, -MG assumes missing header files are generated files ๐Ÿ› ๏ธ. It adds them to the dependency list without raising an error ๐Ÿฅฐ. The dependency filename comes straight from the #include directive, without any path prepended ๐Ÿ“. -MG also suppresses preprocessed output, since a missing header file makes that useless ๐Ÿ™ƒ.
    • This feature is used in automatic updating of makefiles ๐Ÿ”„.
  • -Mno-modules โ€” Disables dependency generation for compiled module interfaces ๐Ÿšซ.
  • -MP โ€” This option tells CPP to add a phony target for each dependency other than the main file, so each one depends on nothing ๐ŸŽญ. These dummy rules work around errors that make gives when you remove header files without updating the Makefile to match ๐Ÿ˜ญ.
    • This is typical output:
test.o: test.c test.h

test.h:
  • -MT target โ€” Changes the target of the rule emitted by dependency generation ๐ŸŽฏ. By default, CPP takes the name of the main input file, deletes any directory components and any file suffix like .c, and appends the platform's usual object suffix ๐Ÿง. That result is the target.
    • An -MT option sets the target to be exactly the string you specify ๐Ÿ’…. If you want multiple targets, you can specify them as a single argument to -MT, or use multiple -MT options ๐ŸŒˆ.
    • For example, -MT '$(objpfx)foo.o' might give:
$(objpfx)foo.o: foo.c
  • -MQ target โ€” Same as -MT, but it quotes any characters that are special to Make ๐Ÿ”. -MQ '$(objpfx)foo.o' gives:
$$(objpfx)foo.o: foo.c
  • The default target is automatically quoted, as if it were given with -MQ โœจ.
  • -MD โ€” -MD is equivalent to -M -MF file, except that -E is not implied ๐Ÿงš. The driver figures out file based on whether an -o option is given ๐Ÿ”Ž. If it is, the driver uses that argument but with a suffix of .d ๐Ÿงพ. Otherwise, it takes the name of the input file, removes any directory components and suffix, and applies a .d suffix ๐Ÿ“.
    • If -MD is used together with -E, any -o switch is understood to specify the dependency output file ๐Ÿ“‚. But if -MD is used without -E, each -o is understood to specify a target object file ๐ŸŽฏ.
    • Since -E is not implied, -MD can generate a dependency output file as a side effect of the compilation process ๐ŸŽ‰.
  • -MMD โ€” Like -MD, but only mention user header files, not system header files ๐Ÿ™…โ€โ™€๏ธ.
  • -fpreprocessed โ€” Tells the preprocessor that the input file has already been preprocessed ๐Ÿ”. This suppresses things like macro expansion, trigraph conversion, escaped newline splicing, and processing of most directives ๐Ÿ™Œ. The preprocessor still recognizes and removes comments, so you can pass a file preprocessed with -C to the compiler without problems ๐Ÿ’–. In this mode, the integrated preprocessor is 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, handle directives but don't expand macros ๐Ÿ“œ.
    • How this behaves depends on the -E and -fpreprocessed options ๐Ÿค”.
    • With -E, preprocessing is limited to handling directives such as #define, #ifdef, and #error ๐Ÿ› ๏ธ. Other preprocessor operations, like macro expansion and trigraph conversion, are not performed ๐Ÿšซ. In addition, the -dD option is implicitly enabled ๐Ÿ’œ.
    • With -fpreprocessed, predefinition of command line and most builtin macros is disabled ๐Ÿ™…โ€โ™€๏ธ. Macros such as __LINE__, which depend on context, are handled normally ๐Ÿ“. This enables compilation of files previously preprocessed with -E -fdirectives-only ๐ŸŽ€.
    • With both -E and -fpreprocessed, the rules for -fpreprocessed take precedence ๐Ÿ‘‘. This enables full preprocessing of files previously preprocessed with -E -fdirectives-only ๐ŸŒธ.
  • -fdollars-in-identifiers โ€” Accept $ in identifiers ๐Ÿ’ฒ.
  • -fextended-identifiers โ€” Accept universal character names and extended characters in identifiers ๐ŸŒˆ. This option is enabled by default for C99 (and later C standard versions) and C++ ๐Ÿซถ.
  • -fno-canonical-system-headers โ€” When preprocessing, don't shorten system header paths with canonicalization ๐Ÿ›ฃ๏ธ.
  • -fmax-include-depth=depth โ€” Sets the maximum depth of nested #include directives ๐Ÿช†. The default is 200 ๐Ÿ’ฏ.
  • -ftabstop=width โ€” Sets the distance between tab stops ๐Ÿ“. This helps the preprocessor report correct column numbers in warnings or errors, even if tabs appear on the line ๐ŸŽฏ. If the value is less than 1 or greater than 100, the option is ignored ๐Ÿ™ˆ. The default is 8 ๐Ÿ“.

-ftrack-macro-expansion[=level] โ€” okay bestie, this one tracks where tokens live across macro expansions ๐Ÿ” so that when an error pops up inside a macro, the compiler can print the current macro expansion stack for you ๐Ÿ’…. Heads up though: it makes the preprocessor and the compiler eat more memory ๐Ÿซ . The level lets you dial down how precise the tracking is if memory gets tight โœจ:

  • 0 turns the whole thing off ๐Ÿ™…โ€โ™€๏ธ
  • 1 tracks locations in a degraded mode for minimal memory overhead ๐Ÿฆ‹. In this mode, every token that comes out of expanding an argument of a function-like macro shares the same location
  • 2 tracks locations completely ๐Ÿ‘‘ and is the most memory hungry option ๐Ÿ’€
  • If you give the option with no argument, the default level is 2

Note that -ftrack-macro-expansion=2 is activated by default ๐ŸŒˆ

  • -fmacro-prefix-map=old=new โ€” when you preprocess files hanging out in the directory old, the __FILE__ and __BASE_FILE__ macros will act like those files live in new instead ๐Ÿ—บ๏ธ. Use . for new to turn an absolute path into a relative one, which can lead to more reproducible builds that are location independent ๐ŸŒธ. This also affects __builtin_FILE() during compilation โœจ. See also -ffile-prefix-map.
  • -fexec-charset=charset โ€” sets the execution character set, used for string and character constants ๐Ÿ’–. The default is UTF-8, and 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 UTF-32 or UTF-16, whichever matches the width of wchar_t. Same deal as -fexec-charset: charset can be any encoding iconv supports, but you'll have problems with encodings that don't fit exactly in wchar_t ๐Ÿ˜ญ
  • -finput-charset=charset โ€” sets the input character set, 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 it from the locale, the default is UTF-8. The locale or this option can override it, but right now the command-line option wins if there's a conflict ๐Ÿ‘‘. charset can be any encoding your system's iconv library routine supports.
  • -fpch-deps โ€” when you're using precompiled headers, this makes the dependency-output flags also list the files from the precompiled header's dependencies ๐Ÿ“š. Without it, only the precompiled header gets listed, not the files used to create it, because those files aren't consulted when a precompiled header is used ๐Ÿ™ˆ.
  • -fpch-preprocess โ€” lets you use a precompiled header together with -E ๐Ÿซถ. It inserts a special #pragma, which looks like #pragma GCC pch_preprocess "filename", into the output to mark where the precompiled header was found and what its filename is. When -fpreprocessed is in use, GCC recognizes this #pragma and loads the PCH โœจ.

This option is off by default, because the preprocessed output is only really suitable as input to GCC ๐Ÿ’…. It gets switched on by -save-temps.

You shouldn't write this #pragma in your own code ๐Ÿ™…โ€โ™€๏ธ, but it's totally safe to edit the filename if the PCH file is available in a different location ๐Ÿงณ. The filename can be absolute, or relative to GCC's current directory.

  • -fworking-directory โ€” turns on linemarkers in the preprocessor output so the compiler knows the current working directory at the time of preprocessing ๐Ÿ—‚๏ธ. With this enabled, the preprocessor emits a second linemarker after the initial one, containing the current working directory followed by two slashes. When that directory shows up in preprocessed input, GCC uses it as the directory reported 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 in the command line, this option has no effect, since no #line directives are emitted whatsoever ๐Ÿšซ.
  • -A predicate=answer โ€” makes an assertion with the predicate predicate and the answer answer ๐Ÿฆ‹. This form is preferred over the older -A predicate(answer) form, which is still supported, because it doesn't use shell special characters ๐Ÿš.
  • -A -predicate=answer โ€” cancels an assertion with the predicate predicate and the answer answer ๐Ÿ™…โ€โ™€๏ธ.
  • -C โ€” don't discard comments! All comments get passed through to the output file, except comments in processed directives, which get deleted along with the directive ๐Ÿ’ฌ.

Be prepared for side effects when using -C ๐Ÿ’€. It causes the preprocessor to treat comments as tokens in their own right. For example, comments at the start of what would be a directive line turn that line into an ordinary source line, since the first token on the line is no longer a #.

  • -CC โ€” don't discard comments, including during macro expansion ๐ŸŒˆ. This is like -C, except comments contained within macros also get passed through to the output file where the macro is expanded.

On top of the side effects of -C, -CC converts all C++-style comments inside a macro into C-style comments ๐Ÿ”„. This stops a later use of that macro from accidentally commenting out the rest of the source line ๐Ÿ™ˆ.

-CC is generally used to support lint comments ๐Ÿงน.

  • -P โ€” inhibits 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 linemarkers ๐Ÿคทโ€โ™€๏ธ.
  • -traditional, -traditional-cpp โ€” tries to imitate pre-standard C preprocessors, as opposed to ISO C preprocessors ๐Ÿ•ฐ๏ธ. See the GNU CPP manual for details.

GCC doesn't otherwise try to emulate a pre-standard C compiler, and these options 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:

    Trigraph:       ??(  ??)  ??<  ??>  ??=  ??/  ??'  ??!  ??-
    Replacement:      [    ]    {    }    #    \    ^    |    ~

By default GCC ignores trigraphs ๐Ÿ™ˆ, but in standard-conforming modes it converts them ๐Ÿ’…. See the -std and -ansi options.

  • -remap โ€” enables special code to work around file systems that only permit very short file names, like MS-DOS ๐Ÿ“.
  • -H โ€” prints the name of each header file used, in addition to the other normal activities ๐Ÿ“œ. Each name is indented to show how deep it is in the #include stack ๐Ÿชœ. Precompiled header files get printed too, even if they turn out to be invalid. An invalid precompiled header file is 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 is a great way to find out what's predefined in your version of the preprocessor ๐Ÿ”. Assuming you have no file foo.h, the command:
touch foo.h; cpp -dM foo.h

shows all the predefined macros.

If you use -dM without the -E option, -dM is interpreted as a synonym for -fdump-rtl-mach ๐Ÿ”.

  • -dD โ€” like -dM, except in two respects: it does not include the predefined macros, and it outputs both the #define directives and the result of preprocessing ๐ŸŽ€. Both kinds of output go to the standard output file.
  • -dN โ€” like -dD, but 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 โ€” only useful for debugging GCC itself ๐Ÿ›. 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 โ€” lets you bypass the compiler driver and pass option directly through to the preprocessor ๐Ÿš€. If option contains commas, it gets split into multiple options at the commas. However, many options are modified, translated or interpreted by the compiler driver before being passed to the preprocessor, and -Wp forcibly bypasses that phase ๐Ÿ’€.
The preprocessor's direct interface is undocumented and subject to change, so whenever possible you should avoid using -Wp and let the driver handle the options instead ๐Ÿซถ.
  • -Xpreprocessor option โ€” passes option as an option to the preprocessor ๐ŸŽ. You can use this to supply system-specific preprocessor options that GCC doesn't recognize.

If you want to pass an option that takes an argument, you must use -Xpreprocessor twice: once for the option, and once for the argument ๐Ÿ‘ฏโ€โ™€๏ธ.

  • -no-integrated-cpp โ€” okay so normally GCC does preprocessing as part of reading and parsing your code all in one go ๐Ÿ’… This flag makes it do the preprocessing as its own separate pass before compiling โœจ The front end gets invoked twice: once just for preprocessing and once to actually compile the preprocessed input. The language front ends are cc1 for C, cc1plus for C++, and cc1obj for Objective-C. This can be super useful together with -B or -wrapper if you want to swap in an alternate preprocessor or do extra processing on your source between preprocessing and compiling ๐Ÿ”ฅ
  • -flarge-source-files โ€” bestie, this one is for when your files are HUGE ๐Ÿ˜ It tells GCC to expect large source files, but the tradeoff is slower compilation and higher memory usage ๐Ÿ˜ญ

Here's the tea: GCC normally tracks both column numbers and line numbers in your source files, and it prints both in diagnostics. But once it has processed a certain number of source lines, it stops tracking column numbers and only tracks line numbers. So diagnostics for later lines won't include column numbers ๐Ÿ’€ 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 makes GCC keep tracking columns for significantly more source lines before it gives up on them ๐Ÿฆ‹


๐Ÿงš Passing Options to the Assembler ๐Ÿงš

You can pass options to the assembler, bestie ๐ŸŽ€

  • -Wa,option โ€” passes option along to the assembler ๐Ÿ’– If option has commas in it, it gets split into multiple options at each comma.
  • -Xassembler option โ€” also passes option to the assembler ๐Ÿซถ This is the move when you need system-specific assembler options that GCC doesn't recognize.

If you want to pass an option that takes an argument, you must use -Xassembler twice, once for the option and once for the argument ๐Ÿ™ˆ


๐Ÿ”— Options for Linking ๐Ÿ”—

These options come into play when the compiler links object files into an executable output file. They are meaningless if the compiler is not doing a link step ๐Ÿ’…

  • object-file-name โ€” any 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. If linking happens, these object files are used as input to the linker.
  • -c, -S, -E โ€” if any of these is used, the linker doesn't run, so object file names should not be used as arguments ๐Ÿšซ
  • -flinker-output=type โ€” this controls code generation of the link-time optimizer ๐Ÿง  By default the linker output is automatically determined by the linker plugin. For debugging the compiler, or if you want incremental linking with a non-LTO object file, it can be handy to control 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 allows building 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 that -fpie is not disabled if it was specified at compilation time ๐Ÿฆ‹

If type is rel, the compiler assumes that incremental linking is happening. The sections containing intermediate code for link-time optimization are merged, pre-optimized, and output to the resulting object file. On top of that, 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 of the objects in the library get 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 is stripped. When multiple object files are linked together, the resulting code is better optimized than with link-time optimizations disabled (for example, cross-module inlining happens), but most of the benefits of whole program optimizations are lost ๐Ÿ˜ญ

During the incremental link (by -r), the linker plugin defaults to rel. Heads up: 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 keep whole program optimization, it's recommended to link such objects into a static library instead. Alternatively, it is possible to use H.J. Lu's binutils, which has support for mixed objects ๐Ÿ™Œ

  • -fuse-ld=bfd โ€” use the bfd linker instead of the default linker ๐Ÿ› ๏ธ
  • -fuse-ld=gold โ€” use the gold linker instead of the default linker ๐Ÿ› ๏ธ
  • -fuse-ld=lld โ€” use the LLVM lld linker instead of the default linker ๐Ÿ› ๏ธ
  • -fuse-ld=mold โ€” use the Modern Linker (mold) instead of the default linker ๐Ÿ› ๏ธ
  • -llibrary, -l library โ€” search the library named library when linking ๐Ÿ” The second form, with the library as a separate argument, is only there for POSIX compliance and is not recommended ๐Ÿ™ƒ

The -l option gets passed directly to the linker by GCC, so refer to your linker documentation for the exact details. The general description below applies to the GNU linker.

The linker searches a standard list of directories for the library. Those directories 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 linking with the shared library unless the -static option is used.

It makes a difference where in the command you write this option! The linker searches and processes libraries and object files in the order they are specified. So foo.o -lz bar.o searches library z after file foo.o but before bar.o. If bar.o refers to functions in z, those functions may not be loaded ๐Ÿ’€

  • -lobjc โ€” you need this special case of the -l option to link an Objective-C or Objective-C++ program ๐ŸŒˆ
  • -nostartfiles โ€” don't use the standard system startup files when linking ๐Ÿš€ The standard system libraries are still used normally, unless -nostdlib, -nolibc, or -nodefaultlibs is used.
  • -nodefaultlibs โ€” don't use the standard system libraries when linking ๐Ÿ™… Only the libraries you specify get passed to the linker, and options specifying linkage of the system libraries, like -static-libgcc or -shared-libgcc, are ignored. The standard startup files are used normally, unless -nostartfiles is used.

The compiler may generate calls to "memcmp", "memset", "memcpy" and "memmove". These entries are usually resolved by entries in libc. When this option is specified, these entry points should be supplied through some other mechanism ๐Ÿซ 

  • -nolibc โ€” don't use the C library or the system libraries tightly coupled with it when linking ๐Ÿงธ It still links with the startup files, libgcc, or toolchain-provided language support libraries such as libgnat, libgfortran, or libstdc++, unless options preventing their inclusion are used as well. This typically removes -lc from the link command line, along with the system libraries that normally go with it and become meaningless when a C library is assumed to be absent, for example -lpthread or -lm in some configurations. This is intended for bare-board targets where there is indeed no C library available.
  • -nostdlib โ€” don't use the standard system startup files or libraries when linking ๐Ÿšซ No startup files are used, and only the libraries you specify get passed to the linker. Options specifying linkage of the system libraries, like -static-libgcc or -shared-libgcc, are ignored.

The compiler may generate calls to "memcmp", "memset", "memcpy" and "memmove". These entries are usually resolved by entries in libc. When this option is specified, these entry points should be supplied through some other mechanism ๐Ÿซ 

One of the standard libraries bypassed by -nostdlib and -nodefaultlibs is libgcc.a, a library of internal subroutines which GCC uses to work around shortcomings of particular machines or to meet special needs for some languages ๐Ÿงฉ

In most cases you still need libgcc.a, even when you want to avoid other standard libraries. In other words, when you specify -nostdlib or -nodefaultlibs, you should usually specify -lgcc as well. This makes sure you have no unresolved references to internal GCC library subroutines. (An example of such an internal subroutine is "__main", which is used to make sure C++ constructors get called โœจ)

  • -e entry, --entry=entry โ€” specifies that the program entry point is entry ๐ŸŽฏ The argument is interpreted by the linker. The GNU linker accepts either a symbol name or an address.
  • -pie โ€” produces a dynamically linked position independent executable on targets that support it ๐Ÿฆ‹ For predictable results, you must also specify the same set of options used for compilation (-fpie, -fPIE, or model suboptions) when you specify this linker option.
  • -no-pie โ€” don't produce a dynamically linked position independent executable ๐Ÿ™…โ€โ™€๏ธ
  • -static-pie โ€” produces a static position independent executable on targets that support it ๐Ÿ’œ A static position independent executable is similar to a static executable, but it can be loaded at any address without a dynamic linker. For predictable results, you must also specify the same set of options used for compilation (-fpie, -fPIE, or model suboptions) when you specify this linker option.
  • -pthread โ€” okay so this one links with the POSIX threads library ๐Ÿงต It's supported on GNU/Linux targets, most other Unix derivatives, and also on x86 Cygwin and MinGW targets. Heads up, bestie: on some targets it also sets flags for the preprocessor, so use it consistently for both compiling and linking ๐Ÿ’…
  • -r โ€” produces a relocatable object as output. This is also known as partial linking ๐Ÿงฉ
  • -rdynamic โ€” passes the flag -export-dynamic to the ELF linker on targets that support it ๐Ÿ”— This tells the linker to add all symbols, not just the used ones, to the dynamic symbol table. It's needed for some uses of dlopen, or if you want 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 prevents 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 all systems support this, so heads up ๐Ÿ™ˆ For predictable results, you must also specify the same set of options you used for compilation (-fpic, -fPIC, or model suboptions) when you use this linker option.[1]
  • -shared-libgcc, -static-libgcc โ€” on systems that provide libgcc as a shared library, these force the use of the shared or static version, respectively ๐ŸŽ€ If no shared version of libgcc was built when the compiler was configured, these have no effect.

There are a few situations where an application should use the shared libgcc instead of the static version. The most common one is when the app wants to throw and catch exceptions across different shared libraries. In that case, each of the libraries and the application itself should use the shared libgcc ๐Ÿง 

So the G++ driver automatically adds -shared-libgcc whenever you build a shared library or a main executable, 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 configuration time that you have a non-GNU linker, or a GNU linker that doesn't support the option --eh-frame-hdr, it links the shared version of libgcc into shared libraries by default. Otherwise, it takes advantage of the linker and optimizes away the linking with the shared version, so it links with the static version of libgcc by default. This lets exceptions propagate through such shared libraries without incurring relocation costs at library load time โœจ

Not optional, bestie: if a library or main executable is supposed to throw or catch exceptions, you must link it using the G++ driver, or using the option -shared-libgcc, so that it's linked with the shared libgcc.
  • -static-libasan โ€” when -fsanitize=address is used to link a program, the GCC driver automatically links against libasan ๐Ÿž If libasan is available as a shared library, and -static isn't used, this links against the shared version. The -static-libasan option directs the GCC driver to link libasan statically, without necessarily linking other libraries statically.
  • -static-libtsan โ€” when -fsanitize=thread is used to link a program, the GCC driver automatically links against libtsan ๐Ÿงต If libtsan is available as a shared library, and -static isn't used, this links against the shared version. The -static-libtsan option directs the GCC driver to link libtsan statically, without necessarily linking other libraries statically.
  • -static-liblsan โ€” when -fsanitize=leak is used to link a program, the GCC driver automatically links against liblsan ๐Ÿซง If liblsan is available as a shared library, and -static isn't used, this links against the shared version. The -static-liblsan option directs the GCC driver to link liblsan statically, without necessarily linking other libraries statically.
  • -static-libubsan โ€” when -fsanitize=undefined is used to link a program, the GCC driver automatically links against libubsan ๐ŸŒˆ If libubsan is available as a shared library, and -static isn't used, this links against the shared version. The -static-libubsan 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 -static isn't used, this links against the shared version, which is normally fine. Sometimes, though, it's useful to freeze the version of libstdc++ your program uses without going all the way to a fully static link. The -static-libstdc++ option 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 overridden by the link editor option -Xlinker -z -Xlinker defs). Only a few systems support this option.
  • -T script โ€” uses script as the linker script ๐Ÿ“œ This 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 on to the linker. It's perfect for system-specific linker options that GCC doesn't recognize ๐Ÿ› ๏ธ

If you want to pass an option that takes a separate argument, you must use -Xlinker twice: once for the option and once for the argument. For example, to pass -assert definitions, you must write -Xlinker -assert -Xlinker definitions. Writing -Xlinker "-assert definitions" does not work, because it passes the whole string as a single argument, which is not what the linker expects ๐Ÿ™…โ€โ™€๏ธ

With the GNU linker, it's usually way easier to pass arguments to linker options using the option=value syntax instead of separate arguments. For example, you can specify -Xlinker -Map=output.map rather than -Xlinker -Map -Xlinker output.map. Other linkers may not support this syntax for command-line options.

  • -Wl,option โ€” passes option to the linker too ๐ŸŽ€ If option contains commas, it gets split into multiple options at the commas. You can use this syntax to pass an argument to the option. For example, -Wl,-Map,output.map passes -Map output.map to the linker. When using the GNU linker, you can also get the same effect with -Wl,-Map=output.map.
  • -u symbol โ€” pretends the symbol symbol is undefined, which forces linking of library modules that define it ๐Ÿซ  You can use -u multiple times with different symbols to force loading of additional library modules.
  • -z keyword โ€” -z gets passed directly on to the linker, along with the keyword. Check the documentation for your linker for permitted values and what they mean ๐Ÿ“–

These options specify directories to search for header files, for libraries and for parts of the compiler ๐ŸŒธ

  • -I dir, -iquote dir, -isystem dir, -idirafter dir โ€” adds the directory dir to the list of directories searched for header files during preprocessing ๐Ÿ—‚๏ธ If dir begins with = or $SYSROOT, then the = or $SYSROOT is replaced by the sysroot prefix. See --sysroot and -isysroot.

Directories given with -iquote only apply to the quote form of the directive, #include "file". Directories given with -I, -isystem, or -idirafter apply to the lookup for both #include "file" and #include <file> directives.

You can mix and match any number 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 swap in 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 ๐Ÿ’…

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

  • -I- โ€” splits the include path ๐Ÿ’” This option has been deprecated.
Please use -iquote instead for -I directories before the -I-, and remove the -I- option.

Any directories specified with -I options before -I- are searched only for headers requested with #include "file". They are not searched for #include <file>. If additional directories are specified with -I options after the -I-, those directories are searched for all #include directives โœจ

In addition, -I- is lowkey a plot twist ๐Ÿ™ˆ. It stops the directory of the current file from being the first directory searched for #include "file", and there is no way to override this effect of -I- ๐Ÿ’€, so use it with care, bestie.

  • -iprefix prefix โ€” Sets prefix as the prefix for any -iwithprefix options that come after it ๐ŸŒธ. If the prefix is a directory, make sure you include the final /.
  • -iwithprefix dir, -iwithprefixbefore dir โ€” Tacks dir onto the prefix you set earlier with -iprefix and adds the result to the include search path โœจ. -iwithprefixbefore puts it in the same spot -I would, while -iwithprefix puts it where -idirafter would.
  • -isysroot dir โ€” This one is basically the --sysroot option, but it only affects header files ๐Ÿ“š. The exception is Darwin targets, where it covers headers and libraries. Check out the --sysroot option for more deets.
  • -imultilib dir โ€” Uses dir as a subdirectory of the directory that holds target-specific C++ headers ๐Ÿงš.
  • -nostdinc โ€” Doesn't search the standard system directories for header files ๐Ÿ™…โ€โ™€๏ธ. Only the directories you explicitly pass with -I, -iquote, -isystem, and/or -idirafter get searched, plus the directory of the current file if it's relevant.
  • -nostdinc++ โ€” Skips the C++-specific standard directories when hunting for header files, but still searches the other standard ones ๐Ÿ’œ. (This one gets used when building the C++ library.)
  • -iplugindir=dir โ€” Sets the directory to search for plugins that get passed with -fplugin=name instead of -fplugin=path/name.so. This one isn't really meant for you to use ๐Ÿ™ˆ, it's only passed along by the driver.
  • -Ldir โ€” Adds directory dir to the list of directories searched for -l ๐Ÿ”.
  • -Bprefix โ€” This is how you tell the compiler where to find its own stuff: 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, it 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's all. The file gets left out of the link if it isn't found by those means.

Another way to specify a prefix much like the -B prefix is to use the environment variable GCC_EXEC_PREFIX ๐ŸŒˆ.

As a special kludge (no cap, it's a weird one ๐Ÿ™ƒ), 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, resolve references to /../ or /./, or make the path absolute when generating a relative prefix ๐Ÿ™…โ€โ™€๏ธ.
  • --sysroot=dir โ€” Uses dir as the logical root directory for headers and libraries ๐ŸŒณ. For example, if the compiler normally searches for headers in /usr/include and libraries in /usr/lib, it searches dir/usr/include and dir/usr/lib instead.

If you use both this option and -isysroot, 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 part of --sysroot still works, but the library part 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 use. That means headers might show up in dir/suffix/usr/include instead of dir/usr/include. This option turns off adding that suffix ๐Ÿšซ.

โœจ Options for Code Generation Conventions โœจ

These machine-independent options control the interface conventions used in code generation ๐Ÿ’….

Most of them have both positive and negative forms, and the negative form of -ffoo is -fno-foo. In the list below, only one of the forms is shown, the one that is not the default. You can figure out the other form by either removing no- or adding it ๐Ÿง .

  • -fstack-reuse=reuse-level โ€” This one controls stack space reuse for user-declared local/auto variables and compiler-generated temporaries ๐Ÿฅž. reuse_level can be all, named_vars, or none. all enables stack reuse for all local variables and temporaries, named_vars enables it only for user-defined local variables with names, and none disables stack reuse completely. The default value is all.

This option is needed when the program extends the lifetime of a scoped local variable or a compiler-generated temporary beyond the end point defined by the language. When the lifetime of a variable ends, and if the variable lives in memory, the optimizing compiler has the freedom to reuse its stack space with other temporaries or scoped local variables whose live range does not overlap with it.

โš ๏ธ Legacy code that extends local lifetime is likely to break with the stack reuse optimization. Be careful, bestie ๐Ÿ’€.

For example,

int *p;
{
  int local1;

  p = &local1;
  local1 = 10;
  ....
}
{
   int local2;
   local2 = 20;
   ...
}

if (*p == 10)  // out of scope use of local1
  {

  }

Another example:

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

A *ap;

void foo(const A& ar)
{
   ap = &ar;
}

void bar()
{
   foo(A(10)); // temp object's lifetime ends when foo returns

   {
     A a(20);
     ....
   }
   ap->i+= 10;  // ap references out of scope temp whose space
                // is reused with a. What is the value of ap->i?
}

The lifetime of a compiler-generated temporary is well defined by the C++ standard. When the lifetime of a temporary ends, and if the temporary lives in memory, the optimizing compiler has the freedom to reuse its stack space with other temporaries or scoped local variables whose live range does not overlap with it. However, some of the legacy code relies on the behavior of older compilers, in which temporaries' stack space is not reused, so aggressive stack reuse can lead to runtime errors ๐Ÿ˜ญ. This option is used to control the temporary stack reuse optimization.

  • -ftrapv โ€” This generates traps for signed overflow on addition, subtraction, and multiplication operations ๐Ÿšจ. The options -ftrapv and -fwrapv override each other, so using -ftrapv -fwrapv on the command-line results in -fwrapv being effective. Note that only active options override, so using -ftrapv -fwrapv -fno-wrapv on the command-line results in -ftrapv being effective.
  • -fwrapv โ€” This tells the compiler to assume that signed arithmetic overflow of addition, subtraction, and multiplication wraps around using twos-complement representation ๐Ÿ”„. This flag enables some optimizations and disables others. The options -ftrapv and -fwrapv override each other, so using -ftrapv -fwrapv on the command-line results in -fwrapv being effective. Note that only active options override, so using -ftrapv -fwrapv -fno-wrapv on the command-line results in -ftrapv being effective.
  • -fwrapv-pointer โ€” This tells the compiler to assume that pointer arithmetic overflow on addition and subtraction wraps around using twos-complement representation ๐Ÿงญ. This flag disables some optimizations which assume pointer overflow is invalid.
  • -fstrict-overflow โ€” This implies -fno-wrapv -fno-wrapv-pointer, and when negated it implies -fwrapv -fwrapv-pointer ๐ŸŽ€.
  • -fexceptions โ€” Enables exception handling ๐Ÿ›ก๏ธ. It generates the extra code needed to propagate exceptions. For some targets, this implies GCC generates frame unwind information for all functions, which can produce significant data size overhead, although it does not affect execution.

If you don't specify this option, GCC enables it by default for languages like C++ that normally require exception handling, and disables it for languages like C that don't normally require it. You may still need to enable this option when compiling C code that needs to interoperate properly with exception handlers written in C++ ๐Ÿค. You may also wish to disable this option if you're compiling older C++ programs that don't use exception handling.

  • -fnon-call-exceptions โ€” Generates code that allows trapping instructions to throw exceptions โšก. Note that this requires platform-specific runtime support, which does not exist everywhere. Moreover, it only allows trapping instructions to throw exceptions, i.e. memory references or floating-point instructions. It does not allow exceptions to be thrown from arbitrary signal handlers such as "SIGALRM". This enables -fexceptions.
  • -fdelete-dead-exceptions: okay so this one is lowkey iconic ๐Ÿ’…. Instructions that might throw exceptions but don't actually contribute to what the program does can be optimized away โœจ. It doesn't affect calls to functions unless they have the pure or const attributes. It's on by default for the Ada and C++ compilers because the language specs allow it ๐ŸŒธ. Optimization passes that remove dead exceptions are switched on separately at different optimization levels ๐Ÿ”ฅ.
  • -funwind-tables: this is giving similar to -fexceptions, except it only generates any static data that's needed and doesn't touch the generated code in any other way ๐Ÿฆ‹. You normally don't have to turn it on yourself. A language processor that needs this handling enables it for you ๐Ÿซถ.
  • -fasynchronous-unwind-tables: generates an unwind table in DWARF format, if the target machine supports it ๐ŸŒˆ. The table is exact at each 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 drama ๐Ÿ™ˆ. On systems with a recent GNU assembler and C library, the C++ compiler uses the STB_GNU_UNIQUE binding so that definitions of template static data members and static local variables in inline functions stay unique, even when RTLD_LOCAL is involved. That's needed to avoid problems with a library used by two different RTLD_LOCAL plugins, where one depends on a definition in one plugin and the other disagrees about how the symbol is bound ๐Ÿ’€.

But here's the tea: this causes dlclose to be ignored for affected DSOs. If your program relies on reinitializing a DSO through dlclose and dlopen, you can use -fno-gnu-unique ๐Ÿ’–.

  • -fpcc-struct-return: returns short struct and union values in memory, like the longer ones, instead of in registers ๐Ÿงธ. It's less efficient, but it lets GCC-compiled files play nicely with files built by other compilers, especially the Portable C Compiler (pcc) ๐Ÿค.

The exact convention for returning structures in memory depends on the target configuration macros. Short structures and unions are the ones whose size and alignment match some integer type ๐Ÿ“.

โš ๏ธ Warning: code compiled with -fpcc-struct-return is not binary compatible with code compiled with -freg-struct-return. Use it to conform to a non-default application binary interface ๐Ÿ™…โ€โ™€๏ธ.
  • -freg-struct-return: returns struct and union values in registers when possible ๐ŸŽ€. It's more efficient for small structures than -fpcc-struct-return โœจ.

If you specify neither -fpcc-struct-return nor -freg-struct-return, GCC defaults to whichever convention is standard for the target. If there's no standard convention, GCC defaults to -fpcc-struct-return, except on targets where GCC is the principal compiler. In those cases, we get to choose the standard, and we went with 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 values ๐ŸŒท. Specifically, the enum type ends up equivalent to the smallest integer type that has enough room ๐Ÿฆ‹.
โš ๏ธ Warning: the -fshort-enums switch makes GCC generate code that isn't binary compatible with code generated without it. Use it to conform to a non-default application binary interface ๐Ÿ˜ญ.
  • -fshort-wchar: overrides the underlying type for wchar_t so it's short unsigned int instead of the target's default ๐Ÿญ. This one is super useful for building programs that run under WINE ๐ŸŒˆ.
โš ๏ธ Warning: the -fshort-wchar switch makes GCC generate code that isn't binary compatible with code generated without it. 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 using the extern keyword, which don't allocate any storage ๐ŸŒธ.

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

-fcommon puts 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 the same object, or to a non-tentative definition. This behavior is inconsistent with C++, and on many targets it comes with a speed and code size penalty on global variable references ๐Ÿ˜ฌ. It's mainly useful for getting legacy code to link without errors ๐Ÿซ .

  • -fno-ident: ignores the #ident directive ๐Ÿ™ˆ.
  • -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 option is used when compiling crtstuff.c. You shouldn't need it for anything else ๐Ÿšซ.
  • -fverbose-asm: adds extra commentary to the generated assembly code so it's easier to read ๐Ÿ“. This is mostly for people who actually need to read the generated assembly, like when debugging the compiler itself ๐Ÿง‘โ€๐Ÿ’ป.

-fno-verbose-asm, which is the default, leaves the extra info out, and that's handy 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 straight to stdout via -o - looks like this:

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

And it gives output similar to this ๐Ÿงšโ€โ™€๏ธ:

        .file   "test.c"
# GNU C11 (GCC) version 7.0.0 20160809 (experimental) (x86_64-pc-linux-gnu)
  [...snip...]
# options passed:
  [...snip...]

        .text
        .globl  test
        .type   test, @function
test:
.LFB0:
        .cfi_startproc
# test.c:4:   int total = 0;
        xorl    %eax, %eax      # <retval>
# test.c:6:   for (i = 0; i < n; i++)
        xorl    %edx, %edx      # i
.L2:
# test.c:6:   for (i = 0; i < n; i++)
        cmpl    %edi, %edx      # n, i
        jge     .L5     #,
# test.c:7:     total += i * i;
        movl    %edx, %ecx      # i, tmp92
        imull   %edx, %ecx      # i, tmp92
# test.c:6:   for (i = 0; i < n; i++)
        incl    %edx    # i
# test.c:7:     total += i * i;
        addl    %ecx, %eax      # tmp92, <retval>
        jmp     .L2     #
.L5:
# test.c:10: }
        ret
        .cfi_endproc
.LFE0:
        .size   test, .-test
        .ident  "GCC: (GNU) 7.0.0 20160809 (experimental)"
        .section        .note.GNU-stack,"",@progbits

The comments are meant for humans rather than machines, so the precise format of them is subject to change ๐Ÿซถ.

  • -frecord-gcc-switches: this makes 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 the 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 info in the assembler output file as comments, so it never reaches the object file ๐Ÿ™…. See also -grecord-gcc-switches for another way of storing compiler options in the object file ๐Ÿ’œ.

  • -fpic: generates position-independent code (PIC) that's suitable for a shared library, if the target machine supports it ๐ŸŒ. This code accesses all constant addresses through a global offset table (GOT). The dynamic loader resolves the GOT entries when the program starts. (The dynamic loader isn't part of GCC; it's part of the operating system ๐Ÿ–ฅ๏ธ.) If the GOT size for the linked executable goes past a machine-specific maximum, the linker gives you an error saying -fpic doesn't work. In that case, recompile with -fPIC instead ๐Ÿ˜ค. (These maximums are 8k on the SPARC, 28k on AArch64 and 32k on the m68k and RS/6000. The x86 has no such limit ๐ŸŽ‰.)

Position-independent code needs special support, so it only works on certain machines. For the x86, GCC supports PIC for System V but not for the Sun 386i. Code generated for the IBM RS/6000 is always position-independent ๐Ÿฆ‹.

When this flag is set, the macros __pic__ and __PIC__ are defined to 1 ๐ŸŒธ.

  • -fPIC: if the target machine supports it, emits position-independent code that's suitable for dynamic linking and avoids any limit on the size of the global offset table ๐Ÿ”ฅ. This option makes a difference on AArch64, m68k, PowerPC and SPARC ๐Ÿ’–.

Position-independent code needs special support, so it only works on certain machines ๐Ÿ™ƒ.

When this flag is set, the macros __pic__ and __PIC__ are defined to 2 โœจ.

  • -fpie, -fPIE โ€” okay so these are the cousins of -fpic and -fPIC ๐Ÿฆ‹, but the position-independent code they make can ONLY be linked into executables ๐Ÿ’…. You'll usually reach for these when compiling stuff that's getting linked with the -pie GCC option โœจ.
    • -fpie and -fPIE both define the macros __pie__ and __PIE__ ๐ŸŽ€. They have the value 1 for -fpie and 2 for -fPIE ๐Ÿ”ฅ.
  • -fno-plt โ€” bestie, don't go through the PLT ๐Ÿ™ˆ for external function calls in position-independent code ๐Ÿ’–. Instead, grab the callee address at the call sites from the GOT and branch to it ๐Ÿฆ‹. It's more efficient because it kills the PLT stubs and lets the optimizations see the GOT loads ๐Ÿ‘‘. On architectures like 32-bit x86, where PLT stubs expect the GOT pointer in a specific register, this gives the compiler more register allocation freedom ๐Ÿ’…. Lazy binding needs the PLT though, so with -fno-plt all external symbols get resolved at load time ๐ŸŒธ.
    • Alternatively, the function attribute noplt can be used to avoid calls through the PLT for specific external functions ๐Ÿงš.
    • In position-dependent code, a few targets also convert calls to functions marked to not use the PLT into calls that go through the GOT instead ๐ŸŒˆ.
  • -fno-jump-tables โ€” don't use jump tables for switch statements, even where they'd be more efficient than other code generation strategies ๐Ÿ™ƒ. This is useful alongside -fpic or -fPIC when you're building code that forms part of a dynamic linker and can't reference the address of a jump table ๐Ÿงฉ. On some targets, jump tables don't need a GOT, so this option isn't needed there โœจ.
  • -fno-bit-tests โ€” don't use bit tests for switch statements, even where they'd be more efficient than other code generation strategies ๐Ÿ’€.
  • -ffixed-reg โ€” treat the register named reg as a fixed register ๐Ÿ”’. Generated code should never refer to it, except maybe as a stack pointer, frame pointer, or in some other fixed role ๐Ÿงฑ.
    • reg must be the name of a register. The accepted register names are machine-specific and are defined in the REGISTER_NAMES macro in the machine description macro file ๐Ÿ—‚๏ธ.
    • This flag has no negative form, because it's a three-way choice ๐ŸŽ€.
  • -fcall-used-reg โ€” treat reg as an allocable register that gets clobbered by function calls ๐ŸŒธ. It can be allocated for temporaries or variables that don't live across a call. Functions compiled this way do not save and restore the register reg ๐Ÿ™….
    • It is an error to use this flag with the frame pointer or stack pointer โŒ.
    • Using this flag for other registers that have fixed pervasive roles in the machine's execution model produces disastrous results ๐Ÿ’€.
    • This flag has no negative form, because it's a three-way choice ๐ŸŽ€.
  • -fcall-saved-reg โ€” treat 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 ๐Ÿ’พ.
    • It is an error to use this flag with the frame pointer or stack pointer โŒ.
    • Using this flag for other registers that have fixed pervasive roles in the machine's execution model produces disastrous results ๐Ÿ’€.
    • A different sort of disaster results from using this flag on a register where function values may be returned ๐ŸŒ‹.
    • This flag has no negative form, because it's a three-way choice ๐ŸŽ€.
  • -fpack-struct[=n] โ€” without a value, pack all structure members together with no holes ๐Ÿ“ฆ. When you give a value (which must be a small power of two), members get packed according to that value, which is the maximum alignment. Objects with default alignment requirements larger than this are output potentially unaligned at the next fitting location ๐Ÿงฉ.
Warning: the -fpack-struct switch causes GCC to generate code that is not binary compatible with code generated without that switch ๐Ÿšจ. It also makes the code suboptimal ๐Ÿข. Only use it to conform to a non-default application binary interface ๐Ÿ’….
  • -fleading-underscore โ€” this option and its counterpart, -fno-leading-underscore, forcibly change the way C symbols are represented in the object file ๐Ÿ”ค. One use is helping to link with legacy assembly code ๐Ÿš๏ธ.
Warning: the -fleading-underscore switch causes GCC to generate code that is not binary compatible with code generated without that switch ๐Ÿšจ. Use it to conform to a non-default application binary interface. Not all targets provide complete support for this switch ๐Ÿ™ˆ.
  • -ftls-model=model โ€” alter the thread-local storage model that's used ๐Ÿงต. The model argument should be one of global-dynamic, local-dynamic, initial-exec or local-exec ๐ŸŽ€. The choice is subject to optimization, though: the compiler may use a more efficient model for symbols not 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, always generate them instead of using descriptors ๐Ÿ”. Otherwise, for targets that don't need them, like for example HP-PA or IA-64, it does nothing ๐Ÿคท.
    • A trampoline is a small piece of code that's created at run time on the stack when the address of a nested function is taken, and it's used to call the nested function indirectly ๐Ÿง . 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 avoid generating trampolines if it computes that's safe and replace them with descriptors ๐Ÿฆ‹. Descriptors are made up of data only, but the generated code must be prepared to deal with them ๐Ÿ’…. As of this writing, -fno-trampolines is enabled by default only for Ada ๐Ÿ‘‘.
    • Code compiled with -ftrampolines and code compiled with -fno-trampolines are not binary compatible if nested functions are present โ˜ ๏ธ. This option must therefore be used on a program-wide basis and be manipulated with extreme care ๐Ÿซฃ.
    • For languages other than Ada, the -ftrampolines and -fno-trampolines options currently have no effect, and trampolines are always generated on platforms that need them for nested functions ๐ŸŒˆ.

  • -fvisibility=[default|internal|hidden|protected] โ€” set the default ELF image symbol visibility to the specified option. All symbols are marked with this unless they're overridden within the code ๐Ÿ‘€. Using this can very substantially improve linking and load times of shared object libraries, produce more optimized code, provide near-perfect API export, and prevent symbol clashes ๐Ÿš€. It's strongly recommended that you use this in any shared objects you distribute ๐Ÿ’–.
    • Despite the nomenclature, default always means public, i.e., available to be linked against from outside the shared object ๐Ÿ“ฃ. protected and internal are pretty useless in real-world usage, so the only other commonly used option is hidden ๐Ÿ™„. If -fvisibility isn't specified, the default is default, i.e., make every symbol public ๐ŸŒธ.
    • A good explanation of the benefits of ensuring ELF symbols have the correct visibility is given in "How To Write Shared Libraries" by Ulrich Drepper, which can be found at <https://www.akkadia.org/drepper/> ๐Ÿ“š. However, a superior solution made possible by this option, instead of marking things hidden when the default is public, is to make the default hidden and mark things public ๐Ÿง . This is the norm with DLLs on Windows, and with -fvisibility=hidden and __attribute__ ((visibility("default"))) instead of __declspec(dllexport), you get almost identical semantics with identical syntax ๐ŸชŸ. This is a great boon to those working with cross-platform projects ๐Ÿซถ.
    • For those adding visibility support to existing code, you may find #pragma GCC visibility useful ๐Ÿ› ๏ธ. It works by enclosing the declarations you want to set visibility for with, for example, #pragma GCC visibility push(hidden) and #pragma GCC visibility pop ๐Ÿ“œ. Bear in mind that symbol visibility should be viewed as part of the API interface contract, so all new code should always specify visibility when it isn't the default ๐Ÿ“. Declarations only for use within the local DSO should always be marked explicitly as hidden to avoid PLT indirection overheads, and making this abundantly clear also aids readability and self-documentation of the code ๐Ÿ’…. Note that due to ISO C++ specification requirements, operator new and operator delete must always be of default visibility โš ๏ธ.
    • Be aware that headers from outside your project, in particular system headers and headers from any other library you use, may not be expecting to be compiled with visibility other than the default ๐Ÿ‘€. You may need to explicitly say #pragma GCC visibility push(default) before including any such headers ๐Ÿซ .
    • extern declarations are not affected by -fvisibility, so a lot of code can be recompiled with -fvisibility=hidden with no modifications โœจ. However, this means calls to extern functions with no explicit visibility use the PLT, so it's more effective to use __attribute ((visibility)) and/or #pragma GCC visibility to tell the compiler which extern declarations should be treated as hidden ๐Ÿงš.
    • -fvisibility does affect C++ vague linkage entities ๐Ÿงฉ. This means that, for instance, an exception class that is thrown between DSOs must be explicitly marked with default visibility so that the type_info nodes are unified between the DSOs ๐Ÿ’œ.
    • An overview of these techniques, their benefits, and how to use them is at <https://gcc.gnu.org/wiki/Visibility> ๐ŸŒˆ.
  • -fstrict-volatile-bitfields โ€” ๐ŸŽ€ Turn this on when you want volatile bit-fields (or other struct fields, though the compiler usually respects those types anyway) to be read or written in a single access as wide as the field's type, lined up to natural alignment when possible. Targets with memory-mapped peripheral registers might need every access to be 16 bits wide. If you declare those bit-fields as "unsigned short" (assuming short is 16 bits on those targets), GCC sticks to 16-bit accesses instead of grabbing a fancier 32-bit one. ๐Ÿ’…

If this option is disabled, the compiler goes for the most efficient instruction ๐Ÿƒโ€โ™€๏ธ. In the example above, that could be a 32-bit load, even though it touches bytes that don't hold any part of the bit-field, or memory-mapped registers unrelated to the one being updated. ๐Ÿ˜ฌ

In some cases, like when the "packed" attribute is on a structure field, there may be no single read or write that's correctly aligned for the target machine. Then GCC falls back to generating multiple accesses instead of code that would fault or truncate the result at run time. ๐Ÿซถ

๐Ÿšจ Note: Because of restrictions in the C/C++11 memory model, write accesses aren't allowed to touch non bit-field members. So it's recommended to define all bits of the field's type as bit-field members. Don't skip this one, bestie!

The default value of this option is set by the application binary interface for the target processor. ๐ŸŒธ

  • -fsync-libcalls โ€” ๐Ÿ”„ 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.

This one is enabled by default, so the only useful form is -fno-sync-libcalls. It's used in the implementation of the libatomic runtime library. โœจ

โœจ GCC Developer Options โœจ

This section is all about command-line options that mostly matter to GCC developers ๐Ÿง‘โ€๐Ÿ’ป. That includes options for compiler testing, digging into compiler bugs, and compile-time performance problems. You'll find options that produce debug dumps at various points in the compilation, options that print stats like memory use and execution time, and options that print info about GCC's configuration, like where it searches for libraries. ๐Ÿ” You should rarely need any of these for ordinary compiling and linking, so don't stress! ๐Ÿ’–

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

If =filename is left off, GCC builds a default dump file name by sticking together the base dump file name, a pass number, a phase letter, and the pass name. The base dump file name is the name of the output file the compiler produced if you explicitly specified one and it isn't an executable. Otherwise, it's the source file name. ๐Ÿ“

The pass number comes from the order passes get registered with the compiler's pass manager. That's usually the same as the order they run in, but passes registered by plugins, target-specific passes, or passes that get registered late are numbered higher than the pass named final, even if they actually run earlier. ๐Ÿคฏ

The phase letter is one of i (inter-procedural analysis), l (language-specific), r (RTL), or t (tree). The files get created in the directory of the output file. ๐Ÿ“‚

  • -fcallgraph-info, -fcallgraph-info=MARKERS โ€” ๐Ÿ•ธ๏ธ Makes the compiler output callgraph information for the program, one file per object file. The info is generated in the common VCG format. You can decorate it with extra per-node and/or per-edge info by passing a comma-separated list of markers. With the su marker, the callgraph gets stack usage info, which is equivalent to -fstack-usage. With the da marker, it gets info about dynamically allocated objects. ๐Ÿง 

When you compile with -flto, no callgraph info is output alongside the object file. At LTO link time, -fcallgraph-info may generate multiple callgraph info files next to the intermediate LTO output files. ๐ŸŒˆ

  • -dletters, -fdump-rtl-pass, -fdump-rtl-pass=filename โ€” ๐Ÿ—‘๏ธ Tells GCC to make debugging dumps during compilation at the times specified by the letters. This is for debugging the RTL-based passes of the compiler. ๐Ÿ›

Some -dletters switches mean something different when you use -E for preprocessing. ๐Ÿค”

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

  • -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 only runs on architectures that have auto inc or auto dec instructions. ๐Ÿ—๏ธ
  • -fdump-rtl-barriers โ€” Dumps after cleaning up the barrier instructions. ๐Ÿงน
  • -fdump-rtl-bbpart โ€” Dumps after partitioning hot and cold basic blocks. ๐Ÿ”ฅ๐ŸงŠ
  • -fdump-rtl-bbro โ€” Dumps after block reordering. ๐Ÿ”€
  • -fdump-rtl-btl1, -fdump-rtl-btl2 โ€” These two 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 โ€” These three 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 โ€” These two 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 โ€” These two 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 โ€” These two enable dumping after the two forward propagation passes. โžก๏ธ
  • -fdump-rtl-gcse1, -fdump-rtl-gcse2 โ€” These two 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 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 โ€” These two enable dumping after the basic block scheduling passes. ๐Ÿ“…
  • -fdump-rtl-ree โ€” Dumps after sign/zero extension elimination. ๐Ÿ”ข
  • -fdump-rtl-seqabstr โ€” Dumps after common sequence discovery. ๐Ÿงต
  • -fdump-rtl-shorten โ€” Dumps after shortening branches. ๐Ÿ“
  • -fdump-rtl-sibling โ€” Dumps after sibling call optimizations. ๐Ÿ‘ฏ
  • -fdump-rtl-split1, -fdump-rtl-split2, -fdump-rtl-split3, -fdump-rtl-split4, -fdump-rtl-split5 โ€” These options enable dumping after five rounds of instruction splitting. โœ‚๏ธ
  • -fdump-rtl-sms โ€” Dumps after modulo scheduling. This pass only runs on some architectures. ๐ŸŽถ
  • -fdump-rtl-stack โ€” Dumps after converting GCC's "flat register file" registers to the x87's stack-like registers. This pass only runs on x86 variants. ๐Ÿฅž
  • -fdump-rtl-subreg1, -fdump-rtl-subreg2 โ€” These two enable dumping after the two subreg expansion passes. ๐Ÿ”Ž
  • -fdump-rtl-unshare โ€” Dumps after all RTL has been unshared. ๐Ÿซง
  • -fdump-rtl-vartrack โ€” Dumps after variable tracking. ๐Ÿ•ต๏ธโ€โ™€๏ธ
  • -fdump-rtl-vregs โ€” Dumps after converting virtual registers to hard registers. ๐Ÿงฒ
  • -fdump-rtl-web โ€” Dumps after live range splitting. ๐Ÿ•ธ๏ธ
  • -fdump-rtl-regclass, -fdump-rtl-subregs_of_mode_init, -fdump-rtl-subregs_of_mode_finish, -fdump-rtl-dfinit, -fdump-rtl-dfinish โ€” These dumps are defined but always produce empty files. ๐Ÿ‘ป
โš ๏ธ Heads up: The five dumps above are defined, but they will always give you empty files. Don't waste your time staring at them! ๐Ÿ™ˆ
  • -da, -fdump-rtl-all โ€” Produces all the dumps listed above. ๐Ÿฐ
  • -dA โ€” Annotates the assembler output with miscellaneous debugging information. ๐Ÿ“
  • -dD โ€” Dumps all macro definitions, at the end of preprocessing, in addition to the normal output. ๐Ÿ“œ
  • -dH โ€” Produces a core dump whenever an error occurs. ๐Ÿ’ฅ

-dp ๐Ÿงš okay so this one annotates the assembler output with a comment showing which pattern and alternative got picked, and it also prints the length and cost of each instruction โœจ

  • -dP ๐Ÿ’… dumps the RTL into the assembler output as a comment right before each instruction, and it also turns on -dp annotation, so you get both, bestie ๐Ÿซถ
  • -dx ๐Ÿฆ‹ skips the full compile and just generates RTL for a function. It's usually paired with -fdump-rtl-expand ๐ŸŒธ

Debug dumps are next, and they're giving main character energy ๐Ÿ‘‘

  • -fdump-debug ๐Ÿ” dumps the debugging info generated during the debug generation phase
  • -fdump-earlydebug ๐ŸŒ… same deal, but for the early debug generation phase
  • -fdump-noaddr ๐Ÿ™ˆ when you're doing debugging dumps, this suppresses address output. It makes it way more doable to diff dumps from different compiler binaries and/or different text / bss / data / heap / stack / dso start locations, and honestly that's so smart ๐Ÿง 
  • -freport-bug ๐Ÿ˜ญ if an internal compiler error (ICE) hits, this gathers up debug info and dumps it into a temporary file so the bug report isn't empty
  • -fdump-unnumbered ๐Ÿ”ข suppresses instruction numbers and address output in debugging dumps. This is perfect for diff-ing dumps from compiler invocations with different options, especially with and without -g ๐ŸŽ€
  • -fdump-unnumbered-links ๐Ÿ”— in debugging dumps (see the -d option above), this suppresses the instruction numbers for the links to the previous and next instructions in a sequence
  • -fdump-ipa-switch, -fdump-ipa-switch-options ๐ŸŒˆ controls dumping the inter-procedural analysis language tree at various stages, and the dump goes into a file. The file name is made by appending a switch-specific suffix to the source file name, and the file lands in the same directory as the output file. These are the dumps you can ask for:
    • all โ€” enables all inter-procedural analysis dumps ๐Ÿ’–
    • cgraph โ€” dumps info about call-graph optimization, unused function removal, and inlining decisions
    • inline โ€” dumps after function inlining

Plus, you can tack on -optimized, -missed, -note, and -all. They mean the same thing as they do for -fopt-info, and the default is -optimized โœจ

For example, -fdump-ipa-inline-optimized-missed will emit info on the callsites that got inlined, along with the callsites that didn't. ๐Ÿงš

By default, the dump has messages about successful optimizations (same as -optimized) together with the low-level details about the analysis.

  • -fdump-lang ๐ŸŒท dumps language-specific info. 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 dumping language-specific info. The options and filename parts work exactly like they do in the -fdump-tree option. Here are the switch values:
    • all โ€” enables all language-specific dumps
    • class โ€” dumps class hierarchy info. Virtual table info gets emitted unless slim is specified. This is C++ only ๐Ÿซถ
    • module โ€” dumps module info. The options lineno (locations), graph (reachability), blocks (clusters), uid (serialization), alias (mergeable), asmname (Elrond), eh (mapper) & vops (macros) can add extra info. This is C++ only too
    • raw โ€” dumps the raw internal tree data. C++ only ๐Ÿ’œ
  • -fdump-passes ๐Ÿ“œ prints the list of optimization passes that your current command-line options turn on and off, and it prints it on stderr
  • -fdump-statistics-option ๐Ÿ“Š enables and controls dumping pass statistics into a separate file. The file name gets a suffix ending in .statistics appended to the source file name, and it's created in the same directory as the output file. If you use the -option form, -stats sums the counters over the whole compilation unit, while -details dumps every event as the passes generate them. With no option at all, the counters get summed for each function compiled.

๐ŸŒณ Tree dumps

  • -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, and the output goes 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 applies to every dump, so the ones that don't make sense just get ignored. These are the options you can use:
  • address ๐Ÿ“ prints the address of each node. This usually isn't meaningful, since it changes depending on the environment and source file. Its main job is tying a dump file to a debug environment
  • asmname ๐Ÿช„ if DECL_ASSEMBLER_NAME has been set for a given decl, this uses that in the dump instead of DECL_NAME. It's handy for working backward from mangled names in the assembly file
  • slim ๐ŸงŠ when dumping front-end intermediate representations, this stops members of a scope or body of a function from being dumped just because that scope got reached. Those items only show up when some other path directly reaches them. When dumping pretty-printed trees, it stops the bodies of control structures from being dumped. When dumping RTL, it prints the RTL in slim (condensed) form instead of the default LISP-like representation
  • raw ๐Ÿงพ prints a raw representation of the tree. By default, trees get pretty-printed into a C-like representation
  • details ๐Ÿ”Ž enables more detailed dumps (not every dump option honors this). It also includes info from the optimization passes
  • stats ๐Ÿ“ˆ enables dumping various statistics about the pass (not every dump option honors this one either)
  • blocks ๐Ÿงฑ enables showing basic block boundaries (disabled in raw dumps)
  • graph ๐Ÿ•ธ for each of the other indicated dump files (-fdump-rtl-pass), this dumps a representation of the control flow graph that's suitable for viewing with GraphViz, to a file named file.passid.pass.dot. Each function in the file gets pretty-printed as a subgraph, so GraphViz can render them all in a single plot. This currently only works for RTL dumps, and the RTL is always dumped in slim form
  • vops ๐ŸŒ€ enables showing virtual operands for every statement
  • lineno ๐Ÿ“ enables showing line numbers for statements
  • uid ๐Ÿ†” enables showing the unique ID (DECL_UID) for each variable
  • verbose ๐Ÿ—’ enables showing the tree dump for each statement
  • eh ๐Ÿ›Ÿ enables showing the EH region number holding each statement
  • scev ๐Ÿ“ enables showing scalar evolution analysis details
  • optimized โœ… enables showing optimization info (only available in certain passes)
  • missed โŒ enables showing missed optimization info (only available in certain passes)
  • note ๐Ÿ“ enables other detailed optimization info (only available in certain passes)
  • all ๐Ÿ’ฏ turns on all options, except raw, slim, verbose and lineno
  • optall ๐Ÿซง turns on all optimization options, i.e., optimized, missed, and note

To figure out which tree dumps are available, or to find the dump for a pass you care about, follow these steps ๐Ÿ•ต๏ธโ€โ™€๏ธ

  1. Invoke GCC with -fdump-passes, then look in the stderr output for a code that matches the pass you're interested in. For example, the codes tree-evrp, tree-vrp1, and tree-vrp2 correspond to the three Value Range Propagation passes. The number at the end tells apart the different 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. You can optionally specify the name of the dump file. If you don't specify one, GCC creates one as described below.
  3. Find the pass dump in a file whose name is made of three parts separated by periods: the name of the source file GCC was invoked to compile, a numeric suffix showing the pass number followed by the letter t for tree passes (and the letter r for RTL passes), and finally the pass code. For example, the Early VRP pass dump might be in a file named myfile.c.038t.evrp in the current working directory.
The numeric codes are not stable, so they may change from one version of GCC to another. Don't hardcode them, bestie ๐Ÿ™…โ€โ™€๏ธ

๐Ÿ”ฎ Optimization info

  • -fopt-info, -fopt-info-options, -fopt-info-options=filename โœจ controls optimization dumps from the various optimization passes. If you use the -options form, options is a list of --separated option keywords that select the dump details and the optimizations.

The options can be split into three groups ๐Ÿงฉ:

  1. options describing what kinds of messages should be emitted,
  2. options describing the verbosity of the dump, and
  3. options describing which optimizations should be included.

The options from each group can be freely mixed, since they don't overlap. But if there's ever a conflict, the later options on the command line override the earlier ones ๐Ÿซถ

The following options control which kinds of messages get emitted:

  • optimized ๐ŸŽ‰ prints info when an optimization is successfully applied. It's up to each pass to decide what info is relevant. For example, the vectorizer passes print the source location of loops that were successfully vectorized
  • missed ๐Ÿ™ prints info about missed optimizations. Individual passes control what info goes into 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

Now for the option that controls the dump verbosity ๐Ÿ’…

By default, only the "high-level" messages get emitted, bestie ๐Ÿ’… This option unlocks the extra detailed messages, which are lowkey only going to be of interest to GCC developers ๐Ÿค“ (no judgement, we all have our obsessions ๐Ÿซถ)

You can slap one or more of these option keywords on to describe a whole group of optimizations โœจ

  • ipa โ€” dumps from all the interprocedural optimizations ๐ŸŒธ
  • loop โ€” dumps from all the loop optimizations ๐Ÿ”
  • inline โ€” dumps from all the inlining optimizations ๐Ÿฆ‹
  • omp โ€” dumps from all the OMP (Offloading and Multi Processing) optimizations ๐Ÿ’œ
  • vec โ€” dumps from all the vectorization optimizations ๐Ÿงš
  • optall โ€” dumps from literally every optimization ๐Ÿ‘‘ It's a superset of the groups above, so it's the main character of the list

If you leave options out, it defaults to optimized-optall, which means it dumps messages about successful optimizations from all the passes, but skips anything treated as "internals" ๐Ÿ’…

If you give it a filename, the dumps from all the applicable optimizations get concatenated into that file. Otherwise, the dump is output onto stderr ๐ŸŽ€ You're allowed to use multiple -fopt-info options, but only one of them can include a filename ๐Ÿ™ˆ If other filenames show up, all but the first such option get ignored, so pick your favorite and let the rest go ๐Ÿ˜ญ

โš ๏ธ Heads up: the output filename gets overwritten in case of multiple translation units. If you want one combined output from multiple translation units, use stderr instead ๐Ÿ’€

In the following example, the optimization info is output to stderr โœจ

gcc -O3 -fopt-info

This example:

gcc -O3 -fopt-info-missed=missed.all

outputs the missed optimization report from all the passes into missed.all ๐Ÿ“ And this one:

gcc -O2 -ftree-vectorize -fopt-info-vec-missed

prints information about missed optimization opportunities from the vectorization passes on stderr ๐Ÿซถ Note that -fopt-info-vec-missed is equivalent to -fopt-info-missed-vec. The order of the optimization group names and message types listed after -fopt-info does not matter, so you can mix and match ๐ŸŒˆ

As another example:

gcc -O3 -fopt-info-inline-optimized-missed=inline.txt

outputs information about missed optimizations, as well as optimized locations, from all the inlining passes into inline.txt ๐Ÿฆ‹

Finally, consider:

gcc -fopt-info-vec-missed=vec.miss -fopt-info-loop-optimized=loop.opt

Here the two output filenames vec.miss and loop.opt are in conflict, since only one output file is allowed ๐Ÿ’€ In this case, only the first option takes effect and the subsequent options are ignored. Thus only vec.miss is produced, which contains dumps from the vectorizer about missed opportunities ๐Ÿฅบ


โœจ -fsave-optimization-record โœจ

Writes a SRCFILE.opt-record.json.gz file detailing what optimizations were performed, for those optimizations that support -fopt-info ๐Ÿ“ฆ

๐Ÿงช This option is experimental, and the format of the data within the compressed JSON file is subject to change. Don't build your whole life on it yet, bestie.

It's roughly equivalent to a machine-readable version of -fopt-info-all, as a collection of messages with source file, line number and column number. On top of that, each message comes with the following extra data ๐Ÿ’–

  • the execution count of the code being optimized, along with metadata about whether this came from actual profile data or just an estimate, so consumers can prioritize messages by code hotness ๐Ÿ”ฅ
  • the function name of the code being optimized, where applicable ๐Ÿงš
  • the "inlining chain" for the code being optimized, so when a function is inlined into several different places (which might themselves be inlined), the reader can tell the copies apart ๐Ÿชž
  • objects identifying those parts of the message that refer to expressions, statements or symbol-table nodes, which of these categories they are, and, when available, their source code location ๐Ÿ“
  • the GCC pass that emitted the message, and
  • the location in GCC's own code from which the message was emitted ๐Ÿคฏ

Additionally, some messages are logically nested within other messages, reflecting implementation details of the optimization passes ๐Ÿช†


โœจ -fsched-verbose=n โœจ

On targets that use instruction scheduling, this option controls how much debugging output the scheduler prints to the dump files ๐Ÿ“œ

  • For n greater than zero, -fsched-verbose outputs the same information as -fdump-rtl-sched1 and -fdump-rtl-sched2 ๐ŸŒธ
  • For n greater than one, it also outputs basic block probabilities, detailed ready list information and unit/insn info ๐Ÿ”
  • For n greater than two, it includes RTL at the abort point, control-flow and regions info ๐ŸŒŠ
  • And for n over four, -fsched-verbose also includes dependence info ๐Ÿคฏ

โœจ -fenable-kind-pass / -fdisable-kind-pass=range-list โœจ

This is a set of options used to explicitly disable or enable optimization passes ๐ŸŽ›๏ธ They're intended for debugging GCC itself. Compiler users should use the regular options for enabling and disabling passes instead, bestie ๐Ÿ™…โ€โ™€๏ธ

  • -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 uses of these options ๐Ÿ‘€

# disable ccp1 for all functions
   -fdisable-tree-ccp1
# disable complete unroll for function whose cgraph node uid is 1
   -fenable-tree-cunroll=1
# disable gcse2 for functions at the following ranges [1,1],
# [300,400], and [400,1000]
# disable gcse2 for functions foo and foo2
   -fdisable-rtl-gcse2=foo,foo2
# disable early inlining
   -fdisable-tree-einline
# disable ipa inlining
   -fdisable-ipa-inline
# enable tree full unroll
   -fenable-tree-unroll

โœจ -fchecking / -fchecking=n โœจ

Enables internal consistency checking ๐Ÿ” The default depends on the compiler configuration. -fchecking=2 enables further internal consistency checking that might affect code generation, so it's a bit of a plot twist ๐ŸŽญ


โœจ -frandom-seed=string โœจ

This option provides a seed that GCC uses in place of random numbers when generating certain symbol names that have to be different in every compiled file ๐ŸŽฒ It's also used to place unique stamps in coverage data files and the object files that produce them. You can use -frandom-seed to produce reproducibly identical object files, which is honestly so iconic ๐Ÿ’œ

The string can either be a number (decimal, octal or hex) or an arbitrary string, in which case it's converted to a number by computing CRC32 ๐Ÿ”ข

๐Ÿ’… The string should be different for every file you compile!

โœจ -save-temps โœจ

Stores the usual "temporary" intermediate files permanently ๐Ÿ“‚ They get named as auxiliary output files, as specified under -dumpbase and -dumpdir.

When used in combination with the -x command-line option, -save-temps is sensible enough to avoid overwriting an input source file that has the same extension as an intermediate file ๐Ÿ™Œ If you want the corresponding intermediate file, you can get it by renaming the source file before using -save-temps ๐Ÿซถ


โœจ -save-temps=cwd โœจ

Equivalent to -save-temps -dumpdir ./ ๐Ÿ“


โœจ -save-temps=obj โœจ

Equivalent to -save-temps -dumpdir outdir/, where outdir/ is the directory of the output file specified after the -o option, including any directory separators ๐Ÿ—‚๏ธ If the -o option is not used, the -save-temps=obj switch behaves like -save-temps=cwd ๐ŸŒธ


โœจ -time[=file] โœจ

Reports the CPU time taken by each subprocess in the compilation sequence โฑ๏ธ For C source files, this is the compiler proper and assembler (plus the linker if linking is done) ๐Ÿ’–

Without the specification of an output file, the output looks like this:

# cc1 0.12 0.01
# as 0.00 0.01

The first number on each line is the "user time", which is the time spent executing the program itself. The second number is the "system time", which is the time spent executing operating system routines on behalf of the program. Both numbers are in seconds โฐ

With the specification of an output file, the output is appended to the named file, and it looks like this:

0.12 0.01 cc1 <options>
0.00 0.01 as <options>

The "user time" and the "system time" get moved before the program name, and the options passed to the program are displayed too, so you can later tell what file was being compiled, and with which options ๐Ÿงพ๐ŸŽ€

  • -fdump-final-insns[=file]: okay so this one dumps the final internal representation (RTL) into a file ๐Ÿ“„ โœจ. If you leave out the optional argument (or file is "."), the dump file name gets made by tacking .gkd onto the dump base name, see -dumpbase ๐Ÿ’….
  • -fcompare-debug[=opts]: bestie, this one is a whole vibe ๐Ÿ”ฅ. If nothing errors during compilation, GCC runs the compiler a second time with opts and -fcompare-debug-second added to the second run's args ๐Ÿ™ˆ. It dumps the final internal representation from both compilations and prints an error if they don't match ๐Ÿ˜ญ. No equal sign? Then the default -gtoggle is used ๐ŸŽ€. The environment variable GCC_COMPARE_DEBUG (if it's defined, non-empty, and nonzero) implicitly turns on -fcompare-debug ๐Ÿ’œ. If GCC_COMPARE_DEBUG is set to a string starting with a dash, that string is used for opts, otherwise the default -gtoggle is used ๐Ÿฆ‹. Then -fcompare-debug= (equal sign, no opts) is the same as -fno-compare-debug, which turns off the dumping and the second compilation, and stops even GCC_COMPARE_DEBUG from taking effect ๐Ÿšซ๐Ÿ’€. To check full coverage while testing -fcompare-debug, set GCC_COMPARE_DEBUG to -fcompare-debug-not-overridden. GCC rejects that as an invalid option in any real compilation (rather than preprocessing, assembly, or linking) ๐Ÿงš. If you only want a warning, setting GCC_COMPARE_DEBUG to -w%n-fcompare-debug not overridden will do ๐ŸŒธ.
  • -fcompare-debug-second: this gets passed to the compiler implicitly for the second compilation requested by -fcompare-debug ๐Ÿฆ‹. It comes along with options that silence warnings, and it leaves out any other options that would make the compiler write output to files or to standard output as a side effect ๐Ÿ™…โ€โ™€๏ธ. Dump files and preserved temporary files get renamed to include the .gk additional 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, so it's mostly only useful for debugging the compiler itself ๐Ÿ› ๏ธ.
  • -gtoggle: turns off debug info generation if leaving this option out would generate it, or turns it on at level 2 otherwise ๐Ÿ”. Where it sits on the command line doesn't matter. It takes effect after all other options are processed, and only once, no matter how many times you give it ๐Ÿซถ. It's mainly meant to be used with -fcompare-debug ๐Ÿ’–.
  • -fvar-tracking-assignments-toggle: toggles -fvar-tracking-assignments the same way -gtoggle toggles -g โœจ.
  • -Q: makes the compiler print out each function name as it gets compiled, and print some statistics about each pass when it finishes ๐Ÿ“Š.
  • -ftime-report: makes the compiler print some statistics about the time each pass takes when it finishes โฑ๏ธ.
  • -ftime-report-details: records the time spent in infrastructure parts separately for each pass ๐Ÿง.
  • -fira-verbose=n: controls how verbose the dump file for the integrated register allocator is ๐ŸŒˆ. The default value is 5. If n is greater than or equal to 10, the dump output goes to stderr in the same format as n minus 10 ๐Ÿ”ฅ.
  • -flto-report: prints a report with internal details on how the link-time optimizer is working ๐Ÿ•ต๏ธโ€โ™€๏ธ. The contents of this report change from version to version ๐Ÿ™ˆ. It's meant to be useful to GCC developers when processing object files in LTO mode (via -flto) ๐Ÿ‘‘. It's disabled by default ๐Ÿ’….
  • -flto-report-wpa: same as -flto-report, but it only prints for the WPA phase of link-time optimization ๐Ÿ’œ.
  • -fmem-report: makes the compiler print some statistics about permanent memory allocation when it finishes ๐Ÿง .
  • -fmem-report-wpa: makes the compiler print some statistics about permanent memory allocation for the WPA phase only ๐ŸŒธ.
  • -fpre-ipa-mem-report and -fpost-ipa-mem-report: makes the compiler print some statistics about permanent memory allocation before or after interprocedural optimization ๐Ÿฆ‹.
  • -fprofile-report: makes the compiler print some statistics about how consistent the (estimated) profile is and what effect each individual pass has ๐Ÿ“ˆ.
  • -fstack-usage: makes the compiler output stack usage information for the program, per function ๐Ÿฅž. The filename for the dump is made by appending .su to the auxname ๐Ÿ“. The auxname comes from the name of the output file if you explicitly specified one and it isn't an executable, otherwise it's the basename of the source file ๐ŸŽ€. Each entry has three fields:
    • The name of the function.
    • A number of bytes.
    • One or more qualifiers: "static", "dynamic", "bounded".

The "static" qualifier means the function manipulates the stack statically: a fixed number of bytes gets allocated for the frame on function entry and released on function exit, and no other stack adjustments get made in the function ๐Ÿงฑ. The second field is that fixed number of bytes ๐Ÿ”ข. The "dynamic" qualifier means the function manipulates the stack dynamically: on top of the static allocation, stack adjustments happen in the body of the function, for example to push and pop arguments around function calls ๐ŸŽข. If "bounded" is also present, the amount of those adjustments is bounded at compile time, and the second field is an upper bound on the total stack used by the function ๐Ÿซง. If it's not present, the amount of those adjustments isn't bounded at compile time, and the second field only represents the bounded part ๐Ÿคทโ€โ™€๏ธ.

  • -fstats: emits statistics about front-end processing at the end of compilation ๐Ÿ“‰. This is only supported by the C++ front end, and the info is generally only useful to the G++ development team ๐Ÿ‘ฉโ€๐Ÿ’ป.
  • -fdbg-cnt-list: prints the name and the counter upper bound for all debug counters ๐Ÿ“‹.
  • -fdbg-cnt=counter-value-list: sets the internal debug counter lower and upper bounds ๐ŸŽฏ. counter-value-list is a comma-separated list of name:lower_bound1-upper_bound1 [:lower_bound2-upper_bound2...] tuples, which set the name of the counter and a list of closed intervals ๐Ÿ’ซ. The lower bound is optional and is zero initialized if it's not set 0๏ธโƒฃ. 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 doesn't do anything else ๐Ÿ–จ๏ธ. With this option, GCC doesn't compile or link anything; it just prints the file name ๐Ÿซถ.
  • -print-multi-directory: prints the directory name for the multilib selected by any other switches on the command line ๐Ÿ“. This directory is supposed to exist in GCC_EXEC_PREFIX ๐Ÿ—‚๏ธ.
  • -print-multi-lib: prints the mapping from multilib directory names to the compiler switches that enable them ๐Ÿ—บ๏ธ. The directory name is separated from the switches by ;, and each switch starts with an @ instead of the -, with no spaces between multiple switches ๐Ÿ’…. This is supposed to make shell processing easier ๐Ÿš.
  • -print-multi-os-directory: prints the path to OS libraries for the selected multilib, relative to some lib subdirectory ๐ŸŒˆ. If OS libraries are in the lib subdirectory and no multilibs are used, this is usually just .. If OS libraries are in libsuffix sibling directories, it prints something like ../lib64, ../lib, or ../lib32. If OS libraries are in lib/subdir subdirectories, it prints something like amd64, sparcv9, or ev6 ๐Ÿง.
  • -print-multiarch: prints the path to OS libraries for the selected multiarch, relative to some lib subdirectory ๐Ÿฆ„.
  • -print-prog-name=program: like -print-file-name, but it searches for a program such as cpp ๐Ÿ”.
  • -print-libgcc-file-name: same as -print-file-name=libgcc.a ๐Ÿ’œ. This is useful when you use -nostdlib or -nodefaultlibs but you still want to link with libgcc.a ๐Ÿซถ. You can do:
gcc -nostdlib <files>... `gcc -print-libgcc-file-name`
  • -print-search-dirs: prints the name of the configured installation directory, plus a list of the program and library directories gcc searches, and then doesn't do anything else ๐Ÿ—บ๏ธ.

This is useful when gcc prints the error message installation problem, cannot exec cpp0: No such file or directory. ๐Ÿ˜ฑ To fix it, you either need to put cpp0 and the other compiler components where gcc expects to find them, or you can set the environment variable GCC_EXEC_PREFIX to the directory where you installed them ๐Ÿ› ๏ธ. Don't forget the trailing /! ๐Ÿ’…

  • -print-sysroot: prints the target sysroot directory that's used during compilation ๐ŸŒธ. This is the target sysroot specified either at configure time or with the --sysroot option, possibly with an extra suffix that depends on compilation options ๐Ÿงฉ. If no target sysroot is specified, the option prints nothing ๐Ÿซฅ.
  • -print-sysroot-headers-suffix: prints the suffix added to the target sysroot when searching for headers ๐Ÿงพ. If the compiler isn't configured with such a suffix, it gives an error instead, and then doesn't do anything else ๐Ÿ™ˆ.
  • -dumpmachine: prints the compiler's target machine (for example, i686-pc-linux-gnu), and then doesn't do anything else ๐Ÿ–ฅ๏ธ.
  • -dumpversion: prints the compiler version (for example, 3.0, 6.3.0 or 7), and then doesn't do anything else ๐ŸŽ€. This is the compiler version used in filesystem paths and specs ๐Ÿ“‚. Depending on how the compiler was configured, it can be just a single number (major version), two numbers separated by a dot (major and minor version), or three numbers separated by dots (major, minor, and patchlevel version) ๐Ÿ”ข.
  • -dumpfullversion: prints the full compiler version, and then doesn't do anything else ๐Ÿ’–. The output is always three numbers separated by dots: major, minor, and patchlevel version ๐Ÿงฎ.
  • -dumpspecs: prints the compiler's built-in specs, and then doesn't do anything else ๐Ÿ“œ. (This is used when GCC itself is being built.) ๐Ÿ› ๏ธ

โœจ Machine-Dependent Options โœจ

Each target machine GCC supports can have its own options ๐Ÿ–ฅ๏ธ. For example, they let you compile for a particular processor variant or ABI, or control optimizations specific to that machine ๐Ÿฆ‹. By convention, the names of machine-specific options start with -m ๐Ÿ’….

Okay so the compiler has a whole AArch64 wardrobe ๐Ÿฆ‹ and we're about to try on every piece, bestie ๐Ÿ’…

๐ŸŒˆ AArch64 Options ๐ŸŒˆ

These options are for AArch64 implementations ๐ŸŒธ

  • -mabi=name โ€” picks the data model you want the code generated for ๐Ÿ’– The valid values are ilp32 (SysV-like, where int, long int and pointers are all 32 bits) and lp64 (SysV-like, where int is 32 bits but long int and pointers are 64 bits) โœจ The default depends on your target configuration. Also, the LP64 and ILP32 ABIs are not link-compatible, so you have to compile your whole program with the same ABI and link it against a compatible set of libraries ๐Ÿ™ˆ
  • -mbig-endian โ€” generates big-endian code ๐Ÿ“ This is the default when GCC is configured for an aarch64_be-*-* target.
  • -mgeneral-regs-only โ€” only uses the general-purpose registers ๐Ÿซถ That means no floating-point or Advanced SIMD registers, but it doesn't put any limits 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-*-* one.
  • -mcmodel=tiny โ€” uses the tiny code model ๐Ÿงš The program and its statically defined symbols have to sit within 1MB of each other. It can be statically or dynamically linked.
  • -mcmodel=small โ€” uses the small code model ๐Ÿฆ‹ The program and its statically defined symbols have to be within 4GB of each other. It can be statically or dynamically linked. This is the default code model, so you're already on it unless you switch ๐Ÿ’œ
  • -mcmodel=large โ€” uses the large code model, which makes no assumptions about addresses and sizes of sections ๐Ÿ‘‘ Programs can only be statically linked with this one. Also, -mcmodel=large is incompatible with -mabi=ilp32, -fpic and -fPIC, so don't mix them ๐Ÿ’€
  • -mstrict-align, -mno-strict-align โ€” the first one avoids (or the second one allows) generating memory accesses that might not be aligned on a natural object boundary, as described in the architecture specification โœจ
  • -momit-leaf-frame-pointer, -mno-omit-leaf-frame-pointer โ€” omits (or keeps) the frame pointer in leaf functions ๐ŸŒธ The former behaviour is the default.
  • -mstack-protector-guard=guard, -mstack-protector-guard-reg=reg, -mstack-protector-guard-offset=offset โ€” generates stack protection code that uses a canary at guard ๐Ÿ›ก๏ธ The supported locations are global (for a global canary) or sysreg (for a canary in an appropriate system register).

With the sysreg choice, -mstack-protector-guard-reg=reg and -mstack-protector-guard-offset=offset also tell GCC which system register to use as the base register for reading the canary, and what offset from that base register to read from ๐Ÿ”ฅ There's no default register or offset for this, because it's entirely meant for use inside 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 โ€” sets the bit size of immediate TLS offsets ๐Ÿฆ‹ The valid values are 12, 24, 32 and 48. This option needs binutils 2.26 or newer, so check your toolchain first ๐Ÿซถ
  • -mfix-cortex-a53-835769, -mno-fix-cortex-a53-835769 โ€” turns the workaround for the ARM Cortex-A53 erratum number 835769 on (or off) ๐Ÿฉน The workaround inserts a NOP instruction between memory instructions and 64-bit integer multiply-accumulate instructions.
  • -mfix-cortex-a53-843419, -mno-fix-cortex-a53-843419 โ€” turns the workaround for the ARM Cortex-A53 erratum number 843419 on (or off) ๐Ÿฉน This workaround is applied at link time, so this option just passes the matching flag along to the linker ๐Ÿ”—
  • -mlow-precision-recip-sqrt, -mno-low-precision-recip-sqrt โ€” enables (or disables) the reciprocal square root approximation โšก This only does anything if -ffast-math or -funsafe-math-optimizations is used as well. When it's on, reciprocal square root results drop to about 16 bits of precision 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 also only works alongside -ffast-math or -funsafe-math-optimizations. When it's on, square root results drop to about 16 bits for single precision and about 32 bits for double precision. If you enable it, it implies -mlow-precision-recip-sqrt.
  • -mlow-precision-div, -mno-low-precision-div โ€” enables (or disables) the division approximation โž— Again, it only has an effect alongside -ffast-math or -funsafe-math-optimizations. When it's on, division results drop to about 16 bits for single precision and about 32 bits for double precision.
  • -mtrack-speculation, -mno-track-speculation โ€” enables (or disables) extra code that tracks speculative execution through conditional branches ๐Ÿ•ต๏ธโ€โ™€๏ธ The tracking state can then be used by the compiler when it expands calls to "__builtin_speculation_safe_copy", so it can make a more efficient code sequence.
  • -moutline-atomics, -mno-outline-atomics โ€” enables (or disables) calls to out-of-line helpers that implement atomic operations โœจ These helpers figure out at runtime whether the LSE instructions from ARMv8.1-A can be used. If they can't, they fall back to the load/store-exclusive instructions that are in the base ARMv8.0 ISA. This option is only applicable when compiling for the base ARMv8.0 instruction set. If you're on 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 target architecture and, optionally, one or more feature modifiers ๐Ÿ›๏ธ This option has the form -march=arch{+[no]feature}*.

Here's the rundown of the permissible arch values and the features each one turns on by default ๐Ÿ‘‘

  • armv8-a โ€” Armv8-A โ€” includes by default: +fp, +simd
  • armv8.1-a โ€” Armv8.1-A โ€” includes by default: armv8-a, +crc, +lse, +rdma
  • armv8.2-a โ€” Armv8.2-A โ€” includes by default: armv8.1-a
  • armv8.3-a โ€” Armv8.3-A โ€” includes by default: armv8.2-a, +pauth
  • armv8.4-a โ€” Armv8.4-A โ€” includes by default: armv8.3-a, +flagm, +fp16fml, +dotprod
  • armv8.5-a โ€” Armv8.5-A โ€” includes by default: armv8.4-a, +sb, +ssbs, +predres
  • armv8.6-a โ€” Armv8.6-A โ€” includes by default: armv8.5-a, +bf16, +i8mm
  • armv8.7-a โ€” Armv8.7-A โ€” includes by default: armv8.6-a, +ls64
  • armv8.8-a โ€” Armv8.8-a โ€” includes by default: armv8.7-a, +mops
  • armv9-a โ€” Armv9-A โ€” includes by default: armv8.5-a, +sve, +sve2
  • armv8-r โ€” Armv8-R โ€” includes by default: armv8-r

The value native works on native AArch64 GNU/Linux and tells the compiler to pick the architecture of the host system. This option has no effect if the compiler can't recognise the architecture of the host system,

The permissible values for feature are listed in the sub-section on aarch64-feature-modifiers,,-march and -mcpu Feature Modifiers. If you specify conflicting feature modifiers, the right-most feature wins ๐Ÿซฐ

GCC uses name to decide what kind of instructions it can emit when generating assembly code ๐Ÿง  If -march is specified without -mtune or -mcpu also being specified, the code is tuned to perform well across a range of target processors that implement the target architecture ๐ŸŒŸ

  • -mtune=name โ€” specifies the target processor that GCC should tune the performance of the code for ๐ŸŽฏ The permissible values are:

generic, cortex-a35, cortex-a53, cortex-a55, cortex-a57, cortex-a72, cortex-a73, cortex-a75, cortex-a76, cortex-a76ae, cortex-a77, cortex-a65, cortex-a65ae, cortex-a34, cortex-a78, cortex-a78ae, cortex-a78c, ares, exynos-m1, emag, falkor, neoverse-512tvb, neoverse-e1, neoverse-n1, neoverse-n2, neoverse-v1, qdf24xx, saphira, phecda, xgene1, vulcan, octeontx, octeontx81, octeontx83, octeontx2, octeontx2t98, octeontx2t96 octeontx2t93, octeontx2f95, octeontx2f95n, octeontx2f95mm, a64fx, thunderx, thunderxt88, thunderxt88p1, thunderxt81, tsv110, thunderxt83, thunderx2t99, thunderx3t110, zeus, cortex-a57.cortex-a53, cortex-a72.cortex-a53, cortex-a73.cortex-a35, cortex-a73.cortex-a53, cortex-a75.cortex-a55, cortex-a76.cortex-a55, cortex-r82, cortex-x1, cortex-x2, cortex-a510, cortex-a710, ampere1, native.

The values cortex-a57.cortex-a53, cortex-a72.cortex-a53, cortex-a73.cortex-a35, cortex-a73.cortex-a53, cortex-a75.cortex-a55 and cortex-a76.cortex-a55 tell GCC to tune for a big.LITTLE system ๐Ÿงฉ

The value neoverse-512tvb tells GCC to tune for Neoverse cores that (a) implement SVE and (b) have a total vector bandwidth of 512 bits per cycle ๐Ÿ’ช In other words, it tunes for Neoverse cores that can run 4 128-bit Advanced SIMD arithmetic instructions a cycle, and an equivalent number of SVE arithmetic instructions per cycle (2 for 256-bit SVE, 4 for 128-bit SVE). This is more general than tuning for one specific core like Neoverse V1, but more specific than the default tuning described below ๐ŸŒธ

On native AArch64 GNU/Linux systems, the value native also tunes performance to the host system. This option has no effect if the compiler can't recognise the processor of the host system ๐Ÿ–ฅ๏ธ

If none of -mtune=, -mcpu= or -march= are specified, the code is tuned to perform well across a range of target processors ๐Ÿซถ

This option can't be suffixed by feature modifiers ๐Ÿ™…โ€โ™€๏ธ

  • -mcpu=name โ€” specifies the target processor, optionally suffixed by one or more feature modifiers ๐ŸŽ€ This option has the form -mcpu=cpu{+[no]feature}*, where the permissible values for cpu are the same as those for -mtune. The permissible values for feature are documented in the sub-section on aarch64-feature-modifiers,,-march and -mcpu Feature Modifiers. Same rule as before: if feature modifiers conflict, the right-most one is used ๐Ÿซฐ

okay so -mcpu=name is the big boss ๐Ÿ‘‘ GCC uses name to figure out which kinds of instructions it can emit when generating assembly code (as if by -march) and which target processor to tune performance for (as if by -mtune). If you use -march or -mtune alongside it, those two win and override the matching part of this option ๐Ÿ’…

-mcpu=neoverse-512tvb is lowkey special ๐Ÿฆ‹ It doesn't point to one specific core. Instead it covers all Neoverse cores that (a) implement SVE and (b) have a total vector bandwidth of 512 bits a cycle. Unless -march overrides it, -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 -mtune overrides it, -mcpu=neoverse-512tvb tunes code the same way as -mtune=neoverse-512tvb โœจ

  • -moverride=string โ€” this one lets you override the tuning decisions the back-end makes in response to a -mtune= switch. The syntax, semantics, and accepted values for string are not guaranteed to stay consistent across releases ๐Ÿ™ˆ
โš ๏ธ bestie, this one is only really useful when you're developing GCC itself, so don't go poking it for fun.
  • -mverbose-cost-dump โ€” turns on verbose cost model dumping in the debug dump files. It's there for debugging the compiler ๐Ÿ”
  • -mpc-relative-literal-loads, -mno-pc-relative-literal-loads โ€” these turn PC-relative literal loads on or off. With the first one, literal pools are accessed using a single instruction and 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 โ€” picks the function scope where return address signing gets applied. The permissible values are none, which disables return address signing, non-leaf, which enables pointer signing for functions that are not leaf functions, and all, which enables pointer signing for all functions. The default is none. This option has been deprecated by -mbranch-protection ๐Ÿ’€
  • -mbranch-protection=none|standard|pac-ret[+leaf+b-key]|bti โ€” picks which branch protection features to use. none is the default and turns off all types of branch protection. standard turns on all of them, and for any feature with extra tuning options, standard sets it to its standard level. pac-ret[+leaf] turns on return address signing to its standard level, signing functions that save the return address to memory (non-leaf functions will practically always do this) using the a-key. The optional argument leaf extends the signing to include leaf functions. The optional argument b-key signs the functions with the B-key instead of the A-key. And bti turns on the branch target identification mechanism ๐Ÿ›ก๏ธ
  • -mharden-sls=opts โ€” enables compiler hardening against straight line speculation (SLS). opts is a comma-separated list of the following options:
    • retbr
    • blr

Also, -mharden-sls=all enables all SLS hardening, while -mharden-sls=none disables all of it ๐Ÿ”’

  • -msve-vector-bits=bits โ€” specifies the number of bits in an SVE vector register. This option only has an effect when SVE is enabled ๐Ÿ“

GCC supports two forms of SVE code generation. There's "vector-length agnostic" output that works with any size of vector register, and "vector-length specific" output that lets GCC make assumptions about the vector length when that helps optimization. The possible values of bits are scalable, 128, 256, 512, 1024 and 2048. Specifying scalable selects vector-length agnostic output. Right now, -msve-vector-bits=128 also generates vector-length agnostic output for big-endian targets. All other values generate vector-length specific code. These values might change in future releases, so no value except scalable should be relied on for code that's portable across different hardware SVE vector lengths ๐Ÿ˜ญ

The default is -msve-vector-bits=scalable, which produces vector-length agnostic code โœจ


โœจ -march and -mcpu Feature Modifiers โœจ

Feature modifiers used with -march and -mcpu can be any of the following, along with their inverses 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 -march and -mcpu.
  • simd โ€” enables Advanced SIMD instructions. This also enables floating-point instructions. It's on by default for all possible values for -march and -mcpu.
  • sve โ€” enables Scalable Vector Extension instructions. This also enables Advanced SIMD and floating-point instructions.
  • lse โ€” enables Large System Extension instructions. This is on by default for -march=armv8.1-a.
  • rdma โ€” enables Round Double Multiply Accumulate instructions. This is on by default for -march=armv8.1-a.
  • fp16 โ€” enables the FP16 extension. This also enables floating-point instructions.
  • fp16fml โ€” enables the FP16 fmla extension. This also enables FP16 extensions and floating-point instructions. It's enabled by default for -march=armv8.4-a. Using this with architectures prior to Armv8.2-A is not supported ๐Ÿ™…โ€โ™€๏ธ
  • rcpc โ€” enables the RcPc extension. This doesn't change code generation from GCC, but it gets passed on to the assembler, so inline asm statements can use instructions from the RcPc extension.
  • dotprod โ€” enables the Dot Product extension. This also enables Advanced SIMD instructions.
  • aes โ€” enables the Armv8-a aes and pmull crypto extension. This also enables Advanced SIMD instructions.
  • sha2 โ€” enables the Armv8-a sha2 crypto extension. This also enables Advanced SIMD instructions.
  • sha3 โ€” enables the sha512 and sha3 crypto extension. This also enables Advanced SIMD instructions. Using this with architectures prior to Armv8.2-A is not supported.
  • sm4 โ€” enables the sm3 and sm4 crypto extension. This also enables Advanced SIMD instructions. Using this with architectures prior to Armv8.2-A is not supported.
  • profile โ€” enables the Statistical Profiling extension. This is only to turn the extension on at the assembler level, and it doesn't affect code generation ๐Ÿ”
  • rng โ€” enables the Armv8.5-a Random Number instructions. This is only to enable the extension at the assembler level and doesn't affect code generation.
  • memtag โ€” enables the Armv8.5-a Memory Tagging Extensions. Using this with architectures prior to Armv8.5-A is not supported.
  • sb โ€” enables the Armv8-a Speculation Barrier instruction. This is only to enable the extension at the assembler level and doesn't affect code generation. It's enabled by default for -march=armv8.5-a.
  • ssbs โ€” enables the Armv8-a Speculative Store Bypass Safe instruction. This is only to enable the extension at the assembler level and doesn't affect code generation. It's enabled by default for -march=armv8.5-a.
  • predres โ€” enables the Armv8-a Execution and Data Prediction Restriction instructions. This is only to enable the extension at the assembler level and doesn't affect code generation. It's enabled by default for -march=armv8.5-a.
  • sve2 โ€” enables the Armv8-a Scalable Vector Extension 2. This also enables SVE instructions.
  • sve2-bitperm โ€” enables SVE2 bitperm instructions. This also enables SVE2 instructions.
  • sve2-sm4 โ€” enables SVE2 sm4 instructions. This also enables SVE2 instructions.
  • sve2-aes โ€” enables SVE2 aes instructions. This also enables SVE2 instructions.
  • sve2-sha3 โ€” enables SVE2 sha3 instructions. This also enables SVE2 instructions.
  • tme โ€” enables the Transactional Memory Extension.
  • i8mm โ€” enables 8-bit Integer Matrix Multiply instructions. This also enables Advanced SIMD and floating-point instructions. It's enabled by default for -march=armv8.6-a. Using this with architectures prior to Armv8.2-A is not supported.
  • f32mm โ€” enables 32-bit Floating point Matrix Multiply instructions. This also enables SVE instructions. Using this with architectures prior to Armv8.2-A is not supported.
  • f64mm โ€” enables 64-bit Floating point Matrix Multiply instructions. This also enables SVE instructions. Using this with architectures prior to Armv8.2-A is not supported.
  • bf16 โ€” enables brain half-precision floating-point instructions. This also enables Advanced SIMD and floating-point instructions. It's enabled by default for -march=armv8.6-a. Using this with architectures prior to Armv8.2-A is not supported.
  • ls64 โ€” enables the 64-byte atomic load and store instructions for accelerators. It's enabled by default for -march=armv8.7-a.
  • mops โ€” enables the instructions that speed up memory operations like "memcpy", "memmove", "memset". It's enabled by default for -march=armv8.8-a
  • flagm โ€” enables the Flag Manipulation instructions Extension.
  • pauth โ€” enables the Pointer Authentication Extension.

Feature crypto implies aes, sha2, and simd, which implies fp. Conversely, nofp implies nosimd, which implies nocrypto, noaes and nosha2 ๐Ÿง 


๐Ÿฆ‹ Adapteva Epiphany Options ๐Ÿฆ‹

These -m options are defined for Adapteva Epiphany ๐ŸŒˆ

  • -mhalf-reg-file โ€” doesn't allocate any register in the range "r32"..."r63". That lets code run on hardware variants that lack these registers.
  • -mprefer-short-insn-regs โ€” preferentially allocates registers that allow short instruction generation. This can increase the instruction count, so it may either reduce or increase overall code size.
  • -mbranch-cost=num โ€” sets the cost of branches to roughly num "simple" instructions. This cost is only a heuristic and isn't guaranteed to give consistent results across releases.
  • -mcmove โ€” enables the generation of conditional moves ๐Ÿ“
  • -mnops=num โ€” emits num NOPs before every other generated instruction.
  • -mno-soft-cmpsf โ€” okay so this one's a speed-vs-accuracy trade-off ๐Ÿ’… For single-precision float comparisons, GCC emits an fsub instruction and checks the flags instead. That's faster than a software comparison, BUT it can give wrong answers with NaNs, or when two different tiny numbers subtract to zero. The default is -msoft-cmpsf, which is slower but IEEE-compliant (the safe, responsible choice ๐Ÿซถ).
  • -mstack-offset=num โ€” sets the offset between the top of the stack and the stack pointer. For example, a value of 8 means the eight bytes in the range sp+0...sp+7 can be used by leaf functions without any stack allocation โœจ Values other than 8 or 16 are untested and probably won't work ๐Ÿ’€ Heads up, this one changes the ABI, so programs built with a different stack offset than the libraries generally won't work together ๐Ÿ˜ญ It's handy for checking whether a different offset gives you better code, but if you actually want working programs with one, the recommended move is configuring the toolchain with the matching --with-stack-offset=num option ๐ŸŽ€
  • -mno-round-nearest โ€” tells the scheduler to assume the rounding mode has been set to truncating ๐ŸŒธ The default is -mround-nearest.
  • -mlong-calls โ€” if an attribute doesn't say otherwise, GCC assumes every call might be out of range of the b / bl instructions. So it loads the function address into a register first, then does the (otherwise direct) call. This is the default ๐Ÿ‘‘
  • -mshort-calls โ€” if an attribute doesn't say otherwise, GCC assumes all direct calls are in range of the b / bl instructions, so it uses those instructions for direct calls ๐Ÿฆ‹ The default is -mlong-calls.
  • -msmall16 โ€” assumes addresses can be loaded as 16-bit unsigned values ๐Ÿงš This doesn't apply to function addresses that have -mlong-calls semantics in effect.
  • -mfp-mode=mode โ€” sets the prevailing mode of the floating-point unit. This decides which FPU mode is provided and expected at function call and return time. If you match this to the mode you mostly need at function start, your programs can be smaller and faster because you skip unnecessary mode switches ๐Ÿ’–

mode can be set to one of the following values:

  • caller โ€” any mode at function entry is valid, and it's kept or restored when the function returns and when it calls other functions. This one's super useful for libraries or other compilation units you want to drop into programs with different FPU modes. You get one object file, and that convenience outweighs the extra size and speed cost of any mode switching you'd need compared to a more specific choice ๐ŸŒˆ
  • truncate โ€” the mode used for floating-point calculations with truncating (round towards zero) rounding. That includes float-to-integer conversion ๐Ÿ“
  • round-nearest โ€” the mode used for floating-point calculations with round-to-nearest-or-even rounding ๐ŸŒธ
  • int โ€” the mode used to do integer calculations in the FPU, like integer multiply or integer multiply-and-accumulate ๐Ÿ”ฅ

The default is -mfp-mode=caller.

  • -mno-split-lohi, -mno-postinc, -mno-postmodify โ€” three code generation tweaks with a shared vibe ๐Ÿ™ˆ They respectively disable 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. Be warned, this is an ABI change! Though plenty of library function interfaces are unaffected, as long as they don't use SIMD vector modes in places that change the size or alignment of relevant types ๐Ÿ˜ญ
  • -msplit-vecmove-early โ€” splits vector moves into single word moves before reload ๐Ÿฆ‹ In theory this could give better register allocation, but so far the reverse seems to be generally true ๐Ÿ’€
  • -m1reg-reg โ€” specifies a register to hold the constant -1, which makes loading small negative constants and certain bitmasks faster ๐Ÿงš Allowable values for reg are r43 and r63, which use that register as a fixed register, and none, which means no register is used for this purpose. The default is -m1reg-none.

๐Ÿฆ‹ AMD GCN Options ๐Ÿฆ‹

These options are defined specifically for the AMD GCN port ๐ŸŽ€

  • -march=gpu, -mtune=gpu โ€” sets the architecture type or tuning for gpu ๐Ÿ‘‘ The supported values for gpu are:
    • fiji โ€” compiles for GCN3 Fiji devices (gfx803).
    • gfx900 โ€” compiles for GCN5 Vega 10 devices (gfx900).
    • gfx906 โ€” compiles for GCN5 Vega 20 devices (gfx906).
  • -msram-ecc=on, -msram-ecc=off, -msram-ecc=any โ€” compiles binaries suitable for devices with the SRAM-ECC feature enabled, disabled, or either mode ๐Ÿ”ฅ Some devices let you enable this per-process, and the compiled code has to match the device mode. The default is any, for devices that support it.
  • -mstack-size=bytes โ€” specifies how many bytes of stack space get requested for each GPU thread (wave-front) ๐Ÿ˜ญ Be careful, since there may be lots of threads and limited memory available! The size of the stack allocation can also affect run-time performance. The default is 32KB when using OpenACC or OpenMP, and 1MB otherwise.
  • -mxnack โ€” compiles binaries suitable for devices with the XNACK feature enabled ๐ŸŒˆ Some devices always require XNACK, and some let the user configure it. The compiled code has to match the device mode. The default is -mno-xnack. Right now this option is just a placeholder for support that isn't implemented yet ๐Ÿ™ˆ

โœจ ARC Options โœจ

The following options control the architecture variant that code is being compiled for ๐Ÿงš

  • -mbarrel-shifter โ€” generates instructions supported by the barrel shifter ๐ŸŒธ This is the default unless -mcpu=ARC601 or -mcpu=ARCEM is in effect.
  • -mjli-always โ€” forces a function call using the jli_s instruction ๐Ÿ’œ This option is only valid for the ARCv2 architecture.
  • -mcpu=cpu โ€” sets the architecture type, register usage, and instruction scheduling parameters for cpu ๐Ÿ‘‘ There are also shortcut alias options for backward compatibility and convenience. The supported values for cpu are:
    • arc600 โ€” compiles for ARC600. Aliases: -mA6, -mARC600.
    • arc601 โ€” compiles for ARC601. Alias: -mARC601.
    • arc700 โ€” compiles for ARC700. Aliases: -mA7, -mARC700. This is the default when configured with --with-cpu=arc700.
    • arcem โ€” compiles for ARC EM.
    • archs โ€” compiles for ARC HS.
    • em โ€” compiles for ARC EM CPU with no hardware extensions ๐Ÿฆ‹
    • em4 โ€” compiles for ARC EM4 CPU.
    • em4_dmips โ€” compiles for ARC EM4 DMIPS CPU.
    • em4_fpus โ€” compiles for ARC EM4 DMIPS CPU with the single-precision floating-point extension.
    • em4_fpuda โ€” compiles for ARC EM4 DMIPS CPU with single-precision floating-point and double assist instructions.
    • hs โ€” compiles for ARC HS CPU with no hardware extensions except the atomic instructions.
    • hs34 โ€” compiles for ARC HS34 CPU.
    • hs38 โ€” compiles for ARC HS38 CPU.
    • hs38_linux โ€” compiles for ARC HS38 CPU with all hardware extensions on.
    • arc600_norm โ€” compiles for ARC 600 CPU with norm instructions enabled.
    • arc600_mul32x16 โ€” compiles for ARC 600 CPU with norm and 32x16-bit multiply instructions enabled.
    • arc600_mul64 โ€” compiles for ARC 600 CPU with norm and mul64-family instructions enabled.
    • arc601_norm โ€” compiles for ARC 601 CPU with norm instructions enabled.
    • arc601_mul32x16 โ€” compiles for ARC 601 CPU with norm and 32x16-bit multiply instructions enabled.
    • arc601_mul64 โ€” compiles for ARC 601 CPU with norm and mul64-family instructions enabled.
    • nps400 โ€” compiles for ARC 700 on the NPS400 chip.
    • em_mini โ€” compiles for ARC EM minimalist configuration, featuring a reduced register set ๐ŸŒˆ
  • -mdpfp, -mdpfp-compact โ€” generates double-precision FPX instructions, tuned for the compact implementation ๐Ÿ’–
  • -mdpfp-fast โ€” generates double-precision FPX instructions, tuned for the fast implementation โญ
  • -mno-dpfp-lrsr โ€” disables lr and sr instructions from using FPX extension aux registers ๐Ÿ™ˆ
  • -mea โ€” generates extended arithmetic instructions ๐Ÿ”ฅ Right now only divaw, adds, subs, and sat16 are supported. Only valid for -mcpu=ARC700.
  • -mno-mpy โ€” doesn't generate mpy-family instructions for ARC700 ๐Ÿ’€ This option is deprecated, so please don't build new stuff around it.
  • -mmul32x16 โ€” generates 32x16-bit multiply and multiply-accumulate instructions โœจ
  • -mmul64 โ€” generates mul64 and mulu64 instructions ๐Ÿงš Only valid for -mcpu=ARC600.
  • -mnorm โ€” generates norm instructions ๐ŸŒธ This is the default if -mcpu=ARC700 is in effect.
  • -mspfp, -mspfp-compact โ€” generates single-precision FPX instructions, tuned for the compact implementation ๐ŸŽ€
  • -mspfp-fast โ€” generates single-precision FPX instructions, tuned for the fast implementation ๐Ÿ‘‘
  • -msimd โ€” enables generation of ARC SIMD instructions through target-specific builtins ๐Ÿฆ‹ Only valid for -mcpu=ARC700.
  • -msoft-float โ€” this option is ignored! It's only here for compatibility ๐Ÿ™ˆ Software floating-point code is emitted by default, and that default can be overridden by the FPX options: -mspfp, -mspfp-compact, or -mspfp-fast for single precision, and -mdpfp, -mdpfp-compact, or -mdpfp-fast for double precision.
  • -mswap โ€” generates swap instructions ๐Ÿ’…
  • -matomic โ€” enables use of the locked load/store conditional extension to implement atomic memory built-in functions โœจ Not available for ARC 6xx or ARC EM cores.
  • -mdiv-rem โ€” enables div and rem instructions for ARCv2 cores ๐Ÿ’œ

Okay bestie, we're still in the ARC pit ๐Ÿฆ‹ and it's giving tiny-chip energy, so let's go ๐Ÿ’…

  • -mcode-density โ€” โœจ Turns on the code density instructions for ARC EM. It's already on by default for ARC HS, so you're probably set ๐ŸŒธ
  • -mll64 โ€” ๐Ÿ’œ Unlocks double load/store operations for ARC HS cores. Lowkey a glow-up ๐Ÿ”ฅ
  • -mtp-regno=regno โ€” ๐Ÿงš Lets you pick the thread pointer register number. You give it the regno you want.
  • -mmpy-option=multo โ€” ๐Ÿ”ฅ Compiles ARCv2 code with a multiplier design option. You can pass multo as either a string or a number, and wlh1 is the default ๐Ÿ’– Here's the menu:
    • 0, none โ€” No multiplier at all, bestie ๐Ÿ’€
    • 1, w โ€” 16x16 multiplier, fully pipelined. Turns on "mpyw" and "mpyuw" ๐ŸŒธ
    • 2, wlh1 โ€” 32x32 multiplier, fully pipelined (1 stage). Also turns on "mpy", "mpyu", "mpym", "mpymu", and "mpy_s" โœจ This is the default
    • 3, wlh2 โ€” 32x32 multiplier, fully pipelined (2 stages). Also turns on "mpy", "mpyu", "mpym", "mpymu", and "mpy_s" ๐Ÿ’…
    • 4, wlh3 โ€” Two 16x16 multipliers, blocking and sequential. Also turns on "mpy", "mpyu", "mpym", "mpymu", and "mpy_s" ๐Ÿฆ‹
    • 5, wlh4 โ€” One 16x16 multiplier, blocking and sequential. Also turns on "mpy", "mpyu", "mpym", "mpymu", and "mpy_s" ๐Ÿซถ
    • 6, wlh5 โ€” One 32x4 multiplier, blocking and sequential. Also turns on "mpy", "mpyu", "mpym", "mpymu", and "mpy_s" ๐ŸŒˆ
    • 7, plus_dmpy โ€” ARC HS SIMD support ๐Ÿ‘‘
    • 8, plus_macd โ€” ARC HS SIMD support ๐Ÿ‘‘
    • 9, plus_qmacw โ€” ARC HS SIMD support ๐Ÿ‘‘
โš ๏ธ This option only works on ARCv2 cores, so don't try it on the others ๐Ÿ™ˆ
  • -mfpu=fpu โ€” ๐Ÿ”ฅ Turns on support for specific floating-point hardware extensions on ARCv2 cores. Here are the fpu values you can pick:
    • fpus โ€” Single-precision floating-point hardware extensions ๐Ÿ’–
    • fpud โ€” Double-precision floating-point hardware extensions. The single-precision one comes along for the ride too. Not available for ARC EM ๐Ÿ™…โ€โ™€๏ธ
    • fpuda โ€” Double-precision hardware extensions using double-precision assist instructions. Single-precision comes with it. Only for ARC EM โœจ
    • fpuda_div โ€” Double-precision with double-precision assist instructions, plus the single-precision floating-point, square-root, and divide extensions. Only for ARC EM ๐Ÿงฎ
    • fpuda_fma โ€” Double-precision with double-precision assist instructions, plus single-precision floating-point and fused multiply and add. Only for ARC EM ๐Ÿฆ‹
    • fpuda_all โ€” Double-precision with double-precision assist instructions, and every single-precision floating-point extension too. Only for ARC EM ๐Ÿ‘‘
    • fpus_div โ€” Single-precision floating-point, square-root, and divide extensions ๐ŸŒธ
    • fpud_div โ€” Double-precision floating-point, square-root, and divide extensions. This one includes fpus_div. Not available for ARC EM ๐Ÿ’œ
    • fpus_fma โ€” Single-precision floating-point and fused multiply and add extensions ๐Ÿซถ
    • fpud_fma โ€” Double-precision floating-point and fused multiply and add extensions. This one includes fpus_fma. Not available for ARC EM ๐Ÿ“
    • fpus_all โ€” Every single-precision floating-point hardware extension ๐ŸŒˆ
    • fpud_all โ€” Every single- and double-precision floating-point hardware extension. Not available for ARC EM ๐Ÿ”ฅ
  • -mirq-ctrl-saved=register-range, blink, lp_count โ€” ๐Ÿ›ก๏ธ Picks the general-purpose registers the processor automatically saves and restores on interrupt entry and exit. The register-range is two registers separated by a dash. It always starts at "r0", and the upper limit is the "fp" register. blink and lp_count are optional. This option is only valid for ARC EM and ARC HS cores โœจ
  • -mrgf-banked-regs=number โ€” ๐Ÿฆ‹ Sets how many registers get replicated into the second register bank when a fast interrupt fires. Fast interrupts are the ones with the highest priority level, P0. They only save the PC and STATUS32 registers, so there are no memory transactions during entry and exit. Use this when you're doing fast interrupts on an ARC V2 family processor. The allowed values are 4, 8, 16, and 32 ๐Ÿ’…
  • -mlpc-width=width โ€” ๐Ÿ”ข Sets the width of the "lp_count" register. Valid widths are 8, 16, 20, 24, 28, and 32 bits. The default is locked at 32 bits. If the width is under 32, the compiler won't try to 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 macro "__ARC_LPC_WIDTH__" with the value of width ๐Ÿงš
  • -mrf16 โ€” ๐ŸŽ€ Tells the compiler to generate code for a 16-entry register file. This option defines the "__ARC_RF16__" preprocessor macro ๐ŸŒธ
  • -mbranch-index โ€” ๐Ÿ“ Enables the use of "bi" or "bih" instructions to implement jump tables ๐Ÿ’œ

The following options are passed through to the assembler, and also define preprocessor macro symbols. Main character energy, no notes ๐Ÿ‘‘

  • -mdsp-packa โ€” Passed down to the assembler to enable the DSP Pack A extensions. Also sets the preprocessor symbol "__Xdsp_packa". > โš ๏ธ This option is deprecated ๐Ÿ’€
  • -mdvbf โ€” Passed down to the assembler to enable the dual Viterbi butterfly extension. Also sets the preprocessor symbol "__Xdvbf". > โš ๏ธ This option is deprecated ๐Ÿ’€
  • -mlock โ€” Passed down to the assembler to enable the locked load/store conditional extension. Also sets the preprocessor symbol "__Xlock" ๐Ÿ”’
  • -mmac-d16 โ€” Passed down to the assembler. Also sets the preprocessor symbol "__Xxmac_d16". > โš ๏ธ This option is deprecated ๐Ÿ’€
  • -mmac-24 โ€” Passed down to the assembler. Also sets the preprocessor symbol "__Xxmac_24". > โš ๏ธ This option is deprecated ๐Ÿ’€
  • -mrtsc โ€” Passed down to the assembler to enable the 64-bit time-stamp counter extension instruction. Also sets the preprocessor symbol "__Xrtsc". > โš ๏ธ This option is deprecated ๐Ÿ’€
  • -mswape โ€” Passed down to the assembler to enable the swap byte ordering extension instruction. Also sets the preprocessor symbol "__Xswape" ๐Ÿ”„
  • -mtelephony โ€” Passed down to the assembler to enable dual- and single-operand instructions for telephony. Also sets the preprocessor symbol "__Xtelephony". > โš ๏ธ This option is deprecated ๐Ÿ’€
  • -mxy โ€” Passed down to the assembler to enable the XY memory extension. Also sets the preprocessor symbol "__Xxy" ๐Ÿง 

The following options control how the assembly code is annotated ๐Ÿ“

  • -misize โ€” Annotates assembler instructions with estimated addresses ๐Ÿ“
  • -mannotate-align โ€” Explains what alignment considerations led to the decision to make an instruction short or long ๐Ÿค“

The following options are passed through to the linker ๐Ÿ”—

  • -marclinux โ€” Passed through to the linker to specify use of the "arclinux" emulation. This is on by default in tool chains built for "arc-linux-uclibc" and "arceb-linux-uclibc" targets when profiling is not requested ๐ŸŒˆ
  • -marclinux_prof โ€” Passed through to the linker to specify use of the "arclinux_prof" emulation. This is on by default in tool chains built for "arc-linux-uclibc" and "arceb-linux-uclibc" targets when profiling is requested ๐Ÿ“Š

The following options control the semantics of generated code ๐Ÿง 

  • -mlong-calls โ€” Generates calls as register indirect calls, so you get access to the full 32-bit address range ๐ŸŒ
  • -mmedium-calls โ€” Doesn't use less than a 25-bit addressing range for calls. That's the offset an unconditional branch-and-link instruction has. Conditional execution of function calls is suppressed so the 25-bit range can be used, instead of the 21-bit range you'd get with conditional branch-and-link. This is the default for tool chains built for "arc-linux-uclibc" and "arceb-linux-uclibc" targets ๐Ÿฆ‹
  • -G num โ€” Puts definitions of externally-visible data in a small data section if that data is no bigger than num bytes. The default num is 4 for any ARC configuration, or 8 when you have double load/store operations ๐Ÿ“ฆ
  • -mno-sdata โ€” Doesn't generate sdata references. This is the default for tool chains built for "arc-linux-uclibc" and "arceb-linux-uclibc" targets ๐Ÿšซ
  • -mvolatile-cache โ€” Uses ordinarily cached memory accesses for volatile references. This is the default ๐Ÿ’…
  • -mno-volatile-cache โ€” Enables cache bypass for volatile references ๐Ÿƒโ€โ™€๏ธ

The following options fine tune code generation ๐ŸŽ›๏ธ

  • -malign-call โ€” Does nothing. It's only kept for backward compatibility ๐Ÿ•ฐ๏ธ
  • -mauto-modify-reg โ€” Enables the use of pre/post modify with register displacement ๐Ÿช„
  • -mbbit-peephole โ€” Enables bbit peephole2 โœจ
  • -mno-brcc โ€” Disables a target-specific pass in arc_reorg that generates compare-and-branch ("brcc") instructions. It has no effect on generating these instructions when they're driven by the combiner pass ๐Ÿ™…โ€โ™€๏ธ
  • -mcase-vector-pcrel โ€” Uses PC-relative switch case tables to enable case table shortening. This is the default for -Os ๐Ÿง
  • -mcompact-casesi โ€” Enables the compact "casesi" pattern. This is the default for -Os, and it's only available for ARCv1 cores. > โš ๏ธ This option is deprecated ๐Ÿ’€
  • -mno-cond-exec โ€” Disables the ARCompact-specific pass that generates conditional execution instructions ๐Ÿšซ

okay so the ARC port has this special pass that's basically a glow-up for conditional execution ๐Ÿฆ‹. The normal target-independent pass is kinda lacking ๐Ÿ˜ญ because delay slot scheduling, operand numbers, literal sizes, instruction lengths, and conditional execution support are all tangled together. So the ARC folks made a pass that goes back in after register allocation, branch shortening, and delay slot scheduling are all done, and hunts for extra conditional execution chances โœจ. It usually improves performance and code size ๐Ÿ”ฅ, but not always, and the tradeoff is extra compile time, which is why there's an option to switch it off ๐Ÿ™ˆ. If your call instructions are going out of their allowable offset range because they got conditionalized, try -mmedium-calls instead ๐Ÿซถ.

  • -mearly-cbranchsi โ€” turns on pre-reload use of the cbranchsi pattern, so it kicks in early ๐ŸŒธ.
  • -mexpand-adddi โ€” expands adddi3 and subdi3 at RTL generation time into add.f, adc etc. ๐Ÿ’€ This one is deprecated, so don't build your whole personality around it.
  • -mindexed-loads โ€” enables indexed loads. Hmm, this one is kinda messy ๐Ÿ™ƒ because some optimizers assume indexed stores exist, and they don't.
โš ๏ธ -mindexed-loads can be problematic, bestie. Some optimizers assume indexed stores exist, which is not the case.
  • -mlra โ€” enables Local Register Allocation. It's still experimental for ARC ๐Ÿงช, so by default the compiler sticks with standard reload (-mno-lra).
  • -mlra-priority-none โ€” doesn't indicate any priority for target registers ๐Ÿซ .
  • -mlra-priority-compact โ€” indicates target register priority for r0..r3 / r12..r15 ๐Ÿ’œ.
  • -mlra-priority-noncompact โ€” reduces target register priority for r0..r3 / r12..r15 ๐Ÿ“.
  • -mmillicode โ€” when you're optimizing for size with -Os, prologues and epilogues that have to save or restore a ton of registers get shortened by calling a special libgcc function, which is called a millicode call โœจ. These calls can cause performance issues and/or linking issues if you link in a nonstandard way, so this option lets you turn millicode call generation on or off ๐ŸŽ€.
  • -mcode-density-frame โ€” lets the compiler emit enter and leave instructions ๐Ÿงš. These are only valid for CPUs with the code-density feature.
  • -mmixed-code โ€” does nothing ๐Ÿ™ˆ. It's just kept around for backward compatibility.
  • -mq-class โ€” deprecated ๐Ÿ’€. Enables q instruction alternatives, and this is the default for -Os.
  • -mRcq โ€” enables Rcq constraint handling ๐Ÿ‘‘. Most short code generation depends on this, and it's the default.
  • -mRcw โ€” enables Rcw constraint handling ๐Ÿ’–. Most ccfsm condexec depends on this, and it's the default.
  • -msize-level=level โ€” fine-tunes size optimization with regards to instruction lengths and alignment ๐Ÿฆ‹. The recognized values for level are:
    • 0 โ€” no size optimization. This level is deprecated and treated like 1.
    • 1 โ€” short instructions get used opportunistically.
    • 2 โ€” on top of that, alignment of loops and of code after barriers gets dropped.
    • 3 โ€” on top of that, optional data alignment gets dropped, and the option Os is enabled ๐Ÿ”ฅ.

This defaults to 3 when -Os is in effect. Otherwise, when this isn't set, the behavior is equivalent to level 1.

  • -mtune=cpu โ€” sets instruction scheduling parameters for cpu, overriding anything implied by -mcpu= ๐ŸŒˆ. The supported values for cpu are:
    • ARC600 โ€” tunes for the ARC600 CPU.
    • ARC601 โ€” tunes for the ARC601 CPU.
    • ARC700 โ€” tunes for the ARC700 CPU with the standard multiplier block.
    • ARC700-xmac โ€” tunes for the ARC700 CPU with the XMAC block.
    • ARC725D โ€” tunes for the ARC725D CPU.
    • ARC750D โ€” tunes for the ARC750D CPU.
  • -mmultcost=num โ€” sets the cost to assume for a multiply instruction, where 4 is equal to a normal instruction โญ.
  • -munalign-prob-threshold=probability โ€” does nothing ๐Ÿ™ƒ. It's only preserved for backward compatibility.

The following options are maintained for backward compatibility, but they're now deprecated and will be removed in a future release ๐Ÿ‘‹:

  • -margonaut โ€” obsolete FPX ๐Ÿฅ€.
  • -mbig-endian, -EB โ€” compiles code for big-endian targets. Using these is now deprecated ๐Ÿ’€. Big-endian code is supported by configuring GCC to build arceb-elf32 and arceb-linux-uclibc targets, and for those, big endian is the default.
  • -mlittle-endian, -EL โ€” compiles code for little-endian targets. Using these is now deprecated ๐Ÿ’€. Little-endian code is supported by configuring GCC to build arc-elf32 and arc-linux-uclibc targets, and for those, little endian is the default.
  • -mbarrel_shifter โ€” replaced by -mbarrel-shifter ๐Ÿ”.
  • -mdpfp_compact โ€” replaced by -mdpfp-compact ๐Ÿ”.
  • -mdpfp_fast โ€” replaced by -mdpfp-fast ๐Ÿ”.
  • -mdsp_packa โ€” replaced by -mdsp-packa ๐Ÿ”.
  • -mEA โ€” replaced by -mea ๐Ÿ”.
  • -mmac_24 โ€” replaced by -mmac-24 ๐Ÿ”.
  • -mmac_d16 โ€” replaced by -mmac-d16 ๐Ÿ”.
  • -mspfp_compact โ€” replaced by -mspfp-compact ๐Ÿ”.
  • -mspfp_fast โ€” replaced by -mspfp-fast ๐Ÿ”.
  • -mtune=cpu โ€” the values arc600, arc601, arc700 and arc700-xmac for cpu are replaced by ARC600, ARC601, ARC700 and ARC700-xmac respectively ๐Ÿ”.
  • -multcost=num โ€” replaced by -mmultcost ๐Ÿ”.

๐ŸŒˆ ARM Options

These -m options are defined for the ARM port ๐Ÿฆ‹:

  • -mabi=name โ€” generates code for the specified ABI. The permissible values are apcs-gnu, atpcs, aapcs, aapcs-linux and iwmmxt.
  • -mapcs-frame โ€” generates a stack frame that's compliant with the ARM Procedure Call Standard for all functions ๐Ÿ“œ, even if it isn't strictly necessary for the code to run correctly. Specifying -fomit-frame-pointer with this option means stack frames won't be generated for leaf functions. The default is -mno-apcs-frame. This option is deprecated ๐Ÿ’€.
  • -mapcs โ€” a synonym for -mapcs-frame, and it's deprecated too ๐Ÿ’€.
  • -mthumb-interwork โ€” generates code that supports calling between the ARM and Thumb instruction sets ๐Ÿค. Without this option, on pre-v5 architectures, the two instruction sets can't be reliably used inside one program. The default is -mno-thumb-interwork, since slightly larger code gets generated when -mthumb-interwork is specified. In AAPCS configurations this option is meaningless ๐Ÿ™ˆ.
  • -mno-sched-prolog โ€” stops the reordering of instructions in the function prologue, and also stops those instructions from being merged with the instructions in the function's body ๐Ÿงฑ. This means all functions start with a recognizable set of instructions (or one of a choice from a small set of different prologues), so you can use that info to find where functions start inside a chunk of executable code. The default is -msched-prolog.
  • -mfloat-abi=name โ€” picks which floating-point ABI to use ๐ŸŽ€. The permissible values are soft, softfp and hard.
    • soft makes GCC generate output containing library calls for floating-point operations.
    • softfp allows code using hardware floating-point instructions, but still uses the soft-float calling conventions.
    • hard allows floating-point instructions and uses FPU-specific calling conventions.

The default depends on the specific target configuration.

โš ๏ธ The hard-float and soft-float ABIs are not link-compatible, bestie. 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 select between the BE8 and BE32 formats โœจ. The option has no effect on little-endian images and is ignored there. The default depends on the selected target architecture: for ARMv6 and later it's BE8, and for older architectures it's BE32. BE32 has been deprecated by ARM ๐Ÿ’€.
โš ๏ธ BE32 format has been deprecated by ARM, so maybe go with BE8 if you can ๐Ÿซถ.
  • -march=name[+extension...] โ€” specifies the name of the target ARM architecture ๐Ÿš€. GCC uses this name to figure out what kind of instructions it can emit when generating assembly code. This option can be used together with the -mcpu= option 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.

On top of that, the following architectures, which don't support the Thumb execution state, are recognized but support for them is deprecated ๐Ÿ’€: armv4.

Lots of these architectures support extensions ๐Ÿงฉ. You can add them by appending +extension to the architecture name. Extension options are processed in order and their capabilities accumulate. An extension will also enable any base extensions it depends on. For example, the +crypto extension will always enable the +simd extension. The exception to the additive setup is extensions prefixed with +no...: these disable the specified option and any other extensions that depend on it being there ๐Ÿšซ.

For example, -march=armv7-a+simd+nofp+vfpv4 is equivalent to writing -march=armv7-a+vfpv4, since the +simd option is entirely disabled by the +nofp option that follows it ๐Ÿ™ƒ.

Most extension names are generic, but what they actually do depends on the architecture they're applied to ๐Ÿ‘‘. For example, the +simd option can be applied to both armv7-a and armv8-a architectures, but it'll enable the original ARMv7-A Advanced SIMD (Neon) extensions for armv7-a, and the ARMv8-A variant for armv8-a ๐Ÿ’….

The table below lists the supported extensions for each architecture ๐Ÿ“‹. Architectures that aren't mentioned don't support any extensions.

  • armv5te, armv6, armv6j, armv6k, armv6kz, armv6t2, armv6z, armv6zk ๐ŸŒธ these all share the same little extension menu below
    • +fp โ€” the VFPv2 floating-point instructions, which are giving main character energy ๐Ÿ’– +vfpv2 works as an alias for this one โœจ
    • +nofp โ€” turns the floating-point instructions off ๐Ÿ™…โ€โ™€๏ธ
  • armv7 ๐Ÿ‘‘ the common subset of the ARMv7-A, ARMv7-R and ARMv7-M architectures
    • +fp โ€” the VFPv3 floating-point instructions with 16 double-precision registers ๐Ÿ”ฅ +vfpv3-d16 is an alias for this one. Ngl, floating-point isn't supported by the base ARMv7-M architecture, but it does work with both ARMv7-A and ARMv7-R ๐Ÿ’…
    • +nofp โ€” turns the floating-point instructions off ๐Ÿ™…โ€โ™€๏ธ
  • armv7-a ๐Ÿฆ‹
    • +mp โ€” the multiprocessing extension ๐Ÿซถ
    • +sec โ€” the security extension ๐Ÿ”
    • +fp โ€” the VFPv3 floating-point instructions with 16 double-precision registers ๐Ÿ’œ +vfpv3-d16 is an alias for this one
    • +simd โ€” the Advanced SIMD (Neon) v1 plus the VFPv3 floating-point instructions ๐ŸŽ€ +neon and +neon-vfpv3 are aliases for this one
    • +vfpv3 โ€” the VFPv3 floating-point instructions with 32 double-precision registers ๐ŸŒˆ
    • +vfpv3-d16-fp16 โ€” the VFPv3 floating-point instructions with 16 double-precision registers, plus the half-precision floating-point conversion operations ๐Ÿ“
    • +vfpv3-fp16 โ€” the VFPv3 floating-point instructions with 32 double-precision registers, plus the half-precision floating-point conversion operations ๐Ÿ“
    • +vfpv4-d16 โ€” the VFPv4 floating-point instructions with 16 double-precision registers โœจ
    • +vfpv4 โ€” the VFPv4 floating-point instructions with 32 double-precision registers โœจ
    • +neon-fp16 โ€” the Advanced SIMD (Neon) v1 plus the VFPv3 floating-point instructions, with the half-precision floating-point conversion operations ๐Ÿงš
    • +neon-vfpv4 โ€” the Advanced SIMD (Neon) v2 plus the VFPv4 floating-point instructions ๐Ÿ”ฅ
    • +nosimd โ€” disables the Advanced SIMD instructions (this does not turn off floating point, so don't panic) ๐Ÿ™ˆ
    • +nofp โ€” disables the floating-point and Advanced SIMD instructions ๐Ÿ™…โ€โ™€๏ธ
  • armv7ve ๐Ÿ’– the extended version of the ARMv7-A architecture, with support for virtualization
    • +fp โ€” the VFPv4 floating-point instructions with 16 double-precision registers ๐ŸŒธ +vfpv4-d16 is an alias for this one
    • +simd โ€” the Advanced SIMD (Neon) v2 plus the VFPv4 floating-point instructions ๐ŸŽ€ +neon-vfpv4 is an alias for this one
    • +vfpv3-d16 โ€” the VFPv3 floating-point instructions with 16 double-precision registers ๐Ÿฆ‹
    • +vfpv3 โ€” the VFPv3 floating-point instructions with 32 double-precision registers ๐Ÿฆ‹
    • +vfpv3-d16-fp16 โ€” the VFPv3 floating-point instructions with 16 double-precision registers, plus the half-precision floating-point conversion operations ๐Ÿ“
    • +vfpv3-fp16 โ€” the VFPv3 floating-point instructions with 32 double-precision registers, plus the half-precision floating-point conversion operations ๐Ÿ“
    • +vfpv4-d16 โ€” the VFPv4 floating-point instructions with 16 double-precision registers โœจ
    • +vfpv4 โ€” the VFPv4 floating-point instructions with 32 double-precision registers โœจ
    • +neon โ€” the Advanced SIMD (Neon) v1 plus the VFPv3 floating-point instructions ๐Ÿ’… +neon-vfpv3 is an alias for this one
    • +neon-fp16 โ€” the Advanced SIMD (Neon) v1 plus the VFPv3 floating-point instructions, with the half-precision floating-point conversion operations ๐Ÿงš
    • +nosimd โ€” disables the Advanced SIMD instructions (floating point stays on) ๐Ÿ™ˆ
    • +nofp โ€” disables the floating-point and Advanced SIMD instructions ๐Ÿ™…โ€โ™€๏ธ
  • armv8-a ๐Ÿ”ฅ
    • +crc โ€” the Cyclic Redundancy Check (CRC) instructions โœจ
    • +simd โ€” the ARMv8-A Advanced SIMD and floating-point instructions ๐ŸŽ€
    • +crypto โ€” the cryptographic instructions ๐Ÿ”
    • +nocrypto โ€” disables the cryptographic instructions ๐Ÿ™…โ€โ™€๏ธ
    • +nofp โ€” disables the floating-point, Advanced SIMD and cryptographic instructions ๐Ÿ™…โ€โ™€๏ธ
    • +sb โ€” the Speculation Barrier Instruction ๐Ÿ›ก๏ธ
    • +predres โ€” the Execution and Data Prediction Restriction Instructions ๐Ÿ›ก๏ธ
  • armv8.1-a ๐ŸŒˆ
    • +simd โ€” the ARMv8.1-A Advanced SIMD and floating-point instructions ๐ŸŽ€
    • +crypto โ€” the cryptographic instructions ๐Ÿ” this one also turns on the Advanced SIMD and floating-point instructions, iykyk ๐Ÿ’–
    • +nocrypto โ€” disables the cryptographic instructions ๐Ÿ™…โ€โ™€๏ธ
    • +nofp โ€” disables the floating-point, Advanced SIMD and cryptographic instructions ๐Ÿ™…โ€โ™€๏ธ
    • +sb โ€” the Speculation Barrier Instruction ๐Ÿ›ก๏ธ
    • +predres โ€” the Execution and Data Prediction Restriction Instructions ๐Ÿ›ก๏ธ
  • armv8.2-a, armv8.3-a ๐Ÿฆ‹ both of these share the list below
    • +fp16 โ€” the half-precision floating-point data processing instructions ๐Ÿ“ this also enables the Advanced SIMD and floating-point instructions
    • +fp16fml โ€” the half-precision floating-point fmla extension ๐Ÿงš this also enables the half-precision floating-point extension, plus the Advanced SIMD and floating-point instructions
    • +simd โ€” the ARMv8.1-A Advanced SIMD and floating-point instructions ๐ŸŽ€
    • +crypto โ€” the cryptographic instructions ๐Ÿ” this also enables the Advanced SIMD and floating-point instructions
    • +dotprod โ€” enables the Dot Product extension ๐Ÿ’œ this also enables Advanced SIMD instructions
    • +nocrypto โ€” disables the cryptographic extension ๐Ÿ™…โ€โ™€๏ธ
    • +nofp โ€” disables the floating-point, Advanced SIMD and cryptographic instructions ๐Ÿ™…โ€โ™€๏ธ
    • +sb โ€” the Speculation Barrier Instruction ๐Ÿ›ก๏ธ
    • +predres โ€” the Execution and Data Prediction Restriction Instructions ๐Ÿ›ก๏ธ
    • +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
    • +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 โ€” 8-bit Integer Matrix Multiply instructions ๐Ÿงฎโœจ This also enables Advanced SIMD and floating-point instructions, so the whole glam package comes with it ๐Ÿ’…

+bf16 โ€” Brain half-precision floating-point instructions ๐Ÿง ๐ŸŒธ This also enables Advanced SIMD and floating-point instructions ๐Ÿซถ

armv7-r

  • +fp.sp โ€” the single-precision VFPv3 floating-point instructions ๐Ÿฆ‹ +vfpv3xd works as an alias for this one ๐Ÿ’…
  • +fp โ€” the VFPv3 floating-point instructions with 16 double-precision registers โœจ +vfpv3-d16 can be used as an alias for this one ๐ŸŽ€
  • +vfpv3xd-d16-fp16 โ€” the single-precision VFPv3 floating-point instructions with 16 double-precision registers, plus the half-precision floating-point conversion operations ๐ŸŒˆ
  • +vfpv3-d16-fp16 โ€” the VFPv3 floating-point instructions with 16 double-precision registers 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, based on the numbers given in the options in the range 0 to 7 ๐Ÿงš

armv8-m.main

  • +dsp โ€” the DSP instructions ๐ŸŽถ
  • +nodsp โ€” disables the DSP extension ๐Ÿ™…
  • +fp โ€” the single-precision floating-point instructions โœจ
  • +fp.dp โ€” the single- and double-precision floating-point instructions ๐Ÿ‘‘
  • +nofp โ€” disables the floating-point extension ๐Ÿšซ
  • +cdecp0, +cdecp1, ... , +cdecp7 โ€” enables the Custom Datapath Extension (CDE) on selected coprocessors, based on 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 ๐Ÿ’€

-march=native makes the compiler auto-detect the architecture of the build computer ๐Ÿ•ต๏ธโ€โ™€๏ธ Right now this only works on GNU/Linux, and not every architecture gets recognized. If the auto-detect doesn't work out, the option just has no effect ๐Ÿซ 

-mtune=name

This one tells GCC which target ARM processor to tune the performance of the code for ๐ŸŽฏ On some ARM implementations you can get better performance by using 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-m55, cortex-x1, cortex-m1.small-multiply, cortex-m0.small-multiply, cortex-m0plus.small-multiply, exynos-m1, marvell-pj4, neoverse-n1, neoverse-n2, neoverse-v1, xscale, iwmmxt, iwmmxt2, ep9312, fa526, fa626, fa606te, fa626te, fmp626, fa726te, xgene1.

It also works for big.LITTLE systems ๐Ÿค The names for those are: cortex-a15.cortex-a7, cortex-a17.cortex-a7, cortex-a57.cortex-a53, cortex-a72.cortex-a53, cortex-a72.cortex-a35, cortex-a73.cortex-a53, cortex-a75.cortex-a55, cortex-a76.cortex-a55.

-mtune=generic-arch tells GCC to tune for a blend of processors within the architecture arch ๐ŸŒˆ The goal is code that runs well on the most popular processors right now, balancing the CPUs that benefit from certain optimizations against avoiding the performance pitfalls of others. Heads up that this can change in future GCC versions as CPU models come and go ๐Ÿ”„

-mtune accepts the same extension options as -mcpu, but the extension options don't affect how the generated code gets tuned ๐Ÿ™ƒ

-mtune=native makes the compiler auto-detect the CPU of the build computer ๐Ÿ–ฅ๏ธ Same deal as before: right now it's only supported on GNU/Linux, not every architecture is recognized, and if the auto-detect fails the option has no effect ๐Ÿ’€

-mcpu=name[+extension...]

This specifies the name of the target ARM processor ๐Ÿ‘‘ GCC uses that name to figure out the target ARM architecture (as if you'd used -march) and the ARM processor type to tune for (as if you'd used -mtune). If you use this option together with -march or -mtune, those options take precedence over the matching part of this one ๐Ÿ’…

A lot of the supported CPUs have optional architectural extensions ๐Ÿงฉ Those extensions are usually enabled by default. If implementations without the extension exist, you can use the extension syntax to turn off the ones that have been left out ๐Ÿ™…โ€โ™€๏ธ For floating-point and Advanced SIMD (Neon) instructions, you also have to think about -mfloat-abi and -mfpu: floating-point and Advanced SIMD instructions only get used if -mfloat-abi isn't set to soft, and any -mfpu setting other than auto will override the available floating-point and SIMD extension instructions ๐ŸŽ€

For example, cortex-a9 shows up in three main configurations: integer only, with just a floating-point unit, or with floating-point and Advanced SIMD ๐Ÿซง By default all the instructions are enabled, but you can use +nosimd to disable just the SIMD instructions, or +nofp to disable both SIMD and floating-point instructions ๐Ÿซถ

The permissible names for this option are the same as the ones for -mtune ๐Ÿ“

These extension options are shared by the listed CPUs:

  • +nodsp โ€” disables the DSP instructions on cortex-m33 and cortex-m35p ๐Ÿ™…
  • +nofp โ€” disables the floating-point instructions on arm9e, arm946e-s, arm966e-s, arm968e-s, arm10e, arm1020e, arm1022e, arm926ej-s, arm1026ej-s, cortex-r5, cortex-r7, cortex-r8, cortex-m4, cortex-m7, cortex-m33 and cortex-m35p. On generic-armv7-a, cortex-a5, cortex-a7, cortex-a8, cortex-a9, cortex-a12, cortex-a15, cortex-a17, cortex-a15.cortex-a7, cortex-a17.cortex-a7, cortex-a32, cortex-a35, cortex-a53 and cortex-a55, it disables the floating-point and SIMD instructions ๐Ÿšซ
  • +nofp.dp โ€” disables the double-precision part of the floating-point instructions on cortex-r5, cortex-r7, cortex-r8, cortex-r52, cortex-r52plus and cortex-m7 ๐Ÿ’”
  • +nosimd โ€” disables the SIMD instructions (but not floating-point) on generic-armv7-a, cortex-a5, cortex-a7 and cortex-a9 ๐ŸŽถ
  • +crypto โ€” enables the cryptographic instructions on cortex-a32, cortex-a35, cortex-a53, cortex-a55, cortex-a57, cortex-a72, cortex-a73, cortex-a75, exynos-m1, xgene1, cortex-a57.cortex-a53, cortex-a72.cortex-a53, cortex-a73.cortex-a35, cortex-a73.cortex-a53 and cortex-a75.cortex-a55 ๐Ÿ”

On top of that, the generic-armv7-a pseudo target defaults to VFPv3 with 16 double-precision registers ๐Ÿงš It supports these extension options: mp, sec, vfpv3-d16, vfpv3, vfpv3-d16-fp16, vfpv3-fp16, vfpv4-d16, vfpv4, neon, neon-vfpv3, neon-fp16, neon-vfpv4. The meanings are the same as for the extensions to -march=armv7-a ๐Ÿ’–

-mcpu=generic-arch is allowed too, and it's the same as -march=arch -mtune=generic-arch. Check out -mtune for more info ๐ŸŒธ

-mcpu=native makes the compiler auto-detect the CPU of the build computer ๐Ÿค– Right now that only works on GNU/Linux, not every architecture is recognized, and if the auto-detect doesn't work 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. Fun fact: neon is just an alias for neon-vfpv3, and vfp is an alias for vfpv2 ๐Ÿฆ‹

The auto setting is the default and it's lowkey special ๐Ÿ’… It tells the compiler to pick the floating-point and Advanced SIMD instructions based on your -mcpu and -march settings โœจ

If your floating-point hardware includes the NEON extension (like -mfpu=neon), bestie, pay attention ๐Ÿ™ˆ GCC's auto-vectorization pass won't generate floating-point operations unless you also add -funsafe-math-optimizations. NEON hardware doesn't fully implement IEEE 754 for floating-point arithmetic (denormal values get treated as zero), so using NEON instructions can cost you precision ๐Ÿ˜ญ

Heads up: NEON can lose precision, so -funsafe-math-optimizations is needed before auto-vectorization generates floating-point operations on NEON hardware.

You can also set the fpu name at function level with the target("fpu=") function attributes or pragmas ๐ŸŽ€

  • -mfp16-format=name โ€” Picks the format of the __fp16 half-precision floating-point type ๐ŸŒธ The valid names are none, ieee and alternative. The default is none, which means __fp16 isn't defined at all.
  • -mstructure-size-boundary=n โ€” Every struct and union gets rounded up to a multiple of n bits ๐Ÿ“ The valid values are 8, 32 and 64. The default depends on your toolchain (the COFF toolchain defaults to 8), and 64 is only allowed if the underlying ABI supports it. Bigger numbers can make code faster and more efficient, but the program can also get bigger ๐Ÿ“ˆ Different values are potentially incompatible, so code built with one value might not play nice with code or libraries built with another if they swap info through structs or unions ๐Ÿ’€
This option is deprecated ๐Ÿšซ
  • -mabort-on-noreturn โ€” At the end of a noreturn function, GCC generates a call to the function abort. It runs if the function tries to return ๐Ÿ›‘
  • -mlong-calls, -mno-long-calls โ€” Tells the compiler to load the function's address into a register first, then make the subroutine call through that register ๐Ÿงญ You need this if the target function is outside the 64-megabyte addressing range of the offset-based subroutine call instruction. Even with this on, not every call turns into a long call. Static functions, functions with the short_call attribute, functions inside a #pragma no_long_calls scope, and functions already compiled within the current compilation unit stay as normal calls ๐Ÿ™Œ The exceptions are weak function definitions, functions with the long_call or section attribute, and functions inside a #pragma long_calls scope, which are always long calls ๐Ÿ’œ This feature isn't enabled by default. -mno-long-calls restores the default behavior, as does putting function calls inside a #pragma long_calls_off scope. These switches have no effect on how calls through function pointers are generated.
  • -msingle-pic-base โ€” Treats the register used for PIC addressing as read-only, instead of loading it in the prologue for each function ๐Ÿ”’ The runtime system is responsible for setting this register to an appropriate value before execution begins.
  • -mpic-register=reg โ€” Picks the register used for PIC addressing ๐ŸŽฏ For the standard PIC base case, the default is any suitable register the compiler chooses. For the single PIC base case, the default is R9 if the target is EABI based or stack-checking is enabled, otherwise it's R10.
  • -mpic-data-is-text-relative โ€” Assumes the displacement between the text and data segments is fixed at static link time ๐Ÿฆ‹ That lets PC-relative addressing access data known to be in the data segment. For non-VxWorks RTP targets, this is enabled by default. When it's disabled on those targets, -msingle-pic-base gets enabled by default.
  • -mpoke-function-name โ€” Writes the name of each function into the text section, right before the function prologue ๐Ÿงš The generated code looks like this:
t0
    .ascii "arm_poke_function_name", 0
    .align
t1
    .word 0xff000000 + (t1 - t0)
arm_poke_function_name
    mov     ip, sp
    stmfd   sp!, {fp, ip, lr, pc}
    sub     fp, ip, #4

When doing a stack backtrace, code can inspect the value of pc stored at fp + 0. If the trace function then looks at location pc - 12 and the top 8 bits are set, we know there's a function name embedded right before this location, and its length is ((pc[-3]) & 0xff000000) โœจ

  • -mthumb, -marm โ€” Pick between generating code that runs in ARM state or Thumb state ๐ŸŒˆ Most configurations default to ARM state, but you can change that by configuring GCC with the --with-mode=state configure option. You can also override ARM and Thumb mode for each function with the target("thumb") and target("arm") function attributes or pragmas ๐Ÿ’–
  • -mflip-thumb โ€” Switches ARM/Thumb modes on alternating functions ๐Ÿ”€ It's there for regression testing of mixed Thumb/ARM code generation and is NOT intended for ordinary use when compiling code.
  • -mtpcs-frame โ€” Generates a stack frame that's compliant with the Thumb Procedure Call Standard for all non-leaf functions. (A leaf function is one that doesn't call any other functions ๐ŸŒฟ) The default is -mno-tpcs-frame.
  • -mtpcs-leaf-frame โ€” Generates a stack frame that's compliant with the Thumb Procedure Call Standard for all leaf functions. (Again, a leaf function is one that doesn't call any other functions ๐Ÿƒ) The default is -mno-apcs-leaf-frame.
  • -mcallee-super-interworking โ€” Gives all externally visible functions in the file being compiled an ARM instruction set header that switches to Thumb mode before running the rest of the function ๐Ÿช„ That lets these functions get called from non-interworking code. This option isn't valid in AAPCS configurations, because interworking is enabled by default there.
  • -mcaller-super-interworking โ€” Lets calls via function pointers (including virtual functions) execute correctly whether or not the target code was compiled for interworking ๐Ÿค There's a small overhead when executing a function pointer with this enabled. This option isn't valid in AAPCS configurations either, since interworking is enabled by default.
  • -mtp=name โ€” Specifies the access model for the thread local storage pointer ๐Ÿงต The valid models are soft, which generates calls to __aeabi_read_tp; cp15, which fetches the thread pointer from cp15 directly (supported in the arm6k architecture); and auto, which uses the best available method for the selected processor. The default is auto.
  • -mtls-dialect=dialect โ€” Picks the dialect for accessing thread local storage ๐ŸŽ€ Two dialects are supported: gnu and gnu2. The gnu dialect selects the original GNU scheme for local and global dynamic TLS models. The gnu2 dialect selects the GNU descriptor scheme, which gives better performance for shared libraries ๐Ÿš€ The descriptor scheme is compatible with the original one, but it needs new assembler, linker and library support. Initial and local exec TLS models aren't affected by this option and always use the original scheme.
  • -mword-relocations โ€” Only generates absolute relocations on word-sized values (i.e. R_ARM_ABS32) ๐Ÿ”— This is enabled by default on targets (uClinux, SymbianOS) where the runtime loader imposes this restriction, and when -fpic or -fPIC is specified. This option conflicts with -mslow-flash-data.
  • -mfix-cortex-m3-ldrd โ€” Some Cortex-M3 cores can cause data corruption when ldrd instructions with overlapping destination and base registers are used ๐Ÿ˜ฑ This option avoids generating those instructions. It's enabled by default when -mcpu=cortex-m3 is specified.
  • -mfix-cortex-a57-aes-1742098, -mno-fix-cortex-a57-aes-1742098, -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 16- and 32-bit values from addresses that aren't 16- or 32-bit aligned ๐Ÿงฉ By default, unaligned access is disabled for all pre-ARMv6, all ARMv6-M and ARMv8-M Baseline architectures, and enabled for all other architectures. If it isn't enabled, words in packed data structures are accessed one byte at a time. The ARM attribute Tag_CPU_unaligned_access is set in the generated object file to either true or false, depending on this option's setting ๐Ÿท๏ธ If unaligned access is enabled, the preprocessor symbol __ARM_FEATURE_UNALIGNED is also defined.
  • -mneon-for-64bits โ€” 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 is using unified asm syntax ๐Ÿ“ The default is currently off, which implies divided syntax. This option has no impact on Thumb2, but that may change in future releases of GCC.
Divided syntax should be considered deprecated ๐Ÿ™ˆ
  • -mrestrict-it โ€” Restricts generation of IT blocks so they conform to the rules of ARMv8-A ๐Ÿ”’ IT blocks can only contain a single 16-bit instruction from a select set of instructions. This option is on by default for ARMv8-A Thumb mode.
  • -mprint-tune-info โ€” okay bestie, this one drops the CPU tuning info as a comment in the assembler file ๐Ÿ’… It's only for regression testing the compiler, so it's NOT something you need for everyday code ๐Ÿ™ˆ It's off by default โœจ
  • -mverbose-cost-dump โ€” turns on verbose cost model dumping in the debug dump files ๐Ÿ” It's there for debugging the compiler itself, so it's giving compiler-nerd energy ๐Ÿค“
  • -mpure-code โ€” no constant data gets stuffed into code sections ๐Ÿšซ Also, when you're compiling for ELF object format, every text section gets 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 following the "ARMv8-M Security Extensions: Requirements on Development Tools Engineering Specification" ๐Ÿ” You can find that spec at https://developer.arm.com/documentation/ecm0359818/latest/ ๐Ÿฆ‹
  • -mfix-cmse-cve-2021-35465 โ€” mitigates a potential security issue with the "VLLDM" instruction on some M-profile devices when you're using CMSE (CVE-2021-365465) ๐Ÿ›ก๏ธ This one is enabled by default when -mcpu= is used with "cortex-m33", "cortex-m35p" or "cortex-m55". Want to turn the mitigation off? Use -mno-fix-cmse-cve-2021-35465 ๐Ÿ™…โ€โ™€๏ธ
  • -mstack-protector-guard=guard, -mstack-protector-guard-offset=offset โ€” generates stack protection code using a canary at guard ๐Ÿ›ก๏ธ The supported locations are global for a global canary, or tls for a canary accessible via the TLS register ๐Ÿงต The -mstack-protector-guard-offset= option is for use with -fstack-protector-guard=tls and NOT for user-land code ๐Ÿšซ
  • -mfdpic, -mno-fdpic โ€” picks the FDPIC ABI, which uses 64-bit function descriptors to represent pointers to functions ๐ŸŽ€ When the compiler is configured for arm-*-uclinuxfdpiceabi targets, this is on by default and implies -fPIE if none of the PIC/PIE-related options is provided. On other targets it only turns on the FDPIC-specific code generation features, so you should explicitly pass the PIC/PIE-related options as needed ๐Ÿง 

Static linking isn't supported, ngl, because it would still involve the dynamic linker when the program self-relocates ๐Ÿ™ƒ If that behavior is acceptable, use -static and -Wl,-dynamic-linker options.

The opposite -mno-fdpic option is useful (and required) for building the Linux kernel with the same (arm-*-uclinuxfdpiceabi) toolchain you use for userland programs ๐Ÿง

โœจ AVR Options โœจ

These options are defined for AVR implementations: ๐Ÿ’ซ

  • -mmcu=mcu โ€” specifies the Atmel AVR instruction set architecture (ISA) or MCU type ๐Ÿ‘‘

The default for this option is avr2 ๐ŸŒธ

GCC supports the following AVR devices and ISAs ๐Ÿงš

  • avr2 โ€” "Classic" devices with up to 8 KiB of program memory. mcu = attiny22, attiny26, at90s2313, at90s2323, at90s2333, at90s2343, at90s4414, at90s4433, at90s4434, at90c8534, at90s8515, at90s8535 ๐Ÿ“
  • avr25 โ€” "Classic" devices with up to 8 KiB of program memory and 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 the "MOVW" instruction. mcu = attiny167, attiny1634, atmega8u2, atmega16u2, atmega32u2, ata5505, ata6617c, ata664251, at90usb82, at90usb162 ๐ŸŒˆ
  • avr4 โ€” "Enhanced" devices with up to 8 KiB of program memory. mcu = atmega48, atmega48a, atmega48p, atmega48pa, atmega48pb, atmega8, atmega8a, atmega8hva, atmega88, atmega88a, atmega88p, atmega88pa, atmega88pb, atmega8515, atmega8535, ata6285, ata6286, ata6289, ata6612c, at90pwm1, at90pwm2, at90pwm2b, at90pwm3, at90pwm3b, at90pwm81 โญ
  • avr5 โ€” "Enhanced" devices with 16 KiB up to 64 KiB of program memory. mcu = atmega16, atmega16a, atmega16hva, atmega16hva2, atmega16hvb, atmega16hvbrevb, atmega16m1, atmega16u4, atmega161, atmega162, atmega163, atmega164a, atmega164p, atmega164pa, atmega165, atmega165a, atmega165p, atmega165pa, atmega168, atmega168a, atmega168p, atmega168pa, atmega168pb, atmega169, atmega169a, atmega169p, atmega169pa, atmega32, atmega32a, atmega32c1, atmega32hvb, atmega32hvbrevb, atmega32m1, atmega32u4, atmega32u6, atmega323, atmega324a, atmega324p, atmega324pa, atmega324pb, atmega325, atmega325a, atmega325p, atmega325pa, atmega328, atmega328p, atmega328pb, atmega329, atmega329a, atmega329p, atmega329pa, atmega3250, atmega3250a, atmega3250p, atmega3250pa, atmega3290, atmega3290a, atmega3290p, atmega3290pa, atmega406, atmega64, atmega64a, atmega64c1, atmega64hve, atmega64hve2, atmega64m1, atmega64rfr2, atmega640, atmega644, atmega644a, atmega644p, atmega644pa, atmega644rfr2, atmega645, atmega645a, atmega645p, atmega649, atmega649a, atmega649p, atmega6450, atmega6450a, atmega6450p, atmega6490, atmega6490a, atmega6490p, ata5795, ata5790, ata5790n, ata5791, ata6613c, ata6614q, ata5782, ata5831, ata8210, ata8510, ata5702m322, at90pwm161, at90pwm216, at90pwm316, at90can32, at90can64, at90scr100, at90usb646, at90usb647, at94k, m3000 ๐ŸŽ€
  • avr51 โ€” "Enhanced" devices with 128 KiB of program memory. mcu = atmega128, atmega128a, atmega128rfa1, atmega128rfr2, atmega1280, atmega1281, atmega1284, atmega1284p, atmega1284rfr2, at90can128, at90usb1286, at90usb1287 ๐Ÿง 
  • avr6 โ€” "Enhanced" devices with a 3-byte PC, i.e. with more than 128 KiB of program memory. mcu = atmega256rfr2, atmega2560, atmega2561, atmega2564rfr2 ๐Ÿš€
  • avrxmega2 โ€” "XMEGA" devices with more than 8 KiB and up to 64 KiB of program memory. mcu = atxmega8e5, atxmega16a4, atxmega16a4u, atxmega16c4, atxmega16d4, atxmega16e5, atxmega32a4, atxmega32a4u, atxmega32c3, atxmega32c4, atxmega32d3, atxmega32d4, atxmega32e5 ๐Ÿ’–
  • avrxmega3 โ€” "XMEGA" devices with up to 64 KiB of combined program memory and RAM, and with program memory visible in the RAM address space. mcu = attiny202, attiny204, attiny212, attiny214, attiny402, attiny404, attiny406, attiny412, attiny414, attiny416, attiny417, attiny804, attiny806, attiny807, attiny814, attiny816, attiny817, attiny1604, attiny1606, attiny1607, attiny1614, attiny1616, attiny1617, attiny3214, attiny3216, attiny3217, atmega808, atmega809, atmega1608, atmega1609, atmega3208, atmega3209, atmega4808, atmega4809 ๐ŸŒธ
  • avrxmega4 โ€” "XMEGA" devices with more than 64 KiB and up to 128 KiB of program memory. mcu = atxmega64a3, atxmega64a3u, atxmega64a4u, atxmega64b1, atxmega64b3, atxmega64c3, atxmega64d3, atxmega64d4 ๐Ÿซถ
  • avrxmega5 โ€” "XMEGA" devices with more than 64 KiB and up to 128 KiB of program memory and more than 64 KiB of RAM. mcu = atxmega64a1, atxmega64a1u ๐Ÿ“
  • avrxmega6 โ€” "XMEGA" devices with more than 128 KiB of program memory. mcu = atxmega128a3, atxmega128a3u, atxmega128b1, atxmega128b3, atxmega128c3, atxmega128d3, atxmega128d4, atxmega192a3, atxmega192a3u, atxmega192c3, atxmega192d3, atxmega256a3, atxmega256a3b, atxmega256a3bu, atxmega256a3u, atxmega256c3, atxmega256d3, atxmega384c3, atxmega384d3 ๐Ÿ‘‘
  • avrxmega7 โ€” "XMEGA" devices with more than 128 KiB of program memory and more than 64 KiB of RAM. mcu = atxmega128a1, atxmega128a1u, atxmega128a4u ๐ŸŒˆ
  • avrtiny โ€” "TINY" Tiny core devices with 512 B up to 4 KiB of program memory. mcu = attiny4, attiny5, attiny9, attiny10, attiny20, attiny40 ๐Ÿงš
  • avr1 โ€” this ISA is implemented by the minimal AVR core and is supported for the assembler only. mcu = attiny11, attiny12, attiny15, attiny28, at90s1200 ๐Ÿ™ˆ
  • -mabsdata โ€” assumes all data in static storage can be accessed by LDS / STS instructions ๐ŸŽฏ This option only has an effect on reduced Tiny devices like ATtiny40. See also the "absdata" AVR Variable Attributes,variable attribute ๐Ÿ’…
  • -maccumulate-args โ€” accumulates outgoing function arguments and acquires/releases the needed stack space for them once, in the function prologue/epilogue โœจ Without this option, outgoing arguments are pushed before calling a function and popped afterwards ๐Ÿ“ฆ

Popping the arguments after the function call can be expensive on AVR, so accumulating the stack space might lead to smaller executables, because arguments don't need to be removed from the stack after each call ๐Ÿงน

This option can lead to reduced code size for functions that make several calls to functions that get their arguments on the stack, like calls to printf-like functions ๐ŸŒŸ

  • -mbranch-cost=cost โ€” sets the branch costs for conditional branch instructions to cost ๐Ÿ’œ Reasonable values for cost are small, non-negative integers. The default branch cost is 0 ๐Ÿซถ
  • -mcall-prologues โ€” function prologues/epilogues get expanded as calls to appropriate subroutines, so the code size is smaller ๐Ÿฆ‹
  • -mdouble=bits, -mlong-double=bits โ€” okay so these two let you set the size (in bits) of the "double" and "long double" types, respectively ๐Ÿ’– The only values for bits are 32 and 64 ๐ŸŽ€. Whether a value is allowed depends on the --with-double= and --with-long-double= configure options (https://gcc.gnu.org/install/configure.html#avr) ๐ŸŒธ, and the default values follow the same rule ๐Ÿซถ.
  • -mgas-isr-prologues โ€” ISRs (interrupt service routines) can use the __gcc_isr pseudo instruction that GNU Binutils supports โœจ If this option is on, you can still turn the feature off for individual ISRs with the "no_gccisr" function attribute (see AVR Function Attributes) ๐Ÿฆ‹ It's turned on by default when optimization is on, but not with -Og (see Optimize Options), and only if GNU Binutils supports PR21683 (https://sourceware.org/PR21683) ๐Ÿ’…
  • -mint8 โ€” this one makes "int" an 8-bit integer ๐Ÿ“ It changes the size of all the types: a "char" is 1 byte, an "int" is 1 byte, a "long" is 2 bytes, and a "long long" is 4 bytes ๐Ÿ˜ญ Please note that this does not conform to the C standards ๐Ÿ’€ but the upside is smaller code size ๐ŸŒˆ
  • -mmain-is-OS_task โ€” don't save registers in "main" ๐Ÿ”ฅ It does the same thing as slapping the AVR Function Attributes "OS_task" attribute onto "main" ๐Ÿ‘‘ This is turned on by default when optimization is on โญ
  • -mn-flash=num โ€” tells the compiler to assume the flash memory is num times 64 KiB big ๐Ÿงš
  • -mno-interrupts โ€” the generated code is not compatible with hardware interrupts ๐Ÿ™ˆ The payoff is that the code size comes out smaller ๐Ÿซง
  • -mrelax โ€” this tries to swap a CALL (or JMP) for the shorter RCALL (or RJMP) whenever that's possible โœจ 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, since jump offsets aren't known until the code is located ๐Ÿง  So the assembler code the compiler generates is the same, but the instructions in the executable might look different from what's in the assembler code ๐Ÿ‘€

Relaxing must be turned on if linker stubs are needed. Check out the section on "EIND" and linker stubs below ๐Ÿ’€
  • -mrmw โ€” assume the device supports the Read-Modify-Write instructions XCH, LAC, LAS and LAT ๐Ÿ’œ
  • -mshort-calls โ€” assume that RJMP and RCALL can reach the whole program memory ๐ŸŒธ

This one is used internally for multilib selection ๐Ÿซถ It's not an optimization option, so you don't need to set it by hand, bestie ๐Ÿ™…

  • -msp8 โ€” treat the stack pointer register as an 8-bit register, which means assuming the high byte of the stack pointer is zero ๐Ÿ’… Generally you don't need to set this by hand โœจ

This option is used internally by the compiler to select and build multilibs for the avr2 and avr25 architectures ๐Ÿงฉ These architectures mix devices with and without SPH ๐ŸŒˆ For any setting other than -mmcu=avr2 or -mmcu=avr25, the compiler driver adds or removes this option from the compiler proper's command line ๐ŸŽ€ That's because the compiler then knows whether the device or architecture has an 8-bit stack pointer (and therefore no SPH register) or not ๐Ÿ’–

  • -mstrict-X โ€” use the address register X the way the hardware intends ๐Ÿฆ‹ That means X is only used for indirect, post-increment, or pre-decrement addressing ๐Ÿ’…

Without this option, the X register can be used the same way as Y or Z, but that 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 gets done like this:

adiw r26, const   ; X += const
ld   <Rn>, X        ; <Rn> = *X
sbiw r26, const   ; X -= const
  • -mtiny-stack โ€” only change the lower 8 bits of the stack pointer ๐ŸŒท
  • -mfract-convert-truncate โ€” allow truncation instead of rounding towards zero for fractional fixed-point types ๐Ÿ“
  • -nodevicelib โ€” don't link against AVR-LibC's device specific library lib<mcu>.a ๐Ÿ™…
  • -nodevicespecs โ€” don't add -specs=device-specs/specs-mcu to the compiler driver's command line ๐ŸŽ€ You're taking full responsibility for the subprocesses (compiler proper, assembler and linker) and their appropriate command line options ๐Ÿ˜ค That means you have to supply your own private device specs file with -specs=path-to-specs-file ๐Ÿง And there's no more need for -mmcu=mcu ๐Ÿซถ

This option can also replace the older way of specifying custom device-specs files. That old way needed -B some-path to point to a directory containing a folder named "device-specs", and that folder had to contain a specs file named "specs-mcu", where mcu was the value given with -mmcu=mcu ๐Ÿ•ฐ๏ธ

  • -Waddr-space-convert โ€” warn about conversions between address spaces when the resulting address space is not contained in the incoming address space โš ๏ธ
  • -Wmisspelled-isr โ€” warn if the ISR is misspelled, meaning it's missing 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 program memory, there's a special function register called "EIND" ๐Ÿ‘‘ It serves 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 it might read EIND directly in order to emulate an indirect call/jump by means of a RET instruction.
  • The compiler assumes that EIND never changes during the startup code or during the application. In particular, EIND is not saved/restored in function or interrupt service routine prologue/epilogue.
  • For indirect calls to functions and computed goto, the linker generates stubs ๐Ÿงธ Stubs are jump pads, sometimes also called trampolines. So the indirect call/jump jumps to such a stub, and the stub contains a direct jump to the desired address.
  • Linker relaxation must be turned on so that the linker generates the stubs correctly in all situations. See the compiler option -mrelax and the linker option --relax. There are corner cases where the linker is supposed to generate stubs but aborts without relaxation and without a helpful error message ๐Ÿ˜ฑ
  • The default linker script is arranged for code with EIND = 0. If code is supposed to work for a setup with EIND != 0, you have to use a custom linker script to place the sections whose name starts with .trampolines into the segment where EIND points to ๐Ÿ—บ๏ธ
  • The startup code from libgcc never sets EIND. Notice that startup code is a blend of code from libgcc and AVR-LibC. For the impact of AVR-LibC on EIND, see the AVR-LibC user manual (http://nongnu.org/avr-libc/user-manual/) ๐Ÿ“–
  • It's legit for user-specific startup code to set up EIND early, for example with initialization code located in section .init3 ๐ŸŒŸ That code runs before the general startup code that initializes RAM and calls constructors, but after the bit of AVR-LibC startup code that sets EIND to the segment where the vector table is located ๐Ÿ’…
#include <avr/io.h>

static void
__attribute__((section(".init3"),naked,used,no_instrument_function))
init3_set_eind (void)
{
  __asm volatile ("ldi r24,pm_hh8(__trampolines_start)\n\t"
                  "out %i0,r24" :: "n" (&EIND) : "r24","memory");
}

The __trampolines_start symbol is defined in the linker script ๐Ÿง

  • Stubs are generated automatically by the linker if the following two conditions are met:
    • The address of a label is taken by means of the gs modifier (short for generate stubs), like so:
LDI r24, lo8(gs(<func>))
LDI r25, hi8(gs(<func>))
  • The final location of that label is in a code segment outside the segment where the stubs are located.
  • The compiler emits such gs modifiers for code labels in the following situations:
    • Taking the address of a function or code label.
    • Computed goto.
    • If the prologue-save function is used, see the -mcall-prologues command-line option.
    • Switch/case dispatch tables. If you do not want such dispatch tables, you can specify the -fno-jump-tables command-line option.
    • C and C++ constructors/destructors called during startup/shutdown.
    • If the tools hit a gs() modifier explained above.
  • Jumping to non-symbolic addresses like this is not supported ๐Ÿšซ
int main (void)
{
    /* Call function at word address 0x2 */
    return ((int(*)(void)) 0x2)();
}

Instead, a stub has to be set up, i.e. the function has to be called through a symbol ("func_4" in the example) ๐ŸŽ€

int main (void)
{
    extern int func_4 (void);

    /* Call function at byte address 0x4 */
    return func_4();
}

and the application has to be linked with -Wl,--defsym,func_4=0x4. Alternatively, func_4 can be defined in the linker script ๐Ÿฆ‹


โœจ Handling of the "RAMPD", "RAMPX", "RAMPY" and "RAMPZ" Special Function Registers โœจ

Some AVR devices support memories larger than the 64 KiB range that can be accessed with 16-bit pointers ๐Ÿง  To reach memory locations outside that 64 KiB range, the content of a "RAMP" register is used as the high part of the address ๐ŸŒ The "X", "Y" and "Z" address registers are concatenated with the "RAMPX", "RAMPY" and "RAMPZ" special function registers, respectively, to get a wide address ๐Ÿ’œ Similarly, "RAMPD" is used together with direct addressing โœจ

  • The startup code initializes the "RAMP" special function registers with zero ๐ŸŒธ
  • If a named address space (see AVR Named Address Spaces) other than generic or __flash is used, then RAMPZ is set as needed before the operation ๐Ÿซถ
  • ๐Ÿ’… If the device supports RAM larger than 64 KiB and the compiler needs to change "RAMPZ" to get an operation done, "RAMPZ" gets reset to zero afterwards. โœจ
  • If the device comes with a specific "RAMP" register, the ISR prologue/epilogue saves and restores that SFR and sets it to zero in case the ISR code might (implicitly) use it. ๐Ÿซถ
๐Ÿ˜ญ Warning, bestie: RAM larger than 64 KiB is not supported by GCC for AVR targets. If you use inline assembler to read from locations outside the 16-bit address range and change one of the "RAMP" registers, you must reset it to zero after the access. Don't skip this part or it's giving chaos. ๐Ÿ’€

โœจ AVR Built-in Macros โœจ

GCC defines several built-in macros so your code can check whether a feature is there or not. ๐Ÿ” Almost any of the following built-in macros are deduced from device capabilities, so they get triggered by the -mmcu= command-line option. ๐ŸŒธ

For even more AVR-specific built-in macros, check out AVR Named Address Spaces and AVR Built-in Functions. ๐Ÿงš

  • "__AVR_ARCH__" โ€” This is a built-in macro that resolves to a decimal number identifying the architecture. It depends on the -mmcu=mcu option. The possible values are:
    • 2, 25, 3, 31, 35, 4, 5, 51, 6 for mcu="avr2", "avr25", "avr3", "avr31", "avr35", "avr4", "avr5", "avr51", "avr6", respectively.
    • 100, 102, 103, 104, 105, 106, 107 for mcu="avrtiny", "avrxmega2", "avrxmega3", "avrxmega4", "avrxmega5", "avrxmega6", "avrxmega7", respectively.

If mcu specifies a device, this 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__", etc. ๐Ÿฆ‹

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 is not an actual 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 the macro is defined to "atmega8". ๐Ÿ“

If device is not a device but only a core architecture like avr51, this macro is not defined.

  • "__AVR_XMEGA__" โ€” The device or architecture belongs to the XMEGA family of devices. ๐ŸŒˆ
  • "__AVR_HAVE_ELPM__" โ€” The device has the "ELPM" instruction. ๐Ÿ”ฅ
  • "__AVR_HAVE_ELPMX__" โ€” The device has the "ELPM Rn,Z" and "ELPM Rn,Z+" instructions. ๐Ÿ’œ
  • "__AVR_HAVE_MOVW__" โ€” The device has the "MOVW" instruction, which does 16-bit register-to-register moves. โญ
  • "__AVR_HAVE_LPMX__" โ€” The device has the "LPM Rn,Z" and "LPM Rn,Z+" instructions. ๐ŸŽ€
  • "__AVR_HAVE_MUL__" โ€” The device has a hardware multiplier. ๐Ÿ’…
  • "__AVR_HAVE_JMP_CALL__" โ€” The device has the "JMP" and "CALL" instructions. This is the case for devices with more than 8 KiB of program memory. ๐Ÿฆ‹
  • "__AVR_HAVE_EIJMP_EICALL__" and "__AVR_3_BYTE_PC__" โ€” The device has the "EIJMP" and "EICALL" instructions. This is the case for devices with more than 128 KiB of program memory. It also means the program counter (PC) is 3 bytes wide. ๐Ÿงš
  • "__AVR_2_BYTE_PC__" โ€” The program counter (PC) is 2 bytes wide. This is the case for devices with up to 128 KiB of program memory. ๐ŸŒธ
  • "__AVR_HAVE_8BIT_SP__" and "__AVR_HAVE_16BIT_SP__" โ€” The compiler treats the stack pointer (SP) register as an 8-bit or 16-bit register, respectively. The definition of these macros is affected by -mtiny-stack. ๐Ÿซถ
  • "__AVR_HAVE_SPH__" and "__AVR_SP8__" โ€” The device has the SPH (high part of stack pointer) special function register, or has an 8-bit stack pointer, respectively. The definition of these macros is affected by -mmcu=, and in the cases of -mmcu=avr2 and -mmcu=avr25 also by -msp8. โœจ
  • "__AVR_HAVE_RAMPD__", "__AVR_HAVE_RAMPX__", "__AVR_HAVE_RAMPY__" and "__AVR_HAVE_RAMPZ__" โ€” The device has the "RAMPD", "RAMPX", "RAMPY" 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. ๐Ÿ’€
  • "__AVR_ISA_RMW__" โ€” The device has Read-Modify-Write instructions (XCH, LAC, LAS and LAT). ๐Ÿ‘‘
  • "__AVR_SFR_OFFSET__=offset" โ€” Instructions that can address I/O special function registers directly, like "IN", "OUT", "SBI", etc., may use a different address than an instruction accessing RAM, like "LD" or "STS". This offset depends on the device architecture and has to be subtracted from the RAM address to get the respective I/O address. ๐Ÿ“
  • "__AVR_SHORT_CALLS__" โ€” The -mshort-calls command-line option is set. ๐Ÿ”ฅ
  • "__AVR_PM_BASE_ADDRESS__=addr" โ€” Some devices support reading from flash memory with "LD*" instructions. The flash memory is seen in the data address space at an offset of "__AVR_PM_BASE_ADDRESS__". If this macro is not defined, this feature is not available. If it is defined, the address space is linear and there is no need to put ".rodata" into RAM. This is handled by the default linker description file and is currently available for "avrtiny" and "avrxmega3". Even more convenient, there is no need to use address spaces like "__flash" or features like the attribute "progmem" and "pgm_read_*". ๐Ÿฆ‹
  • "__WITH_AVRLIBC__" โ€” The compiler is configured to be used together with AVR-Libc. See the --with-avrlibc configure option. ๐Ÿงš
  • "__HAVE_DOUBLE_MULTILIB__" โ€” Defined if -mdouble= acts as a multilib option. ๐ŸŒธ
  • "__HAVE_DOUBLE32__" and "__HAVE_DOUBLE64__" โ€” Defined if the compiler supports 32-bit double or 64-bit double, respectively. The actual layout is specified by the -mdouble= option. ๐Ÿซถ
  • "__DEFAULT_DOUBLE__" โ€” The size in bits of "double" if -mdouble= is not set. To test the layout of "double" in a program, use the built-in macro "__SIZEOF_DOUBLE__". โœจ
  • "__HAVE_LONG_DOUBLE32__", "__HAVE_LONG_DOUBLE64__", "__HAVE_LONG_DOUBLE_MULTILIB__" and "__DEFAULT_LONG_DOUBLE__" โ€” Same as above, but for "long double" instead of "double". ๐ŸŒˆ
  • "__WITH_DOUBLE_COMPARISON__" โ€” 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"). ๐ŸŽ€

โœจ Blackfin Options โœจ

  • -mcpu=cpu[-sirevision] โ€” Specifies the name of the target Blackfin processor. Right now, cpu can be one of bf512, bf514, bf516, bf518, bf522, bf523, bf524, bf525, bf526, bf527, bf531, bf532, bf533, bf534, bf536, bf537, bf538, bf539, bf542, bf544, bf547, bf548, bf549, bf542m, bf544m, bf547m, bf548m, bf549m, bf561 or bf592. ๐Ÿ”ฅ

The optional sirevision specifies the silicon revision of the target Blackfin processor. Any workarounds available for the targeted silicon revision get enabled. If sirevision is none, no workarounds are enabled. If sirevision is any, all workarounds for the targeted processor are enabled. The "__SILICON_REVISION__" macro is defined to two hexadecimal digits representing the major and minor numbers in the silicon revision. If sirevision is none, "__SILICON_REVISION__" is not defined. If sirevision is any, "__SILICON_REVISION__" is defined to be 0xffff. If this optional sirevision is not used, GCC assumes the latest known silicon revision of the targeted Blackfin processor. ๐Ÿ‘‘

GCC defines a preprocessor macro for the specified cpu. For the bfin-elf toolchain, this option causes the hardware BSP provided by libgloss to be linked in if -msim is not given. ๐Ÿงš

Without this option, bf532 is used as the processor by default. ๐ŸŒธ

๐Ÿ™ˆ Note: support for bf561 is incomplete. For bf561, only the preprocessor macro is defined.
  • -msim โ€” Specifies that the program will run on the simulator. This causes the simulator BSP provided by libgloss to be linked in. This option only has an effect for the bfin-elf toolchain. Certain other options, such as -mid-shared-library and -mfdpic, imply -msim. ๐Ÿฆ‹
  • -momit-leaf-frame-pointer โ€” Don't keep the frame pointer in a register for leaf functions. This avoids the instructions that save, set up and restore frame pointers, and it makes an extra register available in leaf functions. ๐Ÿซถ
  • -mspecld-anomaly โ€” When enabled, the compiler makes sure the generated code does not contain speculative loads after jump instructions. If this option is used, "__WORKAROUND_SPECULATIVE_LOADS" is defined. ๐Ÿ’…
  • -mno-specld-anomaly โ€” Don't generate extra code to prevent speculative loads from happening. ๐Ÿ™ˆ
  • -mcsync-anomaly โ€” When enabled, the compiler makes sure the generated code does not contain CSYNC or SSYNC instructions too soon after conditional branches. If this option is used, "__WORKAROUND_SPECULATIVE_SYNCS" is defined. โœจ
  • -mno-csync-anomaly โ€” Don't generate extra code to prevent CSYNC or SSYNC instructions from happening too soon after a conditional branch. ๐ŸŒˆ
  • -mlow64k โ€” When enabled, the compiler is free to take advantage of the knowledge that the entire program fits into the low 64k of memory. ๐Ÿ’œ
  • -mno-low64k โ€” Assume that the program is arbitrarily large. This is the default. ๐Ÿ“
  • -mstack-check-l1 โ€” Does stack checking using information placed into L1 scratchpad memory by the uClinux kernel. ๐ŸŽ€
  • -mid-shared-library โ€” Generates code that supports shared libraries via the library ID method. This allows for execute in place and shared libraries in an environment without virtual memory management. This option implies -fPIC. With a bfin-elf target, this option implies -msim. ๐Ÿงš
  • -mno-id-shared-library โ€” Generates code that doesn't assume ID-based shared libraries are being used. This is the default. ๐Ÿ‘‘
  • -mleaf-id-shared-library โ€” okay so this one makes code that works with ID shared libraries using the library ID method ๐Ÿฆ‹ but assumes your library or executable won't link against any other ID shared libraries. That assumption lets the compiler use faster code for jumps and calls โœจ
  • -mno-leaf-id-shared-library โ€” the opposite energy ๐Ÿ™ˆ this doesn't assume the code avoids linking with ID shared libraries, so you get slower code for jump and call insns ๐Ÿข
  • -mshared-library-id=n โ€” sets the identification number of the ID-based shared library you're compiling ๐ŸŽ€ A value of 0 gives you more compact code ๐Ÿ’œ Any other value forces that number onto the current library, but it's no more space- or time-efficient than just leaving this option out ๐Ÿ’…
  • -msep-data โ€” lowkey iconic: this lets the data segment live in a different area of memory from the text segment ๐Ÿงš That makes execute in place possible in an environment without virtual memory management, because it gets rid of relocations against the text section โญ
  • -mno-sep-data โ€” this one assumes the data segment follows the text segment ๐ŸŒธ This is the default ๐Ÿ’–
  • -mlong-calls, -mno-long-calls โ€” the vibe here is calling a function by first loading its address into a register and then doing a subroutine call on that register ๐Ÿซถ You need this if the target function sits 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 on the default behaviour ๐ŸŒˆ Heads up though: these switches don't change how function calls through function pointers get generated ๐Ÿ’€
  • -mfast-fp โ€” links with the fast floating-point library โšก It relaxes some of the IEEE floating-point standard's rules for checking inputs against Not-a-Number (NAN) ๐Ÿ”ฅ all for performance, bestie
  • -minline-plt โ€” enables inlining of PLT entries in function calls to functions that aren't known to bind locally ๐Ÿฆ‹ Fun fact: it does nothing without -mfdpic ๐Ÿ™ƒ
  • -mmulticore โ€” builds a standalone application for multicore Blackfin processors ๐Ÿ‘‘ This makes the compiler use proper start files and link scripts that support multicore, and it defines the macro "__BFIN_MULTICORE" ๐Ÿ’– It can only be used with -mcpu=bf561[-sirevision] โœจ

This one plays nicely 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" ๐Ÿงš

If you skip this option entirely, you get the single-core application programming model ๐Ÿ’…

  • -mcorea โ€” builds 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 macro "__BFIN_COREA" gets defined ๐Ÿ”ฅ Only usable together with -mmulticore โญ
  • -mcoreb โ€” same vibe, but for Core B of BF561 ๐Ÿฆ‹ It defines "__BFIN_COREB", and when you use this, "coreb_main" should be used instead of "main" ๐Ÿ‘‘ Only usable together with -mmulticore ๐Ÿ’œ
  • -msdram โ€” builds a standalone application for SDRAM ๐ŸŒˆ Proper start files and link scripts put the application into SDRAM, and the macro "__BFIN_SDRAM" is defined ๐ŸŽ€ The loader needs to initialize SDRAM before loading the application ๐Ÿ˜ญ
  • -micplb โ€” assumes ICPLBs are enabled at run time ๐Ÿ™ˆ This affects certain anomaly workarounds ๐Ÿ”ง For Linux targets, the default is to assume ICPLBs are enabled, but for standalone applications the default is off ๐Ÿ’…

๐Ÿฆ‹ C6X Options ๐Ÿฆ‹

  • -march=name โ€” this specifies the name of the target architecture ๐Ÿงš GCC uses that name to figure out what kinds of instructions it's allowed to emit when generating assembly code โœจ The permissible names are: c62x, c64x, c64x+, c67x, c67x+, c674x ๐Ÿ’–
  • -mbig-endian โ€” generates code for a big-endian target ๐ŸŒธ
  • -mlittle-endian โ€” generates code for a little-endian target ๐Ÿ’œ This is the default ๐Ÿ’…
  • -msim โ€” picks startup files and a linker script that suit the simulator ๐ŸŽ€
  • -msdata=default โ€” puts small global and static data in the ".neardata" section, which is pointed to by register B14 ๐Ÿซถ Small uninitialized global and static data goes in the ".bss" section, which sits right next to ".neardata" ๐Ÿ”ฅ Small read-only data goes in the ".rodata" section ๐ŸŒˆ The matching sections for big chunks of data are ".fardata", ".far" and ".const" โœจ
  • -msdata=all โ€” puts all data, not just the small stuff, into the sections reserved for small data ๐Ÿ‘‘ It also uses addressing relative to the B14 register to get to them ๐Ÿฆ‹
  • -msdata=none โ€” makes no use of the sections reserved for small data, and uses absolute addresses to access all data ๐Ÿ™ƒ All initialized global and static data goes in ".fardata", and all uninitialized data goes in ".far" ๐Ÿ’… All constant data goes in the ".const" section ๐Ÿ’–

๐ŸŒธ CRIS Options ๐ŸŒธ

These options are defined specifically for the CRIS ports ๐Ÿงš

  • -march=architecture-type, -mcpu=architecture-type โ€” generates code for the 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, except for cris-axis-linux-gnu, where the default is v10 ๐Ÿ‘‘
  • -mtune=architecture-type โ€” tunes everything applicable about the generated code to 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 โ€” warns when the stack frame of a function goes over n bytes ๐Ÿ˜ญ
  • -metrax4, -metrax100 โ€” these are synonyms for -march=v3 and -march=v8 respectively ๐ŸŒˆ
  • -mmul-bug-workaround, -mno-mul-bug-workaround โ€” works around a bug in the "muls" and "mulu" instructions for CPU models where it applies ๐Ÿ”ง This option is disabled by default ๐Ÿ’…
  • -mpdebug โ€” enables CRIS-specific verbose debug-related information in the assembly code ๐Ÿซถ It also turns off the #NO_APP formatted-code indicator to the assembler at the beginning of the assembly file ๐Ÿ™ˆ
  • -mcc-init โ€” don't use condition-code results from previous instructions ๐ŸŒธ Always emit compare and test instructions before using condition codes โœจ
  • -mno-side-effects โ€” doesn't emit instructions with side effects in addressing modes other than post-increment ๐Ÿงš
  • -mstack-align, -mno-stack-align, -mdata-align, -mno-data-align, -mconst-align, -mno-const-align โ€” these (the no- ones eliminate the arrangement) make the stack frame, individual data and constants aligned to the maximum single data access size for the chosen CPU model ๐Ÿ’– The default is 32-bit alignment ๐ŸŽ€ ABI details such as structure layout aren't affected by these options ๐Ÿ’…
  • -m32-bit, -m16-bit, -m8-bit โ€” kinda like the stack, data and const align options above ๐Ÿฆ‹ These arrange for the stack frame, writable data and constants to all be 32-bit, 16-bit or 8-bit aligned ๐ŸŒˆ The default is 32-bit alignment ๐Ÿ’œ
  • -mno-prologue-epilogue, -mprologue-epilogue โ€” with -mno-prologue-epilogue, the normal function prologue and epilogue that set up the stack frame are left out ๐Ÿ˜ญ No return instructions or return sequences get generated either ๐Ÿ’€
โš ๏ธ Use this option only together with visual inspection of the compiled code ๐Ÿ‘€ No warnings or errors are generated when call-saved registers must be saved, or when storage for local variables needs to be allocated.
  • -mno-gotplt, -mgotplt โ€” with -fpic and -fPIC, -mno-gotplt means don't generate instruction sequences that load addresses for functions from the PLT part of the GOT, and -mgotplt means do generate them ๐Ÿ”ฅ The traditional approach on other architectures is calls to the PLT instead ๐Ÿ™ƒ The default is -mgotplt โœจ
  • -melf โ€” a legacy no-op option that's only recognized with the cris-axis-elf and cris-axis-linux-gnu targets ๐Ÿ•ฐ๏ธ
  • -mlinux โ€” another legacy no-op option, only recognized with the cris-axis-linux-gnu target ๐Ÿ•ฐ๏ธ
  • -sim โ€” recognized for the cris-axis-elf target ๐ŸŽฎ It links with input-output functions from a simulator library ๐ŸŒธ Code, initialized data and zero-initialized data are allocated consecutively ๐Ÿงš
  • -sim2 โ€” like -sim, but it passes linker options to locate initialized data at 0x40000000 and zero-initialized data at 0x80000000 ๐Ÿ‘‘

๐Ÿ’– CR16 Options ๐Ÿ’–

These options are defined specifically for the CR16 ports ๐Ÿซถ

  • -mmac โ€” enables the use of multiply-accumulate instructions ๐Ÿ”ฅ Disabled by default ๐Ÿ’…
  • -mcr16cplus, -mcr16c โ€” generates code for the CR16C or CR16C+ architecture ๐ŸŒˆ The CR16C+ architecture is the default โœจ
  • -msim โ€” links the library libsim.a, which is compatible with the simulator ๐ŸŽ€ Applicable to the ELF compiler only ๐Ÿงš
  • -mint32 โ€” chooses the integer type to be 32-bit wide ๐Ÿฆ‹
  • -mbit-ops โ€” generates "sbit"/"cbit" instructions for bit manipulations ๐Ÿ’œ
  • -mdata-model=model โ€” chooses a data model ๐ŸŒธ The choices for model are near, far or medium, and medium is the default ๐Ÿ’– Heads up: far is not valid with -mcr16c, because the CR16C architecture doesn't support the far data model ๐Ÿ˜ญ

๐Ÿงš C-SKY Options ๐Ÿงš

GCC supports these options when compiling for C-SKY V2 processors โœจ

  • -march=arch โ€” specifies the C-SKY target architecture ๐Ÿ‘‘ Valid values for arch are: ck801, ck802, ck803, ck807, and ck810 ๐ŸŽ€ The default is ck810 ๐Ÿ’…
  • -mcpu=cpu โ€” specifies the C-SKY target processor ๐Ÿ”ฅ Valid values for cpu are: ck801, ck801t, ck802, ck802t, ck802j, ck803, ck803h, ck803t, ck803ht, ck803f, ck803fh, ck803e, ck803eh, ck803et, ck803eht, ck803ef, ck803efh, ck803ft, ck803eft, ck803efht, ck803r1, ck803hr1, ck803tr1, ck803htr1, ck803fr1, ck803fhr1, ck803er1, ck803ehr1, ck803etr1, ck803ehtr1, ck803efr1, ck803efhr1, ck803ftr1, ck803eftr1, ck803efhtr1, ck803s, ck803st, ck803se, ck803sf, ck803sef, ck803seft, ck807e, ck807ef, ck807, ck807f, ck810e, ck810et, ck810ef, ck810eft, ck810, ck810v, ck810f, ck810t, ck810fv, ck810tv, ck810ft, and ck810ftv ๐ŸŒˆ
  • -mbig-endian, -EB, -mlittle-endian, -EL โ€” okay so you get to pick your byte order ๐Ÿ’– Big-endian or little-endian, your call. Little-endian is the default, so you don't have to do anything if you're happy with that ๐ŸŒธ
  • -mfloat-abi=name โ€” ๐Ÿฆ‹ this one picks the floating-point ABI. Your choices are soft, softfp, and hard:
    • soft makes GCC spit out library calls for floating-point operations.
    • softfp lets it use hardware floating-point instructions but still sticks with the soft-float calling conventions.
    • hard gives you floating-point instructions and FPU-specific calling conventions.

The default depends on your target configuration.

โš ๏ธ bestie, 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 against a compatible set of libraries, or it's going to be a whole mess ๐Ÿ’€
  • -mhard-float, -msoft-float โ€” pick hardware or software floating-point implementations. The default is soft float โœจ
  • -mdouble-float, -mno-double-float โ€” when -mhard-float is in effect, this turns on generation of double-precision float instructions. It's the default except when compiling for CK803 ๐Ÿ™ˆ
  • -mfdivdu, -mno-fdivdu โ€” when -mhard-float is in effect, this enables generation of "frecipd", "fsqrtd", and "fdivd" instructions. Also the default except when compiling for CK803 ๐ŸŽ€
  • -mfpu=fpu โ€” selects the floating-point processor. This can only be used with -mhard-float ๐Ÿ”ฅ The values for fpu are:
    • fpv2_sf, which is the same as -mno-double-float -mno-fdivdu
    • fpv2, which is -mdouble-float -mno-divdu
    • fpv2_divd, which is -mdouble-float -mdivdu
  • -melrw, -mno-elrw โ€” enables the extended "lrw" instruction. It's on by default for CK801 and off for everything else ๐Ÿงš
  • -mistack, -mno-istack โ€” turns on interrupt stack instructions. Default is off.
-mistack is required if you want to handle the "interrupt" and "isr" function attributes, so don't skip it!
  • -mmp โ€” enables multiprocessor instructions. Default is off ๐Ÿ’œ
  • -mcp โ€” enables coprocessor instructions. Default is off ๐Ÿฆ‹
  • -mcache โ€” also enables coprocessor instructions. Default is off ๐ŸŒˆ
  • -msecurity โ€” enables C-SKY security instructions. Default is off ๐Ÿ”’
  • -mtrust โ€” enables C-SKY trust instructions. Default is off ๐Ÿซถ
  • -mdsp, -medsp, -mvdsp โ€” enable C-SKY DSP, Enhanced DSP, or Vector DSP instructions, respectively. All three default to off ๐ŸŽ€
  • -mdiv, -mno-div โ€” generates divide instructions. Default is off โœจ
  • -msmart, -mno-smart โ€” generates code for Smart Mode, which only uses registers numbered 0-7 so 16-bit instructions can be used ๐Ÿ’… This gets ignored for CK801, where it's already required, and it defaults to on for CK802. For other targets, it's off.
  • -mhigh-registers, -mno-high-registers โ€” generates code using the high registers numbered 16-31. This isn't supported on CK801, CK802, or CK803, but it's enabled by default for other processors ๐Ÿ‘‘
  • -manchor, -mno-anchor โ€” generates code using global anchor symbol addresses ๐ŸŒธ
  • -mpushpop, -mno-pushpop โ€” generates code using "push" and "pop" instructions. Defaults to on ๐Ÿ“
  • -mmultiple-stld, -mstm, -mno-multiple-stld, -mno-stm โ€” generates code using "stm" and "ldm" instructions. This isn't supported on CK801, but it's enabled by default on other processors ๐Ÿ’–
  • -mconstpool, -mno-constpool โ€” creates constant pools in the compiler instead of handing that job off to the assembler. This is the default and is required for correct code generation on CK801 and CK802. It's optional on other processors ๐Ÿงš
  • -mstack-size, -mno-stack-size โ€” emits ".stack_size" directives for each function in the assembly output. Defaults to off โœจ
  • -mccrt, -mno-ccrt โ€” generates code for the C-SKY compiler runtime instead of libgcc. Defaults to off ๐Ÿฆ‹
  • -mbranch-cost=n โ€” sets the branch costs to roughly "n" instructions. The default is 1 ๐ŸŒˆ
  • -msched-prolog, -mno-sched-prolog โ€” lets the scheduler move around function prologue and epilogue sequences. โš ๏ธ This can give you code that doesn't follow the C-SKY V2 ABI prologue requirements, and that code can't be debugged or backtraced. It's disabled by default, so please don't turn it on unless you know exactly why ๐Ÿ’€
  • -msim โ€” links the library libsemi.a, which works with the simulator. This only applies to the ELF compiler ๐Ÿ”ฅ

๐ŸŽ Darwin Options

These options are defined for all architectures running the Darwin operating system ๐ŸŒธ

Okay so FSF GCC on Darwin doesn't make "fat" object files. It makes an object file for the single architecture GCC was built to target ๐Ÿซถ Apple's GCC is different, though: it does make fat files when you use multiple -arch options. It does that by running the compiler or linker multiple times and then joining the results together with lipo ๐Ÿงš

The subtype of the file (like ppc7400, ppc970, or i686) gets decided by the flags that specify the ISA GCC is targeting, like -mcpu or -march. The -force_cpusubtype_ALL option can override this ๐Ÿ’…

The Darwin tools act differently when they hit an ISA mismatch. The assembler, as, only lets you use instructions that are valid for the subtype of the file it's generating. So you literally cannot put 64-bit instructions in a ppc750 object file ๐Ÿ’€ The linker for shared libraries, /usr/bin/libtool, fails and prints an error if you ask it to make a shared library with a less restrictive subtype than its input files. For example, trying to put a ppc970 object file in a ppc7400 library is a no-go ๐Ÿ™ˆ The linker for executables, ld, quietly gives the executable the most restrictive subtype of any of its input files ๐Ÿคซ

  • -Fdir โ€” adds the framework directory dir to the head of the list of directories searched for header files. These directories are interleaved with the ones from -I options, and they're scanned left-to-right ๐Ÿฆ‹

A framework directory is a directory full of frameworks. 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 just the directory name without the .framework part. Headers for the framework live 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 from the framework that contains the subframework, or in a sibling subframework header. Two subframeworks are siblings if they're in the same framework ๐Ÿ‘ฏ

A subframework shouldn't have the same name as a framework, and GCC will warn you if it does. Right now a subframework can't have subframeworks of its own, but that might get added later ๐ŸŒˆ

The standard frameworks live in /System/Library/Frameworks and /Library/Frameworks. An example include looks like #include <Framework/header.h>, where Framework is the framework's name and header.h is found in either the PrivateHeaders or Headers directory ๐Ÿ“š

  • -iframeworkdir โ€” works like -F, except the directory gets treated as a system directory. The big difference is that with -iframework, the compiler won't warn you about constructs inside header files found through dir. This option is only valid for the C family of languages ๐ŸŽ€
  • -gused โ€” emits debugging info for symbols that are used. For the stabs debugging format, this enables -feliminate-unused-debug-symbols. It's on by default โœจ
  • -gfull โ€” emits debugging info for all symbols and types ๐Ÿ”
  • -mmacosx-version-min=version โ€” the earliest version of MacOS X this executable will run on is version. Typical values include 10.1, 10.2, and 10.3.9 ๐ŸŽ If the compiler was built to use the system's headers by default, the default for this option is the system version the compiler is running on. Otherwise, the default makes choices that are compatible with as many systems and code bases as possible ๐Ÿซถ
  • -mkernel โ€” enables kernel development mode ๐Ÿง‘โ€๐Ÿ’ป The -mkernel option sets -static, -fno-common, -fno-use-cxa-atexit, -fno-exceptions, -fno-non-call-exceptions, -fapple-kext, -fno-weak, and -fno-rtti where applicable. This mode also sets -mno-altivec, -msoft-float, -fno-builtin, and -mlong-branch for PowerPC targets ๐Ÿ‘‘
  • -mone-byte-bool โ€” overrides the defaults for "bool" so that "sizeof(bool)==1". By default, "sizeof(bool)" is 4 when compiling for Darwin/PowerPC and 1 when compiling for Darwin/x86. That means this option does nothing on x86 ๐Ÿ™ƒ
๐Ÿšจ Warning, bestie: the -mone-byte-bool switch makes GCC generate code that isn't binary compatible with code generated without it. You might have to recompile all the other modules in your program, including system libraries. Only use this switch to conform to a non-default data model.
  • -mfix-and-continue, -ffix-and-continue, -findirect-data โ€” generates code that's good for fast turnaround development, like letting GDB dynamically load .o files into programs that are already running ๐Ÿ”ฅ -findirect-data and -ffix-and-continue are only here for backwards compatibility ๐Ÿ•ฐ๏ธ
  • -all_load โ€” loads all members of static archive libraries. See man ld(1) for more information ๐Ÿ“ฆ
  • -arch_errors_fatal โ€” makes errors about files with the wrong architecture fatal ๐Ÿ’€
  • -bind_at_load โ€” marks the output file so the dynamic linker binds all undefined references when the file is loaded or launched ๐Ÿฆ‹
  • -bundle โ€” produces a Mach-o bundle format file. See man ld(1) for more information ๐ŸŽ
  • -bundle_loader executable โ€” specifies the executable that will load the build output file being linked. See man ld(1) for more information ๐Ÿงš
  • -dynamiclib โ€” when you pass this, GCC produces a dynamic library instead of an executable when linking, using the Darwin libtool command ๐Ÿ’œ
  • -force_cpusubtype_ALL โ€” gives GCC's output file the ALL subtype, instead of one controlled by the -mcpu or -march option ๐Ÿ‘‘
  • -allowable_client client_name
  • -client_name
  • -compatibility_version
  • -current_version
  • -dead_strip
  • -dependency-file
  • -dylib_file
  • -dylinker_install_name
  • -dynamic
  • -exported_symbols_list
  • -filelist
  • -flat_namespace
  • -force_flat_namespace
  • -headerpad_max_install_names
  • -image_base
  • -init
  • -install_name
  • -keep_private_externs
  • -multi_module
  • -multiply_defined
  • -multiply_defined_unused
  • -noall_load
  • -no_dead_strip_inits_and_terms
  • -nofixprebinding
  • -nomultidefs
  • -noprebind
  • -noseglinkedit
  • -pagezero_size
  • -prebind
  • -prebind_all_twolevel_modules
  • -private_bundle
  • -read_only_relocs
  • -sectalign
  • -sectobjectsymbols
  • -whyload
  • -seg1addr
  • -sectcreate
  • -sectobjectsymbols
  • -sectorder
  • -segaddr
  • -segs_read_only_addr
  • -segs_read_write_addr
  • -seg_addr_table
  • -seg_addr_table_filename
  • -seglinkedit
  • -segprot
  • -segs_read_only_addr
  • -segs_read_write_addr
  • -single_module
  • -static
  • -sub_library
  • -sub_umbrella
  • -twolevel_namespace
  • -umbrella
  • -undefined
  • -unexported_symbols_list
  • -weak_reference_mismatches
  • -whatsloaded

These options are passed straight through to the Darwin linker ๐ŸŽโœจ. The Darwin linker man page is where you'll find the full tea on all of them, bestie ๐Ÿ’….


๐Ÿ’Ž DEC Alpha Options

These -m options are defined for the DEC Alpha implementations ๐Ÿฆ‹:

  • -mno-soft-float, -msoft-float โ€” Okay so these two are opposites ๐Ÿ™ˆ. -mno-soft-float says "yes, use the hardware floating-point instructions," and -msoft-float says "nope, don't." When you use -msoft-float, the floating-point operations get handled by functions in libgcc.a ๐Ÿงš. Unless those get swapped out for routines that emulate the floating-point stuff, or they're compiled to call those emulation routines, the functions in there will actually issue floating-point operations. So if you're compiling for an Alpha without floating-point operations, you absolutely have to make sure the library is built so it doesn't call them ๐Ÿ˜ญ.

Also, Alpha implementations without floating-point operations are still required to have floating-point registers ๐Ÿ’œ.

  • -mfp-reg, -mno-fp-regs โ€” These tell GCC to generate code that uses (or doesn't use) the floating-point register set ๐ŸŒธ. -mno-fp-regs automatically implies -msoft-float ๐Ÿซถ. If the floating-point register set isn't being used, floating-point operands get passed in integer registers as if they were integers, and floating-point results come back in $0 instead of $f0 ๐Ÿคฏ. This is a non-standard calling sequence, so any function with a floating-point argument or return value that's called by code compiled with -mno-fp-regs has to be compiled with that option too, or it's a whole mess ๐Ÿ’€.

A typical use of this option is building a kernel that doesn't use (and therefore doesn't need to save and restore) any floating-point registers ๐Ÿ‘‘.

  • -mieee โ€” The Alpha architecture has floating-point hardware that's optimized for maximum performance, and it's mostly IEEE compliant ๐Ÿ”ฅ. For full compliance, though, it needs some software help ๐Ÿค. This option generates code that's fully IEEE-compliant, except the inexact-flag doesn't get maintained (more on that below โฌ‡๏ธ). If you turn this on, the preprocessor macro "_IEEE_FP" gets defined during compilation โœจ. The resulting code is slower, but it can correctly support denormalized numbers and exceptional IEEE values like not-a-number and plus/minus infinity ๐ŸŒˆ. Other Alpha compilers call this option -ieee_with_no_inexact.
DEBIAN SPECIFIC: This option is on by default for alpha-linux-gnu, unless -ffinite-math-only (which is part of the -ffast-math set) is specified ๐Ÿ™…โ€โ™€๏ธ. The reason is that the software functions in the GNU libc math libraries generate denormalized numbers, NaNs, and infs, and all of those will cause a program to SIGFPE when it tries to use the results without -mieee ๐Ÿ˜ญ๐Ÿ’”.
  • -mieee-with-inexact โ€” This is like -mieee, except the generated code also maintains the IEEE inexact-flag ๐Ÿ’–. Turning this on makes the generated code fully-compliant IEEE math ๐Ÿ‘‘. Along with "_IEEE_FP", the macro "_IEEE_FP_EXACT" gets defined too โœจ. On some Alpha implementations the code can run significantly slower than the default output ๐Ÿข. Since there's very little code that depends on the inexact-flag, you should normally not specify this option ๐Ÿ™ˆ. Other Alpha compilers call this option -ieee_with_inexact.
  • -mfp-trap-mode=trap-mode โ€” This controls which floating-point related traps are enabled ๐Ÿšจ. Other Alpha compilers call this option -fptm trap-mode. The trap mode can be set to one of four values:
    • n โ€” This is the default (normal) setting ๐ŸŒธ. The only traps that get enabled are the ones that can't be disabled in software, like division by zero.
    • u โ€” In addition to everything n enables, underflow traps are enabled as well ๐Ÿฆ‹.
    • su โ€” Like u, but the instructions are marked as safe for software completion (check the Alpha architecture manual for the deets ๐Ÿ“–).
    • sui โ€” Like su, but inexact traps are enabled as well ๐Ÿ’….
  • -mfp-rounding-mode=rounding-mode โ€” This selects the IEEE rounding mode ๐ŸŽ€. Other Alpha compilers call this option -fprm rounding-mode. The rounding-mode can be one of:
    • n โ€” Normal IEEE rounding mode ๐ŸŒˆ. Floating-point numbers get rounded towards the nearest machine number, or towards the even machine number in case of a tie.
    • m โ€” Round towards minus infinity โฌ‡๏ธ.
    • c โ€” Chopped rounding mode ๐Ÿ“. Floating-point numbers get rounded towards zero.
    • d โ€” Dynamic rounding mode ๐Ÿงš. A field in the floating-point control register (fpcr, see the Alpha architecture reference manual) controls which rounding mode is in effect. The C library initializes this register for rounding towards plus infinity, so unless your program modifies the fpcr, d basically means round towards plus infinity โญ.
  • -mtrap-precision=trap-precision โ€” Okay, real talk: in the Alpha architecture, floating-point traps are imprecise ๐Ÿ˜ญ. Without software help, it's impossible to recover from a floating trap, and the program usually 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 โ€” This option marks the generated code as IEEE conformant ๐Ÿ“œ. You must not use this option unless you also specify -mtrap-precision=i and either -mfp-trap-mode=su or -mfp-trap-mode=sui ๐Ÿšซ. Its only effect is to emit the line .eflag 48 in the function prologue of the generated assembly file ๐Ÿงพ.
  • -mbuild-constants โ€” Normally GCC looks at a 32- or 64-bit integer constant to see if it can build it from smaller constants in two or three instructions ๐Ÿงฉ. If it can't, it outputs the constant as a literal and generates code to load it from the data segment at run time. With this option, you're telling GCC to build all integer constants using code, even if that takes more instructions (the maximum is six) ๐Ÿ› ๏ธ. You typically use this when building 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 โ€” These indicate whether GCC should generate code that uses the optional BWX, CIX, FIX and MAX instruction sets ๐ŸŒŸ. The default is to use the instruction sets supported by the CPU type you specify with the -mcpu= option, or the CPU that GCC was built on if you don't specify one ๐Ÿ’œ.
  • -mfloat-vax, -mfloat-ieee โ€” These generate code that uses (or doesn't use) VAX F and G floating-point arithmetic instead of IEEE single and double precision ๐Ÿฆ–.
  • -mexplicit-relocs, -mno-explicit-relocs โ€” Older Alpha assemblers had no way to generate symbol relocations except through assembler macros ๐Ÿ™ƒ. Using those macros doesn't allow optimal instruction scheduling. GNU binutils as of version 2.12 supports a new syntax that lets the compiler explicitly mark which relocations apply to which instructions ๐ŸŽ‰. This option is mostly useful for debugging, since GCC detects the capabilities of the assembler when it's built and sets the default accordingly ๐Ÿ”.
  • -msmall-data, -mlarge-data โ€” When -mexplicit-relocs is in effect, static data is accessed via gp-relative relocations ๐ŸŒธ. When -msmall-data is used, objects 8 bytes long or smaller are placed in a small data area (the ".sdata" and ".sbss" sections) and accessed via 16-bit relocations off of the $gp register ๐Ÿฆ‹. This limits the size of the small data area to 64KB, but lets the variables be directly accessed with a single instruction โšก.

The default is -mlarge-data ๐Ÿ˜. With this option, the data area is limited to just below 2GB. Programs that need more than 2GB of data must use "malloc" or "mmap" to allocate the data in the heap instead of in the program's data segment ๐Ÿง .

When generating code for shared libraries, -fpic implies -msmall-data, and -fPIC implies -mlarge-data ๐Ÿ’–.

  • -msmall-text, -mlarge-text โ€” When -msmall-text is used, the compiler assumes the code of the entire program (or shared library) fits in 4MB, so it's reachable with a branch instruction ๐Ÿƒโ€โ™€๏ธ. When -msmall-data is used, the compiler can assume all local symbols share the same $gp value, which cuts the number of instructions needed for a function call from 4 to 1 ๐Ÿค.

The default is -mlarge-text ๐ŸŒˆ.

  • -mcpu=cpu_type โ€” okay bestie, this one sets the instruction set AND the scheduling parameters for machine type cpu_type ๐Ÿ’–. You can name it with the EV style name or the matching chip number, both work โœจ. GCC has scheduling params for the EV4, EV5, and EV6 family and picks the default instruction set from whatever processor you specify ๐Ÿ”ฅ. No processor type? It defaults to the processor the compiler was built on ๐Ÿ™ˆ. Supported values for cpu_type are:
    • ev4, ev45, 21064 โ€” schedules as an EV4 and has no instruction set extensions ๐ŸŒธ
    • ev5, 21164 โ€” schedules as an EV5 and has no instruction set extensions ๐ŸŒธ
    • ev56, 21164a โ€” schedules as an EV5 and supports the BWX extension ๐Ÿฆ‹
    • pca56, 21164pc, 21164PC โ€” schedules as an EV5 and supports the BWX and MAX extensions ๐Ÿฆ‹
    • ev6, 21264 โ€” schedules as an EV6 and supports the BWX, FIX, and MAX extensions ๐Ÿ’œ
    • ev67, 21264a โ€” schedules as an EV6 and supports the BWX, CIX, FIX, and MAX extensions ๐Ÿ‘‘

Native toolchains also support the value native, which picks the best architecture option for the host processor, it's giving convenience ๐Ÿ’…. -mcpu=native has no effect if GCC does not recognize the processor ๐Ÿ’€.

  • -mtune=cpu_type โ€” this one is lowkey the chill sibling ๐Ÿซถ. It sets ONLY the instruction scheduling parameters for machine type cpu_type, and the instruction set stays exactly the same โœจ.

Native toolchains also support the value native, which picks the best architecture option for the host processor ๐ŸŒˆ. -mtune=native has no effect if GCC does not recognize the processor ๐Ÿ˜ญ.

  • -mmemory-latency=time โ€” this sets the latency the scheduler should assume for typical memory references as the application sees them ๐Ÿงš. The number is highly dependent on the application's memory access patterns and the size of the external cache on the machine, so it's a whole vibe check ๐Ÿ”ฅ. Valid options for time are:
    • number โ€” a decimal number representing clock cycles ๐Ÿ”ข
    • L1, L2, L3, main โ€” the compiler has estimates of clock cycles for "typical" EV4 & EV5 hardware, covering the Level 1, 2 & 3 caches (also called Dcache, Scache, and Bcache) and main memory ๐Ÿ“. Note that L3 is only valid for EV5 ๐Ÿ™ˆ.

๐Ÿงš eBPF Options ๐Ÿงš

  • -mframe-limit=bytes โ€” this is the hard limit for frame sizes, in bytes ๐Ÿ’–. Right now the value you pass should be less than or equal to 32767. It defaults to whatever limit is imposed by the version of the Linux kernel being targeted ๐Ÿง.
  • -mkernel=version โ€” this is the minimum kernel version that'll run your compiled program โœจ. GCC uses it to decide which instructions to use, which kernel helpers to allow, etc. ๐Ÿ‘‘ Currently, version can be one of 4.0, 4.1, 4.2, 4.3, 4.4, 4.5, 4.6, 4.7, 4.8, 4.9, 4.10, 4.11, 4.12, 4.13, 4.14, 4.15, 4.16, 4.17, 4.18, 4.19, 4.20, 5.0, 5.1, 5.2, latest and native ๐ŸŒธ.
  • -mbig-endian โ€” generate code for a big-endian target ๐Ÿฆ‹.
  • -mlittle-endian โ€” generate code for a little-endian target. This is the default, so you're already good ๐Ÿซถ.
  • -mjmpext โ€” enable generation of extra conditional-branch instructions. Enabled for CPU v2 and above ๐Ÿ’œ.
  • -mjmp32 โ€” enable 32-bit jump instructions. Enabled for CPU v3 and above โญ.
  • -malu32 โ€” enable 32-bit ALU instructions. Enabled for CPU v3 and above โญ.
  • -mcpu=version โ€” this picks which version of the eBPF ISA you're targeting ๐ŸŽ€. Newer versions may not be supported by all kernels, so check your vibes first ๐Ÿ™ˆ. The default is v3. Supported values for version are:
    • v1 โ€” the first stable eBPF ISA, with no special features or extensions ๐ŸŒฑ
    • v2 โ€” supports the jump extensions, as in -mjmpext ๐Ÿฆ‹
    • v3 โ€” all features of v2, plus:
      • -<32-bit jump operations, as in -mjmp32> ๐Ÿ’…
      • -<32-bit ALU operations, as in -malu32> ๐Ÿ’…
  • -mco-re โ€” enable BPF Compile Once - Run Everywhere (CO-RE) support ๐ŸŒˆ. It requires and is implied by -gbtf.
  • -mno-co-re โ€” disable BPF Compile Once - Run Everywhere (CO-RE) support ๐Ÿšซ. BPF CO-RE support is enabled by default when generating BTF debug information for the BPF target, so you'd have to opt out on purpose ๐Ÿ™ˆ.
  • -mxbpf โ€” generate code for an expanded version of BPF that relaxes some of the restrictions imposed by the BPF architecture ๐Ÿ”ฅ. Like, it does things such as:
    • -<Save and restore callee-saved registers at function entry and exit, respectively.> โœจ

๐Ÿฆ‹ FR30 Options ๐Ÿฆ‹

These options are defined specifically for the FR30 port, bestie ๐ŸŽ€.

  • -msmall-model โ€” use the small address space model ๐ŸŒธ. This can produce smaller code, but it does assume that all symbolic values and addresses fit into a 20-bit range ๐Ÿ™ˆ.
  • -mno-lsim โ€” assume runtime support has 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 โ€” this says the program will run on the simulator ๐Ÿ–ฅ๏ธ. It causes an alternate runtime startup and library to be linked.
โš ๏ธ Bestie, you must NOT use this option when generating programs that will run on real hardware! You have to provide your own runtime library for whatever I/O functions are needed ๐Ÿ˜ญ.
  • -mlra โ€” enable Local Register Allocation ๐ŸŒ€. It's still experimental for FT32, so by default the compiler uses standard reload ๐Ÿงช.
  • -mnodiv โ€” do not use div and mod instructions ๐Ÿšซ.
  • -mft32b โ€” enable use of the extended instructions of the FT32B processor โญ.
  • -mcompress โ€” compress all code using the Ft32B code compression scheme ๐Ÿ—œ๏ธ.
  • -mnopm โ€” do not generate code that reads program memory ๐Ÿ™…โ€โ™€๏ธ.

๐ŸŒˆ FRV Options ๐ŸŒˆ

  • -mgpr-32 โ€” only use the first 32 general-purpose registers ๐Ÿ“.
  • -mgpr-64 โ€” use all 64 general-purpose registers ๐Ÿ‘‘.
  • -mfpr-32 โ€” use only the first 32 floating-point registers ๐ŸŒธ.
  • -mfpr-64 โ€” use all 64 floating-point registers ๐Ÿ’….
  • -mhard-float โ€” use hardware instructions for floating-point operations ๐Ÿ”ฅ.
  • -msoft-float โ€” use library routines for floating-point operations ๐Ÿงธ.
  • -malloc-cc โ€” dynamically allocate condition code registers โœจ.
  • -mfixed-cc โ€” don't try to dynamically allocate condition code registers. Only use icc0 and fcc0 ๐ŸŽ€.
  • -mdword โ€” change the ABI to use double word insns ๐Ÿ’–.
  • -mno-dword โ€” don't use double word instructions ๐Ÿšซ.
  • -mdouble โ€” use floating-point double instructions ๐Ÿฆ‹.
  • -mno-double โ€” don't use floating-point double instructions ๐Ÿ™ˆ.
  • -mmedia โ€” use media instructions ๐ŸŽถ.
  • -mno-media โ€” don't use media instructions ๐Ÿ”‡.
  • -mmuladd โ€” use multiply and add/subtract instructions โž•.
  • -mno-muladd โ€” don't use multiply and add/subtract instructions โž–.
  • -mfdpic โ€” select the FDPIC ABI, which uses function descriptors to represent pointers to functions ๐Ÿงš. Without any PIC/PIE-related options, it implies -fPIE. With -fpic or -fpie, it assumes GOT entries and small data are within a 12-bit range from the GOT base address. With -fPIC or -fPIE, GOT offsets are computed with 32 bits ๐Ÿงฎ. With a bfin-elf target, this option implies -msim ๐Ÿ™ˆ.
  • -minline-plt โ€” enable inlining of PLT entries in function calls to functions that are not known to bind locally ๐ŸŒŸ. It has no effect without -mfdpic. It's enabled by default if you're optimizing for speed and compiling for shared libraries (i.e., -fPIC or -fpic), or when an optimization option such as -O3 or above is in the command line ๐Ÿš€.
  • -mTLS โ€” assume a large TLS segment when generating thread-local code ๐Ÿงต.
  • -mtls โ€” do not assume a large TLS segment when generating thread-local code ๐Ÿชก.
  • -mgprel-ro โ€” enable the use of "GPREL" relocations in the FDPIC ABI for data that is known to be in read-only sections ๐Ÿ“–. It's enabled by default, except for -fpic or -fpie. Even though it may help make the global offset table smaller, it trades 1 instruction for 4 in those cases ๐Ÿค”. With -fPIC or -fPIE, it trades 3 instructions for 4, one of which may be shared by multiple symbols. It also avoids the need for a GOT entry for the referenced symbol, so it's more likely to be a win ๐Ÿ†. If it isn't, -mno-gprel-ro can be used to disable it ๐Ÿ™…โ€โ™€๏ธ.
  • -multilib-library-pic โ€” link with the (library, not FD) pic libraries ๐Ÿ“š. It's implied by -mlibrary-pic, as well as by -fPIC and -fpic without -mfdpic. You should never have to use it explicitly ๐Ÿซถ.
  • -mlinked-fp โ€” follow the EABI requirement of always creating a frame pointer whenever a stack frame is allocated ๐Ÿ—๏ธ. This option is enabled by default and can be disabled with -mno-linked-fp ๐Ÿ™ˆ.
  • -mlong-calls โ€” use indirect addressing to call functions outside the current compilation unit ๐Ÿ“ž. This allows the functions to be placed anywhere within the 32-bit address space ๐ŸŒ.
  • -malign-labels โ€” try to align labels to an 8-byte boundary by inserting NOPs into the previous packet ๐Ÿ“. This option only has an effect when VLIW packing is enabled. It doesn't create new packets; it merely adds NOPs to existing ones ๐Ÿ’….
  • -mlibrary-pic โ€” generate position-independent EABI code ๐Ÿงญ.
  • -macc-4 โ€” use only the first four media accumulator registers 4๏ธโƒฃ.
  • -macc-8 โ€” use all eight media accumulator registers 8๏ธโƒฃ.
  • -mpack โ€” pack VLIW instructions ๐Ÿ“ฆ.
  • -mno-pack โ€” do not pack VLIW instructions ๐Ÿ™…โ€โ™€๏ธ.
  • -mno-eflags โ€” do not mark ABI switches in e_flags ๐Ÿšซ.
  • -mcond-move โ€” enable the use of conditional-move instructions (default) โœจ.

This switch is mainly for debugging the compiler and will likely be removed in a future version ๐Ÿ™ˆ.

  • -mno-cond-move โ€” disable the use of conditional-move instructions ๐Ÿšซ.

This switch is mainly for debugging the compiler and will likely be removed in a future version ๐Ÿ™ˆ.

  • -mscc โ€” enable the use of conditional set instructions (default) ๐Ÿ’œ.

This switch is mainly for debugging the compiler and will likely be removed in a future version ๐Ÿ™ˆ.

  • -mno-scc โ€” disable the use of conditional set instructions ๐Ÿšซ.

This switch is mainly for debugging the compiler and will likely be removed in a future version ๐Ÿ™ˆ.

  • -mcond-exec โ€” enable the use of conditional execution (default) ๐ŸŒท.

This switch is mainly for debugging the compiler and will likely be removed in a future version ๐Ÿ™ˆ.

  • -mno-cond-exec โ€” disable the use of conditional execution ๐Ÿšซ.

This switch is mainly for debugging the compiler and will likely be removed in a future version ๐Ÿ™ˆ.

  • -mvliw-branch โ€” ๐Ÿ’– Turns on the pass that packs branches into VLIW instructions. This one's the default โœจ. It's mainly a compiler-debugging switch and will likely get removed in a future version ๐Ÿ™ˆ.
  • -mno-vliw-branch โ€” ๐Ÿšซ Skips that branch-packing pass entirely. Same deal: debugging-only, and it'll probably be yeeted later.
  • -mmulti-cond-exec โ€” ๐Ÿ”ฅ Enables optimization of "&&" and "||" in conditional execution (default). Debugging-only, likely removed down the road.
  • -mno-multi-cond-exec โ€” ๐Ÿ™… Turns that "&&" and "||" conditional execution optimization off. Also mostly for debugging, and likely to be removed.
  • -mnested-cond-exec โ€” ๐ŸŒˆ Enables nested conditional execution optimizations (default). Debugging-only, and it'll likely be removed later.
  • -mno-nested-cond-exec โ€” ๐Ÿซถ Disables those nested conditional execution optimizations. Also debugging-only and likely to be removed.
  • -moptimize-membar โ€” โœจ Removes redundant "membar" instructions from the compiler-generated code. It's on by default, so you get the cleanup for free ๐Ÿ’….
  • -mno-optimize-membar โ€” ๐Ÿ™ˆ Stops the automatic removal of redundant "membar" instructions, so they stay in 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 so these -m options only exist 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, and it's giving main character energy.
    • When compiling, it turns on -mbionic, -fPIC, -fno-exceptions and -fno-rtti by default.
    • When linking, the GCC driver passes 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 -mbionic, -fPIC, -fno-exceptions and -fno-rtti won't be enabled by default.
  • -tno-android-ld โ€” ๐Ÿ”— Turns off the linking effects of -mandroid, so the linker just gets standard Linux linking options.

๐ŸŒธ H8/300 Options ๐ŸŒธ

these -m options are defined for the H8/300 implementations, bestie ๐Ÿ“

  • -mrelax โ€” โฉ Shortens some address references at link time when it's possible. It uses the linker option -relax to do it.
  • -mh โ€” ๐Ÿ’… Generates code for the H8/300H.
  • -ms โ€” ๐Ÿ’– Generates code for the H8S.
  • -mn โ€” ๐ŸŒ™ Generates code for the H8S and H8/300H in the normal mode. This one has to be used with either -mh or -ms.
  • -ms2600 โ€” ๐Ÿฆ‹ Generates code for the H8S/2600. This one 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, and 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, and this option is only valid for H8S targets.
  • -mint32 โ€” ๐Ÿ”ข Makes "int" data 32 bits by default.
  • -malign-300 โ€” ๐Ÿ“ On the H8/300H and H8S, it 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 moves them to 2-byte boundaries. It has no effect on the H8/300.

๐Ÿ’œ HPPA Options ๐Ÿ’œ

these -m options are defined for the HPPA family of computers, and there's a lot of them, so grab a snack ๐Ÿฟ

  • -march=architecture-type โ€” ๐Ÿ›๏ธ Generates code for the architecture you pick. The choices are 1.0 for PA 1.0, 1.1 for PA 1.1, and 2.0 for PA 2.0 processors. To find the right one for your machine on an HP-UX system, check out /usr/lib/sched.models. 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, in that order.
  • -mcaller-copies โ€” ๐Ÿ“ฆ The caller copies function arguments that get passed by hidden reference. Use this one with care, because it's not compatible with the default 32-bit runtime.
Heads up, bestie: this one isn't compatible with the default 32-bit runtime, so use it carefully. Only aggregates bigger than eight bytes get passed by hidden reference, though, and the option gives you better compatibility with OpenMP ๐Ÿซถ.
  • -mjump-in-delay โ€” ๐Ÿ—ฟ This option gets ignored. It's only here for compatibility purposes.
  • -mdisable-fpregs โ€” ๐Ÿšซ Stops floating-point registers from being used in any way. This is necessary for compiling kernels that do lazy context switching of floating-point registers.
Danger zone! If you use this option and then try to do floating-point operations, the compiler aborts ๐Ÿ’€.
  • -mdisable-indexing โ€” ๐Ÿ™… Stops the compiler from using indexing address modes. This sidesteps some pretty obscure problems when compiling MIG generated code under MACH.
  • -mno-space-regs โ€” ๐Ÿš€ Generates code that assumes the target has no space registers. This lets GCC generate faster indirect calls and use unscaled index address modes. This kind of code is suitable for level 0 PA systems and kernels.
  • -mfast-indirect-calls โ€” โšก Generates code that assumes calls never cross space boundaries, so GCC can emit code that does faster indirect calls.
This one doesn't work if you have shared libraries or nested functions in the picture ๐Ÿ˜ญ.
  • -mfixed-range=register-range โ€” ๐Ÿ“Œ Generates code that treats the given register range as fixed registers. A fixed register is one the register allocator can't use, which is super useful when compiling kernel code. You write a register range as two registers separated by a dash, and you can separate multiple ranges with a comma.
  • -mlong-load-store โ€” ๐Ÿ” Generates 3-instruction load and store sequences, which the HP-UX 10 linker sometimes needs. This is equivalent to the +k option on the HP compilers.
  • -mportable-runtime โ€” ๐Ÿงณ Uses the portable calling conventions HP proposed for ELF systems.
  • -mgas โ€” ๐Ÿงฉ Enables assembler directives that only GAS understands.
  • -mschedule=cpu-type โ€” ๐Ÿ—“๏ธ Schedules code according to the constraints for the machine type cpu-type. The choices are 700 7100, 7100LC, 7200, 7300 and 8000. Check /usr/lib/sched.models on an HP-UX system to find the right scheduling option for your machine. The default scheduling is 8000.
  • -mlinker-opt โ€” ๐Ÿ”ง Enables the optimization pass in the HP-UX linker.
Big warning, bestie: this makes symbolic debugging impossible ๐Ÿ™ˆ. It also triggers a bug in the HP-UX 8 and HP-UX 9 linkers, where they give bogus error messages when linking some programs.
  • -msoft-float โ€” ๐Ÿงฎ Generates output that contains library calls for floating point.
Heads up! The required libraries aren't available for all HPPA targets. Normally the facilities of the machine's usual C compiler get used, but that can't be done directly in cross-compilation. You'll have to make your own arrangements to provide suitable library functions for cross-compilation ๐Ÿ˜ฌ.
  • -msoft-float changes the calling convention in the output file, so it's only useful if you compile your whole program with this option.
  • You also need to compile libgcc.a, the library that comes with GCC, with -msoft-float for this to work.
  • -msio โ€” ๐Ÿ–ฅ๏ธ Generates the predefine "_SIO" for server IO. The default is -mwsio, which generates the predefines "__hp9000s700", "__hp9000s700__" and "_WSIO" for workstation IO. These options are available under HP-UX and HI-UX.
  • -mgnu-ld โ€” ๐Ÿฃ Uses options specific to GNU ld. This passes -shared to ld when building a shared library. It's the default when GCC is configured, explicitly or implicitly, with the GNU linker. This option doesn't affect which ld gets called. It only changes which parameters get passed to that ld. The ld that gets called is determined by the --with-ld configure option, GCC's program search path, and finally by the user's PATH. You can print the linker GCC uses with which gcc -print-prog-name=ld. This option is only available on the 64-bit HP-UX GCC, i.e. configured with hppa*64*-*-hpux*.
  • -mhp-ld โ€” ๐Ÿง Uses options specific to HP ld. This passes -b to ld when building a shared library, and it passes +Accept TypeMismatch to ld on all links. It's the default when GCC is configured, explicitly or implicitly, with the HP linker. Just like -mgnu-ld, it doesn't affect which ld gets called, only the parameters passed to it. The ld that gets called is determined by the --with-ld configure option, GCC's program search path, and finally by the user's PATH. You can print the linker GCC uses with which gcc -print-prog-name=ld. This option is only available on the 64-bit HP-UX GCC, i.e. configured with hppa*64*-*-hpux*.
  • -mlong-calls โ€” ๐Ÿ“ž Generates code that uses long call sequences. This makes sure a call can always reach linker generated stubs. By default, long calls only get generated when the distance from the call site to the beginning of the function or translation unit (depending on the case) goes past a predefined limit set by the branch type being used. The limits for normal calls are 7,600,000 and 240,000 bytes, for the PA 2.0 and PA 1.X architectures respectively. Sibcalls are always limited at 240,000 bytes.
    • Distances get measured from the beginning of functions when you use the -ffunction-sections option, or when you use the -mgas and -mno-portable-runtime options together under HP-UX with the SOM linker.
    • > It's normally not a great idea to use this one, because it degrades performance ๐Ÿ˜”. It may still be useful in large applications, especially when partial linking is used to build the application ๐ŸŒˆ.

The types of long calls you get depend on what your assembler and linker can handle, plus the type of code being generated. Systems that support long absolute calls, and long pic symbol-difference or pc-relative calls, should see a relatively small impact. But on 32-bit ELF systems in pic code, an indirect call gets used, and it's quite long ๐Ÿ˜ญ

  • -munix=unix-std โ€” Generates compiler predefines and picks a startfile for the UNIX standard you choose ๐ŸŒธ The choices are 93, 95 and 98. 93 works on all HP-UX versions. 95 is available on HP-UX 10.10 and later. 98 is available on HP-UX 11.11 and later. The defaults are 93 for HP-UX 10.00, 95 for HP-UX 10.10 through 11.00, and 98 for HP-UX 11.11 and later.

-munix=93 gives you the same predefines as GCC 3.3 and 3.4. -munix=95 adds predefines for "XOPEN_UNIX" and "_XOPEN_SOURCE_EXTENDED", plus the startfile unix95.o. -munix=98 adds predefines for "_XOPEN_UNIX", "_XOPEN_SOURCE_EXTENDED", "_INCLUDE__STDC_A1_SOURCE" and "_INCLUDE_XOPEN_SOURCE_500", plus the startfile unix98.o.

โš ๏ธ bestie, this option changes the interfaces for various library routines, and it also affects how the C library behaves. Be extremely careful with it ๐Ÿ’€

Library code that's meant to work with more than one UNIX standard has to test, set and restore the variable __xpg4_extended_mask as needed. Most GNU software doesn't do this, so... just know that ๐Ÿ™ˆ

  • -nolibdld โ€” Stops the generation of link options that search libdld.sl when -static is used on HP-UX 10 and later ๐Ÿ”—
  • -static โ€” Okay so, the HP-UX version of setlocale in libc depends on libdld.sl, and there's no archive version of libdld.sl. That means that when you use -static, special link options are needed to sort this out ๐Ÿงš

On HP-UX 10 and later, the GCC driver adds the link options it needs to link with libdld.sl whenever -static is used. This makes the resulting binary dynamic. On the 64-bit port, the linkers make dynamic binaries by default anyway. You can use -nolibdld to stop the GCC driver from adding these link options ๐Ÿ’…

  • -threads โ€” Adds multithreading support using the dce thread library under HP-UX. It sets flags for both the preprocessor and the linker ๐Ÿงต

๐Ÿ’– IA-64 Options ๐Ÿ’–

These are the -m options defined for the Intel IA-64 architecture. Let's go ๐Ÿ”ฅ

  • -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 code for the GNU assembler, or doesn't. Using -mgnu-as is the default โœจ
  • -mgnu-ld, -mno-gnu-ld โ€” Generates code for the GNU linker, or doesn't. Using -mgnu-ld is the default ๐Ÿฆ‹
  • -mno-pic โ€” Generates code that doesn't use a global pointer register. The result isn't position independent code, and it violates the IA-64 ABI. Not the vibe ngl ๐Ÿ’€
  • -mvolatile-asm-stop, -mno-volatile-asm-stop โ€” Generates (or doesn't generate) a stop bit right before and right after volatile asm statements ๐Ÿ›‘
  • -mregister-names, -mno-register-names โ€” Generates (or doesn't generate) in, loc, and out register names for the stacked registers. This might make the assembler output more readable ๐Ÿ‘€
  • -mno-sdata, -msdata โ€” Disables (or enables) optimizations that use the small data section. This can be handy for working around optimizer bugs ๐Ÿ› ๏ธ
  • -mconstant-gp โ€” Generates code that uses a single constant global pointer value. This is useful when compiling kernel code ๐Ÿ‘‘
  • -mauto-pic โ€” Generates code that is self-relocatable. This implies -mconstant-gp. It's useful when compiling firmware code ๐Ÿงšโ€โ™€๏ธ
  • -minline-float-divide-min-latency โ€” Generates code for inline divides of floating-point values using the minimum latency algorithm โšก
  • -minline-float-divide-max-throughput โ€” Generates code for inline divides of floating-point values using the maximum throughput algorithm ๐Ÿš€
  • -mno-inline-float-divide โ€” Doesn't generate inline code for divides of floating-point values ๐Ÿ™…โ€โ™€๏ธ
  • -minline-int-divide-min-latency โ€” Generates code for inline divides of integer values using the minimum latency algorithm โšก
  • -minline-int-divide-max-throughput โ€” Generates code for inline divides of integer values using the maximum throughput algorithm ๐Ÿš€
  • -mno-inline-int-divide โ€” Doesn't generate inline code for divides of integer values ๐Ÿ™…โ€โ™€๏ธ
  • -minline-sqrt-min-latency โ€” Generates code for inline square roots using the minimum latency algorithm ๐ŸŒŸ
  • -minline-sqrt-max-throughput โ€” Generates code for inline square roots using the maximum throughput algorithm ๐ŸŒŸ
  • -mno-inline-sqrt โ€” Doesn't generate inline code for sqrt ๐Ÿ™…โ€โ™€๏ธ
  • -mfused-madd, -mno-fused-madd โ€” Does (or doesn't) generate code that uses the fused multiply/add or multiply/subtract instructions. Using these instructions is the default ๐Ÿ”ฅ
  • -mno-dwarf2-asm, -mdwarf2-asm โ€” Doesn't (or does) generate assembler code for the DWARF line number debugging info. This might be useful when you're not using the GNU assembler ๐Ÿ›
  • -mearly-stop-bits, -mno-early-stop-bits โ€” Allows stop bits to be placed earlier than right before the instruction that triggered the stop bit. This can improve instruction scheduling, but it doesn't always ๐Ÿคทโ€โ™€๏ธ
  • -mfixed-range=register-range โ€” Generates code that treats the given register range as fixed registers. A fixed register is one the register allocator can't use. This is useful when compiling kernel code ๐Ÿ”’ A register range is written as two registers separated by a dash, and you can specify multiple register ranges by separating them with a comma.
  • -mtls-size=tls-size โ€” Specifies the bit size of immediate TLS offsets. Valid values are 14, 22, and 64 ๐Ÿ“
  • -mtune=cpu-type โ€” Tunes the instruction scheduling for a particular CPU. Valid values are itanium, itanium1, merced, itanium2, and mckinley ๐ŸŽฏ
  • -milp32, -mlp64 โ€” Generates code for a 32-bit or 64-bit environment. The 32-bit environment sets int, long and pointer to 32 bits. The 64-bit environment sets int to 32 bits and long and pointer to 64 bits. These are HP-UX specific flags ๐ŸŽ€
  • -mno-sched-br-data-spec, -msched-br-data-spec โ€” Disables (or enables) data speculative scheduling before reload. This produces ld.a instructions and the matching check instructions (ld.c / chk.a). The default setting is disabled ๐Ÿง
  • -msched-ar-data-spec, -mno-sched-ar-data-spec โ€” Enables (or disables) data speculative scheduling after reload. This produces ld.a instructions and the matching check instructions (ld.c / chk.a). The default setting is enabled ๐Ÿ’œ
  • -mno-sched-control-spec, -msched-control-spec โ€” Disables (or enables) control speculative scheduling. This feature is only available during region scheduling (i.e. before reload). It produces the ld.s instructions and the matching check instructions chk.s. The default setting is disabled ๐ŸŒ™
  • -msched-br-in-data-spec, -mno-sched-br-in-data-spec โ€” Enables (or disables) speculative scheduling of instructions that depend on the data speculative loads before reload. This only matters when -msched-br-data-spec is enabled. The default setting is enabled ๐Ÿ’…
  • -msched-ar-in-data-spec, -mno-sched-ar-in-data-spec โ€” Enables (or disables) speculative scheduling of instructions that depend on the data speculative loads after reload. This only matters when -msched-ar-data-spec is enabled. The default setting is enabled ๐Ÿ’…
  • -msched-in-control-spec, -mno-sched-in-control-spec โ€” Enables (or disables) speculative scheduling of instructions that depend on the control speculative loads. This only matters when -msched-control-spec is enabled. The default setting is enabled ๐Ÿซถ
  • -mno-sched-prefer-non-data-spec-insns, -msched-prefer-non-data-spec-insns โ€” If enabled, data-speculative instructions only get picked for scheduling when there are no other choices at the moment. This makes data speculation much more conservative. The default setting is disabled ๐Ÿข
  • -mno-sched-prefer-non-control-spec-insns, -msched-prefer-non-control-spec-insns โ€” If enabled, control-speculative instructions only get picked for scheduling when there are no other choices at the moment. This makes control speculation much more conservative. The default setting is disabled ๐Ÿข
  • -mno-sched-count-spec-in-critical-path, -msched-count-spec-in-critical-path โ€” If enabled, speculative dependencies get considered when computing instruction priorities. This makes speculation a bit more conservative. The default setting is disabled ๐Ÿงฎ
  • -msched-spec-ldc โ€” Uses a simple data speculation check. This option is on by default โœ…
  • -msched-control-spec-ldc โ€” Uses a simple check for control speculation. This option is on by default โœ…
  • -msched-stop-bits-after-every-cycle โ€” Places a stop bit after every cycle when scheduling. This option is on by default โœ…
  • -msched-fp-mem-deps-zero-cost โ€” Assumes that floating-point stores and loads aren't likely to cause a conflict when placed into the same instruction group. This option is disabled by default ๐Ÿ™ˆ
  • -msel-sched-dont-check-control-spec โ€” Generates checks for control speculation in selective scheduling. This flag is disabled by default ๐Ÿ™ˆ
  • -msched-max-memory-insns=max-insns โ€” Sets a limit on the number of memory insns per instruction group, giving lower priority to later memory insns that try to schedule in the same instruction group. This is often useful for preventing cache bank conflicts. The default value is 1 ๐Ÿงฑ
  • -msched-max-memory-insns-hard-limit โ€” Makes the limit set by msched-max-memory-insns a hard limit, so no more than that number of memory insns can go in one instruction group. Otherwise the limit is "soft", which means non-memory operations are preferred once the limit is reached, but memory operations can still get scheduled ๐Ÿง 

๐Ÿฆ‹ LM32 Options ๐Ÿฆ‹

These -m options are defined for the LatticeMico32 architecture ๐ŸŒธ

  • -mbarrel-shift-enabled โ€” Enables barrel-shift instructions โœจ

-mdivide-enabled Enable divide and modulus instructions.

Continuing on from the M32C stuff โ€” the rest of the -m options ๐Ÿฆ‹

Okay so this is where the M32C options wrap up ๐Ÿ’… ...

-mdivide-enabled Turns on the divide and modulus instructions โœจ

-mmultiply-enabled Turns on the multiply instructions ๐ŸŒธ

-msign-extend-enabled Turns on the sign extend instructions ๐Ÿซถ

-muser-enabled Turns on user-defined instructions ๐Ÿ‘‘


โœจ M32C Options โœจ

okay bestie, this is the M32C section and it's giving hardware realness ๐Ÿ”ฅ

  • -mcpu=name โ€” picks which CPU you're making code for ๐Ÿ’– name can be r8c (R8C/Tiny series), m16c (M16C, up to /60), m32cm (M16C/80 series), or m32c (M32C/80 series) ๐Ÿ“
  • -msim โ€” tells GCC your program is going to run on the simulator ๐Ÿงš This links in a different runtime library that handles stuff like file I/O.
โš ๏ธ Do NOT use -msim if your code is going on real hardware! You need to bring your own runtime library for whatever I/O you need ๐Ÿ˜ญ
  • -memregs=number โ€” sets how many memory-based pseudo-registers GCC uses while generating code ๐ŸŽ€ These act like real registers, so it's a tradeoff: fitting code into registers versus the performance hit from using memory instead ๐Ÿ’œ Every module in your program has to be compiled with the same value, and you can't use this with GCC's default runtime libraries ๐Ÿ™ˆ

โœจ M32R/D Options โœจ

these -m options are 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 that all subroutines are reachable with the "bl" instruction. This is the default โœจ

The addressability of a particular object can be set with the "model" attribute ๐Ÿ’–

  • -mmodel=medium โ€” assumes objects can be anywhere in the 32-bit address space (the compiler generates "seth/add3" instructions to load their addresses) and that all subroutines are reachable with the "bl" instruction ๐ŸŒธ
  • -mmodel=large โ€” assumes objects can be anywhere in the 32-bit address space (the compiler generates "seth/add3" instructions to load their addresses) and that subroutines may not be reachable with the "bl" instruction. The compiler generates the much slower "seth/add3/jl" instruction sequence instead ๐Ÿ’€
  • -msdata=none โ€” disables the small data area ๐Ÿซถ Variables go into one of ".data", ".bss", or ".rodata" (unless the "section" attribute is specified). This is the default.

The small data area is made of the ".sdata" and ".sbss" sections. Objects can be explicitly put in the small data area with the "section" attribute using one of those sections ๐Ÿงš

  • -msdata=sdata โ€” puts small global and static data in the small data area, but doesn't generate special code to reference them ๐ŸŽ€
  • -msdata=use โ€” puts small global and static data in the small data area and generates special instructions to reference them ๐Ÿ”ฅ
  • -G num โ€” puts global and static objects less than or equal to num bytes into the small data or BSS sections instead of the normal data or BSS sections ๐Ÿ‘‘ The default value of num is 8. The -msdata option has to be set to sdata or use for this to do anything.

All modules should be compiled with the same -G num value ๐Ÿซถ Mixing different values of num may or may not work. If it doesn't, the linker gives an error message, so incorrect code is not generated ๐Ÿ™Œ

  • -mdebug โ€” makes the M32R-specific code in the compiler display some statistics that might help you debug programs ๐Ÿ”
  • -malign-loops โ€” aligns all loops to a 32-byte boundary ๐ŸŒˆ
  • -mno-align-loops โ€” doesn't enforce 32-byte alignment for loops. This is the default ๐Ÿ’…
  • -missue-rate=number โ€” issues number instructions per cycle. number can only be 1 or 2 โญ
  • -mbranch-cost=number โ€” number can only be 1 or 2. If it's 1, branches are preferred over conditional code. If it's 2, the opposite applies ๐Ÿฆ‹
  • -mflush-trap=number โ€” specifies the trap number used to flush the cache. The default is 12. Valid numbers are between 0 and 15 inclusive ๐Ÿ’œ
  • -mno-flush-trap โ€” specifies that the cache cannot be flushed by using a trap ๐Ÿฅ€
  • -mflush-func=name โ€” specifies the name of the operating system function to call to flush the cache. The default is _flush_cache, but a function call is only used if a trap isn't available ๐ŸŒธ
  • -mno-flush-func โ€” indicates there's no OS function for flushing the cache ๐Ÿ’€

โœจ M680x0 Options โœจ

these are the -m options for M680x0 and ColdFire processors ๐Ÿงš The default settings 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 valid values of arch are 68000, 68010, 68020, 68030, 68040, 68060 and cpu32. ColdFire architectures are picked using Freescale's ISA classification, and the valid values are isaa, isaaplus, isab and isac โœจ

GCC defines a macro "__mcfarch__" whenever it's generating code for a ColdFire target. The arch in that macro is one of the -march arguments above ๐Ÿซถ

When -march and -mtune are used together, they select code that runs on a family of similar processors but is optimized for one particular microarchitecture ๐ŸŒˆ

  • -mcpu=cpu โ€” generates code for a specific M680x0 or ColdFire processor. The M680x0 CPUs are 68000, 68010, 68020, 68030, 68040, 68060, 68302, 68332 and cpu32. 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. Other combinations of -mcpu and -march get rejected ๐Ÿ˜ญ

GCC defines the macro "__mcf_cpu_cpu" when a ColdFire target CPU is selected. It also defines "__mcf_family_family", where the value of family comes from the table above ๐Ÿ”

  • -mtune=tune โ€” tunes the code for a particular microarchitecture, within the limits set by -march and -mcpu ๐Ÿฆ‹ The M680x0 microarchitectures are 68000, 68010, 68020, 68030, 68040, 68060 and cpu32. The ColdFire microarchitectures are cfv1, cfv2, cfv3, cfv4 and cfv4e ๐Ÿ’œ

You can also use -mtune=68020-40 for code that needs to run relatively well on 68020, 68030 and 68040 targets. -mtune=68020-60 is similar but includes 68060 targets too. 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 -ansi or a non-GNU -std option is used. If GCC is tuning for a range of architectures, selected by -mtune=68020-40 or -mtune=68020-60, it defines the macros for every architecture in the range ๐Ÿงš

GCC also defines the macro "__muarch__" when tuning for ColdFire microarchitecture uarch, where uarch is one of the arguments above ๐Ÿ‘‘

  • -m68000 / -mc68000 โ€” generates output for a 68000. This is the default when the compiler is configured for 68000-based systems. It's equivalent to -march=68000 ๐Ÿ’…

Use this for microcontrollers with a 68000 or EC000 core, including the 68008, 68302, 68306, 68307, 68322, 68328 and 68356 ๐Ÿซถ

  • -m68010 โ€” generates output for a 68010. This is the default when the compiler is configured for 68010-based systems. It's equivalent to -march=68010 ๐ŸŒˆ
  • -m68020 / -mc68020 โ€” generates output for a 68020. This is the default when the compiler is configured for 68020-based systems. It's equivalent to -march=68020 โœจ
  • -m68030 โ€” generates output for a 68030. This is the default when the compiler is configured for 68030-based systems. It's equivalent to -march=68030 ๐Ÿ“
  • -m68040 โ€” generates output for a 68040. This is the default when the compiler is configured for 68040-based systems. It's equivalent to -march=68040 ๐Ÿ”ฅ

This option stops the use of 68881/68882 instructions that would have to be emulated in software on the 68040. Use it if your 68040 doesn't have code to emulate those instructions ๐Ÿ’€

  • -m68060 โ€” generates output for a 68060. This is the default when the compiler is configured for 68060-based systems. It's equivalent to -march=68060 ๐Ÿ‘‘

This option stops the use of 68020 and 68881/68882 instructions that 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 for microcontrollers with a CPU32 or CPU32+ core, including the 68330, 68331, 68332, 68333, 68334, 68336, 68340, 68341, 68349 and 68360 ๐Ÿฆ‹

  • -m5200 โ€” generates output for a 520X ColdFire CPU. This is the default when the compiler is configured for 520X-based systems. It's equivalent to -mcpu=5206, and is now deprecated in favor of that option ๐Ÿ’€

Use this for microcontrollers with a 5200 core, including the MCF5202, MCF5203, MCF5204 and MCF5206 ๐Ÿ’œ

  • -m5206e โ€” generates output for a 5206e ColdFire CPU. This option is now deprecated in favor of the equivalent -mcpu=5206e โš ๏ธ

okay bestie, the M680x0 options are still going strong ๐Ÿ’…

  • -m528x โ€” generates output for a member of the ColdFire 528X family ๐ŸŒธ It's deprecated now, so just use the equivalent -mcpu=528x instead ๐Ÿซถ
  • -m5307 โ€” generates output for a ColdFire 5307 CPU ๐Ÿฆ‹ Also deprecated, so -mcpu=5307 is the move ๐Ÿ’–
  • -m5407 โ€” generates output for a ColdFire 5407 CPU โœจ Deprecated too, so go with -mcpu=5407 ๐ŸŽ€
  • -mcfv4e โ€” for a ColdFire V4e family CPU, think 547x/548x ๐Ÿ”ฅ This one includes hardware floating-point instructions. It's the same as -mcpu=547x, and it's deprecated in favor of that option ๐Ÿ’€
  • -m68020-40 โ€” generates output for a 68040, but without any of the new instructions ๐Ÿงš The result runs pretty efficiently on a 68020/68881, a 68030, or a 68040. The generated code does use the 68881 instructions, which are emulated on the 68040. It's equivalent to -march=68020 -mtune=68020-40 ๐ŸŒˆ
  • -m68020-60 โ€” same energy, but for a 68060 ๐Ÿ’œ No new instructions, and it still runs relatively efficiently on a 68020/68881, a 68030, or a 68040. The generated code does use the 68881 instructions, which are emulated on the 68060. It's equivalent to -march=68020 -mtune=68020-60 โœจ
  • -mhard-float, -m68881 โ€” turns on floating-point instructions ๐ŸŒŠ This is the default for 68020 and up, and for ColdFire devices that have an FPU. It defines the macro "__HAVE_68881__" on M680x0 targets and "__mcffpu__" on ColdFire targets.
  • -msoft-float โ€” no floating-point instructions, just library calls instead ๐Ÿซ  This is the default for 68000, 68010, and 68832 targets. It's also the default for ColdFire devices with no FPU.
  • -mdiv, -mno-div โ€” generates (or doesn't generate) the 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 is taken from the target CPU, either the default CPU or whichever one -mcpu picks. For example, it's "off" for -mcpu=5206 and "on" for -mcpu=5206e. GCC defines the macro "__mcfhwdiv__" when this option is enabled.
  • -mshort โ€” makes type int 16 bits wide, just like short int ๐Ÿ“ Parameters passed on the stack also get aligned to a 16-bit boundary, even on targets whose API mandates promotion to 32-bit.
  • -mno-short โ€” don't make int 16 bits wide. This is the default ๐Ÿ’…
  • -mnobitfield, -mno-bitfield โ€” no bit-field instructions ๐Ÿšซ The -m68000, -mcpu32 and -m5200 options imply -mnobitfield.
  • -mbitfield โ€” yes to 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 it returns. That saves one instruction in the caller, since there's no need to pop the arguments there. This calling convention is incompatible with the one normally used on Unix, so you can't use it if you need to call libraries compiled with the Unix compiler.
Warning, bestie: you must provide function prototypes for all functions that take variable numbers of arguments (including "printf"), or incorrect code gets generated for calls to those functions. Seriously incorrect code also results if you call a function with too many arguments. Normally, extra arguments are harmlessly ignored, but not here ๐Ÿ’€

The "rtd" instruction is supported by the 68010, 68020, 68030, 68040, 68060 and CPU32 processors, but not by the 68000 or 5200. The default is -mno-rtd.

  • -malign-int, -mno-align-int โ€” controls whether GCC aligns "int", "long", "long long", "float", "double", and "long double" variables on a 32-bit boundary (-malign-int) or a 16-bit boundary (-mno-align-int) ๐Ÿ“ Aligning on 32-bit boundaries makes code run somewhat faster on processors with 32-bit busses, but it costs more memory.
Warning: if you use the -malign-int switch, GCC aligns structures containing the above types differently than most published application binary interface specifications for the m68k. Be careful with that one ๐Ÿ™ˆ

Use the pc-relative addressing mode of the 68000 directly, instead of using a global offset table. At present, this option implies -fpic, allowing at most a 16-bit offset for pc-relative addressing. -fPIC is not presently supported with -mpcrel, though this could be supported for 68020 and higher processors.

  • -mno-strict-align, -mstrict-align โ€” -mno-strict-align does not assume, and -mstrict-align does assume, that unaligned memory references are handled by the system ๐Ÿคท
  • -msep-data โ€” generates code that lets the data segment live in a different area of memory from the text segment ๐Ÿง  This allows execute-in-place in an environment 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 via the library ID method ๐Ÿ“š This allows execute-in-place and shared libraries in an environment without virtual memory management. It implies -fPIC.
  • -mno-id-shared-library โ€” generates code that doesn't assume ID-based shared libraries are being used. This is the default.
  • -mshared-library-id=n โ€” specifies the identification number of the ID-based shared library being compiled ๐Ÿ”ข Specifying a value of 0 generates more compact code. Specifying other values forces the allocation of that number to the current library, but it's no more space- or time-efficient than omitting this option.
  • -mxgot, -mno-xgot โ€” for ColdFire position-independent code, generates code that works if the GOT has more than 8192 entries ๐ŸŒธ This code is larger and slower than code generated without this option. On M680x0 processors this option isn't needed, since -fPIC does the job.

GCC normally uses a single instruction to load values from the GOT. That's relatively efficient, but it only works if the GOT is smaller than about 64k. Anything larger causes the linker to report an error such as:

relocation truncated to fit: R_68K_GOT16O foobar

If this happens, recompile your code with -mxgot. It should then work with very large GOTs. However, code generated with -mxgot is less efficient, since it takes 4 instructions to fetch the value of a global symbol.

Note that some linkers, including newer versions of the GNU linker, can create multiple GOTs and sort GOT entries. If you have such a linker, you should only need -mxgot when compiling a single object file that accesses more than 8192 GOT entries. Very few do ๐Ÿ™„

These options have no effect unless GCC is generating position-independent code.

  • -mlong-jump-table-offsets โ€” uses 32-bit offsets in switch tables ๐Ÿ“ The default is to use 16-bit offsets.

๐Ÿฆ‹ MCore Options ๐Ÿฆ‹

These are the -m options defined for the Motorola M*Core processors ๐Ÿ’œ

  • -mhardlit, -mno-hardlit โ€” inlines constants into the code stream if it can be done in two instructions or less ๐Ÿ’ช
  • -mdiv, -mno-div โ€” uses the divide instruction. (Enabled by default). โž—
  • -mrelax-immediate, -mno-relax-immediate โ€” allows arbitrary-sized immediates in bit operations ๐ŸŒฟ
  • -mwide-bitfields, -mno-wide-bitfields โ€” always treats bit-fields as "int"-sized ๐Ÿ“
  • -m4byte-functions, -mno-4byte-functions โ€” forces all functions to be aligned to a 4-byte boundary ๐ŸŽ€
  • -mcallgraph-data, -mno-callgraph-data โ€” emits callgraph information ๐Ÿ•ธ๏ธ
  • -mslow-bytes, -mno-slow-bytes โ€” prefers word access when reading byte quantities ๐ŸŒŠ
  • -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 been provided, so it omits the simulator library (libsim.a) from the linker command line ๐Ÿ™…
  • -mstack-increment=size โ€” sets the maximum amount for a single stack increment operation ๐Ÿ“š Large values can speed up programs that contain functions needing a large amount of stack space, but they can also trigger a segmentation fault if the stack is extended too much. The default value is 0x1000.

๐ŸŒˆ MeP Options ๐ŸŒˆ

  • -mabsdiff โ€” enables the "abs" instruction, which is the absolute difference between two registers ๐Ÿงฎ
  • -mall-opts โ€” enables all the optional instructions---average, multiply, divide, bit operations, leading zero, absolute difference, min/max, clip, and saturation โœจ
  • -maverage โ€” enables the "ave" instruction, which computes the average of two registers ๐ŸŒŠ
  • -mbased=n โ€” variables of size n bytes or smaller get placed in the ".based" section by default ๐Ÿฆ‹ Based variables use the $tp register as a base register, and there's a 128-byte limit to the ".based" section.
  • -mbitops โ€” enables the bit operation instructions: bit test ("btstm"), set ("bsetm"), clear ("bclrm"), invert ("bnotm"), and test-and-set ("tas") ๐Ÿ’–
  • -mc=name โ€” selects which section constant data is placed in. name may be tiny, near, or far ๐Ÿ‘
  • -mclip โ€” enables the "clip" instruction ๐Ÿ’ฆ Note that -mclip is not useful unless you also provide -mminmax.
  • -mconfig=name โ€” selects one of the built-in core configurations ๐Ÿงฉ Each MeP chip has one or more modules in it, and each module has a core CPU plus a variety of coprocessors, optional instructions, and peripherals. The "MeP-Integrator" tool, which is not part of GCC, provides these configurations through this option. Using this option is the same as using all the corresponding command-line options. The default configuration is default.
  • -mcop โ€” enables the coprocessor instructions. By default, this is a 32-bit coprocessor ๐Ÿค– Note that the coprocessor is normally enabled via the -mconfig= option.
  • -mcop32 โ€” enables the 32-bit coprocessor's instructions ๐Ÿค–
  • -mcop64 โ€” enables the 64-bit coprocessor's instructions ๐Ÿš€

๐ŸŽ€ Machine-dependent options continued ๐ŸŽ€

  • -mivc2 โ€” okay so this turns on IVC2 scheduling ๐Ÿ”ฅ. IVC2 is a 64-bit VLIW coprocessor, which is giving very powerful ๐Ÿ’ช
  • -mdc โ€” constant variables get placed in the ".near" section ๐Ÿ“ฆ
  • -mdiv โ€” unlocks the "div" and "divu" instructions โž—
  • -meb โ€” big-endian code, bestie ๐ŸŒธ
  • -mel โ€” little-endian code, bestie ๐Ÿฆ‹
  • -mio-volatile โ€” tells the compiler that any variable with the "io" attribute should be treated as volatile. Main character energy for hardware registers ๐Ÿ‘‘
  • -ml โ€” variables go to the ".far" section by default ๐ŸŒ
  • -mleadz โ€” enables the "leadz" (leading zero) instruction ๐Ÿƒ
  • -mm โ€” variables go to the ".near" section by default ๐Ÿก
  • -mminmax โ€” enables the "min" and "max" instructions ๐Ÿ“
  • -mmult โ€” enables the multiplication and multiply-accumulate instructions โœ–๏ธ
  • -mno-opts โ€” disables all the optional instructions that -mall-opts turns on. Not the vibe if you wanted them ๐Ÿ™…
  • -mrepeat โ€” enables the "repeat" and "erepeat" instructions, which are used for low-overhead looping ๐Ÿ”
  • -ms โ€” every variable defaults to the ".tiny" section ๐Ÿงš. Heads up, there's a 65536-byte limit on this section ๐Ÿ˜ญ. Accesses to these variables use the %gp base register.
  • -msatur โ€” enables the saturation instructions. Ngl, the compiler doesn't generate these on its own right now ๐Ÿ’€. This flag is only here for compatibility with other tools, like "as".
  • -msdram โ€” links the SDRAM-based runtime instead of the default ROM-based one ๐Ÿง 
  • -msim โ€” links the simulator run-time libraries ๐ŸŽฎ
  • -msimnovec โ€” links the simulator runtime libraries, but skips the built-in support for reset and exception vectors and tables ๐Ÿ™ˆ
  • -mtf โ€” all functions default to the ".far" section. Without this flag, functions default to ".near" ๐Ÿ’œ
  • -mtiny=n โ€” variables that are n bytes or smaller get allocated to the ".tiny" section ๐ŸŒท. They use the $gp base register. The default for this option is 4, but the ".tiny" section still has that 65536-byte limit, so don't forget ๐Ÿ˜ญ.

๐Ÿ’– MicroBlaze Options ๐Ÿ’–

  • -msoft-float โ€” software emulation for floating point. This is the default ๐Ÿซถ
  • -mhard-float โ€” uses hardware floating-point instructions โšก
  • -mmemcpy โ€” does not optimize block moves, and uses memcpy instead ๐Ÿ“‹
  • -mno-clearbss โ€” deprecated ๐Ÿฅ€. Use -fno-zero-initialized-in-bss instead.
  • -mcpu=cpu-type โ€” uses features of, and schedules code for, the given CPU โœจ. Supported values follow the format vX.YY.Z, where X is a major version, YY is the minor version, and Z is compatibility code. Example values are v3.00.a, v4.00.b, v5.00.a, v5.00.b, v6.00.a.
  • -mxl-soft-mul โ€” software multiply emulation. This is the default ๐Ÿข
  • -mxl-soft-div โ€” software emulation for divides. Also the default ๐Ÿข
  • -mxl-barrel-shift โ€” uses the hardware barrel shifter ๐Ÿ›ข๏ธ
  • -mxl-pattern-compare โ€” uses pattern compare instructions ๐Ÿ”
  • -msmall-divides โ€” uses a 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, and the default ๐Ÿ . Uses the startup code crt0.o.
    • xmdstub โ€” for use with the Xilinx Microprocessor Debugger (XMD) based software intrusive debug agent called xmdstub ๐Ÿž. This one uses the startup file crt1.o and sets the start address of the program to 0x800.
    • bootstrap โ€” for applications that get loaded 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 back to the bootloader on a processor reset, instead of the application.
    • novectors โ€” for applications that don't need any of the MicroBlaze vectors ๐Ÿšซ. This can be handy 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 get 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 โ€” big-endian code ๐ŸŒธ
  • -EL โ€” little-endian code ๐Ÿฆ‹. This is the default for mips*el-*-* configurations.
  • -march=arch โ€” generates code that runs on arch ๐Ÿš€. This can be the name of a generic MIPS ISA, or the name of a particular processor. The ISA names are mips1, mips2, mips3, mips4, mips32, mips32r2, mips32r3, mips32r5, mips32r6, mips64, mips64r2, mips64r3, mips64r5 and mips64r6. The processor names are 4kc, 4km, 4kp, 4ksc, 4kec, 4kem, 4kep, 4ksd, 5kc, 5kf, 20kc, 24kc, 24kf2_1, 24kf1_1, 24kec, 24kef2_1, 24kef1_1, 34kc, 34kf2_1, 34kf1_1, 34kn, 74kc, 74kf2_1, 74kf1_1, 74kf3_2, 1004kc, 1004kf2_1, 1004kf1_1, i6400, i6500, interaptiv, loongson2e, loongson2f, loongson3a, gs464, gs464e, gs264e, m4k, m14k, m14kc, m14ke, m14kec, m5100, m5101, octeon, octeon+, octeon2, octeon3, orion, p5600, p6600, r2000, r3000, r3900, r4000, r4400, r4600, r4650, r4700, r5900, r6000, r8000, rm7000, rm9000, r10000, r12000, r14000, r16000, sb1, sr71000, vr4100, vr4111, vr4120, vr4130, vr4300, vr5000, vr5400, vr5500, xlr and xlp. The special value from-abi picks the most compatible architecture for the selected ABI. That means mips1 for 32-bit ABIs and mips3 for 64-bit ABIs.

The native Linux/GNU toolchain also supports the value native, which picks the best architecture option for the host processor. -march=native has no effect if GCC doesn't recognize the processor ๐Ÿคท.

In processor names, a final 000 can be abbreviated as k (for example, -march=r2k) โœ‚๏ธ. Prefixes are optional, and vr may be written r.

Names of the form nf2_1 refer to processors with FPUs clocked at half the rate of the core. Names of the form nf1_1 refer to processors with FPUs clocked at the same rate as the core. Names of the form nf3_2 refer to processors with FPUs clocked at a 3:2 ratio with respect to the core. For compatibility reasons, nf is accepted as a synonym for nf2_1, while nx and bfx are accepted as synonyms for nf1_1.

GCC defines two macros based on the value of this option ๐Ÿงฉ. The first is "_MIPS_ARCH", which gives the name of the target architecture as a string. The second has the form "_MIPS_ARCH_foo", where foo is the capitalized value of "_MIPS_ARCH". For example, -march=r2000 sets "_MIPS_ARCH" to "r2000" and defines the macro "_MIPS_ARCH_R2000".

Note that the "_MIPS_ARCH" macro uses the processor names given above. In other words, it has the full prefix and doesn't abbreviate 000 as k. In the case of from-abi, the macro names the resolved architecture (either "mips1" or "mips3"). It names the default architecture when no -march option is given.

  • -mtune=arch โ€” optimizes for arch ๐ŸŽฏ. Among other things, this option controls the way instructions are scheduled, and the perceived cost of arithmetic operations. The list of arch values is the same as for -march.

When this option isn't used, GCC optimizes for the processor specified by -march. By using -march and -mtune together, you can generate code that runs on a whole family of processors, but optimize it for one particular member of that family ๐Ÿ‘‘.

-mtune defines the macros "_MIPS_TUNE" and "_MIPS_TUNE_foo", which work the same way as the -march ones described above ๐Ÿงฉ.

  • -mips1 โ€” equivalent to -march=mips1 โœจ
  • -mips2 โ€” equivalent to -march=mips2 โœจ
  • -mips3 โ€” equivalent to -march=mips3 โœจ
  • -mips4 โ€” equivalent to -march=mips4 โœจ
  • -mips32 โ€” equivalent to -march=mips32 โœจ
  • -mips32r3 โ€” equivalent to -march=mips32r3 โœจ
  • -mips32r5 โ€” equivalent to -march=mips32r5 โœจ
  • -mips32r6 โ€” equivalent to -march=mips32r6 โœจ
  • -mips64 โ€” equivalent to -march=mips64 โœจ
  • -mips64r2 โ€” equivalent to -march=mips64r2 โœจ
  • -mips64r3 โ€” equivalent to -march=mips64r3 โœจ
  • -mips64r5 โ€” equivalent to -march=mips64r5 โœจ
  • -mips64r6 โ€” equivalent to -march=mips64r6 โœจ
  • -mips16, -mno-mips16 โ€” generates (or doesn't generate) MIPS16 code ๐Ÿงƒ. If GCC is targeting a MIPS32 or MIPS64 architecture, it makes use of the MIPS16e ASE.

MIPS16 code generation can also be controlled on a per-function basis using the "mips16" and "nomips16" attributes ๐ŸŽ›๏ธ.

  • -mflip-mips16 โ€” generates MIPS16 code on alternating functions ๐Ÿ”€. This option is provided for regression testing of mixed MIPS16/non-MIPS16 code generation. It is not intended for ordinary use when compiling user code, so please don't go using it in your everyday builds ๐Ÿ™….
  • -minterlink-compressed, -mno-interlink-compressed โ€” requires (or doesn't require) that code using the standard (uncompressed) MIPS ISA be link-compatible with MIPS16 and microMIPS code, and vice versa ๐Ÿ”—.

For example, code using the standard ISA encoding can't jump directly to MIPS16 or microMIPS code. It has to either use a call or an indirect jump. So -minterlink-compressed disables direct jumps unless GCC knows the target of the jump isn't compressed.

  • -minterlink-mips16, -mno-interlink-mips16 โ€” aliases of -minterlink-compressed and -mno-interlink-compressed ๐Ÿฅฐ. These options predate the microMIPS ASE and are kept around for backwards compatibility.
  • -mabi=32, -mabi=o64, -mabi=n32, -mabi=64, -mabi=eabi โ€” generates code for the given ABI ๐Ÿ“œ.

The EABI has a 32-bit and a 64-bit variant. GCC normally generates 64-bit code when you pick a 64-bit architecture, but you can use -mgp32 to get 32-bit code instead ๐ŸŒŸ.

For info about the O64 ABI, check out <https://gcc.gnu.org/projects/mipso64-abi.html> ๐Ÿ“–.

Okay so GCC has this fun little variant of the o32 ABI where the floating-point registers are 64 bits wide instead of 32 ๐Ÿฆ‹ You can pick this combo with -mabi=32 -mfp64. It's lowkey picky, though: it relies on the mthc1 and mfhc1 instructions, so it's only supported on MIPS32R2, MIPS32R3 and MIPS32R5 processors ๐Ÿ’œ

The register assignments for arguments and return values stay exactly the same, but each scalar value gets passed in one 64-bit register instead of a pair of 32-bit ones. Scalar floating-point values come back in $f0 alone, not a $f0/$f1 pair ๐ŸŽ€ The call-saved set doesn't change either, so the even-numbered double-precision registers are still the ones that get saved โœจ

Two more o32 variants exist to help you transition from 32-bit to 64-bit registers: FPXX (-mfpxx) and FP64A (-mfp64 -mno-odd-spreg). ๐ŸŒธ

FPXX is giving "works either way" energy. It mandates that all code must execute correctly whether it's running with 32-bit or 64-bit registers. Code can be interlinked with FP32 or FP64, but not both ๐Ÿซถ

FP64A is FP64's chill cousin, except it forbids the use of odd-numbered single-precision registers. Pair it with the "FRE" mode of FPUs in MIPS32R5 processors and FP32 and FP64A code can interlink and run in the same process without switching FPU modes. Iconic ๐Ÿ‘‘

  • -mabicalls, -mno-abicalls โ€” Generate (or skip generating) code that's suitable for SVR4-style dynamic objects. -mabicalls is the default on SVR4-based systems ๐Ÿ’…
  • -mshared, -mno-shared โ€” Generate (or skip generating) 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 options like -fPIC and -fpic say. But as an extension, the GNU toolchain lets executables use absolute accesses for locally-binding symbols. It can also use shorter GP initialization sequences and generate direct calls to locally-defined functions. That mode gets selected by -mno-shared ๐Ÿงš

-mno-shared depends on binutils 2.16 or higher, and the objects it makes can only be linked by the GNU linker. Still, it doesn't change the ABI of the final executable. It only affects the ABI of relocatable objects. Using -mno-shared generally makes executables both smaller and quicker ๐Ÿš€ -mshared is the default.

  • -mplt, -mno-plt โ€” Assume (or don't assume) that the static and dynamic linkers support PLTs and copy relocations. This option only affects -mno-shared -mabicalls. For the n64 ABI, it does nothing without -msym32 ๐Ÿ™ˆ

You can make -mplt the default by configuring GCC with --with-mips-plt. Otherwise the default is -mno-plt.

  • -mxgot, -mno-xgot โ€” Lift (or don't lift) the usual restrictions on the size of the global offset table (GOT) ๐Ÿ’€

GCC normally uses a single instruction to load values from the GOT. It's relatively efficient, but it only works if the GOT is smaller than about 64k. Anything bigger makes the linker throw 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 a bit less efficient, since it takes three instructions to fetch the value of a global symbol ๐Ÿ˜ญ

Some linkers can create multiple GOTs. If you've got one of those, you should only need -mxgot when a single object file accesses more than 64k's worth of GOT entries. Very few linkers do ๐Ÿ“

These options have no effect unless GCC is generating position-independent code.

  • -mgp32 โ€” Assume general-purpose registers are 32 bits wide. ๐ŸŒˆ
  • -mgp64 โ€” Assume general-purpose registers are 64 bits wide. ๐ŸŒˆ
  • -mfp32 โ€” Assume floating-point registers are 32 bits wide. ๐Ÿฆ‹
  • -mfp64 โ€” Assume floating-point registers are 64 bits wide. ๐Ÿฆ‹
  • -mfpxx โ€” Don't assume 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. Do the floating-point math with library calls instead. ๐Ÿงธ
  • -mno-float โ€” Same vibe as -msoft-float, but it also swears the program doesn't do any floating-point operations at all ๐Ÿ™…โ€โ™€๏ธ

-mno-float is only supported by some bare-metal MIPS configurations, where it might pick a special set of libraries that have zero floating-point support. That includes stuff like the floating-point printf formats. If code compiled with -mno-float accidentally has floating-point operations in it, it'll probably fail at link time or run time ๐Ÿ˜ฑ

  • -msingle-float โ€” Assume the floating-point coprocessor only supports single-precision operations. ๐ŸŒธ
  • -mdouble-float โ€” Assume the floating-point coprocessor supports double-precision operations. This is the default ๐Ÿ’–
  • -modd-spreg, -mno-odd-spreg โ€” Enable (or disable) the use of odd-numbered single-precision floating-point registers for the o32 ABI. Enabled by default for processors that are known to support these registers. When using the o32 FPXX ABI, -mno-odd-spreg is set by default ๐ŸŽ€
  • -mabs=2008, -mabs=legacy โ€” These control how special not-a-number (NaN) IEEE 754 floating-point data gets treated by the abs.fmt and neg.fmt machine instructions ๐Ÿง

By default, or when -mabs=legacy is used, the legacy treatment is selected. In this mode, those instructions count as arithmetic, so they get avoided wherever correct operation matters and the input might be a NaN. A longer sequence that manually manipulates the sign bit of the floating-point datum is used instead, unless -ffinite-math-only has also been specified ๐Ÿ™ƒ

-mabs=2008 selects the IEEE 754-2008 treatment. Here those instructions count as non-arithmetic, so they work correctly in every case, including when the input operand is a NaN. That means they're always used for the respective operations ๐ŸŒŸ

  • -mnan=2008, -mnan=legacy โ€” These control the encoding of special not-a-number (NaN) IEEE 754 floating-point data ๐ŸŒˆ

-mnan=legacy selects the legacy encoding. Quiet NaNs (qNaNs) are marked by the first bit of their trailing significand field being 0, and signaling NaNs (sNaNs) are marked by that first bit being 1.

-mnan=2008 selects the IEEE 754-2008 encoding. Now qNaNs have the first bit of their trailing significand field set to 1, and sNaNs have it set to 0.

The default is -mnan=legacy, unless GCC has been 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. When neither option is specified, GCC uses those instructions if the target architecture supports them โšก

-mllsc is handy if the runtime environment can emulate the instructions, and -mno-llsc can be useful when you're compiling for nonstandard ISAs. You can make either one the default by configuring GCC with --with-llsc or --without-llsc, respectively. --with-llsc is the default for some configurations, so check the installation documentation for the deets ๐Ÿ“š

  • -mdsp, -mno-dsp โ€” Use (or don't use) revision 1 of the MIPS DSP ASE. This defines the preprocessor macro __mips_dsp, and it also sets __mips_dsp_rev to 1 ๐Ÿ’…
  • -mdspr2, -mno-dspr2 โ€” Use (or don't use) revision 2 of the MIPS DSP ASE. This defines the preprocessor macros __mips_dsp and __mips_dspr2, and it sets __mips_dsp_rev to 2 ๐Ÿ’…
  • -msmartmips, -mno-smartmips โ€” Use (or don't use) the MIPS SmartMIPS ASE ๐Ÿง 
  • -mpaired-single, -mno-paired-single โ€” Use (or don't use) paired-single floating-point instructions. This option requires hardware floating-point support to be enabled ๐Ÿซถ
  • -mdmx, -mno-mdmx โ€” Use (or don't use) MIPS Digital Media Extension instructions. This only works when generating 64-bit code, and it needs hardware floating-point support enabled ๐ŸŽฌ
  • -mips3d, -mno-mips3d โ€” Use (or don't use) the MIPS-3D ASE. The option -mips3d implies -mpaired-single ๐ŸŒ€
  • -mmicromips, -mno-micromips โ€” Generate (or don't generate) microMIPS code ๐Ÿฆ‹

microMIPS code generation can also be controlled per function, using the "micromips" and "nomicromips" attributes ๐ŸŽ€

  • -mmt, -mno-mt โ€” Use (or don't use) MT Multithreading instructions ๐Ÿงต
  • -mmcu, -mno-mcu โ€” Use (or don't use) the MIPS MCU ASE instructions ๐Ÿ”ง
  • -meva, -mno-eva โ€” Use (or don't use) the MIPS Enhanced Virtual Addressing instructions ๐ŸŒ
  • -mvirt, -mno-virt โ€” Use (or don't use) the MIPS Virtualization (VZ) instructions ๐Ÿ–ฅ๏ธ
  • -mxpa, -mno-xpa โ€” Use (or don't use) the MIPS eXtended Physical Address (XPA) instructions ๐Ÿ“
  • -mcrc, -mno-crc โ€” Use (or don't use) the MIPS Cyclic Redundancy Check (CRC) instructions ๐Ÿ”
  • -mginv, -mno-ginv โ€” Use (or don't use) the MIPS Global INValidate (GINV) instructions ๐Ÿงน
  • -mloongson-mmi, -mno-loongson-mmi โ€” Use (or don't use) the MIPS Loongson MultiMedia extensions Instructions (MMI) ๐ŸŽถ
  • -mloongson-ext, -mno-loongson-ext โ€” Use (or don't use) the MIPS Loongson EXTensions (EXT) instructions ๐Ÿงฉ
  • -mloongson-ext2, -mno-loongson-ext2 โ€” Use (or don't use) the MIPS Loongson EXTensions r2 (EXT2) instructions ๐Ÿงฉ
  • -mlong64 โ€” Force long types to be 64 bits wide. Check out -mlong32 for the lowdown on the default and how the pointer size gets decided ๐Ÿ“
  • -mlong32 โ€” Force long, int, and pointer types to be 32 bits wide ๐Ÿ“

The default size of ints, longs and pointers depends on the ABI. Every supported ABI uses 32-bit ints. The n64 ABI uses 64-bit longs, and so does the 64-bit EABI, but 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 โ€” okay so -msym32 tells GCC to assume every symbol has a 32-bit value, no matter which ABI you picked. -mno-sym32 says nah, don't assume that ๐Ÿ’… It's a total power combo with -mabi=64 and -mno-abicalls because GCC can then write shorter, faster references to symbolic addresses โœจ
  • -G num โ€” puts externally-visible data into a small data section ๐ŸŽ€ as long as that data is no bigger than num bytes. GCC can then access the data more efficiently (see -mgpopt for the deets). The default -G value depends on your configuration ๐ŸŒˆ
  • -mlocal-sdata, -mno-local-sdata โ€” extends the -G behaviour to local data too, like static variables in C. -mlocal-sdata is the default for all configurations. If the linker starts complaining that an app is using too much small data, try rebuilding the less performance-critical parts with -mno-local-sdata. You could also build big libraries with -mno-local-sdata so they leave more room for the main program ๐Ÿซถ
  • -mextern-sdata, -mno-extern-sdata โ€” assumes (or doesn't assume) that externally-defined data lives in a small data section if its size is within the -G limit. -mextern-sdata is the default for all configurations. Heads up bestie ๐Ÿ˜ญ if you compile a module Mod with -mextern-sdata -G num -mgpopt, and Mod references a variable Var that is no bigger than num bytes, you must make sure Var is placed in a small data section. If Var is defined by another module, you must either compile that module with a high-enough -G setting or attach a "section" attribute to Var's definition. If Var is common, you must link the application with a high-enough -G setting. The easiest way to keep all of this happy is to compile and link every module with the same -G option. However, if you're building a library that supports several different small data limits, compile it with the highest supported -G setting and add -mno-extern-sdata so the library stops making assumptions about externally-defined data ๐Ÿงš
  • -mgpopt, -mno-gpopt โ€” uses (or doesn't use) GP-relative accesses for symbols that are known to be in a small data section; see -G, -mlocal-sdata and -mextern-sdata. -mgpopt is the default for all configurations. -mno-gpopt is useful when the $gp register might not hold the value of "_gp". For example, if the code is part of a library that might be used in a boot monitor, programs that call boot monitor routines pass an unknown value in $gp. (In those situations, the boot monitor itself is usually compiled with -G0.) -mno-gpopt implies -mno-local-sdata and -mno-extern-sdata ๐Ÿ’œ

  • -membedded-data, -mno-embedded-data โ€” allocates variables to the read-only data section first if possible, then to the small data section if possible, otherwise to data. It gives slightly slower code than the default, but it cuts down on the RAM needed while running, so it may be preferred for some embedded systems ๐Ÿ“
  • -muninit-const-in-rodata, -mno-uninit-const-in-rodata โ€” puts uninitialized "const" variables in the read-only data section. This only means something when paired with -membedded-data ๐ŸŒธ
  • -mcode-readable=setting โ€” controls whether GCC may generate code that reads from executable sections. There are three possible settings, bestie:
    • -mcode-readable=yes โ€” instructions can freely access executable sections. This is the default setting โœจ
    • -mcode-readable=pcrel โ€” MIPS16 PC-relative load instructions can access executable sections, but other instructions must not. This is useful on 4KSc and 4KSd processors when the code TLBs have the Read Inhibit bit set. It's also useful on processors that can be configured with a dual instruction/data SRAM interface and that, like the M4K, automatically redirect PC-relative loads to the instruction RAM ๐Ÿฆ‹
    • -mcode-readable=no โ€” instructions must not access executable sections. This can be useful on targets configured with a dual instruction/data SRAM interface that (unlike the M4K) do not automatically redirect PC-relative loads to the instruction RAM ๐Ÿ™ˆ
  • -msplit-addresses, -mno-split-addresses โ€” enables (disables) use of the %hi() and %lo() assembler relocation operators. This one has been superseded by -mexplicit-relocs, but it's kept around for backwards compatibility ๐Ÿ•ฐ๏ธ
  • -mexplicit-relocs, -mno-explicit-relocs โ€” uses (doesn't use) assembler relocation operators when dealing with symbolic addresses. The alternative, selected by -mno-explicit-relocs, is to use assembler macros instead. -mexplicit-relocs is the default if GCC was configured to use an assembler that supports relocation operators ๐Ÿ‘‘
  • -mcheck-zero-division, -mno-check-zero-division โ€” traps (or doesn't trap) on integer division by zero. The default is -mcheck-zero-division ๐Ÿ”ฅ
  • -mdivide-traps, -mdivide-breaks โ€” MIPS systems check for division by zero by generating either a conditional trap or a break instruction. Traps give you smaller code, but they're only supported on MIPS II and later. Also, some versions of the Linux kernel have a bug that stops trap from generating the proper signal (SIGFPE). 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 with --with-divide=breaks. Divide-by-zero checks can be completely disabled using -mno-check-zero-division ๐Ÿ’€
  • -mload-store-pairs, -mno-load-store-pairs โ€” enables (disables) an optimization that pairs consecutive load or store instructions to enable load/store bonding. It's enabled by default, but it only takes effect when the selected architecture is known to support bonding ๐Ÿงšโ€โ™€๏ธ
  • -munaligned-access, -mno-unaligned-access โ€” enables (disables) direct unaligned access for MIPS Release 6. MIPSr6 requires load/store unaligned-access support, either by hardware or by trap&emulate. So -mno-unaligned-access may be needed by kernel ๐Ÿซ 
  • -mmemcpy, -mno-memcpy โ€” forces (doesn't force) the use of "memcpy" for non-trivial block moves. The default is -mno-memcpy, which lets GCC inline most constant-sized copies ๐ŸŒˆ
  • -mlong-calls, -mno-long-calls โ€” -mlong-calls disables use of the "jal" instruction, while -mno-long-calls doesn't disable it. Calling functions with "jal" is more efficient, but it requires the caller and callee to be in the same 256 megabyte segment. This option has no effect on abicalls code. The default is -mno-long-calls ๐Ÿ“ž
  • -mmad, -mno-mad โ€” enables (disables) use of the "mad", "madu" and "mul" instructions, as provided by the R4650 ISA ๐Ÿ”ข
  • -mimadd, -mno-imadd โ€” enables (disables) use of the "madd" and "msub" integer instructions. The default is -mimadd on architectures that support "madd" and "msub", except for the 74k architecture, where it was found to generate slower code ๐ŸŒ
  • -mfused-madd, -mno-fused-madd โ€” enables (disables) use of the floating-point multiply-accumulate instructions, when they're available. The default is -mfused-madd โœจ
On the R8000 CPU, when multiply-accumulate instructions are used, the intermediate product is calculated to infinite precision and is not subject to the FCSR Flush to Zero bit. This may be undesirable in some circumstances. On other processors, the result is numerically identical to the equivalent computation using separate multiply, add, subtract and negate instructions.
  • -nocpp โ€” tells the MIPS assembler to not run its preprocessor over user assembler files (with a .s suffix) when assembling them ๐Ÿ™…โ€โ™€๏ธ
  • -mfix-24k, -mno-fix-24k โ€” works around the 24K E48 (lost data on stores during refill) errata. The workarounds are implemented by the assembler rather than by GCC ๐Ÿ› ๏ธ
  • -mfix-r4000, -mno-fix-r4000 โ€” works around certain R4000 CPU errata:
    • A double-word or a variable shift may give an incorrect result if executed immediately after starting an integer division.
    • A double-word or a variable shift may give an incorrect result if executed while an integer multiplication is in progress.
    • An integer division may give an incorrect result if started in a delay slot of a taken branch or a jump.
  • -mfix-r4400, -mno-fix-r4400 โ€” works around certain R4400 CPU errata:
    • A double-word or a variable shift may give an incorrect result if executed immediately after starting an integer division.
  • -mfix-r10000, -mno-fix-r10000 โ€” works around certain R10000 errata:
    • "ll"/"sc" sequences may not behave atomically on revisions prior to 3.0. They may deadlock on revisions 2.6 and earlier.

This option can only be used if the target architecture supports branch-likely instructions. -mfix-r10000 is the default when -march=r10000 is used; -mno-fix-r10000 is the default otherwise ๐ŸŽฏ

  • -mfix-r5900, -mno-fix-r5900 โ€” do not attempt to schedule the preceding instruction into the delay slot of a branch instruction placed at the end of a short loop of six instructions or fewer. Instead, always schedule a nop instruction there. The short loop bug can, under certain conditions, cause loops to execute only once or twice, due to a hardware bug in the R5900 chip. The workaround is implemented by the assembler rather than by GCC ๐Ÿงธ
  • -mfix-rm7000, -mno-fix-rm7000 โ€” works around the RM7000 "dmult"/"dmultu" errata. The workarounds are implemented by the assembler rather than by GCC ๐Ÿ”ง
  • -mfix-vr4120, -mno-fix-vr4120 โ€” works around certain VR4120 errata:
    • "dmultu" does not always produce the correct result.
    • "div" and "ddiv" do not always produce the correct result if one of the operands is negative.

The workarounds for the division errata rely on special functions in libgcc.a. At present, these functions are only provided by the mips64vr*-elf configurations. Other VR4120 errata require a nop to be inserted between certain pairs of instructions. These errata are handled by the assembler, not by GCC itself ๐Ÿฆ„

  • -mfix-vr4130 โ€” okay so this one is a workaround for the VR4130 "mflo"/"mfhi" errata ๐Ÿ’… The fixing happens in the assembler, not GCC, but GCC avoids mflo and mfhi altogether when the VR4130 "macc", "macchi", "dmacc" and "dmacchi" instructions are available instead ๐Ÿฆ‹
  • -mfix-sb1, -mno-fix-sb1 โ€” this works around certain SB-1 CPU core errata โœจ Right now it only patches the SB-1 revision 2 "F1" and "F2" floating-point errata ๐Ÿ”ฅ
  • -mr10k-cache-barrier=setting โ€” this decides whether GCC inserts cache barriers to dodge the side effects of speculation on R10K processors ๐Ÿ™ˆ

Okay, so, like a lot of processors, the R10K tries to guess which way a conditional branch will go and speculatively runs instructions from the "taken" branch ๐Ÿ”ฎ If the guess was wrong, it aborts them later. The catch? On the R10K, even aborted instructions can still have side effects ๐Ÿ’€

This mostly affects kernel stores and, depending on your system, kernel loads ๐ŸŒธ For example, a speculatively-executed store might pull the target memory into cache and mark that cache line as dirty, even if the store gets aborted later. If a DMA operation writes to the same memory before that "dirty" line is flushed, the cached data overwrites the DMA-ed data ๐Ÿ˜ญ For the full story (including other potential problems), check the R10K processor manual.

One workaround is to insert cache barrier instructions before every memory access that might be speculatively executed and might have side effects even if aborted โœจ -mr10k-cache-barrier=setting controls how GCC does this. It assumes that aborted accesses to any byte in the following regions don't have side effects:

  1. the memory occupied by the current function's stack frame;
  2. the memory occupied by an incoming stack argument;
  3. the memory occupied by an object with a link-time-constant address.

It's the kernel's job to make sure speculative accesses to these regions are actually safe ๐Ÿซถ

If your input program has a function declaration like this:

void foo (void);

then the implementation of "foo" has to let "j foo" and "jal foo" be executed speculatively ๐Ÿ‘‘ GCC follows this rule for functions it compiles itself, and it expects non-GCC functions (like hand-written assembly) to do the same ๐Ÿ’–

The option comes in three flavours:

  • -mr10k-cache-barrier=load-store โ€” inserts a cache barrier before a load or store that might be speculatively executed and might have side effects even if aborted ๐Ÿงš
  • -mr10k-cache-barrier=store โ€” inserts a cache barrier only before a store that might be speculatively executed and might have side effects even if aborted ๐Ÿ“
  • -mr10k-cache-barrier=none โ€” turns off cache barrier insertion entirely. This is the default setting ๐Ÿฆ‹
  • -mflush-func=func, -mno-flush-func โ€” picks the function GCC calls to flush the I and D caches, or tells it to call no such function at all ๐ŸŒˆ If you do call one, it has to take the same arguments as the common "_flush_func": the address of the memory range being flushed, the size of that range, and the number 3 (to flush both caches) ๐Ÿ’œ The default depends on the target GCC was configured for, but it's commonly either "_flush_func" or "__cpu_flush" โœจ
  • mbranch-cost=num โ€” sets the cost of branches to roughly num "simple" instructions ๐Ÿ’… Heads up, this is only a heuristic, so it's not guaranteed to give consistent results across releases ๐Ÿ™ˆ A cost of zero just lands you on the default, which is based on -mtune
  • -mbranch-likely, -mno-branch-likely โ€” enables or disables Branch Likely instructions, no matter what the selected architecture defaults to ๐Ÿ”ฅ By default they may be generated if the selected architecture supports them ๐ŸŒธ The exception is MIPS32 and MIPS64, plus processors implementing those architectures. For those, Branch Likely instructions aren't generated by default, because those architectures specifically deprecate their use ๐Ÿ™…โ€โ™€๏ธ
  • -mcompact-branches=never, -mcompact-branches=optimal, -mcompact-branches=always โ€” these control which form of branch gets generated ๐Ÿฆ‹ The default is -mcompact-branches=optimal
    • -mcompact-branches=never โ€” makes sure compact branch instructions are never generated ๐Ÿšซ
    • -mcompact-branches=always โ€” makes sure a compact branch instruction gets generated if one is available. If it isn't, a delay slot form of the branch is used instead ๐Ÿ‘‘
    • -mcompact-branches=optimal โ€” uses a delay slot branch if one is available in the current ISA and the delay slot gets successfully filled. If the delay slot isn't filled, a compact branch is picked if one is available ๐Ÿง 

This option is supported from MIPS Release 6 onwards ๐ŸŽ€

  • -mfp-exceptions, -mno-fp-exceptions โ€” decides whether FP exceptions are enabled ๐Ÿ’– This affects how FP instructions get scheduled on 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, we can use both FP pipes ๐Ÿ”ฅ Otherwise, we can only use one FP pipe ๐Ÿ˜ญ

  • -mvr4130-align, -mno-vr4130-align โ€” the VR4130 pipeline is two-way superscalar, but it can only issue two instructions together if the first one is 8-byte aligned ๐ŸŒธ When this is enabled, GCC aligns pairs of instructions it thinks should run in parallel ๐Ÿงš

This only has an effect when you're optimizing for the VR4130 ๐Ÿฆ‹ It usually makes code faster, but the trade-off is that it makes the code bigger. It's enabled by default at optimization level -O3 ๐Ÿ‘‘

  • -msynci, -mno-synci โ€” enables (or disables) generation of "synci" instructions on architectures that support them โœจ If enabled, the "synci" instructions get generated when "__builtin___clear_cache" is compiled ๐Ÿ”ฎ

This option defaults to -mno-synci, but you can override the default by configuring GCC with --with-synci ๐Ÿ“

For single processor systems, it's generally safe to use "synci" ๐Ÿ’…

Careful, bestie! On many multi-core (SMP) systems, synci doesn't invalidate the instruction caches on all cores, and it may lead to undefined behavior ๐Ÿ’€
  • -mrelax-pic-calls, -mno-relax-pic-calls โ€” tries to turn PIC calls that normally get dispatched via register $25 into direct calls ๐ŸŒˆ This is only possible if the linker can resolve the destination at link time and the destination is within range for a direct call ๐ŸŽ€

-mrelax-pic-calls is the default if GCC was configured to use an assembler and a linker that support the ".reloc" assembly directive, and -mexplicit-relocs is in effect ๐Ÿซถ With -mno-explicit-relocs, this optimization can be done by the assembler and the linker alone, without any help from the compiler ๐Ÿงš

  • -mmcount-ra-address, -mno-mcount-ra-address โ€” emits (or doesn't emit) code that lets "_mcount" modify the calling function's return address ๐Ÿฆ‹ When enabled, this extends the usual "_mcount" interface with a new ra-address parameter. It has type "intptr_t *" and gets passed in register $12 ๐Ÿ’œ "_mcount" can then change the return address by doing both of the following:
    • Returning the new address in register $31.
    • Storing the new address in "*ra-address", if ra-address is nonnull.

The default is -mno-mcount-ra-address ๐Ÿ”ฅ

  • -mframe-header-opt, -mno-frame-header-opt โ€” enables (or disables) frame header optimization in the o32 ABI ๐ŸŒธ With the o32 ABI, calling functions allocate 16 bytes on the stack for the called function to write out register arguments ๐Ÿ“ When this is enabled, the optimization skips allocating the frame header if it can be determined that it's unused โœจ

This optimization is off by default at all optimization levels ๐Ÿ˜ญ

  • -mlxc1-sxc1, -mno-lxc1-sxc1 โ€” when applicable, enables (or disables) the generation of "lwxc1", "swxc1", "ldxc1", "sdxc1" instructions ๐Ÿงš Enabled by default ๐Ÿ’–
  • -mmadd4, -mno-madd4 โ€” when applicable, enables (or disables) the generation of 4-operand "madd.s", "madd.d" and related instructions ๐Ÿ‘‘ Enabled by default ๐Ÿซถ

๐ŸŒˆ MMIX Options ๐ŸŒˆ

These options are defined for the MMIX:

  • -mlibfuncs, -mno-libfuncs โ€” specifies that intrinsic library functions are being compiled, passing all values in registers, no matter the size ๐Ÿ’…
  • -mepsilon, -mno-epsilon โ€” generates floating-point comparison instructions that compare with respect to the "rE" epsilon register ๐Ÿ”ฎ
  • -mabi=mmixware, -mabi=gnu โ€” generates code that passes function parameters and return values that (in the called function) are seen as registers $0 and up ๐Ÿฆ‹ That's different from the GNU ABI, which uses global registers $231 and up โœจ
  • -mzero-extend, -mno-zero-extend โ€” when reading data from memory in sizes shorter than 64 bits, uses (or doesn't use) zero-extending load instructions by default, instead of sign-extending ones ๐ŸŒธ
  • -mknuthdiv, -mno-knuthdiv โ€” makes the result of a division yielding a remainder have the same sign as the divisor ๐Ÿ“ With the default, -mno-knuthdiv, the sign of the remainder follows the sign of the dividend. Both methods are arithmetically valid, though the latter is almost exclusively used ๐Ÿ’œ
  • -mtoplevel-symbols, -mno-toplevel-symbols โ€” prepends (or doesn't prepend) a : to all global symbols, so the assembly code can be used with the "PREFIX" assembly directive ๐Ÿงš
  • -melf โ€” generates an executable in the ELF format, rather than the default mmo format used by the mmix simulator ๐ŸŽ€
  • -mbranch-predict, -mno-branch-predict โ€” uses (or doesn't use) the probable-branch instructions, when static branch prediction indicates a probable branch ๐Ÿ”ฅ
  • -mbase-addresses, -mno-base-addresses โ€” okay so this one decides whether the compiler uses base addresses at all ๐ŸŒธ Turn it on and it generates code that does, turn it off and it doesn't. Using a base address automatically generates a request (the assembler and linker handle it ๐Ÿซถ) 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 it holds. This usually gives you short and fast code โœจ, but the number of different data items you can address is limited, so a program with lots of static data may need -mno-base-addresses ๐Ÿ’…
  • -msingle-exit, -mno-single-exit โ€” forces (or doesn't force) the generated code to have a single exit point in each function ๐Ÿฆ‹

โœจ MN10300 Options โœจ

These -m options are defined for Matsushita MN10300 architectures ๐ŸŒˆ

  • -mmult-bug โ€” generates code that avoids bugs in the multiply instructions for the MN10300 processors. This is the default ๐Ÿ”ฅ
  • -mno-mult-bug โ€” does not generate code to avoid those multiply instruction bugs on the MN10300 processors ๐Ÿ’€
  • -mam33 โ€” generates code using features specific to the AM33 processor ๐Ÿ‘‘
  • -mno-am33 โ€” doesn't 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 name when scheduling instructions ๐ŸŽ€ This doesn't 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 it's only returned in "a0", and trying to call those functions without a prototype throws errors ๐Ÿ˜ญ This option is on by default, so use -mno-return-pointer-on-d0 to turn it off.
  • -mno-crt0 โ€” don't 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 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 the AM33 or later. This is the default โœจ It defines the preprocessor macro __LIW__.
  • -mno-liw โ€” stops the compiler from generating Long Instruction Word instructions. It defines the preprocessor macro __NO_LIW__.
  • -msetlb โ€” lets the compiler generate the SETLB and Lcc instructions if the target is the AM33 or later. This is the default ๐ŸŒธ It defines the preprocessor macro __SETLB__.
  • -mno-setlb โ€” stops the compiler from generating SETLB or Lcc instructions. It defines the preprocessor macro __NO_SETLB__.

โœจ Moxie Options โœจ

  • -meb โ€” generates big-endian code ๐Ÿ“ This is the default for moxie-*-* configurations.
  • -mel โ€” generates little-endian code ๐Ÿ’œ
  • -mmul.x โ€” generates mul.x and umul.x instructions ๐Ÿ’… This is the default for moxiebox-*-* configurations.
  • -mno-crt0 โ€” don't link in the C run-time initialization object file ๐Ÿซถ

โœจ MSP430 Options โœจ

These options are defined for the MSP430 ๐Ÿ’–

  • -masm-hex โ€” forces the assembly output to always use hex constants. Normally these are signed decimals, but this option is there for testsuite and/or aesthetic purposes ๐ŸŽ€
  • -mmcu= โ€” picks the MCU you're targeting ๐Ÿ‘‘ It's used to create a C preprocessor symbol based on the MCU name, converted to upper case and pre- and post-fixed with __. That symbol is then used by the msp430.h header file to select an MCU-specific supplementary header file โœจ
    • It also sets the ISA to use. If the MCU name is one that's known to only support the 430 ISA, that's the one selected. Otherwise the 430X ISA is selected. The generic msp430 MCU name can also be used to select the 430 ISA, and the generic msp430x MCU name selects the 430X ISA.
    • An MCU-specific linker script is added to the linker command line. The script's name is the MCU name with .ld appended, so -mmcu=xxx defines the C preprocessor symbol __XXX__ and makes the linker search for a script called xxx.ld ๐Ÿงš
    • The ISA and hardware multiply support for each MCU is hard-coded into GCC. However, an external devices.csv file can be used to extend device support beyond those hard-coded ones ๐ŸŒˆ
    • GCC searches for devices.csv using the following methods, in the given precedence order, where the first method takes precedence over the second, which takes precedence over the third:
      1. Include path specified with "-I" and "-L": devices.csv will be 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: define the value of the global environment variable MSP430_GCC_INCLUDE_DIR as the full path to the directory containing devices.csv, and GCC will search that directory for it. If devices.csv is found, this directory is also registered as an include path and 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: finally, GCC examines 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 there, the MCU data will be read. Like above, this directory is also registered as an include path and 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 โ€” enables or disables warnings about conflicts between the MCU name given 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 ๐Ÿ™ˆ
  • -mcpu= โ€” specifies the ISA to use. Accepted values are msp430, msp430x and msp430xv2. This option is deprecated ๐Ÿ’€ Use -mmcu= to select the ISA instead.
  • -msim โ€” links to the simulator runtime libraries and linker script ๐Ÿ“ This overrides any scripts that would be selected by -mmcu=.
  • -mlarge โ€” uses large-model addressing (20-bit pointers, 20-bit "size_t") ๐ŸŒธ
  • -msmall โ€” uses small-model addressing (16-bit pointers, 16-bit "size_t") ๐Ÿฆ‹
  • -mrelax โ€” gets passed to the assembler and linker, and lets the linker do certain optimizations that can't happen until the final link โญ
  • -mhwmult= โ€” describes the type of hardware multiply the target supports ๐Ÿ”ฅ Accepted values:
    • none โ€” no hardware multiply
    • 16bit โ€” the original 16-bit-only multiply from early MCUs
    • 32bit โ€” the 16/32-bit multiply from later MCUs
    • f5series โ€” the 16/32-bit multiply from F5-series MCUs
    • auto โ€” tells GCC to deduce the hardware multiply support from the MCU name given by -mmcu. If there's no -mmcu option, or the MCU name isn't recognized, no hardware multiply support is assumed. auto is the default setting โœจ
    • Hardware multiplies are normally performed by calling a library routine, which saves space in the generated code ๐Ÿงธ When compiling at -O3 or higher, though, the hardware multiplier is invoked inline. That makes the code bigger but faster โšก
    • The hardware multiply routines disable interrupts while they run and restore the previous interrupt state when they finish ๐Ÿ’œ That makes them safe to use inside interrupt handlers as well as in normal code.
  • -minrt โ€” enables a minimum runtime environment, meaning no static initializers or constructors ๐Ÿงธ This is intended for memory-constrained devices. The compiler includes special symbols in some objects that tell the linker and runtime which code fragments are required.
  • -mtiny-printf โ€” enables reduced code size printf and puts library functions ๐ŸŽ€
Careful: these tiny implementations are not reentrant, so use them with caution in multi-threaded applications ๐Ÿ˜ฌ
  • Support for streams has been removed, and the string to be printed is always sent to stdout via the write syscall. The string isn't buffered before it's sent to write.
  • This option requires Newlib Nano IO, so GCC must be configured with --enable-newlib-nano-formatted-io.
  • -mmax-inline-shift= โ€” takes an integer between 0 and 64 inclusive, and sets the maximum number of inline shift instructions that should be emitted to perform a shift by a constant amount ๐Ÿ’… When this value needs to be exceeded, an mspabi helper function is used instead. The default value is 4.
    • This only affects cases where a shift by multiple positions can't be completed with a single instruction (e.g. all shifts >1 on the 430 ISA).
    • Shifts of a 32-bit value are at least twice as costly, so the value passed for this option is divided by 2 and the resulting value is used instead ๐Ÿงฎ
  • -mcode-region=, -mdata-region= โ€” these tell the compiler where to place functions and data that don't have one of the "lower", "upper", "either" or "section" attributes ๐Ÿ—บ๏ธ Possible values are "lower", "upper", "either" or "any". The first three behave like the corresponding attribute. The fourth, "any", is the default, and it leaves placement entirely up to the linker script and how it assigns the standard sections (.text, .data, etc.) to the memory regions ๐ŸŒˆ
  • -msilicon-errata= โ€” passes a request to the assembler to enable the fixes for the named silicon errata ๐Ÿฉน
  • -msilicon-errata-warn= โ€” ๐Ÿ› Okay so this one tells the assembler to turn on warning messages for when a silicon errata might need to be applied. Heads up, bestie ๐Ÿซถ
  • -mwarn-devices-csv, -mno-warn-devices-csv โ€” Warns you if devices.csv can't be found or if there's trouble parsing it. It's on by default (default: on) ๐Ÿ’…

๐ŸŒธ NDS32 Options ๐ŸŒธ

These ones are made for NDS32 implementations ๐Ÿฆ‹

  • -mbig-endian โ€” Generates code in big-endian mode ๐ŸŒˆ
  • -mlittle-endian โ€” Generates code in little-endian mode โœจ
  • -mreduced-regs โ€” Uses the reduced-set registers for register allocation ๐ŸŽ€
  • -mfull-regs โ€” Uses the full-set registers for register allocation ๐Ÿ‘‘
  • -mcmov โ€” Generates conditional move instructions ๐Ÿ’–
  • -mno-cmov โ€” Does not generate conditional move instructions ๐Ÿ™ˆ
  • -mext-perf โ€” Generates performance extension instructions ๐Ÿ”ฅ
  • -mno-ext-perf โ€” Does not generate performance extension instructions ๐Ÿ’€
  • -mext-perf2 โ€” Generates performance extension 2 instructions ๐Ÿš€
  • -mno-ext-perf2 โ€” Does not generate performance extension 2 instructions ๐Ÿซ 
  • -mext-string โ€” Generates string extension instructions ๐Ÿงต
  • -mno-ext-string โ€” Does not generate string extension instructions ๐Ÿšซ
  • -mv3push โ€” Generates v3 push25/pop25 instructions ๐Ÿฆ‹
  • -mno-v3push โ€” 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 โ€” Sets the size of each interrupt vector. It has to be either 4 or 16, no in-between ๐Ÿงš
  • -mcache-block-size=num โ€” Sets the size of each cache block. It has to be a power of 2 between 4 and 512 ๐Ÿ’œ
  • -march=arch โ€” Names the target architecture ๐ŸŒธ
  • -mcmodel=code-model โ€” Sets the code model to one of these:
    • small โ€” All the data and read-only data segments have to fit within 512KB of addressing space. The text segment has to fit within 16MB of addressing space โœจ
    • medium โ€” The data segment has to fit within 512KB, but the read-only data segment can stretch across 4GB of addressing space. The text segment should still stay within 16MB of addressing space ๐ŸŒˆ
    • large โ€” All the text and data segments can live anywhere 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 made for the Altera Nios II processor ๐Ÿ’…

  • -G num โ€” Puts global and static objects that are num bytes or smaller into the small data or BSS sections, instead of the normal data or BSS sections. The default value of num is 8 ๐Ÿ“
  • -mgpopt=option, -mgpopt, -mno-gpopt โ€” Generates (or doesn't generate) GP-relative accesses. These are the option names it recognizes:
    • none โ€” No GP-relative accesses at all ๐Ÿ™ˆ
    • local โ€” Generates GP-relative accesses for small data objects that aren't external, weak, or uninitialized common symbols. It also uses GP-relative addressing for objects you've explicitly put in a small data section with a "section" attribute ๐Ÿ’–
    • global โ€” Same as local, but it also generates GP-relative accesses for small data objects that are external, weak, or common. If you go with this one, every part of your program (libraries included) has to be compiled with the same -G setting, so don't skip that ๐Ÿšจ
    • data โ€” Generates GP-relative accesses for all data objects in the program. If you use this, the entire data and BSS segments have to fit in 64K of memory, and you need an appropriate linker script to place 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, the entire text, data, and BSS segments have to fit in 64K of memory, and you need an appropriate linker script to place them within the addressable range of the global pointer ๐Ÿ’€

-mgpopt is the same as -mgpopt=local, and -mno-gpopt is the same as -mgpopt=none โœจ

The default is -mgpopt, except when -fpic or -fPIC is specified to generate position-independent code. Heads up that the Nios II ABI doesn't allow GP-relative accesses from shared libraries ๐Ÿซถ

You might need to set -mno-gpopt explicitly when you're building programs with lots of small data, including big GOT data sections. In that case, the 16-bit offset for GP-relative addressing might not be large enough to reach the whole small data section ๐Ÿงš

  • -mgprel-sec=regexp โ€” Adds section names that can be reached through 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 one doesn't change how -G behaves. The sections you list are added on top of the standard .sdata and .sbss small-data sections that -mgpopt already recognizes ๐Ÿ’œ

  • -mr0rel-sec=regexp โ€” Names the sections that can be accessed through a 16-bit offset from r0, meaning the low 32K or high 32K of the 32-bit address space. It's most useful with "section" attributes on variable declarations and a custom linker script. The regexp is a POSIX Extended Regular Expression ๐ŸŒ™

Unlike GP-relative addressing for small data, zero-based addressing is never generated by default, and standard linker scripts don't use any conventional section names for the low or high areas of memory. So this one is a bit of a special case ๐Ÿฆ‹

  • -mel, -meb โ€” Generates little-endian (default) or big-endian (experimental) code, respectively ๐ŸŒˆ
  • -march=arch โ€” Specifies the name of the target Nios II architecture. GCC uses this name to figure out which kinds of instructions it's allowed to emit when generating assembly code. The permissible names are r1 and r2 ๐Ÿ‘‘

Programs can read the preprocessor macro "__nios2_arch__", which has the value 1 or 2, telling you the targeted ISA level ๐ŸŽ€

  • -mbypass-cache, -mno-bypass-cache โ€” -mbypass-cache forces all load and store instructions to skip the cache by using the I/O variants of those instructions. The default is not to bypass the cache ๐Ÿ’…
  • -mno-cache-volatile, -mcache-volatile โ€” Volatile memory accesses bypass the cache using the I/O variants of the load and store instructions. The default is not to bypass the cache ๐Ÿงต
  • -mno-fast-sw-div, -mfast-sw-div โ€” -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, -mhw-div โ€” Enables or disables the compiler emitting the mul, mulx, and div families of instructions. The default is to emit mul, and not emit div or mulx ๐Ÿ”ฅ
  • -mbmx, -mno-bmx, -mcdx, -mno-cdx โ€” Enables or disables generation of Nios II R2 BMX (bit manipulation) and CDX (code density) instructions. Turning these on also requires -march=r2. Since they're optional extensions to the R2 architecture, the default is not to emit them ๐ŸŒธ
  • -mcustom-insn=N, -mno-custom-insn โ€” Each -mcustom-insn=N enables a custom instruction with encoding N when generating code that uses insn. For example, -mcustom-fadds=253 generates custom instruction 253 for single-precision floating-point add operations, instead of the default behavior of using a library call ๐Ÿฆ‹

These are the supported values of insn. Unless noted otherwise, the floating-point operations are expected to use normal IEEE 754 semantics and map directly to the C operators or the equivalent GCC built-in functions ๐Ÿ’–

โœจ Single-precision floating point โœจ

  • fadds, fsubs, fdivs, fmuls โ€” Binary arithmetic operations โž•
  • fnegs โ€” Unary negation โž–
  • fabss โ€” Unary absolute value ๐Ÿ“
  • fcmpeqs, fcmpges, fcmpgts, fcmples, fcmplts, fcmpnes โ€” Comparison operations โš–๏ธ
  • fmins, fmaxs โ€” Floating-point minimum and maximum. These are only generated if -ffinite-math-only is specified ๐Ÿงš
  • fsqrts โ€” Unary square root operation ๐ŸŒฑ
  • fcoss, fsins, ftans, fatans, fexps, flogs โ€” Floating-point trigonometric and exponential functions. These are only generated if -funsafe-math-optimizations is also specified ๐ŸŒˆ

๐Ÿ’œ Double-precision floating point ๐Ÿ’œ

  • faddd, fsubd, fdivd, fmuld โ€” Binary arithmetic operations โž•
  • fnegd โ€” Unary negation โž–
  • fabsd โ€” Unary absolute value ๐Ÿ“
  • fcmpeqd, fcmpged, fcmpgtd, fcmpled, fcmpltd, fcmpned โ€” Comparison operations โš–๏ธ
  • fmind, fmaxd โ€” Double-precision minimum and maximum. These are only generated if -ffinite-math-only is specified ๐Ÿงš
  • fsqrtd โ€” Unary square root operation ๐ŸŒฑ
  • fcosd, fsind, ftand, fatand, fexpd, flogd โ€” Double-precision trigonometric and exponential functions. These are only generated if -funsafe-math-optimizations is also specified ๐ŸŒˆ

๐Ÿซถ Conversions ๐Ÿซถ

  • fextsd โ€” Converts from single precision to double precision ๐Ÿ“ˆ
  • ftruncds โ€” Converts from double precision to single precision ๐Ÿ“‰
  • fixsi, fixsu, fixdi, fixdu โ€” Converts floating point to signed or unsigned integer types, truncating towards zero ๐Ÿฐ
  • round โ€” Converts single-precision floating point to a signed integer, rounding to the nearest integer and ties away from zero. This corresponds to the __builtin_lroundf function when -fno-math-errno is used ๐ŸŽฏ
  • floatis, floatus, floatid, floatud โ€” Converts signed or unsigned integer types to floating-point types ๐Ÿฆ‹

Okay bestie, the double-precision stuff on Nios II is a whole vibe ๐Ÿ’…โœจ You need all of these transfer instructions for internal registers X and Y before any double-precision floating-point instruction will work ๐Ÿ”ฅ Custom instructions that take two double-precision source operands expect the first operand in the 64-bit register X. The other operand (or the only operand of a unary operation) 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 you back the most significant 32 bits in the destination register, and the other half lands in 32-bit register Y ๐Ÿ’– GCC automatically generates the necessary code sequences to write register X and/or read register Y whenever you use double-precision floating-point instructions, so you literally don't have to do it yourself ๐Ÿซถ

  • fwrx โ€” Writes src1 into the least significant half of X and src2 into the most significant half of X ๐Ÿฆ‹
  • fwry โ€” Writes src1 into Y ๐ŸŒธ
  • frdxhi, frdxlo โ€” Reads the most or least (respectively) significant half of X and stores it in dest ๐Ÿ’œ
  • frdy โ€” Reads the value of Y and stores it into dest โœจ

Also, if you want more local control over when Nios II custom instructions get generated, you can use the target("custom-insn=N") and target("no-custom-insn") function attributes or pragmas ๐ŸŽ€


โœจ -mcustom-fpu-cfg=name โœจ

This option turns on a predefined, named set of custom instruction encodings (see -mcustom-insn above). Right now 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: any custom instruction assignments you give through individual -mcustom-insn= options will override the ones from -mcustom-fpu-cfg=, no matter what order they appear in on the command line ๐Ÿ‘‘

You can also get more local control over picking an FPU configuration with the target("custom-fpu-cfg=name") function attribute or pragma ๐Ÿ’…

The name fph2 is short for Nios II Floating Point Hardware 2 Component ๐ŸŒˆ

๐Ÿ’€ Okay, real talk: 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 suppresses linking with the GCC-provided C runtime startup and termination code, and it's typically used together with -msys-crt0= to specify the location of the alternate startup code the HAL BSP provides ๐Ÿ“
  • -msmallc โ€” Links with a limited version of the C library, -lsmallc, instead of Newlib ๐ŸŒธ
  • -msys-crt0=startfile โ€” startfile is the file name of the startfile (crt0) to use when linking. This option is only useful together with -mhal ๐Ÿ’–
  • -msys-lib=systemlib โ€” systemlib is the library name of the library that provides the low-level system calls the C library needs, like "read" and "write". This is typically used to link with a library provided by a HAL BSP ๐Ÿฆ‹

๐Ÿ’œ Nvidia PTX Options ๐Ÿ’œ

These options are defined for Nvidia PTX ๐Ÿ”ฅ

  • -m64 โ€” Ignored, but kept around for backward compatibility. Only the 64-bit ABI is supported ๐Ÿซถ
  • -misa=ISA-string โ€” Generates code for the specified PTX ISA (e.g. sm_35). ISA strings must be lower-case. Valid ISA strings include sm_30 and sm_35. The default ISA is sm_35 โœจ
  • -mptx=version-string โ€” Generates code for the specified PTX version (e.g. 7.0). Valid version strings include 3.1, 6.0, 6.3, and 7.0. The default PTX version is 6.0, unless a higher minimal version is required for the PTX ISA specified via -misa= ๐ŸŒˆ
  • -mmainkernel โ€” Links in code for a __main kernel. This is for stand-alone execution instead of offloading execution ๐Ÿ‘‘
  • -moptimize โ€” Applies partitioned execution optimizations. This is the default whenever any level of optimization is selected ๐Ÿ’…
  • -msoft-stack โ€” Generates code that doesn't use .local memory directly for stack storage. Instead, a per-warp stack pointer is maintained explicitly. This enables variable-length stack allocation (with variable-length arrays or alloca), and when global memory is used for the underlying storage, it makes it possible to access automatic variables from other threads, or with atomic instructions. This code generation variant is used for OpenMP offloading, but the option is exposed on its own for the purpose of testing the compiler. To generate code suitable for linking into programs using OpenMP offloading, use -mgomp instead ๐Ÿงš
  • -muniform-simt โ€” Switches to a code generation variant that lets all threads in each warp execute, while keeping memory state and side effects 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 use in OpenMP offloading. This enables -msoft-stack and -muniform-simt, and selects the corresponding multilib variant ๐Ÿ’–

๐ŸŒˆ OpenRISC Options ๐ŸŒˆ

These options are defined for OpenRISC ๐Ÿ“

  • -mboard=name โ€” Configures a board-specific runtime. This gets passed to the linker for newlib board library linking. The default is "or1ksim" ๐ŸŽ€
  • -mnewlib โ€” This option is ignored; it's only here for compatibility purposes. It used to select linker and preprocessor options for use with newlib ๐Ÿซถ
  • -msoft-div, -mhard-div โ€” Selects software or hardware divide (l.div, l.divu) instructions. The default is hardware divide ๐Ÿ”ฅ
  • -msoft-mul, -mhard-mul โ€” Selects software or hardware multiply (l.mul, l.muli) instructions. The default is hardware multiply โœจ
  • -msoft-float, -mhard-float โ€” Selects software or hardware for floating point operations. The default is software ๐ŸŒธ
  • -mdouble-float โ€” When -mhard-float is selected, this enables generation of double-precision floating point instructions. By default, functions from libgcc are used to perform double-precision floating point operations ๐Ÿ’œ
  • -munordered-float โ€” When -mhard-float is selected, this enables generation of unordered floating point compare and set flag (lf.sfun*) instructions. By default, functions from libgcc are used to perform unordered floating point compare and set flag operations ๐Ÿงš
  • -mcmov โ€” Enables generation of conditional move (l.cmov) instructions. By default, the equivalent gets generated using set and branch ๐Ÿฆ‹
  • -mror โ€” Enables generation of rotate right (l.ror) instructions. By default, functions from libgcc are used to perform rotate right operations ๐Ÿ‘‘
  • -mrori โ€” Enables generation of rotate right with immediate (l.rori) instructions. By default, functions from libgcc are used to perform rotate right with immediate operations ๐Ÿ’…
  • -msext โ€” Enables generation of sign extension (l.ext*) instructions. By default, memory loads are used to perform sign extension ๐Ÿ“
  • -msfimm โ€” Enables generation of compare and set flag with immediate (l.sf*i) instructions. By default, extra instructions get generated to store the immediate in a register first ๐ŸŽ€
  • -mshftimm โ€” Enables generation of shift with immediate (l.srai, l.srli, l.slli) instructions. By default, extra instructions get generated to store the immediate in a register first ๐Ÿ’–
  • -mcmodel=small โ€” Generates OpenRISC code for the small model: the GOT is limited to 64k. This is the default model ๐ŸŒˆ
  • -mcmodel=large โ€” Generates OpenRISC code for the large model: the GOT may grow up to 4G in size ๐Ÿ‘‘

๐ŸŒธ PDP-11 Options ๐ŸŒธ

These options are defined for the PDP-11 ๐Ÿงš

  • -mfpu โ€” Uses hardware FPP floating point. This is the default. (FIS floating point on the PDP-11/40 is not supported.) Implies -m45 ๐Ÿ’œ
  • -msoft-float โ€” Doesn't use hardware floating point ๐Ÿซถ
  • -mac0 โ€” Returns floating-point results in ac0 (fr0 in Unix assembler syntax) ๐Ÿฆ‹
  • -mno-ac0 โ€” Returns floating-point results in memory. This is the default ๐Ÿ”ฅ
  • -m40 โ€” Generates code for a PDP-11/40. Implies -msoft-float -mno-split ๐Ÿ“
  • -m45 โ€” Generates code for a PDP-11/45. This is the default โœจ
  • -m10 โ€” Generates code for a PDP-11/10. Implies -msoft-float -mno-split ๐ŸŽ€
  • -mint16, -mno-int32 โ€” Uses 16-bit "int". This is the default ๐ŸŒธ
  • -mint32, -mno-int16 โ€” Uses 32-bit "int" ๐Ÿ’–
  • -msplit โ€” The target has split instruction and data space. Implies -m45 ๐Ÿ‘‘
  • -munix-asm โ€” Uses Unix assembler syntax ๐Ÿ’…
  • -mdec-asm โ€” Uses DEC assembler syntax ๐ŸŒˆ
  • -mgnu-asm โ€” Uses GNU assembler syntax. This is the default ๐Ÿงš
  • -mlra โ€” Uses the new LRA register allocator. By default, the old "reload" allocator is used ๐Ÿ’œ

๐ŸŽ€ picoChip Options ๐ŸŽ€

These -m options are defined for picoChip implementations, so if you're on picoChip, these are your extra toys ๐Ÿงš

  • -mae=ae_type โ€” sets the instruction set, register set, and instruction scheduling parameters for array element type ae_type. The supported values are ANY, MUL, and MAC. โœจ
    • -mae=ANY โ€” a completely generic AE type ๐Ÿซถ Code built this way runs on any of the other AE types, but it isn't as efficient as code built for a specific one, and some operations (like multiplication) don't work properly on every AE type.
    • -mae=MUL โ€” the MUL AE type ๐Ÿ‘‘ It's the most useful one for compiled code and the default.
    • -mae=MAC โ€” a DSP-style MAC AE ๐Ÿ’… Code built with this can perform poorly on byte (char) manipulation, since the DSP AE has no hardware support for byte load/stores ๐Ÿ˜ญ
  • -msymbol-as-address โ€” lets the compiler use a symbol name directly as an address in a load/store instruction, skipping the step of loading it into a register first ๐Ÿฆ‹ This usually makes bigger programs that run faster, but the results vary from program to program, so it's a user option instead of being permanently enabled.
  • -mno-inefficient-warnings โ€” turns off warnings about inefficient code ๐Ÿ™ˆ Those can show up when you do byte-level memory operations on the MAC AE type, because MAC has no hardware support for them, so every byte load/store has to be synthesized from word load/stores. The warning is basically telling you to rewrite the code to avoid byte operations, or to target an AE type with the right hardware support. This option silences it.

โœจ PowerPC Options โœจ

These are listed under


โœจ PRU Options โœจ

These command-line options are defined for the PRU target ๐ŸŒˆ

  • -minrt โ€” links with a minimum runtime environment that has no support for static initializers and constructors ๐Ÿ’– Using this can significantly shrink the final ELF binary.
Beware! The compiler could still generate code with static initializers and constructors, so it's on you, the programmer, to make sure your source program doesn't use those features ๐Ÿ’€
  • -mmcu=mcu โ€” picks the PRU MCU variant you want ๐ŸŒธ Check Newlib for the exact list of supported MCUs.
  • -mno-relax โ€” makes GCC pass --no-relax to the linker instead of --relax ๐ŸŽ€
  • -mloop โ€” lets GCC use the LOOP instruction, or not ๐Ÿ” You decide whether it's allowed.
  • -mabi=variant โ€” picks the ABI variant to output code for โญ -mabi=ti gives you the unmodified TI ABI, while -mabi=gnu gives you a GNU variant that plays nicer with certain GCC assumptions. Here are the differences:
    • Function Pointer Size โ€” the TI ABI says function (code) pointers are 16-bit, whereas GNU only supports 32-bit data and code pointers ๐Ÿงš
    • Optional Return Value Pointer โ€” function return values larger than 64 bits get passed using a hidden pointer as the first argument of the function. The TI ABI says that pointer can be NULL if the caller isn't using the returned value. GNU always passes and expects a valid return value pointer.
    • The current -mabi=ti implementation just raises a compile error whenever any of the above code constructs shows up ๐Ÿ˜ญ So the standard C library can't be built, and it gets omitted when linking with -mabi=ti.
    • Relaxation โ€” relaxation is a GNU feature, and for safety reasons it's disabled when using -mabi=ti ๐Ÿซถ The TI toolchain doesn't emit relocations for QBBx instructions, so the GNU linker can't adjust them when shortening adjacent LDI32 pseudo instructions.

โœจ RISC-V Options โœจ

These command-line options are defined for RISC-V targets ๐Ÿฆ‹

  • -mbranch-cost=n โ€” sets the cost of branches to roughly n instructions ๐Ÿ’…
  • -mplt, -mno-plt โ€” when generating PIC code, these decide whether PLTs are allowed or not ๐ŸŒธ They're ignored for non-PIC code. The default is -mplt.
  • -mabi=ABI-string โ€” specifies the integer and floating-point calling convention ๐Ÿ‘‘ An ABI string has two parts: the size of integer types, and the registers used for floating-point types. For example, -march=rv64ifd -mabi=lp64d means long and pointers are 64-bit (which implicitly makes int 32-bit), and floating-point values up to 64 bits wide get passed in F registers. Compare that with -march=rv64ifd -mabi=lp64f, which still lets the compiler generate code that uses the F and D extensions, but only allows floating-point values up to 32 bits long to be passed in registers. Or -march=rv64ifd -mabi=lp64, where no floating-point arguments get passed in registers.
    • The default for this is system dependent, so if you want a specific calling convention, specify one explicitly ๐Ÿซถ
    • The valid calling conventions are: ilp32, ilp32f, ilp32d, lp64, lp64f, and lp64d.
    • Some calling conventions are impossible on some ISAs ๐Ÿ’€ For example, -march=rv32if -mabi=ilp32d is invalid, because the ABI requires 64-bit values to be passed in F registers, but F registers are only 32 bits wide.
    • There's also the ilp32e ABI, which can only be used with the rv32e architecture. It isn't well specified at present and is subject to change โš ๏ธ
  • -mfdiv, -mno-fdiv โ€” do or don't use hardware floating-point divide and square root instructions โœจ This 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 โ€” picks the version of the RISC-V Unprivileged (formerly User-Level) ISA specification your code should conform 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.
    • When -march= isn't specified, the setting from -mcpu gets used ๐Ÿงš
    • If both -march and -mcpu= are left unspecified, the default is system dependent, so users who want specific architecture extensions should specify one explicitly ๐Ÿ’œ
  • -mcpu=processor-string โ€” uses the architecture of, and optimizes output for, the given processor, identified by its particular CPU name โญ The permissible values are: sifive-e20, sifive-e21, sifive-e24, sifive-e31, sifive-e34, sifive-e76, sifive-s21, sifive-s51, sifive-s54, sifive-s76, sifive-u54, and sifive-u74.
  • -mtune=processor-string โ€” optimizes output for the given processor, identified by microarchitecture or particular CPU name ๐ŸŽ€ The permissible values are: rocket, sifive-3-series, sifive-5-series, sifive-7-series, size, and all valid options for -mcpu=.
    • When -mtune= isn't specified, the setting from -mcpu gets used, and the default is rocket if neither is specified ๐Ÿฆ‹
    • The size choice isn't meant for end-users ๐Ÿ™ˆ It's used when -Os is specified. It overrides the instruction cost info provided by -mtune=, but it doesn't override the pipeline info. This helps reduce code size while still giving good performance.
  • -mpreferred-stack-boundary=num โ€” tries to keep the stack boundary aligned to a 2 raised to num byte boundary ๐Ÿงฑ If -mpreferred-stack-boundary isn't specified, the default is 4 (16 bytes or 128-bits).
Warning: If you use this switch, you must build all modules with the same value, including any libraries. That includes the system libraries and startup modules ๐Ÿ˜ญ
  • -msmall-data-limit=n โ€” puts global and static data smaller than n bytes into a special section (on some targets) ๐Ÿ’–
  • -msave-restore, -mno-save-restore โ€” do or don't use smaller but slower prologue and epilogue code that uses library function calls ๐Ÿข The default is to use fast inline prologues and epilogues โšก
  • -mshorten-memrefs, -mno-shorten-memrefs โ€” do or don't try to make more use of compressed load/store instructions ๐Ÿ—œ๏ธ This works by replacing a load/store of base register + large offset with a new load/store of new base + small offset. If the new base gets stored in a compressed register, then the new load/store can be compressed. Right now it only targets 32-bit integer load/stores.
  • -mstrict-align, -mno-strict-align โ€” -mstrict-align means don't generate unaligned memory accesses, and -mno-strict-align means go ahead and generate them ๐Ÿซ  The default depends on whether the processor you're optimizing for supports fast unaligned access or not.
  • -mcmodel=medlow โ€” generates code for the medium-low code model ๐ŸŒ™ The program and its statically defined symbols must lie within a single 2 GiB address range, and must lie between absolute addresses -2 GiB and +2 GiB. Programs can be statically or dynamically linked. This is the default code model ๐Ÿ‘‘
  • -mcmodel=medany โ€” generates code for the medium-any code model ๐ŸŒŽ The program and its statically defined symbols must be within any single 2 GiB address range. Programs can be statically or dynamically linked.
    • Code from the medium-any code model is position-independent, but it isn't guaranteed to function correctly when linked into position-independent executables or libraries ๐Ÿฅบ
  • -mexplicit-relocs, -mno-exlicit-relocs โ€” use or don't use assembler relocation operators when dealing with symbolic addresses ๐Ÿงฉ The alternative is to use assembler macros instead, which may limit optimization.
  • -mrelax, -mno-relax โ€” take advantage of linker relaxations to reduce the number of instructions required to materialize symbol addresses โœ‚๏ธ The default is to take advantage of linker relaxations.

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

Okay so the next few are all about the RISC-V tea, bestie โ˜•โœจ

  • -memit-attribute, -mno-emit-attribute โ€” -memit-attribute tells GCC to emit a RISC-V attribute that records extra info inside your ELF objects ๐Ÿ“ฆ, and -mno-emit-attribute tells it not to. โš ๏ธ This feature needs at least binutils 2.32, so check your toolchain first, bestie!
  • -malign-data=type โ€” this controls how GCC aligns variables and constants that are array, struct, or union types ๐Ÿ’œ. You get two choices: xlen uses the x register width as the alignment value (and it's the default ๐Ÿ‘‘), while natural uses natural alignment.
  • -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-*-* one.
  • -mstack-protector-guard=guard, -mstack-protector-guard-reg=reg, -mstack-protector-guard-offset=offset โ€” these generate stack protection code using a canary at guard ๐Ÿ›ก๏ธ. The supported locations are global for a global canary, or tls for a per-thread canary in the TLS block.

With the tls choice, -mstack-protector-guard-reg=reg and -mstack-protector-guard-offset=offset get to pick the details ๐ŸŽ€. The first says which register to use as the base register for reading the canary, and the second says what offset from that base register to read from. There is no default register or offset, because this is entirely for use within the Linux kernel ๐Ÿง.


๐ŸŒธ RL78 Options ๐ŸŒธ

  • -msim โ€” links in extra target libraries so your code can run inside a simulator ๐Ÿงš.
  • -mmul=none, -mmul=g10, -mmul=g13, -mmul=g14, -mmul=rl78 โ€” this picks the flavour 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 found on RL78/G13 (S2 core) targets. The g14 value uses the multiplication and division instructions supported by RL78/G14 (S3 core) parts. The value rl78 is an alias for g14, and the value mg10 is an alias for none.

In addition, a C preprocessor macro gets defined based on this option ๐ŸŒˆ. The possible values are __RL78_MUL_NONE__, __RL78_MUL_G13__, or __RL78_MUL_G14__.

  • -mcpu=g10, -mcpu=g13, -mcpu=g14, -mcpu=rl78 โ€” this specifies which RL78 core you're targeting ๐Ÿ‘‘. The default is the G14 core, also known as an S3 core or just RL78. The G13 (S2) core has no multiply or divide instructions and uses a hardware peripheral for those jobs instead ๐Ÿ”ง. The G10 (S1) core has no register banks, so it uses a different calling convention ๐Ÿคทโ€โ™€๏ธ.

If you set this option, it also picks which type of hardware multiply support to use ๐Ÿ’–. The exception is if you override it with an explicit -mmul=none on the command line. So -mcpu=g13 enables the G13 hardware multiply peripheral, and -mcpu=g10 disables hardware multiplications altogether ๐Ÿ˜ญ.

Heads up, bestie ๐Ÿ’€: even though the RL78/G14 core is the default target, specifying -mcpu=g14 or -mcpu=rl78 on the command line does change how the toolchain behaves, because it also enables G14 hardware multiply support. If these options aren't on the command line, software multiplication routines get used even though the code targets the RL78 core. This is for backwards compatibility with older toolchains that didn't have hardware multiply and divide support.

In addition, 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're only here for backwards compatibility, so you don't need them in new code, periodt ๐Ÿ’….
  • -mallregs โ€” lets the compiler use all of the available registers ๐ŸŒˆ. By default, registers r24..r31 are reserved for interrupt handlers ๐Ÿ™ˆ. With this option turned on, those registers can be used in ordinary functions too.
  • -m64bit-doubles, -m32bit-doubles โ€” this makes the double data type 64 bits (-m64bit-doubles) or 32 bits (-m32bit-doubles) in size ๐Ÿฆ‹. The default is -m32bit-doubles.
  • -msave-mduc-in-interrupts, -mno-save-mduc-in-interrupts โ€” this says whether interrupt handler functions should preserve the MDUC registers ๐Ÿ›ก๏ธ. You only need it if normal code might use the MDUC registers, for example because it does multiplication and division. The default is to ignore the MDUC registers, because that makes the interrupt handlers faster โšก. The target option -mg13 has 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 ๐Ÿ“. You use them to specify which instructions are available on the processor you're using. The default value of these options is determined when GCC is configured ๐Ÿ”ง. Specifying -mcpu=cpu_type overrides the specification of these options, and we recommend you use -mcpu=cpu_type instead of the options below ๐Ÿ’œ.

  • -mpowerpc-gpopt, -mno-powerpc-gpopt โ€” -mpowerpc-gpopt lets GCC use the optional PowerPC architecture instructions in the General Purpose group, including floating-point square root ๐Ÿงฎ.
  • -mpowerpc-gfxopt, -mno-powerpc-gfxopt โ€” -mpowerpc-gfxopt lets GCC use the optional PowerPC architecture instructions in the Graphics group, including floating-point select ๐ŸŽจ.
  • -mmfcrf, -mno-mfcrf โ€” -mmfcrf lets GCC generate the move from condition register field instruction. That's implemented on the POWER4 processor and other processors that support the PowerPC V2.01 architecture ๐Ÿ”ฅ.
  • -mpopcntb, -mno-popcntb โ€” -mpopcntb lets GCC generate the popcount and double-precision FP reciprocal estimate instruction. That's implemented on the POWER5 processor and other processors that support the PowerPC V2.02 architecture ๐Ÿ’….
  • -mpopcntd, -mno-popcntd โ€” -mpopcntd lets GCC generate the popcount instruction. That's implemented on the POWER7 processor and other processors that support the PowerPC V2.06 architecture ๐Ÿ‘‘.
  • -mfprnd, -mno-fprnd โ€” -mfprnd lets GCC generate the FP round to integer instructions. Those are implemented on the POWER5+ processor and other processors that support the PowerPC V2.03 architecture ๐ŸŒธ.
  • -mcmpb, -mno-cmpb โ€” -mcmpb lets GCC generate the compare bytes instruction. That's implemented on the POWER6 processor and other processors that support the PowerPC V2.05 architecture ๐Ÿฆ‹.
  • -mhard-dfp, -mno-hard-dfp โ€” -mhard-dfp lets GCC generate the decimal floating-point instructions implemented on some POWER processors ๐Ÿงš.
  • -mpowerpc64, -mno-powerpc64 โ€” -mpowerpc64 lets GCC generate the additional 64-bit instructions found in the full PowerPC64 architecture, and it treats GPRs as 64-bit doubleword quantities ๐Ÿ’–. GCC defaults to -mno-powerpc64.
  • -mcpu=cpu_type โ€” this sets the architecture type, register usage, and instruction scheduling parameters for the machine type cpu_type ๐ŸŽ€. The supported values for cpu_type are 401, 403, 405, 405fp, 440, 440fp, 464, 464fp, 476, 476fp, 505, 601, 602, 603, 603e, 604, 604e, 620, 630, 740, 7400, 7450, 750, 801, 821, 823, 860, 970, 8540, a2, e300c2, e300c3, e500mc, e500mc64, e5500, e6500, ec603e, G3, G4, G5, titan, power3, power4, power5, power5+, power6, power6x, power7, power8, power9, power10, powerpc, powerpc64, powerpc64le, rs64, and native ๐ŸŒˆ.

-mcpu=powerpc, -mcpu=powerpc64, and -mcpu=powerpc64le specify pure 32-bit PowerPC (either endian), 64-bit big endian PowerPC, and 64-bit little endian PowerPC architecture machine types ๐Ÿงš. An appropriate, generic processor model is assumed for scheduling purposes.

Specifying native as the cpu type detects and selects the architecture option that matches the host processor of the system doing the compilation ๐Ÿ”.

The other options each specify a specific processor. Code generated under those options runs best on that processor, and may not run at all on others ๐Ÿ™ˆ.

Watch out ๐Ÿ’€: -mcpu=native has no effect if GCC doesn't recognize the processor.

The -mcpu options automatically enable or disable the following options ๐Ÿ”ฅ:

-maltivec  -mfprnd  -mhard-float  -mmfcrf  -mmultiple -mpopcntb
-mpopcntd  -mpowerpc64 -mpowerpc-gpopt  -mpowerpc-gfxopt -mmulhw
-mdlmzb  -mmfpgpr  -mvsx -mcrypto  -mhtm  -mpower8-fusion
-mpower8-vector -mquad-memory  -mquad-memory-atomic  -mfloat128
-mfloat128-hardware -mprefixed -mpcrel -mmma -mrop-protect

The particular options set for any CPU vary between compiler versions, depending on what setting seems to produce optimal code for that CPU ๐Ÿ’…. So they don't necessarily reflect the actual hardware's capabilities. If you want to set an individual option to a particular value, you can specify it after the -mcpu option, like -mcpu=970 -mno-altivec โœจ.

On AIX, the -maltivec and -mpowerpc64 options are not enabled or disabled by the -mcpu option at present, because AIX doesn't have full support for these options ๐Ÿ™ˆ. You can still enable or disable them individually if you're sure it'll work in your environment ๐Ÿซถ.

  • -mtune=cpu_type โ€” this sets the instruction scheduling parameters for the machine type cpu_type, but it doesn't set the architecture type or register usage the way -mcpu=cpu_type does ๐ŸŽถ. The same values for cpu_type are used for -mtune as for -mcpu. If you specify both, the generated code uses the architecture and registers set by -mcpu, but the scheduling parameters set by -mtune ๐Ÿ’œ.
  • -mcmodel=small โ€” generates PowerPC64 code for the small model, where the TOC is limited to 64k ๐ŸŒธ.
  • -mcmodel=medium โ€” generates PowerPC64 code for the medium model, where the TOC and other static data may be up to a total of 4G in size ๐Ÿฆ‹. This is the default for 64-bit Linux ๐Ÿง.
  • -mcmodel=large โ€” generates PowerPC64 code for the large model, where the TOC may be up to 4G in size ๐Ÿ‘‘. Other data and code is only limited by the 64-bit address space โœจ.
  • -maltivec, -mno-altivec โ€” okay so this one is the AltiVec switch ๐Ÿ’… -maltivec makes GCC generate AltiVec code and unlocks built-in functions for more direct access to the AltiVec instruction set โœจ. -mno-altivec says "nah, don't use them" ๐Ÿ™ˆ. You might also need -mabi=altivec to turn on the AltiVec ABI enhancements ๐ŸŽ€

When -maltivec is on, the element order for AltiVec intrinsics like vec_splat, vec_extract, and vec_insert follows the endianness of your target ๐ŸŒˆ Element zero is the leftmost element in a vector register on a big-endian platform, and the rightmost one on a little-endian platform. Main character energy for real ๐Ÿ‘‘

  • -mvrsave, -mno-vrsave โ€” generates VRSAVE instructions when you're making AltiVec code ๐Ÿฆ‹
  • -msecure-plt โ€” this one is lowkey iconic ๐Ÿ”ฅ It lets ld and ld.so build executables and shared libraries with non-executable .plt and .got sections. It's a PowerPC 32-bit SYSV ABI option, so only for that crowd ๐Ÿงš
  • -mbss-plt โ€” the opposite vibe ๐ŸŒธ It generates a BSS .plt section that ld.so fills in, and it needs both the .plt and .got sections to be writable and executable. Also a PowerPC 32-bit SYSV ABI option ๐Ÿ’€
  • -misel, -mno-isel โ€” turns ISEL instruction generation on or off โœจ
  • -mvsx, -mno-vsx โ€” generates code that uses (or skips) vector/scalar (VSX) instructions, and turns on the built-in functions for direct access to the VSX instruction set ๐Ÿ’–
  • -mcrypto, -mno-crypto โ€” enables (or disables) the built-ins 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-ins for the Hardware Transactional Memory (HTM) instructions, also added in version 2.07 of the PowerPC ISA ๐Ÿซถ
  • -mpower8-fusion, -mno-power8-fusion โ€” generates code that keeps some integer operations next to each other, so they can get fused together on POWER8 and later processors ๐Ÿ“ The -mno- version doesn't keep them together.
  • -mpower8-vector, -mno-power8-vector โ€” uses (or doesn't use) the vector and scalar instructions added in version 2.07 of the PowerPC ISA โญ The positive one also unlocks built-ins for more direct access to those vector instructions ๐Ÿ’…
  • -mquad-memory, -mno-quad-memory โ€” uses (or avoids) the non-atomic quad word memory instructions ๐Ÿฆ‹ Heads up: -mquad-memory needs 64-bit mode โš ๏ธ
  • -mquad-memory-atomic, -mno-quad-memory-atomic โ€” same energy, but for the atomic quad word memory instructions ๐ŸŒˆ Also needs 64-bit mode.
  • -mfloat128, -mno-float128 โ€” enables or disables the __float128 keyword for IEEE 128-bit floating point ๐ŸŽ€ You get either software emulation or hardware instructions for it.

You need VSX (-mvsx) enabled to use IEEE 128-bit floating point support, and it's only supported on Linux ๐Ÿง By default, -mfloat128 is on for PowerPC Linux systems using VSX, and off everywhere else.

If you use the ISA 3.0 instruction set (-mpower9-vector or -mcpu=power9) on a 64-bit system, IEEE 128-bit floating point support also turns on generation of ISA 3.0 IEEE 128-bit floating point instructions โœจ Otherwise, if you don't ask for ISA 3.0 instructions, or you're targeting a 32-bit big endian system, IEEE 128-bit floating point gets handled with software emulation ๐Ÿ’€

  • -mfloat128-hardware, -mno-float128-hardware โ€” enables or disables using ISA 3.0 hardware instructions to support the __float128 data type ๐Ÿ”ฅ It's on by default on PowerPC Linux systems using the ISA 3.0 instruction set, and off 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 the code runs on any PowerPC variant. The 64-bit environment sets int to 32 bits and long and pointer to 64 bits, and generates code for PowerPC64, same as -mpowerpc64 ๐Ÿงš
  • -mfull-toc, -mno-fp-in-toc, -mno-sum-in-toc, -mminimal-toc โ€” these all tweak how the TOC (Table Of Contents) gets made, and every executable file has one ๐Ÿ“– -mfull-toc is the default. With it, GCC gives at least one TOC entry to each unique non-automatic variable reference in your program, and also puts floating-point constants in the TOC. The catch is that only 16,384 entries fit in the TOC ๐Ÿ˜ญ

If the linker yells that you've overflowed the TOC space, you can shrink its usage with -mno-fp-in-toc and/or -mno-sum-in-toc ๐Ÿซถ -mno-fp-in-toc keeps floating-point constants out of the TOC, and -mno-sum-in-toc makes GCC calculate the sum of an address and a constant at run time instead of stashing that sum in the TOC. You can use one or both. Each one makes the code very slightly slower and larger, but it saves TOC space.

If you're still out of TOC space even with both of those, try -mminimal-toc ๐Ÿ’œ It makes only one TOC entry per file. Your code gets slower and larger, but it uses extremely little TOC space. Maybe only use it on files with less frequently-executed code.

  • -maix64, -maix32 โ€” -maix64 enables the 64-bit AIX ABI and calling convention, with 64-bit pointers, a 64-bit long type, and the infrastructure to support them ๐ŸŒˆ It implies -mpowerpc64. -maix32 turns the 64-bit ABI off and implies -mno-powerpc64. Just so you know, GCC defaults to -maix32 ๐Ÿ“
  • -mxl-compat, -mno-xl-compat โ€” makes your code match IBM XL compiler semantics more closely when you're using the AIX-compatible ABI ๐ŸŽ€ With it on, floating-point arguments passed to prototyped functions go on the stack past the register save area (RSA), 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 comparing values and converting to double, and uses XL symbol names for the long double support routines.

The AIX calling convention got extended, but that wasn't documented at first, to handle an obscure K&R C case: calling a function that takes the address of its arguments with fewer arguments than it declared ๐Ÿ™ˆ IBM XL compilers read floating-point arguments that don't fit in the RSA from the stack when a subroutine is compiled without optimization. Storing floating-point arguments on the stack is inefficient and rarely needed, so this option is not on by default. Only turn it on when calling subroutines compiled by IBM XL compilers without optimization.

  • -mpe โ€” supports the IBM RS/6000 SP Parallel Environment (PE) ๐Ÿ›ฐ๏ธ It links your message-passing app with special startup code so it can actually run. The system needs PE installed in the standard location (/usr/lpp/ppe.poe/), or you need to override the specs file with the -specs= option to point at the right directory โœจ 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 larger types (like floating-point doubles) and puts them on their natural size-based boundary ๐ŸŒธ -malign-power tells GCC to follow the ABI-specified alignment rules instead. GCC defaults to the standard alignment defined in the ABI.

On 64-bit Darwin, natural alignment is the default, and -malign-power isn't supported there ๐Ÿ’€

  • -msoft-float, -mhard-float โ€” generates code that doesn't use (or does use) the floating-point register set ๐ŸŒˆ If you use -msoft-float, software floating-point emulation is provided, but you have to pass the option to GCC when linking too โš ๏ธ
  • -mmultiple, -mno-multiple โ€” uses (or doesn't use) the load multiple word and store multiple word instructions ๐Ÿงš These are generated by default on POWER systems, but not on PowerPC systems. Don't use -mmultiple on little-endian PowerPC systems, because 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 โ€” uses (or doesn't use) the load or store instructions that update the base register to the address of the calculated memory location ๐Ÿ’– These are generated by default. Heads up on -mno-update: there's a small window between when the stack pointer gets updated and when the address of the previous frame gets stored, so code that walks the stack frame across interrupts or signals might end up with corrupted data โš ๏ธ
  • -mavoid-indexed-addresses, -mno-avoid-indexed-addresses โ€” generates code that tries to avoid (or doesn't avoid) indexed load or store instructions ๐Ÿฆ‹ These can cost performance on Power6 processors in certain situations, like stepping through large arrays that cross a 16M boundary. It's enabled by default when targeting Power6, and disabled otherwise.
  • -mfused-madd, -mno-fused-madd โ€” uses (or doesn't use) the floating-point multiply and accumulate instructions โœจ These are generated by default if hardware floating point is used. The machine-dependent -mfused-madd option is now mapped to the machine-independent -ffp-contract=fast option, and -mno-fused-madd is mapped to -ffp-contract=off ๐Ÿซถ
  • -mmulhw, -mno-mulhw โ€” okay so these turn the half-word multiply and multiply-accumulate instructions on or off ๐Ÿ”ฅ. They're used on the IBM 405, 440, 464 and 476 processors, and they're on by default when you're targeting those chips ๐Ÿ’….
  • -mdlmzb, -mno-dlmzb โ€” this one switches the string-search dlmzb instruction on or off on the IBM 405, 440, 464 and 476 processors โœจ. It's generated by default for those processors too, so you're already getting it ๐Ÿงš.
  • -mno-bit-align, -mbit-align โ€” on System V.4 and embedded PowerPC systems, these decide whether structures and unions with bit-fields get forced to line up with the base type of the bit-field ๐Ÿฆ‹. -mno-bit-align says "nah, don't force it," and -mbit-align says "yes, force it" ๐Ÿ’–.
    • Here's the vibe: by default, a structure with nothing but 8 unsigned bit-fields of length 1 gets aligned to a 4-byte boundary and ends up 4 bytes big ๐Ÿ“. Add -mno-bit-align and that same structure lines up on a 1-byte boundary and is only 1 byte ๐Ÿ˜ญ.
  • -mno-strict-align, -mstrict-align โ€” on System V.4 and embedded PowerPC systems, these decide whether the compiler just trusts the system to handle unaligned memory references ๐Ÿซถ. -mno-strict-align is the "yeah, the system's got it" option, and -mstrict-align is the "don't assume that" option ๐ŸŒธ.
  • -mrelocatable, -mno-relocatable โ€” these control whether a static executable is allowed to get moved to a different address at run time ๐ŸŒˆ. With -mrelocatable, a simple embedded PowerPC loader has to relocate the whole .got2 section and the 4-byte locations listed in the .fixup section, which is a table of 32-bit addresses this option generates ๐Ÿ‘‘. For it to actually work, every object you link together has to be compiled with -mrelocatable or -mrelocatable-lib ๐Ÿ”ฅ. Heads up: -mrelocatable code aligns the stack to an 8-byte boundary ๐Ÿ’€.
  • -mrelocatable-lib, -mno-relocatable-lib โ€” this is basically -mrelocatable with a twist โœจ. It still makes a .fixup section so static executables can be relocated at run time, but it doesn't use the smaller stack alignment that -mrelocatable does ๐Ÿฆ‹. Objects built with -mrelocatable-lib can be linked with objects built with any combo of the -mrelocatable options, so it's super flexible ๐Ÿงš.
  • -mno-toc, -mtoc โ€” on System V.4 and embedded PowerPC systems, these decide whether the compiler assumes register 2 holds a pointer to a global area with the addresses the program uses ๐ŸŽ€. -mno-toc says don't assume it, and -mtoc says go ahead and assume it ๐Ÿ’….
  • -mlittle, -mlittle-endian โ€” on System V.4 and embedded PowerPC systems, this compiles your code for little-endian mode ๐ŸŒธ. -mlittle-endian and -mlittle do the exact same thing, so pick whichever you vibe with ๐Ÿซถ.
  • -mbig, -mbig-endian โ€” same energy as above but for big-endian mode on System V.4 and embedded PowerPC systems ๐Ÿ’œ. -mbig-endian is identical to -mbig โœจ.
  • -mdynamic-no-pic โ€” on Darwin and Mac OS X systems, this compiles code so it isn't relocatable, but its external references still are ๐Ÿ“. The result works for applications but not for shared libraries ๐Ÿ˜ญ.
  • -msingle-pic-base โ€” this treats the register used for PIC addressing as read-only, so it doesn't get loaded in the prologue for every function ๐ŸŒˆ. Instead, the runtime system is in charge of setting that register to the right value before execution starts ๐Ÿ‘‘.
  • -mprioritize-restricted-insns=priority โ€” this controls the priority given to dispatch-slot restricted instructions during the second scheduling pass ๐Ÿ’…. The priority argument takes 0, 1, or 2, which means no priority, highest priority, or second-highest priority for those instructions ๐Ÿ”ฅ.
  • -msched-costly-dep=dependence_type โ€” this picks which dependences the target considers costly during instruction scheduling ๐Ÿงš. The dependence_type argument takes one of these values:
    • no โ€” no dependence is costly ๐Ÿ™ˆ.
    • all โ€” every dependence is costly ๐Ÿ’€.
    • true_store_to_load โ€” a true dependence from store to load is costly ๐Ÿ’œ.
    • store_to_load โ€” any dependence from store to load is costly โœจ.
    • number โ€” any dependence whose latency is greater than or equal to number is costly ๐Ÿฆ‹.
  • -minsert-sched-nops=scheme โ€” this picks which NOP insertion scheme gets used during the second scheduling pass ๐ŸŒธ. The scheme argument takes one of these:
    • no โ€” don't insert NOPs at all ๐Ÿซถ.
    • pad โ€” pad any dispatch group with vacant issue slots using NOPs, based on the scheduler's grouping ๐ŸŽ€.
    • regroup_exact โ€” insert NOPs to force costly dependent insns into separate groups, using exactly as many NOPs as needed to push an insn into a new group, based on the estimated processor grouping ๐Ÿ”ฅ.
    • number โ€” insert NOPs to force costly dependent insns into separate groups, using number NOPs to push an insn into a new group ๐Ÿ’….
  • -mcall-sysv โ€” on System V.4 and embedded PowerPC systems, this compiles code using the calling conventions from the March 1995 draft of the System V Application Binary Interface, PowerPC processor supplement ๐Ÿ‘‘. It's the default unless you configured GCC using powerpc-*-eabiaix ๐ŸŒˆ.
  • -mcall-sysv-eabi, -mcall-eabi โ€” these are shorthand for specifying both -mcall-sysv and -meabi ๐Ÿ’–.
  • -mcall-sysv-noeabi โ€” shorthand for specifying both -mcall-sysv and -mno-eabi ๐Ÿงš.
  • -mcall-aixdesc โ€” on System V.4 and embedded PowerPC systems, this compiles code for the AIX operating system ๐Ÿฆ‹.
  • -mcall-linux โ€” on System V.4 and embedded PowerPC systems, this compiles code for the Linux-based GNU system ๐Ÿง.
  • -mcall-freebsd โ€” on System V.4 and embedded PowerPC systems, this compiles code for the FreeBSD operating system ๐Ÿ˜ˆ.
  • -mcall-netbsd โ€” on System V.4 and embedded PowerPC systems, this compiles code for the NetBSD operating system ๐ŸŒธ.
  • -mcall-openbsd โ€” on System V.4 and embedded PowerPC systems, this compiles code for the OpenBSD operating system ๐Ÿซถ.
  • -mtraceback=traceback_type โ€” this selects the type of traceback table ๐ŸŽ€. Valid values for traceback_type are full, part, and no ๐Ÿ’….
  • -maix-struct-return โ€” returns all structures in memory, as the AIX ABI specifies ๐Ÿ”ฅ.
  • -msvr4-struct-return โ€” returns structures smaller than 8 bytes in registers, as the SVR4 ABI specifies ๐Ÿ‘‘.
  • -mabi=abi-type โ€” this extends the current ABI with a particular extension, or removes one ๐ŸŒˆ. Valid values are altivec, no-altivec, ibmlongdouble, ieeelongdouble, elfv1, elfv2, and, for AIX, vec-extabi and vec-default ๐Ÿ’œ.
  • -mabi=ibmlongdouble โ€” switches the current ABI to IBM extended-precision long double โœจ. This probably won't work if your system defaults to IEEE extended-precision long double ๐Ÿ’€. If you change the long double type away from IEEE extended-precision, the compiler will issue a warning unless you use the -Wno-psabi option ๐Ÿ™ˆ. This one needs -mlong-double-128 enabled ๐Ÿ”ฅ.
  • -mabi=ieeelongdouble โ€” switches the current ABI to IEEE extended-precision long double ๐Ÿฆ‹. This probably won't work if your system defaults to IBM extended-precision long double ๐Ÿ’€. If you change the long double type away from IBM extended-precision, the compiler will issue a warning unless you use the -Wno-psabi option ๐Ÿ™ˆ. This one needs -mlong-double-128 enabled ๐Ÿ”ฅ.
  • -mabi=elfv1 โ€” switches the current ABI to ELFv1 ๐Ÿงš. This is the default ABI for big-endian PowerPC 64-bit Linux ๐Ÿง. Overriding the default ABI needs special system support and is likely to fail in spectacular ways ๐Ÿ’€.
  • -mabi=elfv2 โ€” switches the current ABI to ELFv2 โœจ. This is the default ABI for little-endian PowerPC 64-bit Linux ๐ŸŒธ. Overriding the default ABI needs special system support and is likely to fail in spectacular ways ๐Ÿ’€.
  • -mgnu-attribute, -mno-gnu-attribute โ€” these emit .gnu_attribute assembly directives that set tag/value pairs in a .gnu.attributes section ๐ŸŽ€. Those pairs describe ABI variations in function parameters or return values ๐Ÿ’–.
  • -mprototype, -mno-prototype โ€” on System V.4 and embedded PowerPC systems, -mprototype assumes every call to a variable argument function is properly prototyped ๐Ÿซถ. Without that, the compiler has to insert an instruction before every non-prototyped call to set or clear bit 6 of the condition code register ("CR") ๐Ÿ”ฅ. That bit says whether floating-point values are passed in the floating-point registers, in case the function takes variable arguments ๐Ÿงš. With -mprototype, only calls to prototyped variable argument functions set or clear that bit ๐Ÿ’….
  • -msim โ€” on embedded PowerPC systems, this assumes the startup module is called sim-crt0.o and the standard C libraries are libsim.a and libc.a ๐ŸŒˆ. 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 indicates that eabi extended relocations are used ๐ŸŽ€.
  • -meabi, -mno-eabi โ€” on System V.4 and embedded PowerPC systems, these decide whether you adhere to the Embedded Applications Binary Interface (EABI), a set of modifications to the System V.4 specifications โœจ. Here's the breakdown ๐Ÿซถ:
    • -meabi means 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 means the stack is aligned to a 16-byte boundary ๐Ÿ”ฅ, no EABI initialization function is called from main ๐Ÿ™ˆ, and the -msdata option only uses r13 to point to a single small data area ๐Ÿฆ‹.

The -meabi option is on by default if you configured GCC using one of the powerpc*-*-eabi* options ๐Ÿ’–.

--msdata=eabi โ€” โœจ On System V.4 and embedded PowerPC, small initialized const globals and statics go into the .sdata2 section, which is pointed to by register r2. Small initialized non-const globals and statics go into .sdata, pointed to by register r13. Small uninitialized globals and statics go into .sbss, which sits right next to .sdata. Heads up: -msdata=eabi is incompatible with -mrelocatable, and it also turns on -memb ๐Ÿ’…

  • -msdata=sysv โ€” ๐ŸŒธ On System V.4 and embedded PowerPC, small global and static data goes into .sdata, pointed to by register r13. Small uninitialized globals and statics go into .sbss, which is adjacent to .sdata. Also, -msdata=sysv is incompatible with -mrelocatable ๐Ÿ™ˆ
  • -msdata=default, -msdata โ€” ๐Ÿฆ‹ On System V.4 and embedded PowerPC, if -meabi is used, the code gets compiled the same as -msdata=eabi. Otherwise, it gets compiled the same as -msdata=sysv.
  • -msdata=data โ€” ๐Ÿงš On System V.4 and embedded PowerPC, small global data goes into .sdata, and small uninitialized global data goes into .sbss. The twist is that register r13 is not used to address small data. This is the default unless some other -msdata option is used.
  • -msdata=none, -mno-sdata โ€” ๐Ÿ“ On embedded PowerPC, all initialized global and static data goes into .data, and all uninitialized data goes into .bss.
  • -mreadonly-in-sdata โ€” ๐Ÿ’œ Read-only objects get put into .sdata too. This is the default.
  • -mblock-move-inline-limit=num โ€” ๐Ÿ”ฅ Inline all block moves (like calls to memcpy or structure copies) that are less than or equal to num bytes. The minimum value for num is 32 bytes on 32-bit targets and 64 bytes on 64-bit targets. The default value is target-specific.
  • -mblock-compare-inline-limit=num โ€” ๐Ÿ‘‘ Generate non-looping inline code for all block compares (like calls to memcmp or structure compares) that are less than or equal to num bytes. If num is 0, all inline expansion (both non-loop and loop) of block compare is disabled. The default value is target-specific.
  • -mblock-compare-inline-loop-limit=num โ€” ๐ŸŒˆ Generate an inline expansion using loop code for all block compares that are less than or equal to num bytes, but greater than the limit for non-loop inline block compare expansion. If the block length isn't constant, at most num bytes will be compared before memcmp is called to compare the rest of the block. The default value is target-specific.
  • -mstring-compare-inline-limit=num โ€” โญ Compare at most num string bytes with inline code. If the difference or end of string isn't found at the end of the inline compare, a call to strcmp or strncmp takes care of the rest of the comparison. The default is 64 bytes.
  • -G num โ€” ๐ŸŽ€ On embedded PowerPC, global and static items less than or equal to num bytes go into the small data or BSS sections instead of the normal data or BSS section. By default, num is 8. The -G num switch is also passed to the linker. All modules should be compiled with the same -G num value.
  • -mregnames, -mno-regnames โ€” ๐Ÿซถ On System V.4 and embedded PowerPC, GCC does (or does not) emit register names in the assembly output using symbolic forms.
  • -mlongcall, -mno-longcall โ€” ๐Ÿ˜ญ By default, GCC assumes that all calls are far away, so a longer and more expensive calling sequence is required. This is needed for calls farther than 32 megabytes (33,554,432 bytes) from the current location. A short call is 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 detect out-of-range calls and generate glue code on the fly. On these systems, long calls are unnecessary and generate slower code. As of this writing, the AIX linker can do this, and so can the GNU linker for PowerPC/64. The plan is to add this feature to the GNU linker for 32-bit PowerPC systems too.

On PowerPC64 ELFv2 and 32-bit PowerPC systems with newer GNU linkers, GCC can generate long calls using an inline PLT call sequence (see -mpltseq). PowerPC with -mbss-plt and PowerPC64 ELFv1 (big-endian) do not support inline PLT calls.

On Darwin/PPC systems, #pragma longcall generates jbsr callee, L42, plus a branch island (glue code). The two target addresses represent the callee and the branch island. The Darwin/PPC linker prefers the first address and generates bl callee if the PPC bl instruction reaches the callee directly. Otherwise, the linker generates bl L42 to call the branch island. The branch island is appended to the body of the calling function, and it computes the full 32-bit address of the callee and jumps to it.

On Mach-O (Darwin) systems, this option 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 โ€” ๐Ÿ’– Implement (or do not implement) -fno-plt and long calls using an inline PLT call sequence. That sequence supports lazy linking and long calls to functions in dlopen'd shared libraries. Inline PLT calls are only supported on PowerPC64 ELFv2 and 32-bit PowerPC systems with newer GNU linkers. They're enabled by default if the support is detected when configuring GCC, and, in the case of 32-bit PowerPC, if GCC is configured with --enable-secureplt. -mpltseq code and -mbss-plt 32-bit PowerPC relocatable objects may not be linked together.
  • -mtls-markers, -mno-tls-markers โ€” ๐Ÿงš Mark (or do not mark) calls to __tls_get_addr with a relocation that specifies the function argument. The relocation lets the linker reliably connect the function call with the argument setup instructions for TLS optimization. That in turn lets GCC schedule the sequence better ๐Ÿ“ˆ
  • -mrecip, -mno-recip โ€” โœจ This option enables the use of the reciprocal estimate and reciprocal square root estimate instructions, with extra Newton-Raphson steps to boost precision, instead of doing a divide or a square root and divide for floating-point arguments. You should use the -ffast-math option when using -mrecip (or at least -funsafe-math-optimizations, -ffinite-math-only, -freciprocal-math and -fno-trapping-math). Note that while the throughput of the sequence is generally higher than the throughput of the non-reciprocal instruction, the precision can drop by up to 2 ulp (i.e. the inverse of 1.0 equals 0.99999994) for reciprocal square roots.
โš ๏ธ Precision bestie alert: with -mrecip, reciprocal square roots can lose up to 2 ulp of precision.
  • -mrecip=opt โ€” ๐Ÿ’… This controls which reciprocal estimate instructions may be used. opt is a comma-separated list of options, and any of them can be preceded by a ! to invert it:
    • all โ€” enable all estimate instructions.
    • default โ€” enable the default instructions, which is equivalent to -mrecip.
    • none โ€” disable all estimate instructions, which is equivalent to -mno-recip.
    • div โ€” enable the reciprocal approximation instructions for both single and double precision.
    • divf โ€” enable the single-precision reciprocal approximation instructions.
    • divd โ€” enable the double-precision reciprocal approximation instructions.
    • rsqrt โ€” enable the reciprocal square root approximation instructions for both single and double precision.
    • rsqrtf โ€” enable the single-precision reciprocal square root approximation instructions.
    • rsqrtd โ€” enable the double-precision reciprocal square root approximation instructions.

So, for example, -mrecip=all,!rsqrtd enables all of the reciprocal estimate instructions except for the FRSQRTE, XSRSQRTEDP, and XVRSQRTEDP instructions, which handle the double-precision reciprocal square root calculations. ๐Ÿ™ˆ

  • -mrecip-precision, -mno-recip-precision โ€” ๐ŸŒธ Assume (or do not assume) that the reciprocal estimate instructions give higher-precision estimates than the PowerPC ABI requires. Selecting -mcpu=power6, -mcpu=power7 or -mcpu=power8 automatically selects -mrecip-precision. The double-precision square root estimate instructions aren't generated by default on low-precision machines, since they don't give an estimate that converges after three steps.
  • -mveclibabi=type โ€” ๐Ÿ‘‘ Specifies the ABI type to use for vectorizing intrinsics using an external library. The only type supported right now is mass, which tells GCC to use IBM's Mathematical Acceleration Subsystem (MASS) libraries for vectorizing intrinsics with external libraries. When generating code for power7, GCC currently emits calls to the following functions:
"acosd2", "acosf4", "acoshd2", "acoshf4", "asind2", "asinf4", "asinhd2", "asinhf4",
"atan2d2", "atan2f4", "atand2", "atanf4", "atanhd2", "atanhf4", "cbrtd2", "cbrtf4",
"cosd2", "cosf4", "coshd2", "coshf4", "erfcd2", "erfcf4", "erfd2", "erff4",
"exp2d2", "exp2f4", "expd2", "expf4", "expm1d2", "expm1f4", "hypotd2", "hypotf4",
"lgammad2", "lgammaf4", "log10d2", "log10f4", "log1pd2", "log1pf4", "log2d2", "log2f4",
"logd2", "logf4", "powd2", "powf4", "sind2", "sinf4", "sinhd2", "sinhf4",
"sqrtd2", "sqrtf4", "tand2", "tanf4", "tanhd2", and "tanhf4"

Both -ftree-vectorize and -funsafe-math-optimizations must also be enabled. The MASS libraries must be specified at link time.

  • -mfriz, -mno-friz โ€” ๐Ÿฆ‹ Generate (or do not generate) the friz instruction when -funsafe-math-optimizations is used to optimize rounding of floating-point values to 64-bit integers and back to floating point. The friz instruction doesn't return the same value if the floating-point number is too large to fit in an integer.

-mpointers-to-nested-functions -mno-pointers-to-nested-functions

Okay so these two are a PACKAGE deal ๐Ÿงš Generate (or don't generate) code that loads up the static chain register ("r11") when you call through a pointer, on AIX and 64-bit Linux systems, where a function pointer points to a 3-word descriptor. That descriptor holds the function address, the TOC value that gets loaded into register "r2", and the static chain value that gets loaded into register "r11". ๐Ÿ’… -mpointers-to-nested-functions is on by default, so you're already set!

โš ๏ธ If you use -mno-pointers-to-nested-functions, you can't call through pointers to nested functions, and you also can't call through pointers to functions compiled in other languages that use the static chain. Bestie, that's a whole no-go zone ๐Ÿ’€

-msave-toc-indirect -mno-save-toc-indirect

Lowkey a bit of a technical one ๐ŸŒธ On AIX and 64-bit Linux systems, these decide whether the TOC value gets saved in the reserved stack location during the function prologue, but only if the function calls through a pointer. If the TOC value doesn't get saved in the prologue, it gets saved right before the call through the pointer instead. -mno-save-toc-indirect is the default, so that's the one you get unless you ask for something else โœจ

-mcompat-align-parm -mno-compat-align-parm

Okay this one is giving throwback ๐Ÿ•ฐ๏ธ These make the compiler generate (or not generate) code that passes structure parameters with a maximum alignment of 64 bits, so it stays compatible with older versions of GCC.

Older versions of GCC (prior to 4.9.0) incorrectly didn't align a structure parameter on a 128-bit boundary when that structure had a member that needed 128-bit alignment. Newer versions of GCC fixed that bug ๐Ÿ™ˆ You can use this option if you need your code to play nicely with functions compiled by those older versions.

-mno-compat-align-parm is the default, so you don't have to think about it unless you're dealing with the old stuff ๐Ÿซถ

-mstack-protector-guard=guard -mstack-protector-guard-reg=reg -mstack-protector-guard-offset=offset -mstack-protector-guard-symbol=symbol

Main character energy, these are about stack protection! ๐Ÿ›ก๏ธ They generate stack protection code that uses 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. tls is the default with GNU libc version 2.4 or later.

If you pick tls, then -mstack-protector-guard-reg=reg and -mstack-protector-guard-offset=offset tell the compiler which register to use as the base register for reading the canary, and what offset from that base to use. The defaults for those come from the relevant ABI, so you don't have to set them yourself ๐Ÿฆ‹

-mstack-protector-guard-symbol=symbol overrides the offset with a symbol reference to a canary in the TLS block. Iykyk ๐Ÿ˜Œ

-mpcrel -mno-pcrel

Generate (or don't generate) pc-relative addressing. ๐Ÿงญ Just a heads up, -mpcrel only works if you also have the medium code model (-mcmodel=medium) and prefixed addressing (-mprefixed) turned on. No cap, it needs both of those as its besties ๐Ÿ‘ฏ

-mprefixed -mno-prefixed

Generate (or don't generate) addressing modes that use prefixed load and store instructions. โœจ -mprefixed needs -mcpu=power10 (or later) to be enabled, so make sure your CPU target is on board first ๐Ÿ’–

-mmma -mno-mma

Generate (or don't generate) the MMA instructions. ๐Ÿ”ฅ The -mma option needs -mcpu=power10 (or later) to be enabled too, same energy as -mprefixed ๐ŸŒˆ

-mrop-protect -mno-rop-protect

Generate (or don't generate) ROP protection instructions, but only when the target processor actually supports them ๐Ÿ” Heads up, though: right now this option disables the shrink-wrap optimization (-fshrink-wrap). So it's a trade-off, bestie ๐Ÿ™ˆ

-mprivileged -mno-privileged

Generate (or don't generate) code that runs in privileged state. ๐Ÿ‘‘ Very powerful, very serious, so use it with intention โœจ

-mblock-ops-unaligned-vsx -mno-block-ops-unaligned-vsx

Generate (or don't generate) unaligned VSX loads and stores for inline expansion of memcpy and memmove. ๐Ÿฆ‹ Think of it as the compiler deciding whether to use unaligned VSX moves when it inlines those two.


โœจ RX Options โœจ

These command-line options are defined for RX targets, so they only matter if you're building for an RX chip ๐ŸŒธ

-m64bit-doubles -m32bit-doubles

Make the double data type 64 bits (-m64bit-doubles) or 32 bits (-m32bit-doubles) in size. The default is -m32bit-doubles, and that's because RX floating-point hardware only works on 32-bit values. Makes sense, right? ๐Ÿ’…

-fpu -nofpu

Enables (-fpu) or disables (-nofpu) the use of RX floating-point hardware. ๐Ÿ”ฅ The default is enabled for the RX600 series and disabled for the RX200 series.

Floating-point instructions are only generated for 32-bit floating-point values, though, so the FPU hardware isn't used for doubles if -m64bit-doubles is used. Plot twist ๐Ÿ˜ญ

Note: if -fpu is enabled, then -funsafe-math-optimizations is also enabled automatically. The reason is that the RX FPU instructions are themselves unsafe ๐Ÿ’€

-mcpu=name

Selects the type of RX CPU to target. Three types are supported right now: the generic RX600 and RX200 series hardware, and the specific RX610 CPU. The default is RX600 ๐Ÿงš

The only difference between RX600 and RX610 is that the RX610 doesn't support the MVTIPL instruction. That's it, that's the tea โ˜•

The RX200 series doesn't have a hardware floating-point unit, so -nofpu is enabled by default when this type is selected ๐Ÿซถ

-mbig-endian-data -mlittle-endian-data

Store data (but not code) in big-endian format. The default is -mlittle-endian-data, which stores data in little-endian format. ๐ŸŒˆ

-msmall-data-limit=N

Specifies the maximum size in bytes of global and static variables that can be placed into the small data area. Using the small data area can lead to smaller and faster code, BUT the area is limited and it's up to you to make sure it doesn't overflow ๐Ÿ˜ฌ

When the small data area is used, one of the RX's registers (usually "r13") is reserved to point to this area, so the compiler can't use it anymore. That could make your code slower and/or bigger if variables get pushed onto the stack instead of being held in that register ๐Ÿ’€

Note: common variables (uninitialized variables) and constants are NOT placed into the small data area, because they get assigned to other sections in the output executable โœจ

The default value is zero, which disables this feature. Also, this feature is NOT enabled by default at higher optimization levels (-O2 etc.) because of the potentially detrimental effects of reserving a register. You'll have to experiment and figure out whether it helps your program ๐Ÿ”ฌ See the description of the -mpid option for how the actual register that holds the small data area pointer gets chosen.

-msim -mno-sim

Use the simulator runtime. The default is to use the libgloss board-specific runtime. ๐Ÿงช

-mas100-syntax -mno-as100-syntax

When generating assembler output, use a syntax that's compatible with Renesas's AS100 assembler. This syntax can also be handled by the GAS assembler, but it has some restrictions, so it isn't generated by default ๐Ÿ’…

-mmax-constant-size=N

Specifies the maximum size, in bytes, of a constant that can be used as an operand in an RX instruction. The RX instruction set does allow constants up to 4 bytes long, but a longer value means a longer instruction. So sometimes it's actually beneficial to restrict the size of constants used in instructions. Constants that are too big get placed into a constant pool and referenced via register indirection ๐Ÿง 

The value N can be between 0 and 4. A value of 0 (the default) or 4 means constants of any size are allowed ๐ŸŒธ

-mrelax

Enables linker relaxation. Linker relaxation is when the linker tries to shrink your program by finding shorter versions of various instructions. โœ‚๏ธ Disabled by default.

-mint-register=N

Specifies the number of registers to reserve for fast interrupt handler functions. The value N can be between 0 and 4. A value of 1 means register "r13" is reserved for the exclusive use of fast interrupt handlers. A value of 2 reserves "r13" and "r12". A value of 3 reserves "r13", "r12" and "r11", and a value of 4 reserves "r13" through "r10". A value of 0, the default, doesn't reserve any registers ๐Ÿฆ‹

-msave-acc-in-interrupts

Specifies that interrupt handler functions should preserve the accumulator register. This is only necessary if normal code might use the accumulator, for example because it does 64-bit multiplications. The default is to ignore the accumulator, because that makes the interrupt handlers faster โšก

-mpid -mno-pid

Enables the generation of position independent data. When enabled, any access to constant data is done via an offset from a base address held in a register. This lets the location of constant data be figured out at run time without the executable needing to be relocated, which is a huge win for embedded apps with tight memory constraints ๐Ÿ“ Data that can be modified isn't affected by this option.

Note: using this feature reserves a register (usually "r13") for the constant data base address. That can make your code slower and/or bigger, especially in complicated functions ๐Ÿ˜ญ

Which register ends up holding the constant data base address depends on whether -msmall-data-limit and/or -mint-register are enabled. Starting with "r13" and working downwards, registers get allocated first to satisfy -mint-register, then -mpid, and finally -msmall-data-limit. So it's possible for the small data area register to be "r8" if both -mint-register=4 and -mpid are specified on the command line ๐Ÿงฉ

By default this feature is not enabled. You can restore the default with the -mno-pid command-line option ๐Ÿ’œ

-mno-warn-multiple-fast-interrupts -mwarn-multiple-fast-interrupts

Prevents GCC from issuing a warning if it finds more than one fast interrupt handler while compiling a file. The default is to issue a warning for each extra fast interrupt handler found, because the RX only supports one such interrupt ๐Ÿšจ

-mallow-string-insns -mno-allow-string-insns

Enables or disables the use of the string manipulation instructions "SMOVF", "SCMPU", "SMOVB", "SMOVU", "SUNTIL" "SWHILE" and also the "RMPA" instruction. These instructions may prefetch data, which isn't safe to do when accessing an I/O register. (See section 12.2.7 of the RX62N Group User's Manual for more information.) โš ๏ธ

Okay so the RX string instructions are ON by default ๐Ÿ’–, but here's the tea: GCC can't reliably spot every time a string instruction pokes an I/O register ๐Ÿ™ˆ, so it can't switch them off automatically. That means it's on you, bestie, to pass -mno-allow-string-insns if your program touches I/O space ๐Ÿซถ.

When they're enabled, GCC defines the C preprocessor symbol __RX_ALLOW_STRING_INSNS__. When they're not, it defines __RX_DISALLOW_STRING_INSNS__ instead โœจ.

  • -mjsr, -mno-jsr โ€” Use only (or not only) JSR instructions to call functions ๐Ÿ“ž. This is the move when your code size goes past the reach of BSR instructions ๐Ÿฆ‹. Heads up: -mno-jsr doesn't mean "never use JSR" ๐Ÿ™…โ€โ™€๏ธ. It just means any type of branch is fair game ๐Ÿ’….
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 handle fast interrupts โšก. GCC makes sure it only uses r10, r11, r12 and/or r13, and only when the normal use of those registers has been restricted with -ffixed-reg or -mint-register ๐Ÿซถ.

โœจ S/390 and zSeries Options โœจ

These are the -m options 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 math ๐Ÿ”ข. With -msoft-float, the functions in libgcc.a do the floating-point work instead ๐Ÿ› ๏ธ. With -mhard-float, GCC 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, the functions in libgcc.a handle decimal-floating-point operations instead. With -mhard-dfp, GCC generates decimal-floating-point hardware instructions โš™๏ธ. This is the default for -march=z9-ec or higher ๐ŸŒธ.
  • -mlong-double-64, -mlong-double-128 โ€” These switches control the size of the long double type ๐Ÿ“. A size of 64 bits makes long double the same as double ๐Ÿ’–. This is the default โœจ.
  • -mbackchain, -mno-backchain โ€” Store (or don't store) the address of the caller's frame as a backchain pointer in the callee's stack frame ๐Ÿ”—. A backchain may be needed for debugging with tools that don't understand DWARF call frame information ๐Ÿ•ต๏ธโ€โ™€๏ธ. With -mno-packed-stack in effect, the backchain pointer lives at the bottom of the stack frame ๐Ÿ . With -mpacked-stack in effect, the backchain goes into the topmost word of the 96/160 byte register save area ๐ŸŽ€.

In general, code compiled with -mbackchain is call-compatible with code compiled with -mno-backchain ๐Ÿค. But using the backchain for debugging usually means the whole binary needs to be built with -mbackchain ๐Ÿ˜ญ. Also, the combination of -mbackchain, -mpacked-stack and -mhard-float is not supported ๐Ÿ’€. If you want to build a Linux kernel, use -msoft-float ๐Ÿซถ.

The default is to not maintain the backchain ๐Ÿ™…โ€โ™€๏ธ.

  • -mpacked-stack, -mno-packed-stack โ€” Use (or don'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 eat stack space ๐Ÿ˜ค. With -mpacked-stack, register save slots are densely packed at the top of the save area, and unused space gets reused for other stuff ๐Ÿง . Way more efficient with the stack space ๐Ÿ’…. However, when -mbackchain is also in effect, the topmost word of the save area is always used for the backchain, and the return address register is always saved two words below the backchain ๐Ÿ“.

As long as the stack frame backchain isn't used, code generated with -mpacked-stack is call-compatible with code generated with -mno-packed-stack โœ…. Now, 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 ๐Ÿ’€. To build a Linux kernel, use -msoft-float ๐Ÿซถ.

The default is to not use the packed stack layout ๐Ÿ™…โ€โ™€๏ธ.

  • -msmall-exec, -mno-small-exec โ€” Generate (or don't generate) code that uses the bras instruction for subroutine calls ๐Ÿ“ž. This only works reliably if the total executable size doesn't go over 64k ๐Ÿ“, so be careful ๐Ÿ˜ฌ. The default is the basr instruction instead, which doesn't have that limit ๐Ÿ’–.
  • -m64, -m31 โ€” With -m31, GCC generates code compliant with the GNU/Linux for S/390 ABI ๐Ÿงฉ. With -m64, it generates code compliant with the GNU/Linux for zSeries ABI ๐ŸŒˆ. This lets GCC generate 64-bit instructions, which is the big win ๐Ÿ”ฅ. For the s390 targets the default is -m31, while the s390x targets default to -m64 ๐Ÿ‘‘.
  • -mzarch, -mesa โ€” With -mzarch, GCC generates code using the instructions available on z/Architecture ๐Ÿฆ‹. With -mesa, it uses the instructions available on ESA/390 ๐Ÿ•ฐ๏ธ. Note that -mesa is not possible with -m64 ๐Ÿ™…โ€โ™€๏ธ. When generating code compliant with the GNU/Linux for S/390 ABI, the default is -mesa. When generating code compliant with the GNU/Linux for zSeries ABI, the default is -mzarch ๐Ÿ’œ.
  • -mhtm, -mno-htm โ€” The -mhtm option turns on a set of builtins that use instructions from the transactional execution facility, introduced with the IBM zEnterprise EC12 machine generation ๐Ÿง. These are part of the S/390 System z Built-in Functions ๐Ÿ”ง. -mhtm is enabled by default when you use -march=zEC12 โœจ.
  • -mvx, -mno-vx โ€” With -mvx, GCC generates code using the instructions from the vector extension facility, introduced with the IBM z13 machine generation ๐Ÿš€. This option changes the ABI for some vector type values when it comes to alignment and calling conventions โš ๏ธ. If vector type values are used in an ABI-relevant context, a GAS .gnu_attribute command gets added to mark the resulting binary with the ABI it used ๐Ÿท๏ธ. -mvx is enabled by default when you use -march=z13 ๐ŸŒŸ.
  • -mzvector, -mno-zvector โ€” The -mzvector option turns on vector language extensions and builtins, using instructions from the vector extension facility introduced with the IBM z13 machine generation ๐Ÿ’…. It adds support for vector as a keyword to define vector type variables and arguments ๐ŸŽ€. Heads up: vector is only available when GNU extensions are enabled ๐Ÿ™ˆ. It won't be expanded when you request strict standard compliance, e.g. with -std=c99 ๐Ÿšซ. On top of the GCC low-level builtins, -mzvector also enables a set of builtins added for compatibility with AltiVec-style implementations like Power and Cell ๐Ÿงš. To use these builtins, you need to include the header file vecintrin.h ๐Ÿ“„. -mzvector is disabled by default ๐Ÿ™…โ€โ™€๏ธ.
  • -mmvcle, -mno-mvcle โ€” Generate (or don't generate) code using the mvcle instruction for block moves ๐Ÿšš. With -mno-mvcle, it uses an mvc loop instead. This is the default unless you're optimizing for size ๐Ÿ“.
  • -mdebug, -mno-debug โ€” Print (or don't print) extra debug information while compiling ๐Ÿ”. The default is to not print debug information ๐Ÿ™…โ€โ™€๏ธ.
  • -march=cpu-type โ€” Generate code that runs on cpu-type, which is the name of a system representing a certain processor type ๐Ÿ–ฅ๏ธ. Possible values for cpu-type are z900/arch5, z990/arch6, z9-109, z9-ec/arch7, z10/arch8, z196/arch9, zEC12, z13/arch11, z14/arch12, z15/arch13, and native ๐ŸŒˆ. The default is -march=z900 ๐Ÿ‘‘.

Choosing native as the cpu type picks the best architecture option for the host processor ๐Ÿง . -march=native has no effect if GCC doesn't recognize the processor ๐Ÿคทโ€โ™€๏ธ.

  • -mtune=cpu-type โ€” Tune everything applicable in the generated code to cpu-type, except for the ABI and the set of available instructions ๐ŸŽ›๏ธ. The list of cpu-type values is the same as for -march ๐Ÿ’–. The default is whatever value is used for -march โœจ.
  • -mtpf-trace, -mno-tpf-trace โ€” Generate code that adds (or doesn't add) TPF OS specific branches to trace routines in the operating system ๐Ÿ›ฐ๏ธ. This option is off by default, even when compiling for the TPF OS ๐Ÿ™ˆ.
  • -mtpf-trace-skip, -mno-tpf-trace-skip โ€” Generate code that changes (or doesn't change) the default branch targets enabled by -mtpf-trace so they point to specialized trace routines ๐ŸŽฏ. These let you selectively skip function trace entries for the TPF OS ๐Ÿฆ‹. This option is off by default, even when compiling for the TPF OS and specifying -mtpf-trace ๐Ÿ’€.
  • -mfused-madd, -mno-fused-madd โ€” Generate code that uses (or doesn't use) the floating-point multiply and accumulate instructions โœ–๏ธโž•. These are generated by default if hardware floating point is used ๐Ÿ’œ.
  • -mwarn-framesize=framesize โ€” Emit a warning if the current function exceeds the given frame size ๐Ÿšจ. Since this is a compile-time check, it doesn't have to be a real problem when the program runs ๐Ÿซถ. It's meant to catch functions that most probably cause a stack overflow ๐Ÿ˜ฑ. It's super useful in environments with a limited stack size, e.g. the Linux kernel ๐Ÿง.
  • -mwarn-dynamicstack โ€” Emit a warning if the function calls alloca or uses dynamically-sized arrays ๐Ÿ“‰. This is generally a bad idea with a limited stack size ๐Ÿ’€.
  • -mstack-guard=stack-guard, -mstack-size=stack-size โ€” okay so these two are a package deal ๐Ÿงš With them on, the S/390 back end slips extra instructions into the function prologue that set off a trap when the stack reaches stack-guard bytes above the stack-size mark. Heads up, the stack on S/390 grows downward ๐Ÿ“‰, so that's the direction it's watching. If you leave out stack-guard, GCC picks the smallest power of 2 that's bigger than the compiled function's frame size ๐Ÿ”ข These are built for debugging stack overflow problems ๐Ÿ•ต๏ธโ€โ™€๏ธ The extra code adds only a little overhead, so you can use it on production-like systems without a big performance hit ๐Ÿ’… The values have to be exact powers of 2, and stack-size has to be bigger than stack-guard without going over 64k. To be efficient, the extra code assumes the stack starts at an address aligned to the stack-size value. And -mstack-guard only works together with -mstack-size, bestie ๐Ÿซถ
  • -mhotpatch=pre-halfwords,post-halfwords โ€” if hotpatch is turned on, every function in the compilation unit gets a "hot-patching" prologue โœจ The function label gets prepended with pre-halfwords worth of two-byte NOP instructions (max 1000000). After the label, 2 * post-halfwords bytes get tacked on, using the largest NOP-like instructions the architecture allows (max 1000000).
    • If both arguments are zero, hotpatching is disabled ๐Ÿ™…โ€โ™€๏ธ
    • You can override this for individual functions with the "hotpatch" attribute ๐Ÿ”ฅ

๐ŸŒˆ Score Options ๐ŸŒˆ

These options are defined for Score implementations:

  • -meb โ€” compile for big-endian mode. This is the default ๐Ÿ’œ
  • -mel โ€” compile for little-endian mode ๐Ÿ“
  • -mnhwloop โ€” disable generation of "bcnz" instructions ๐Ÿ™ˆ
  • -muls โ€” enable generation of unaligned load and store instructions ๐Ÿงš
  • -mmac โ€” enable the use of multiply-accumulate instructions. These are disabled by default ๐Ÿ’€
  • -mscore5 โ€” specify SCORE5 as the target architecture โญ
  • -mscore5u โ€” specify SCORE5U as the target architecture โญ
  • -mscore7 โ€” specify SCORE7 as the target architecture. This is the default ๐Ÿ‘‘
  • -mscore7d โ€” specify SCORE7D as the target architecture โœจ

๐Ÿฆ‹ SH Options ๐Ÿฆ‹

These -m options are defined for the SH implementations:

  • -m1 โ€” generate code for the SH1 ๐ŸŒธ
  • -m2 โ€” generate code for the SH2 ๐ŸŒธ
  • -m2e โ€” generate code for the SH2e ๐ŸŒธ
  • -m2a-nofpu โ€” generate code for the SH2a without an FPU, or for a SH2a-FPU in a way that the floating-point unit isn't used ๐Ÿซถ
  • -m2a-single-only โ€” generate code for the SH2a-FPU in such a way that no double-precision floating-point operations are used ๐Ÿ’…
  • -m2a-single โ€” generate code for the SH2a-FPU, assuming the floating-point unit is in single-precision mode by default ๐Ÿ’…
  • -m2a โ€” generate code for the SH2a-FPU, assuming the floating-point unit is in double-precision mode by default ๐Ÿ’…
  • -m3 โ€” generate code for the SH3 ๐ŸŒธ
  • -m3e โ€” generate code for the SH3e ๐ŸŒธ
  • -m4-nofpu โ€” generate code for the SH4 without a floating-point unit ๐Ÿซง
  • -m4-single-only โ€” generate code for the SH4 with a floating-point unit that only supports single-precision arithmetic ๐Ÿซง
  • -m4-single โ€” generate code for the SH4, assuming the floating-point unit is in single-precision mode by default ๐Ÿซง
  • -m4 โ€” generate code for the SH4 ๐Ÿซง
  • -m4-100 โ€” generate code for SH4-100 ๐Ÿ”ฅ
  • -m4-100-nofpu โ€” generate code for SH4-100 in such a way that the floating-point unit is not used ๐Ÿ”ฅ
  • -m4-100-single โ€” generate code for SH4-100, assuming the floating-point unit is in single-precision mode by default ๐Ÿ”ฅ
  • -m4-100-single-only โ€” generate code for SH4-100 in such a way that no double-precision floating-point operations are used ๐Ÿ”ฅ
  • -m4-200 โ€” generate code for SH4-200 ๐ŸŒˆ
  • -m4-200-nofpu โ€” generate code for SH4-200 in such a way that the floating-point unit is not used ๐ŸŒˆ
  • -m4-200-single โ€” generate code for SH4-200, assuming the floating-point unit is in single-precision mode by default ๐ŸŒˆ
  • -m4-200-single-only โ€” generate code for SH4-200 in such a way that no double-precision floating-point operations are used ๐ŸŒˆ
  • -m4-300 โ€” generate code for SH4-300 ๐Ÿ“
  • -m4-300-nofpu โ€” generate code for SH4-300 in such a way that the floating-point unit is not used ๐Ÿ“
  • -m4-300-single โ€” generate code for SH4-300 in such a way that no double-precision floating-point operations are used ๐Ÿ“
  • -m4-300-single-only โ€” generate code for SH4-300 in such a way 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 a SH4a in such a way that the floating-point unit is not used ๐Ÿ’œ
  • -m4a-single-only โ€” generate code for the SH4a in such a way 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 that 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 ๐Ÿšจ
Standard C library functions break with -mdalign unless you recompile the library first, so don't skip that step, bestie ๐Ÿ’€
  • -mrelax โ€” shorten some address references at link time, when possible. This uses the linker option -relax โšก
  • -mbigtable โ€” use 32-bit offsets in "switch" tables. The default is 16-bit offsets ๐ŸŽ€
  • -mbitops โ€” enable the use of bit manipulation instructions on SH2A ๐ŸŽ€
  • -mfmovd โ€” enable the use of the instruction "fmovd". Check -mdalign for alignment constraints ๐ŸŽ€
  • -mrenesas โ€” comply with the calling conventions defined by Renesas ๐Ÿ‘‘
  • -mno-renesas โ€” comply with the calling conventions GCC used before the Renesas conventions were available. This is the default for all targets of the SH toolchain ๐Ÿ‘‘
  • -mnomacsave โ€” mark the "MAC" register as call-clobbered, even if -mrenesas is given ๐Ÿซถ
  • -mieee, -mno-ieee โ€” control the IEEE compliance of floating-point comparisons, which affects how cases where the result of a comparison is unordered get handled ๐Ÿง 
    • By default -mieee is implicitly enabled.
    • If -ffinite-math-only is enabled, -mno-ieee is implicitly set, which gives you faster floating-point greater-equal and less-equal comparisons โšก
    • The implicit settings can be overridden by specifying either -mieee or -mno-ieee ๐Ÿ’…
  • -minline-ic_invalidate โ€” inline code that invalidates instruction cache entries after setting up nested function trampolines. This option has no effect if -musermode is in effect and the selected code generation option (e.g. -m4) doesn't allow the use of the "icbi" instruction ๐Ÿง 
    • If the selected code generation option doesn't allow the "icbi" instruction, and -musermode is not in effect, the inlined code manipulates the instruction cache address array directly with an associative write.
This needs privileged mode at run time, and it also fails if the cache line had been mapped via the TLB and has become unmapped ๐Ÿ˜ญ
  • -misize โ€” dump instruction size and location in the assembly code ๐Ÿ“
  • -mpadstruct โ€” this option is deprecated ๐Ÿชฆ It pads structures to a multiple of 4 bytes, which is incompatible with the SH ABI.
Deprecated and incompatible with the SH ABI, so please don't reach for this one, bestie ๐Ÿ™…โ€โ™€๏ธ
  • -matomic-model=model โ€” sets the model of atomic operations and additional parameters as a comma-separated list. For details on the atomic built-in functions, see __atomic Builtins. These models and parameters are supported:
    • none โ€” disable compiler-generated atomic sequences and emit library calls for atomic operations. This is the default if the target is not "sh*-*-linux*" ๐Ÿซ 
    • soft-gusa โ€” generate GNU/Linux-compatible gUSA software atomic sequences for the atomic built-in functions. The generated sequences need extra support from the interrupt/exception handling code of the system, and they're only suitable for SH3* and SH4* single-core systems. This option is enabled by default when the target is "sh*-*-linux*" and SH3* or SH4*. When the target is SH4A, this option also partially uses the hardware atomic instructions "movli.l" and "movco.l" to create more efficient code, unless strict is specified ๐ŸŒธ
    • soft-tcb โ€” generate software atomic sequences that use a variable in the thread control block. This is a variation of the gUSA sequences that can also be used on SH1* and SH2* targets. The generated sequences need extra support from the interrupt/exception handling code and are only suitable for single-core systems. When using this model, the gbr-offset= parameter has to be specified as well ๐Ÿงš
    • soft-imask โ€” generate software atomic sequences that temporarily disable interrupts by setting "SR.IMASK = 1111". This model only works when the program runs in privileged mode, and it's only suitable for single-core systems. Extra support from the interrupt/exception handling code is not required. This model is enabled by default when the target is "sh*-*-linux*" and SH1* or SH2* ๐Ÿ”
    • hard-llcs โ€” generate hardware atomic sequences using only the "movli.l" and "movco.l" instructions. This is only available on SH4A and is suitable for multi-core systems. Since the hardware instructions only support 32-bit atomic variable access, 8- or 16-bit variable access is emulated with 32-bit accesses. Code compiled with this option is also compatible with other software atomic model interrupt/exception handling systems if it's executed on an SH4A system. Extra support from the interrupt/exception handling code of the system is not required for this model ๐Ÿ‘‘
  • gbr-offset= โ€” okay so this one sets the byte offset of the variable inside the thread control block structure, and the generated atomic sequences use that spot ๐Ÿ’– It only matters when the soft-tcb model is selected. For every other model it gets ignored ๐Ÿฆ‹ The value has to be an integer multiple of four and fall somewhere in the range 0-1020 โœจ
  • strict โ€” this one stops you from mixing multiple atomic models, even when they'd normally be compatible ๐Ÿ™…โ€โ™€๏ธ The compiler only makes atomic sequences for the model you specified, and nothing else ๐Ÿ’…

  • -mtas โ€” this makes the compiler generate the tas.b opcode for __atomic_test_and_set ๐Ÿ”ฅ Heads up, though: depending on your hardware and software setup, this can tank overall performance because of the operand cache line flushes that tas.b brings along ๐Ÿ˜ญ On multi-core SH4A processors, tas.b has to be used with caution, since it can cause data corruption with certain cache configurations ๐Ÿ’€
  • -mprefergot โ€” when you're generating position-independent code, this emits function calls through the Global Offset Table instead of the Procedure Linkage Table ๐ŸŒธ
  • -musermode, -mno-usermode โ€” these decide whether the compiler is allowed to generate privileged mode code ๐Ÿ‘‘ -mno-usermode says no, and -musermode says yes ๐Ÿ™ˆ 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 does nothing at all, because those chips have no user mode ๐Ÿฅ€
  • -multcost=number โ€” sets the cost the compiler assumes for a multiply insn โœจ
  • -mdiv=strategy โ€” picks the division strategy used for integer division operations ๐Ÿงฎ The strategy can be one of these:
    • call-div1 โ€” calls a library function that uses the single-step division instruction div1 to do the math ๐ŸŽ€ Dividing by zero gives an unspecified result and doesn't trap ๐Ÿ™ƒ This is the default except for SH4, SH2A, and SHcompact.
    • call-fp โ€” calls a library function that does the operation in double precision floating point ๐Ÿฆ‹ Dividing by zero causes a floating-point exception โš ๏ธ This is the default for SHcompact with an FPU. If you specify this for targets without a double precision FPU, it falls back to call-div1 ๐Ÿ’…
    • call-table โ€” calls a library function that uses a lookup table for small divisors and the div1 instruction with case distinction for larger divisors ๐Ÿงš Dividing by zero gives an unspecified result and doesn't trap ๐Ÿ™ƒ This is the default for SH4. If you specify this for targets without dynamic shift instructions, it defaults to call-div1 instead ๐Ÿ’œ

If you don't specify a division strategy, the compiler picks the default based on the current target ๐ŸŽฏ For SH2A, the default is to use the divs and divu instructions instead of library function calls ๐Ÿ”ฅ

  • -maccumulate-outgoing-args โ€” reserves space once for outgoing arguments in the function prologue, instead of around each call ๐ŸŒท This is generally great for performance and size ๐Ÿ“ˆ It's also needed for unwinding, so the stack frame doesn't get changed around conditional code ๐Ÿซถ
  • -mdivsi3_libfunc=name โ€” sets the name of the library function used for 32-bit signed division to name ๐Ÿ“ This only changes the name used in the call division strategies. The compiler still expects the same sets of input, output, and clobbered registers as if this option weren't there ๐Ÿง 
  • -mfixed-range=register-range โ€” generates code that treats the given register range as fixed registers ๐Ÿ”’ A fixed register is one the register allocator isn't allowed to use, which is super useful when you're compiling kernel code ๐Ÿ–ฅ๏ธ A register range is written as two registers separated by a dash, and you can list multiple ranges separated by commas โœจ
  • -mbranch-cost=num โ€” tells the compiler to assume num is the cost of a branch instruction ๐ŸŒˆ Higher numbers make the compiler try harder to generate branch-free code when it's possible ๐Ÿ’… If you don't specify it, the value is picked based on the processor type you're compiling for ๐ŸŽ€
  • -mzdcbranch, -mno-zdcbranch โ€” these tell the compiler whether zero displacement conditional branch instructions bt and bf are fast ๐Ÿƒโ€โ™€๏ธ With -mzdcbranch, the compiler prefers zero displacement branch code sequences โœจ It's enabled by default for SH4 and SH4A ๐Ÿฆ‹ You can explicitly turn it off with -mno-zdcbranch ๐Ÿ™…โ€โ™€๏ธ
  • -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 option is disabled by default ๐Ÿ˜Œ You can turn it on to work around hardware bugs found in the original SH7055 ๐Ÿ”ง
  • -mfused-madd, -mno-fused-madd โ€” these decide whether the code uses the floating-point multiply and accumulate instructions โœ–๏ธโž• They're generated by default when 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 โ€” allow or disallow the compiler from emitting the fsca instruction for sine and cosine approximations ๐Ÿ“ The option -mfsca has to be used together with -funsafe-math-optimizations ๐Ÿง It's enabled by default for SH4A ๐ŸŒธ Using -mno-fsca disables sine and cosine approximations even if -funsafe-math-optimizations is in effect ๐Ÿ™…โ€โ™€๏ธ
  • -mfsrra, -mno-fsrra โ€” allow or disallow the compiler from emitting the fsrra instruction for reciprocal square root approximations ๐Ÿงฎ The option -mfsrra has to be used together with -funsafe-math-optimizations and -ffinite-math-only ๐Ÿ“š It's enabled by default for SH4A ๐ŸŒŸ Using -mno-fsrra disables reciprocal square root approximations even if -funsafe-math-optimizations and -ffinite-math-only are in effect ๐Ÿšซ
  • -mpretend-cmove โ€” prefers zero-displacement conditional branches for conditional move instruction patterns ๐ŸŽ€ This can make the code run faster on the SH4 processor ๐ŸŽ๏ธ
  • -mfdpic โ€” generates code using the FDPIC ABI ๐Ÿงš

โœจ Solaris 2 Options โœจ

These -m options are supported on Solaris 2 ๐ŸŒž

  • -mclear-hwcap โ€” tells the compiler to remove the hardware capabilities generated by the Solaris assembler ๐Ÿงน You only need this when object files use ISA extensions the current machine doesn't support, but they check at runtime whether or not to use them ๐Ÿคทโ€โ™€๏ธ
  • -mimpure-text โ€” used alongside -shared, this tells the compiler not to pass -z text to the linker when linking a shared object ๐Ÿ‘ With it, you can link position-dependent code into a shared object ๐Ÿ˜ณ
Okay, real talk bestie: -mimpure-text suppresses the "relocations remain against allocatable but non-writable sections" linker error message ๐Ÿ™ˆ But the necessary relocations trigger copy-on-write, so the shared object isn't actually shared across processes ๐Ÿ˜ญ Instead of using -mimpure-text, you should compile all your source code with -fpic or -fPIC ๐Ÿ’–

These switches are supported in addition to the above on Solaris 2 ๐ŸŒˆ

  • -pthreads โ€” this is just a synonym for -pthread ๐Ÿซถ

โœจ SPARC Options โœจ

These -m options are supported on the SPARC ๐ŸŒป

  • -mno-app-regs, -mapp-regs โ€” specify -mapp-regs to generate output using global registers 2 through 4, which the SPARC SVR4 ABI reserves for applications ๐ŸŽ€ Like global register 1, each of global registers 2 through 4 is then treated as an allocable register that gets clobbered by function calls ๐Ÿฅน This is the default ๐Ÿ’…

To be fully SVR4 ABI-compliant (with some performance loss), specify -mno-app-regs ๐Ÿซ  You should compile libraries and system software with this option ๐Ÿ“ฆ

  • -mflat, -mno-flat โ€” with -mflat, the compiler doesn't generate save/restore instructions and uses a "flat" or single register window model ๐ŸชŸ This model is compatible with the regular register window model ๐Ÿค The local registers and the input registers (0--5) are still treated as "call-saved" registers and get saved on the stack as needed ๐Ÿ“ฅ With -mno-flat (the default), the compiler generates save/restore instructions, except for leaf functions ๐Ÿƒ This is the normal operating mode โœจ
  • -mfpu, -mhard-float โ€” generate output containing floating-point instructions ๐Ÿ”ฅ This is the default ๐Ÿ’…
  • -mno-fpu, -msoft-float โ€” generate output containing library calls for floating point ๐Ÿ“ž
Warning, bestie: the requisite libraries aren't available for all SPARC targets ๐Ÿ˜ฌ Normally the facilities of the machine's usual C compiler get used, but that can't be done directly in cross-compilation ๐Ÿ™ƒ You have to make your own arrangements to provide suitable library functions for cross-compilation ๐Ÿ› ๏ธ The embedded targets sparc-*-aout and sparclite-*-* do provide software floating-point support ๐Ÿซถ

-msoft-float changes the calling convention in the output file, so it's only useful if you compile all of a program with this option ๐Ÿงต In particular, you need to compile libgcc.a, the library that comes with GCC, with -msoft-float for this to work ๐Ÿ’€

  • -mhard-quad-float โ€” generate output containing quad-word (long double) floating-point instructions ๐ŸŒŒ
  • -msoft-quad-float โ€” generate output containing library calls for quad-word (long double) floating-point instructions โ˜๏ธ The functions called are the ones specified in the SPARC ABI, and this is the default ๐Ÿ’…

As of this writing, there are no SPARC implementations with hardware support for quad-word floating-point instructions ๐Ÿ˜ญ They all invoke a trap handler for one of these instructions, and then the trap handler emulates the effect of the instruction ๐Ÿซ  Because of the trap handler overhead, this is much slower than calling the ABI library routines, so -msoft-quad-float is the default ๐ŸŒท

  • -mno-unaligned-doubles, -munaligned-doubles โ€” assume that doubles have 8-byte alignment ๐Ÿ“ This is the default โœจ

Okay so the end of the -munaligned-doubles bit is lowkey important ๐Ÿ‘€ With it on, GCC only assumes doubles have 8-byte alignment if they're tucked inside another type or have an absolute address. Otherwise it goes with 4-byte alignment. This helps avoid some rare compatibility drama with code from other compilers ๐Ÿซถ but it's not the default, because it costs performance, especially for floating-point code ๐Ÿ“‰

  • -muser-mode, -mno-user-mode โ€” no code that can only run in supervisor mode ๐Ÿ” This only matters for the casa instruction that gets emitted for the LEON3 processor. And yep, this is the default ๐Ÿ’…
  • -mfaster-structs, -mno-faster-structs โ€” with -mfaster-structs, the compiler assumes structures 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.
๐Ÿšจ The catch: this changed alignment directly violates the SPARC ABI. So it's only meant for targets where the developer knows and accepts that their code isn't fully in line with the ABI rules. Use with care, bestie ๐Ÿ˜ญ
  • -mstd-struct-return, -mno-std-struct-return โ€” with the first one, the compiler adds checking code to functions that return structures or unions, so it can catch size mismatches between the two sides of a function call, as per the 32-bit ABI ๐Ÿ” The default is -mno-std-struct-return. This option does nothing in 64-bit mode ๐Ÿ™…โ€โ™€๏ธ
  • -mlra, -mno-lra โ€” turns on Local Register Allocation โœจ This has been the default for SPARC since GCC 7, so if you want the old Reload behaviour, you have to pass -mno-lra ๐Ÿ•ฐ๏ธ
  • -mcpu=cpu_type โ€” sets the instruction set, register set, and instruction scheduling parameters for the machine type cpu_type ๐Ÿง  The supported values are v7, cypress, v8, supersparc, hypersparc, leon, leon3, leon3v7, leon5, sparclite, f930, f934, sparclite86x, sparclet, tsc701, v9, ultrasparc, ultrasparc3, niagara, niagara2, niagara3, niagara4, niagara7 and m8.

Native Solaris and GNU/Linux toolchains also accept native, which picks the best architecture option for the host processor ๐Ÿ–ฅ๏ธ If GCC doesn't recognize the processor, -mcpu=native just does nothing ๐Ÿคทโ€โ™€๏ธ

Default instruction scheduling parameters get used for the values that pick an architecture rather than an implementation. Those are v7, v8, sparclite, sparclet and v9.

Here's the full lineup of each 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 it's been configured otherwise), GCC makes code for the V7 variant of SPARC ๐ŸŒธ With -mcpu=cypress, it also optimizes for the Cypress CY7C602 chip, which was used in the SPARCStation/SPARCServer 3xx series. This is also a good fit for the older SPARCStation 1, 2, IPX and so on ๐Ÿฆ‹

With -mcpu=v8, GCC makes 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 SPARC-V7 โœจ With -mcpu=supersparc, it also optimizes for the SuperSPARC chip, found in the SPARCStation 10, 1000 and 2000 series ๐Ÿ–ค

With -mcpu=sparclite, GCC makes code for the SPARClite variant ๐Ÿ’œ This adds the integer multiply, integer divide step and scan ("ffs") instructions that exist in SPARClite but not SPARC-V7. With -mcpu=f930, it also optimizes for the Fujitsu MB86930, which is the original SPARClite and has no FPU. With -mcpu=f934, it optimizes for the Fujitsu MB86934, the more recent SPARClite that does have an FPU ๐Ÿ”ฅ

With -mcpu=sparclet, GCC makes 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 SPARC-V7. With -mcpu=tsc701, it also optimizes for the TEMIC SPARClet chip.

With -mcpu=v9, GCC makes code for the V9 variant ๐ŸŒˆ This adds 64-bit integer and floating-point move instructions, 3 additional floating-point condition code registers, and conditional move instructions. With -mcpu=ultrasparc, it optimizes for the Sun UltraSPARC I/II/IIi chips. With -mcpu=ultrasparc3, it optimizes for the Sun UltraSPARC III/III+/IIIi/IIIi+/IV/IV+ chips. With -mcpu=niagara, it optimizes for Sun UltraSPARC T1 chips. With -mcpu=niagara2, it optimizes for Sun UltraSPARC T2 chips. With -mcpu=niagara3, it optimizes for Sun UltraSPARC T3 chips. With -mcpu=niagara4, it optimizes for Sun UltraSPARC T4 chips. With -mcpu=niagara7, it optimizes for Oracle SPARC M7 chips. And with -mcpu=m8, it optimizes for Oracle M8 chips ๐Ÿ‘‘

  • -mtune=cpu_type โ€” sets the instruction scheduling parameters for the machine type cpu_type, but doesn't touch the instruction set or register set the way -mcpu=cpu_type does ๐ŸŽฏ

You can use the same values as -mcpu=cpu_type, but only the ones that pick out a particular CPU implementation are actually useful here. Those are cypress, supersparc, hypersparc, leon, leon3, leon3v7, leon5, f930, f934, sparclite86x, tsc701, ultrasparc, ultrasparc3, niagara, niagara2, niagara3, niagara4, niagara7 and m8. On native Solaris and GNU/Linux toolchains, native works here too ๐Ÿ’–

  • -mv8plus, -mno-v8plus โ€” generates code for the SPARC-V8+ ABI ๐Ÿงฉ The difference from the V8 ABI is that the global and out registers are treated as 64 bits wide. This is turned on by default on Solaris in 32-bit mode for all SPARC-V9 processors โœจ
  • -mvis, -mno-vis โ€” makes GCC take advantage of the UltraSPARC Visual Instruction Set extensions ๐ŸŽ€ The default is -mno-vis.
  • -mvis2, -mno-vis2 โ€” takes advantage of version 2.0 of the UltraSPARC Visual Instruction Set extensions ๐Ÿ“ผ The default is -mvis2 when you're targeting a CPU that supports these instructions, like UltraSPARC-III and later. Setting -mvis2 also sets -mvis.
  • -mvis3, -mno-vis3 โ€” takes advantage of version 3.0 of the VIS extensions ๐Ÿš€ The default is -mvis3 when targeting a CPU that supports these, like niagara-3 and later. Setting -mvis3 also sets -mvis2 and -mvis.
  • -mvis4, -mno-vis4 โ€” takes advantage of version 4.0 of the VIS extensions ๐Ÿฆ„ The default is -mvis4 when targeting a CPU that supports these, like niagara-7 and later. Setting -mvis4 also sets -mvis3, -mvis2 and -mvis.
  • -mvis4b, -mno-vis4b โ€” takes advantage of version 4.0 of the VIS extensions, plus the extra VIS instructions introduced in the Oracle SPARC Architecture 2017 ๐Ÿช„ The default is -mvis4b when targeting a CPU that supports them, like m8 and later. Setting -mvis4b also sets -mvis4, -mvis3, -mvis2 and -mvis.
  • -mcbcond, -mno-cbcond โ€” takes advantage of the UltraSPARC Compare-and-Branch-on-Condition instructions ๐Ÿ”€ The default is -mcbcond when targeting a CPU that supports them, like Niagara-4 and later.
  • -mfmaf, -mno-fmaf โ€” takes advantage of the UltraSPARC Fused Multiply-Add Floating-point instructions ๐Ÿงฎ The default is -mfmaf when targeting a CPU that supports them, like Niagara-3 and later.
  • -mfsmuld, -mno-fsmuld โ€” takes advantage of the Floating-point Multiply Single to Double (FsMULd) instruction ๐Ÿ’ซ The default is -mfsmuld when targeting a CPU that supports the architecture versions V8 or V9 with an FPU, except -mcpu=leon.
  • -mpopc, -mno-popc โ€” takes advantage of the UltraSPARC Population Count instruction ๐Ÿ”ข The default is -mpopc when targeting a CPU that supports it, like Niagara-2 and later.
  • -msubxc, -mno-subxc โ€” takes advantage of the UltraSPARC Subtract-Extended-with-Carry instruction ๐Ÿ“ The default is -msubxc when targeting a CPU that supports it, like Niagara-7 and later.
  • -mfix-at697f โ€” turns on the documented workaround for the single erratum of the Atmel AT697F processor (which matches 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 on top of everything above, and they work on SPARC-V9 processors in 64-bit environments ๐ŸŒธ

  • -m32, -m64 โ€” generates code for a 32-bit or 64-bit environment ๐Ÿ’œ The 32-bit environment sets int, long and pointer to 32 bits. The 64-bit environment sets int to 32 bits and long and pointer to 64 bits.
  • -mcmodel=which โ€” sets the code model to one of these ๐Ÿ—บ๏ธ
    • medlow โ€” the Medium/Low code model: 64-bit addresses, and programs must be linked in the low 32 bits of memory ๐Ÿงธ Programs can be statically or dynamically linked.
    • medmid โ€” the Medium/Middle code model: 64-bit addresses, and programs must be linked in the low 44 bits of memory ๐ŸŒ™ The text and data segments must each be less than 2GB in size, and the data segment has to sit within 2GB of the text segment.
  • medany: okay, the Medium/Anywhere code model ๐ŸŒˆ gives you 64-bit addresses and lets programs be linked anywhere in memory ๐Ÿ—บ๏ธ. The catch is that the text and data segments each have to be less than 2GB, and the data segment must sit within 2GB of the text segment ๐Ÿ“ (strict, but it's giving organized).
  • embmedany: the Medium/Anywhere code model for embedded systems ๐Ÿงš has 64-bit addresses, and the text and data segments must each be less than 2GB. 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 ๐Ÿ™…โ€โ™€๏ธ, so no cap, that's a hard no.
  • -mmemory-model=mem-model: sets the memory model that's in force on the processor to one of these ๐Ÿ’…:
    • default: the default memory model for the processor and operating system.
    • rmo: Relaxed Memory Order
    • pso: Partial Store Order
    • tso: Total Store Order
    • sc: Sequential Consistency

These memory models are formally defined in Appendix D of the SPARC-V9 architecture manual, and they get set in the processor's PSTATE.MM field ๐ŸŽ€.

  • -mstack-bias, -mno-stack-bias: with -mstack-bias, GCC assumes the stack pointer (and the frame pointer, if there is one) is offset by -2047. That offset has to be added back whenever stack frame references get made ๐Ÿง . This is the default in 64-bit mode. Otherwise, GCC assumes no such offset is present ๐Ÿฆ‹.

โœจ Options for System V โœจ

These extra options are available on System V Release 4 so they can play nicely with other compilers on those systems ๐Ÿซถ:

  • -G: creates a shared object ๐Ÿซง. It's recommended to use -symbolic or -shared instead.
  • -Qy: identifies the version of each tool the compiler used, and puts that info in a ".ident" assembler directive in the output ๐Ÿ”.
  • -Qn: refrains from adding ".ident" directives to the output file. This is the default ๐Ÿ™ˆ.
  • -YP,dirs: searches the directories dirs, and no others, for libraries specified with -l ๐Ÿ“š.
  • -Ym,dir: looks in the directory dir to find the M4 preprocessor ๐ŸŒธ. The assembler uses this option.

โœจ TILE-Gx Options โœจ

These -m options are supported on the TILE-Gx ๐Ÿ’–:

  • -mcmodel=small: generates code for the small model. The distance for direct calls is limited to 500M in either direction. PC-relative addresses are 32 bits, and absolute addresses support the full address range โœจ.
  • -mcmodel=large: generates code for the large model. There's no limitation on call distance, PC-relative addresses, or absolute addresses ๐Ÿ‘‘.
  • -mcpu=name: selects the type of CPU to target. Right now the only supported type is tilegx ๐ŸŽ€.
  • -m32, -m64: generates code for a 32-bit or 64-bit environment. The 32-bit environment sets int, long, and pointer to 32 bits. The 64-bit environment sets int to 32 bits, and long and pointer to 64 bits ๐ŸŒˆ.
  • -mbig-endian, -mlittle-endian: generates code in big or little endian mode, respectively ๐Ÿงš.

โœจ TILEPro Options โœจ

These -m options are supported on the TILEPro ๐Ÿ“:

  • -mcpu=name: selects the type of CPU to target. Right now the only supported type is tilepro ๐Ÿ’œ.
  • -m32: generates code for a 32-bit environment, which sets int, long, and pointer to 32 bits. This is the only supported behavior, so the flag is basically ignored ๐Ÿ™ƒ.

โœจ V850 Options โœจ

These -m options are defined for V850 implementations ๐Ÿ’…:

  • -mlong-calls, -mno-long-calls: treats all calls as being far away (near). If calls are assumed to be far away, the compiler always loads the function's address into a register and calls indirectly 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 register "ep" points to ๐ŸŒธ. The tiny data area can hold up to 256 bytes in total, with 128 bytes for byte references.
  • -msda=n: puts static or global variables whose size is n bytes or less into the small data area that register "gp" points to ๐Ÿ’–. The small data area can hold up to 64 kilobytes.
  • -mzda=n: puts static or global variables whose size is n bytes or less into the first 32 kilobytes of memory ๐Ÿงธ.
  • -mv850: specifies that the target processor is the V850 ๐ŸŽฏ.
  • -mv850e3v5: specifies that the target processor is the V850E3V5. The preprocessor constant "__v850e3v5__" is defined if this option is used ๐ŸŒŸ.
  • -mv850e2v4: specifies that the target processor is the V850E3V5. This is an alias for the -mv850e3v5 option ๐Ÿฆ‹.
  • -mv850e2v3: specifies that the target processor is the V850E2V3. The preprocessor constant "__v850e2v3__" is defined if this option is used ๐Ÿ“.
  • -mv850e2: specifies that the target processor is the V850E2. The preprocessor constant "__v850e2__" is defined if this option is used ๐Ÿ’œ.
  • -mv850e1: specifies that the target processor is the V850E1. The preprocessor constants "__v850e1__" and "__v850e__" are defined if this option is used ๐Ÿ”ฅ.
  • -mv850es: specifies that the target processor is the V850ES. This is an alias for the -mv850e1 option ๐Ÿซถ.
  • -mv850e: specifies that the target processor is the V850E. The preprocessor constant "__v850e__" is defined if this option is used ๐Ÿ‘‘.

If none of -mv850, -mv850e, -mv850e1, -mv850e2, -mv850e2v3, or -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: this option suppresses generation of the "CALLT" instruction for the v850e, v850e1, v850e2, v850e2v3, and v850e3v5 flavors of the v850 architecture ๐Ÿ™…โ€โ™€๏ธ.

This option is enabled by default when the RH850 ABI is in use (see -mrh850-abi), and disabled by default when the GCC ABI is in use. If "CALLT" instructions are being generated, then the C preprocessor symbol "__V850_CALLT__" is defined ๐Ÿ’….

  • -mrelax, -mno-relax: passes on (or does not pass on) the -mrelax command-line option to the assembler ๐Ÿงต.
  • -mlong-jumps, -mno-long-jumps: disables (or re-enables) the generation of PC-relative jump instructions ๐Ÿฆ˜.
  • -msoft-float, -mhard-float: 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 ๐Ÿ”. The use of 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: enables support for the old GCC version of the V850 ABI ๐Ÿ•ฐ๏ธ. With this version of the ABI, the following rules apply:
    • Integer sized structures and unions are returned in register "r10".
    • Large structures and unions (more than 8 bytes in size) are passed by reference.
    • Functions are aligned to 32-bit boundaries, unless optimizing for size.
    • The -m8byte-align command-line option is not supported.
    • The -mdisable-callt command-line option is supported but not enabled by default.

When this version of the ABI is enabled, the C preprocessor symbol "__V850_GCC_ABI__" is defined ๐ŸŽ€.

  • -m8byte-align, -mno-8byte-align: enables support for "double" and "long long" types to be aligned on 8-byte boundaries ๐Ÿ“. The default is to restrict the alignment of all objects to at most 4 bytes. When -m8byte-align is in effect, the C preprocessor symbol "__V850_8BYTE_ALIGN__" is defined.
  • -mbig-switch: generates code suitable for big switch tables ๐ŸŒท. Only use this option if the assembler or linker complains about out-of-range branches within a switch table ๐Ÿ˜ญ.
  • -mapp-regs: makes r2 and r5 get used in the code the compiler generates. This setting is the default ๐Ÿ’œ.
  • -mno-app-regs: makes r2 and r5 get treated as fixed registers ๐Ÿ“Œ.

โœจ VAX Options โœจ

These -m options are defined for the VAX ๐Ÿฆ•:

  • -munix: doesn't output certain jump instructions (like aobleq and so on) that the Unix assembler for the VAX can't handle across long ranges ๐Ÿ™ˆ.
  • -mgnu: does output those jump instructions, on the assumption that the GNU assembler is being used ๐Ÿงš.
  • -mg: outputs code for G-format floating-point numbers instead of D-format ๐Ÿ”ข.
  • -mlra, -mno-lra: enables Local Register Allocation. This is still experimental for the VAX, so by default the compiler uses standard reload ๐Ÿงช.

โœจ Visium Options โœจ

  • -mdebug: a program that performs file I/O and is destined to run on an MCM target should be linked with this option ๐Ÿ› ๏ธ. It causes the libraries libc.a and libdebug.a to be linked. The program should be run on the target under the control of the GDB remote debugging stub ๐Ÿฆ‹.
  • -msim โ€” okay so, a program that does file I/O and is meant to run on the simulator needs to be linked with option. ๐Ÿ™ˆ That makes the linker pull in libc.a and libsim.a โœจ
  • -mfpu, -mhard-float โ€” generates code with floating-point instructions. This is the default, so you're already getting it ๐Ÿ’…
  • -mno-fpu, -msoft-float โ€” generates code that uses library calls for floating-point instead ๐Ÿซถ
โš ๏ธ -msoft-float changes the calling convention in the output file, so it only slaps if you compile your whole program with it. You also need to compile libgcc.a (the library that comes with GCC) with -msoft-float for this to work ๐Ÿ˜ญ
  • -mcpu=cpu_type โ€” sets the instruction set, register set, and instruction scheduling parameters for the machine type cpu_type. The supported values are mcm, gr5 and gr6 ๐ŸŒธ
    • mcm is just a synonym for gr5, kept around for backward compatibility ๐Ÿ“
    • By default (unless it was 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 cpu_type, but it does not touch the instruction set or register set that -mcpu=cpu_type would ๐Ÿฆ‹
  • -msv-mode โ€” generates code for supervisor mode, where there are no restrictions on access to general registers. This is the default ๐Ÿ‘‘
  • -muser-mode โ€” generates code for user mode, where access to some general registers is forbidden. On the GR5, registers r24 to r31 can't be accessed in this mode. On the GR6, only registers r29 to r31 are affected ๐Ÿงš

๐ŸŽ€ VMS Options

These -m options are defined for the VMS implementations ๐Ÿ’œ

  • -mvms-return-codes โ€” returns VMS condition codes from "main". The default is to return POSIX-style condition (e.g. error) codes โœจ
  • -mdebug-main=prefix โ€” flags the first routine whose name starts with prefix as the main routine for the debugger ๐Ÿ”
  • -mmalloc64 โ€” defaults to 64-bit memory allocation routines ๐ŸŒˆ
  • -mpointer-size=size โ€” sets the default size of pointers. The possible options for size are 32 or short for 32-bit pointers, 64 or long for 64-bit pointers, and no for supporting only 32-bit pointers ๐Ÿซง
    • The no option disables "pragma pointer_size", so heads up ๐Ÿ™ˆ

๐Ÿฆ‹ VxWorks Options

The options in this section are defined for all VxWorks targets. Options specific to the target hardware are listed with the other options for that target ๐ŸŒธ

  • -mrtp โ€” GCC can generate code for both VxWorks kernels and real time processes (RTPs). This option switches from the former to the latter. It also defines the preprocessor macro "__RTP__" ๐Ÿ’…
  • -non-static โ€” links an RTP executable against shared libraries instead of static libraries. The options -static and -shared can also be used for RTPs, and -static is the default ๐Ÿงš
  • -Bstatic, -Bdynamic โ€” these get passed down to the linker. They're defined for compatibility with Diab ๐Ÿ”—
  • -Xbind-lazy โ€” enables lazy binding of function calls. This option is equivalent to -Wl,-z,now and is defined for compatibility with Diab ๐Ÿฆ‹
  • -Xbind-now โ€” disables lazy binding of function calls. This option is the default and is defined for compatibility with Diab ๐Ÿ’–

๐Ÿ’œ x86 Options

These -m options are defined for the x86 family of computers ๐Ÿ’ป

  • -march=cpu-type โ€” generates instructions for the machine type cpu-type. Unlike -mtune=cpu-type, which only tunes the generated code for the specified cpu-type, -march=cpu-type lets GCC generate code that may not run at all on processors other than the one you pointed at ๐Ÿ‘‘. 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 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 that the x86-64 psABI documents for that particular micro-architecture level ๐Ÿ“. Since these cpu-type values don't have a corresponding -mtune setting, using -march with them enables generic tuning. If you want specific tuning, use 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 โ€” Intel Pentium CPU with no MMX support ๐ŸŒธ
  • lakemont โ€” Intel Lakemont MCU, based on the Intel Pentium CPU ๐Ÿงš
  • pentium-mmx โ€” Intel Pentium MMX CPU, based on the Pentium core with MMX instruction set support โœจ
  • pentiumpro โ€” Intel Pentium Pro CPU ๐Ÿ’œ
  • i686 โ€” when used with -march, the Pentium Pro instruction set is used, so the code runs on all i686 family chips. When used with -mtune, it has the same meaning as generic ๐Ÿฆ‹
  • pentium2 โ€” Intel Pentium II CPU, based on the Pentium Pro core with MMX and FXSR instruction set support ๐ŸŽ€
  • pentium3, pentium3m โ€” Intel Pentium III CPU, based on the Pentium Pro core with MMX, FXSR and SSE instruction set support ๐ŸŒˆ
  • pentium-m โ€” Intel Pentium M, a low-power version of the Intel Pentium III CPU with MMX, SSE, SSE2 and FXSR instruction set support. Used by Centrino notebooks ๐Ÿ’ป
  • pentium4, pentium4m โ€” 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 โ€” Intel Core 2 CPU with 64-bit extensions, MMX, SSE, SSE2, SSE3, SSSE3, CX16, SAHF and FXSR instruction set support โ˜•
  • nehalem โ€” 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 โ€” 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 โ€” 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 โ€” 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 โ€” 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 with 64-bit extensions, MOVBE, MMX, SSE, SSE2, SSE3, SSSE3, SSE4.1, SSE4.2, POPCNT, CX16, SAHF, FXSR, AVX, XSAVE, PCLMUL, FSGSBASE, RDRND, F16C, AVX2, BMI, BMI2, LZCNT, FMA, MOVBE, HLE, RDSEED, ADCX and PREFETCHW instruction set support ๐Ÿ’œ
  • skylake โ€” Intel Skylake CPU with 64-bit extensions, MOVBE, MMX, SSE, SSE2, SSE3, SSSE3, SSE4.1, SSE4.2, POPCNT, CX16, SAHF, FXSR, AVX, XSAVE, PCLMUL, FSGSBASE, RDRND, F16C, AVX2, BMI, BMI2, LZCNT, FMA, MOVBE, HLE, RDSEED, ADCX, PREFETCHW, AES, CLFLUSHOPT, XSAVEC, XSAVES and SGX instruction set support ๐Ÿ‘‘
  • bonnell โ€” Intel Bonnell CPU with 64-bit extensions, MOVBE, MMX, SSE, SSE2, SSE3 and SSSE3 instruction set support ๐ŸŒธ
  • silvermont โ€” Intel Silvermont CPU with 64-bit extensions, MOVBE, MMX, SSE, SSE2, SSE3, SSSE3, SSE4.1, SSE4.2, POPCNT, CX16, SAHF, FXSR, PCLMUL, PREFETCHW and RDRND instruction set support ๐Ÿ“
  • goldmont โ€” Intel Goldmont CPU with 64-bit extensions, 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 with 64-bit extensions, 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 with 64-bit extensions, 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 ๐Ÿซง
  • knl โ€” Intel Knight's Landing CPU with 64-bit extensions, MOVBE, MMX, SSE, SSE2, SSE3, SSSE3, SSE4.1, SSE4.2, POPCNT, CX16, SAHF, FXSR, AVX, XSAVE, PCLMUL, FSGSBASE, RDRND, F16C, AVX2, BMI, BMI2, LZCNT, FMA, MOVBE, HLE, RDSEED, ADCX, PREFETCHW, AVX512PF, AVX512ER, AVX512F, AVX512CD and PREFETCHWT1 instruction set support ๐ŸŒˆ
  • knm ๐ŸŒธ Okay bestie, this is Intel Knights Mill! It 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 ๐Ÿฆ‹ This is the Intel Skylake Server CPU, and it's giving 64-bit extensions, MOVBE, MMX, SSE, SSE2, SSE3, SSSE3, SSE4.1, SSE4.2, POPCNT, CX16, SAHF, FXSR, AVX, XSAVE, PCLMUL, FSGSBASE, RDRND, F16C, AVX2, BMI, BMI2, LZCNT, FMA, MOVBE, HLE, RDSEED, ADCX, PREFETCHW, AES, CLFLUSHOPT, XSAVEC, XSAVES, SGX, AVX512F, CLWB, AVX512VL, AVX512BW, AVX512DQ and AVX512CD instruction set support ๐Ÿ”ฅ
  • cannonlake ๐Ÿงš Next up is the Intel Cannonlake Server CPU, which brings 64-bit extensions, MOVBE, MMX, SSE, SSE2, SSE3, SSSE3, SSE4.1, SSE4.2, POPCNT, CX16, SAHF, FXSR, AVX, XSAVE, PCLMUL, FSGSBASE, RDRND, F16C, AVX2, BMI, BMI2, LZCNT, FMA, MOVBE, HLE, RDSEED, ADCX, PREFETCHW, AES, CLFLUSHOPT, XSAVEC, XSAVES, SGX, AVX512F, AVX512VL, AVX512BW, AVX512DQ, AVX512CD, PKU, AVX512VBMI, AVX512IFMA and SHA instruction set support ๐ŸŒˆ
  • icelake-client ๐Ÿ’– This is the Intel Icelake Client CPU! Lowkey so complete: 64-bit extensions, MOVBE, MMX, SSE, SSE2, SSE3, SSSE3, SSE4.1, SSE4.2, POPCNT, CX16, SAHF, FXSR, AVX, XSAVE, PCLMUL, FSGSBASE, RDRND, F16C, AVX2, BMI, BMI2, LZCNT, FMA, MOVBE, HLE, RDSEED, ADCX, PREFETCHW, AES, CLFLUSHOPT, XSAVEC, XSAVES, SGX, AVX512F, AVX512VL, AVX512BW, AVX512DQ, AVX512CD, PKU, AVX512VBMI, AVX512IFMA, SHA, AVX512VNNI, GFNI, VAES, AVX512VBMI2, VPCLMULQDQ, AVX512BITALG, RDPID and AVX512VPOPCNTDQ instruction set support ๐Ÿ‘‘
  • icelake-server ๐ŸŽ€ The Intel Icelake Server CPU is the server sibling, and it has 64-bit extensions, MOVBE, MMX, SSE, SSE2, SSE3, SSSE3, SSE4.1, SSE4.2, POPCNT, CX16, SAHF, FXSR, AVX, XSAVE, PCLMUL, FSGSBASE, RDRND, F16C, AVX2, BMI, BMI2, LZCNT, FMA, MOVBE, HLE, RDSEED, ADCX, PREFETCHW, AES, CLFLUSHOPT, XSAVEC, XSAVES, SGX, AVX512F, AVX512VL, AVX512BW, AVX512DQ, AVX512CD, PKU, AVX512VBMI, AVX512IFMA, SHA, AVX512VNNI, GFNI, VAES, AVX512VBMI2, VPCLMULQDQ, AVX512BITALG, RDPID, AVX512VPOPCNTDQ, PCONFIG, WBNOINVD and CLWB instruction set support ๐Ÿซถ
  • cascadelake ๐Ÿ“ Meet the Intel Cascadelake CPU! It comes with 64-bit extensions, MOVBE, MMX, SSE, SSE2, SSE3, SSSE3, SSE4.1, SSE4.2, POPCNT, CX16, SAHF, FXSR, AVX, XSAVE, PCLMUL, FSGSBASE, RDRND, F16C, AVX2, BMI, BMI2, LZCNT, FMA, MOVBE, HLE, RDSEED, ADCX, PREFETCHW, AES, CLFLUSHOPT, XSAVEC, XSAVES, SGX, AVX512F, CLWB, AVX512VL, AVX512BW, AVX512DQ, AVX512CD and AVX512VNNI instruction set support ๐ŸŒธ
  • cooperlake ๐Ÿ’œ This is the Intel cooperlake CPU (lowercase in the original, and I'm keeping it that way for the vibe check), with 64-bit extensions, MOVBE, MMX, SSE, SSE2, SSE3, SSSE3, SSE4.1, SSE4.2, POPCNT, CX16, SAHF, FXSR, AVX, XSAVE, PCLMUL, FSGSBASE, RDRND, F16C, AVX2, BMI, BMI2, LZCNT, FMA, MOVBE, HLE, RDSEED, ADCX, PREFETCHW, AES, CLFLUSHOPT, XSAVEC, XSAVES, SGX, AVX512F, CLWB, AVX512VL, AVX512BW, AVX512DQ, AVX512CD, AVX512VNNI and AVX512BF16 instruction set support โœจ
  • tigerlake ๐Ÿฆ‹ The Intel Tigerlake CPU is giving 64-bit extensions, MOVBE, MMX, SSE, SSE2, SSE3, SSSE3, SSE4.1, SSE4.2, POPCNT, CX16, SAHF, FXSR, AVX, XSAVE, PCLMUL, FSGSBASE, RDRND, F16C, AVX2, BMI, BMI2, LZCNT, FMA, MOVBE, HLE, RDSEED, ADCX, PREFETCHW, AES, CLFLUSHOPT, XSAVEC, XSAVES, SGX, AVX512F, AVX512VL, AVX512BW, AVX512DQ, AVX512CD, PKU, AVX512VBMI, AVX512IFMA, SHA, AVX512VNNI, GFNI, VAES, AVX512VBMI2, VPCLMULQDQ, AVX512BITALG, RDPID, AVX512VPOPCNTDQ, MOVDIRI, MOVDIR64B, CLWB, AVX512VP2INTERSECT and KEYLOCKER instruction set support ๐Ÿ”ฅ
  • sapphirerapids ๐Ÿ‘‘ The Intel sapphirerapids CPU (also lowercase, slay anyway) comes with 64-bit extensions, MOVBE, MMX, SSE, SSE2, SSE3, SSSE3, SSE4.1, SSE4.2, POPCNT, CX16, SAHF, FXSR, AVX, XSAVE, PCLMUL, FSGSBASE, RDRND, F16C, AVX2, BMI, BMI2, LZCNT, FMA, MOVBE, HLE, RDSEED, ADCX, PREFETCHW, AES, CLFLUSHOPT, XSAVEC, XSAVES, SGX, AVX512F, CLWB, AVX512VL, AVX512BW, AVX512DQ, AVX512CD, AVX512VNNI, AVX512BF16, MOVDIRI, MOVDIR64B, AVX512VP2INTERSECT, ENQCMD, CLDEMOTE, PTWRITE, WAITPKG, SERIALIZE, TSXLDTRK, UINTR, AMX-BF16, AMX-TILE, AMX-INT8, AVX-VNNI and AVX512FP16 instruction set support ๐Ÿ’…
  • alderlake ๐Ÿงš The Intel Alderlake CPU is the one with a shorter, cute list: 64-bit extensions, MOVBE, MMX, SSE, SSE2, SSE3, SSSE3, SSE4.1, SSE4.2, POPCNT, AES, PREFETCHW, PCLMUL, RDRND, XSAVE, XSAVEC, XSAVES, XSAVEOPT, FSGSBASE, PTWRITE, RDPID, SGX, 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 ๐ŸŒธ Last Intel one, the Intel Rocketlake CPU! It has 64-bit extensions, MOVBE, MMX, SSE, SSE2, SSE3, SSSE3, SSE4.1, SSE4.2, POPCNT, CX16, SAHF, FXSR, AVX, XSAVE, PCLMUL, FSGSBASE, RDRND, F16C, AVX2, BMI, BMI2, LZCNT, FMA, MOVBE, HLE, RDSEED, ADCX, PREFETCHW, AES, CLFLUSHOPT, XSAVEC, XSAVES, AVX512F, AVX512VL, AVX512BW, AVX512DQ, AVX512CD, PKU, AVX512VBMI, AVX512IFMA, SHA, AVX512VNNI, GFNI, VAES, AVX512VBMI2, VPCLMULQDQ, AVX512BITALG, RDPID and AVX512VPOPCNTDQ instruction set support ๐Ÿ’–
  • k6 ๐ŸŽ€ This is the AMD K6 CPU, with MMX instruction set support. Simple and iconic ๐Ÿ’…
  • k6-2, k6-3 ๐Ÿฆ‹ These are the improved versions of the AMD K6 CPU, and they come with MMX and 3DNow! instruction set support โœจ
  • athlon, athlon-tbird ๐ŸŒˆ The AMD Athlon CPU, which has MMX, 3dNOW!, enhanced 3DNow! and SSE prefetch instructions support ๐Ÿ”ฅ
  • athlon-4, athlon-xp, athlon-mp ๐Ÿ‘‘ These are the improved AMD Athlon CPUs. They have MMX, 3DNow!, enhanced 3DNow! and full SSE instruction set support, so they're a whole mood ๐Ÿ’œ
  • k8, opteron, athlon64, athlon-fx ๐ŸŒธ These are processors based on the AMD K8 core with x86-64 instruction set support, including the AMD Opteron, Athlon 64, and Athlon 64 FX processors. Okay, and this supersets MMX, SSE, SSE2, 3DNow!, enhanced 3DNow! and 64-bit instruction set extensions, so it's a full package ๐Ÿซถ
  • k8-sse3, opteron-sse3, athlon64-sse3 ๐Ÿ“ These are the improved versions of the AMD K8 cores, and the big upgrade here is SSE3 instruction set support โœจ
  • amdfam10, barcelona ๐Ÿงš These are CPUs based on AMD Family 10h cores with x86-64 instruction set support. Lowkey iconic: this supersets MMX, SSE, SSE2, SSE3, SSE4A, 3DNow!, enhanced 3DNow!, ABM and 64-bit instruction set extensions ๐Ÿ’–
  • bdver1 ๐Ÿ’… These are CPUs based on AMD Family 15h cores with x86-64 instruction set support. It supersets FMA4, AVX, XOP, LWP, AES, PCLMUL, CX16, MMX, SSE, SSE2, SSE3, SSE4A, SSSE3, SSE4.1, SSE4.2, ABM and 64-bit instruction set extensions ๐Ÿ”ฅ
  • bdver2 ๐Ÿฆ‹ This is an AMD Family 15h core based CPU with x86-64 instruction set support. It supersets BMI, TBM, F16C, FMA, FMA4, AVX, XOP, LWP, AES, PCLMUL, CX16, MMX, SSE, SSE2, SSE3, SSE4A, SSSE3, SSE4.1, SSE4.2, ABM and 64-bit instruction set extensions ๐ŸŒˆ
  • bdver3 ๐Ÿ‘‘ Another AMD Family 15h core based CPU with x86-64 instruction set support! It supersets BMI, TBM, F16C, FMA, FMA4, FSGSBASE, AVX, XOP, LWP, AES, PCLMUL, CX16, MMX, SSE, SSE2, SSE3, SSE4A, SSSE3, SSE4.1, SSE4.2, ABM and 64-bit instruction set extensions ๐Ÿ’œ
  • bdver4 ๐ŸŽ€ Still AMD Family 15h core based, with x86-64 instruction set support. It supersets BMI, BMI2, TBM, F16C, FMA, FMA4, FSGSBASE, AVX, AVX2, XOP, LWP, AES, PCLMUL, CX16, MOVBE, MMX, SSE, SSE2, SSE3, SSE4A, SSSE3, SSE4.1, SSE4.2, ABM and 64-bit instruction set extensions ๐Ÿ’…
  • znver1 ๐Ÿซถ These are AMD Family 17h core based CPUs with x86-64 instruction set support. They supersede... well, they 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, and this one 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, and yep, it's a whole upgrade. It supersets BMI, BMI2, CLWB, F16C, FMA, FSGSBASE, AVX, AVX2, ADCX, RDSEED, MWAITX, SHA, CLZERO, AES, PCLMUL, CX16, MOVBE, MMX, SSE, SSE2, SSE3, SSE4A, SSSE3, SSE4.1, SSE4.2, ABM, XSAVEC, XSAVES, CLFLUSHOPT, POPCNT, RDPID, WBNOINVD, PKU, VPCLMULQDQ, VAES, and 64-bit instruction set extensions โœจ
  • btver1 ๐Ÿงš These are CPUs based on AMD Family 14h cores with x86-64 instruction set support. They 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 ๐Ÿซถ This is the IDT WinChip C6 CPU, which gets dealt with in the same way as i486 with additional MMX instruction set support ๐ŸŒธ
  • winchip2 ๐Ÿ’… This is the IDT WinChip 2 CPU, which is handled the same way as i486, with additional MMX and 3DNow! instruction set support โœจ
  • c3 ๐Ÿ“ The VIA C3 CPU has MMX and 3DNow! instruction set support. Quick heads-up, bestie: no scheduling is implemented for this chip ๐Ÿ™ˆ
  • c3-2 ๐ŸŒˆ The VIA C3-2 (Nehemiah/C5XL) CPU has MMX and SSE instruction set support. No scheduling is implemented for this chip either ๐Ÿงš
  • c7 ๐ŸŽ€ The VIA C7 (Esther) CPU comes with MMX, SSE, SSE2 and SSE3 instruction set support. Again, no scheduling is implemented for this chip ๐Ÿฆ‹
  • samuel-2 ๐Ÿ’œ The VIA Eden Samuel 2 CPU has MMX and 3DNow! instruction set support. No scheduling is implemented for this chip, so keep that in mind ๐Ÿ™ˆ
  • nehemiah ๐Ÿ‘‘ The VIA Eden Nehemiah CPU has MMX and SSE instruction set support. And yup, no scheduling is implemented for this chip ๐Ÿ’–
  • esther โ€” ๐Ÿ’– VIA Eden Esther CPU with MMX, SSE, SSE2 and SSE3 instruction set support. (No scheduling is implemented for this chip.)
  • eden-x2 โ€” โœจ VIA Eden X2 CPU with x86-64, MMX, SSE, SSE2 and SSE3 instruction set support. (No scheduling is implemented for this chip.)
  • eden-x4 โ€” ๐Ÿ”ฅ VIA Eden X4 CPU with x86-64, MMX, SSE, SSE2, SSE3, SSSE3, SSE4.1, SSE4.2, AVX and AVX2 instruction set support. (No scheduling is implemented for this chip.)
  • nano โ€” ๐Ÿฆ‹ Generic VIA Nano CPU with x86-64, MMX, SSE, SSE2, SSE3 and SSSE3 instruction set support. (No scheduling is implemented for this chip.)
  • nano-1000 โ€” ๐ŸŒธ VIA Nano 1xxx CPU with x86-64, MMX, SSE, SSE2, SSE3 and SSSE3 instruction set support. (No scheduling is implemented for this chip.)
  • nano-2000 โ€” ๐ŸŽ€ VIA Nano 2xxx CPU with x86-64, MMX, SSE, SSE2, SSE3 and SSSE3 instruction set support. (No scheduling is implemented for this chip.)
  • nano-3000 โ€” ๐Ÿงš VIA Nano 3xxx CPU with x86-64, MMX, SSE, SSE2, SSE3, SSSE3 and SSE4.1 instruction set support. (No scheduling is implemented for this chip.)
  • nano-x2 โ€” ๐Ÿ‘‘ VIA Nano Dual Core CPU with x86-64, MMX, SSE, SSE2, SSE3, SSSE3 and SSE4.1 instruction set support. (No scheduling is implemented for this chip.)
  • nano-x4 โ€” ๐Ÿ’œ VIA Nano Quad Core CPU with x86-64, MMX, SSE, SSE2, SSE3, SSSE3 and SSE4.1 instruction set support. (No scheduling is implemented for this chip.)
  • geode โ€” ๐Ÿ“ AMD Geode embedded processor with MMX and 3DNow! instruction set support.

  • -mtune=cpu-type โ€” ๐ŸŽฏ Okay so this one tunes everything that can be tuned in the generated code to cpu-type, except for the ABI and the set of available instructions. Picking a specific cpu-type schedules things nicely for that particular chip, but GCC will never 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 makes code tuned for Pentium 4 that still runs on i686 machines. ๐Ÿ’…
    • The choices for cpu-type are the same as for -march. In addition, -mtune supports 2 extra choices for cpu-type:
    • 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 don't know exactly what CPU your users will have, this is the one you want. ๐Ÿซถ
    • As new processors hit the marketplace, the behavior of this option will change. So if you upgrade to a newer version of GCC, the code generation controlled by this option will shift to match whatever processors are most common when that version of GCC is released. ๐ŸŒˆ
    • There is no -march=generic option, because -march indicates the instruction set the compiler can use, and there's no generic instruction set that applies to all processors. -mtune, on the other hand, indicates the processor (or, in this case, collection of processors) the code is optimized for. ๐Ÿง 
    • intel โ€” ๐Ÿ’– Produces code optimized for the most current Intel processors, which are Haswell and Silvermont for this version of GCC. If you know the CPU your code will run on, use the matching -mtune or -march option instead of -mtune=intel. But if you want your application to perform better on both Haswell and Silvermont, this is the one. ๐Ÿ”ฅ
    • As new Intel processors get deployed, the behavior of this option will change. So if you upgrade to a newer version of GCC, the code generation controlled by this option will reflect the most current Intel processors at the time that version of GCC is released. โญ
    • There is no -march=intel option, because -march indicates the instruction set the compiler can use, and there's no common instruction set that applies to all processors. -mtune indicates the processor (or, in this case, collection of processors) the code is optimized for. ๐ŸŽ€
  • -mcpu=cpu-type โ€” ๐Ÿ™ˆ A deprecated synonym for -mtune. Use -mtune instead, bestie.
  • -mfpmath=unit โ€” ๐Ÿงฎ Generates floating-point arithmetic for the selected unit. The choices for unit are:
    • 387 โ€” ๐ŸŒธ Uses the standard 387 floating-point coprocessor that's on the majority of chips, and emulates it otherwise. Code compiled with this option runs almost everywhere. The temporary results are computed in 80-bit precision instead of the precision specified by the type, so you can get slightly different results compared to most other chips. See -ffloat-store for a more detailed description. This is the default choice for non-Darwin x86-32 targets.
    • sse โ€” ๐Ÿš€ Uses scalar floating-point instructions from the SSE instruction set. This is supported by Pentium III and newer chips, and in the AMD line by Athlon-4, Athlon XP and Athlon MP chips. The earlier version of SSE only supports single-precision arithmetic, so double and extended-precision arithmetic still get done using 387. A later version, present only in Pentium 4 and AMD x86-64 chips, supports double-precision arithmetic too.
      • For the x86-32 compiler, you must use -march=cpu-type, -msse or -msse2 switches to enable SSE extensions and make this option effective. For the x86-64 compiler, these extensions are enabled by default.
      • The resulting code should be considerably faster in most cases and avoid the numerical instability problems of 387 code, but it may break some existing code that expects temporaries to be 80 bits. ๐Ÿ™ƒ
      • This is the default choice for the x86-64 compiler, Darwin x86-32 targets, and the default choice for x86-32 targets with the SSE2 instruction set when -ffast-math is enabled.
    • sse,387, sse+387, both โ€” ๐Ÿงช Attempts to use both instruction sets at once. This effectively doubles the amount of available registers, and on chips with separate execution units for 387 and SSE, the execution resources too. Use this option with care! It's still experimental, because the GCC register allocator doesn't model separate functional units well, which can lead to unstable performance. ๐Ÿ’€
  • -masm=dialect โ€” ๐Ÿ“œ Outputs assembly instructions using the selected dialect. This also affects which dialect is used for basic "asm" and extended "asm". Supported choices (in dialect order) are att or intel. The default is att. Darwin does not support intel.
  • -mieee-fp, -mno-ieee-fp โ€” ๐Ÿ”ข Controls whether or not the compiler uses IEEE floating-point comparisons. These correctly handle the case where the result of a comparison is unordered.
  • -m80387, -mhard-float โ€” ๐ŸŒˆ Generates output containing 80387 instructions for floating point.
  • -mno-80387, -msoft-float โ€” ๐Ÿซง Generates output containing library calls for floating point.
Warning: the requisite libraries are not part of GCC. Normally the facilities of the machine's usual C compiler are used, but this cannot be done directly in cross-compilation. You must make your own arrangements to provide suitable library functions for cross-compilation. ๐Ÿ˜ญ
On machines where a function returns floating-point results in the 80387 register stack, some floating-point opcodes may be emitted even if -msoft-float is used.
  • -mno-fp-ret-in-387 โ€” ๐Ÿ™… Do not use the FPU registers for return values of functions. The usual calling convention has functions return values of types "float" and "double" in an FPU register, even if there is no FPU. The idea is that the operating system should emulate an FPU. The option -mno-fp-ret-in-387 causes such values to be returned in ordinary CPU registers instead.
  • -mno-fancy-math-387 โ€” ๐Ÿงฎ Some 387 emulators don't support the "sin", "cos" and "sqrt" instructions for the 387. Specify this option to avoid generating those instructions. This option is overridden when -march indicates that the target CPU always has an FPU, so the instruction doesn't need emulation. These instructions are not generated unless you also use the -funsafe-math-optimizations switch.
  • -malign-double, -mno-align-double โ€” ๐Ÿ“ Controls whether GCC aligns "double", "long double", and "long long" variables on a two-word boundary or a one-word boundary. Aligning "double" variables on a two-word boundary produces code that runs somewhat faster on a Pentium, at the expense of more memory. On x86-64, -malign-double is enabled by default.
Warning: if you use the -malign-double switch, structures containing the above types are aligned differently than the published application binary interface specifications for the x86-32, and they are not binary compatible with structures in code compiled without that switch. ๐Ÿ’”
  • -m96bit-long-double, -m128bit-long-double โ€” ๐Ÿ“ These switches control the size of the "long double" type. The x86-32 application binary interface specifies the size to be 96 bits, so -m96bit-long-double is the default in 32-bit mode. Modern architectures (Pentium and newer) prefer "long double" to be aligned to an 8- or 16-byte boundary. In arrays or structures conforming to the ABI, that isn't possible. So specifying -m128bit-long-double aligns "long double" to a 16-byte boundary by padding it with an additional 32-bit zero.
    • In the x86-64 compiler, -m128bit-long-double is the default choice, since its ABI specifies that "long double" is aligned on a 16-byte boundary. ๐Ÿ’…
    • Notice that neither of these options enables any extra precision over the x87 standard of 80 bits for a "long double".
Warning: if you override the default value for your target ABI, this changes the size of structures and arrays containing "long double" variables, as well as modifying the function calling convention for functions taking "long double". Hence they are not binary-compatible with code compiled without that switch. ๐Ÿฅบ
  • -mlong-double-64, -mlong-double-80, -mlong-double-128 โ€” okay so these three decide how big the long double type is ๐Ÿ“โœจ. -mlong-double-64 makes long double exactly the same as double ๐ŸŒธ (that's the default for the 32-bit Bionic C library ๐Ÿค–). -mlong-double-128 makes it equivalent to __float128 ๐ŸŒˆ, which is the default for the 64-bit Bionic C library ๐Ÿ’…. -mlong-double-80 is the third one in the lineup.
Warning: if you override the default for your target ABI, the size of structures and arrays holding long double variables changes ๐Ÿ’€, and so does the calling convention for functions that take long double. So your code won't be binary-compatible with stuff compiled without that switch ๐Ÿ™ˆ.
  • -malign-data=type โ€” this one is all about how GCC lines up your variables in memory ๐Ÿ“๐ŸŽ€. The type can be compat, which uses the increased alignment that GCC 4.8 and earlier used ๐Ÿ•ฐ๏ธ; abi, which uses the alignment the psABI specifies ๐Ÿ“œ; or cacheline, which bumps the alignment to match the cache line size ๐Ÿงš. compat is the default, so you're already set unless you say otherwise ๐Ÿ’–.
  • -mlarge-data-threshold=threshold โ€” when you've got -mcmodel=medium turned on, any data object bigger than threshold gets tossed into the large data section ๐Ÿ“. The value has to be the same for every object linked into the binary โš ๏ธ, and it defaults to 65535 โœจ.
  • -mrtd โ€” a whole different function-calling convention, babe ๐Ÿฆ‹. Functions that take a fixed number of arguments return with the ret num instruction, which pops their arguments on the way out. That saves one instruction in the caller, since the caller doesn't have to pop anything ๐Ÿงน.

You can make just one function use this sequence with the stdcall function attribute ๐ŸŽฏ, and you can override -mrtd for a specific function with the cdecl attribute ๐Ÿ”.

Warning: this calling convention is NOT the one normally used on Unix ๐Ÿšซ, so don't use it if you need to call libraries compiled with the Unix compiler ๐Ÿ˜ญ.

Also, you MUST provide function prototypes for every function that takes a variable number of arguments (printf included) ๐Ÿซถ, or GCC generates incorrect code for those calls. And if you call a function with too many arguments, you get seriously incorrect code ๐Ÿ’€. (Normally, extra arguments are harmlessly ignored, so this one is a plot twist ๐Ÿ™ƒ.)

  • -mregparm=num โ€” controls how many registers get used to pass integer arguments ๐Ÿง . By default, no registers are used for arguments, and at most 3 registers can be used. You can control this for one specific function with the regparm function attribute ๐ŸŽ€.
Warning: if you use this switch and num is nonzero, every module must be built with the same value ๐Ÿšจ, including any libraries, the system libraries, and the startup modules. No exceptions, bestie ๐Ÿ˜ค.
  • -msseregparm โ€” uses SSE register passing conventions for float and double arguments and return values ๐Ÿ”ฅ. You can control this for a specific function with the sseregparm function attribute ๐Ÿฆ‹.
Warning: same deal here ๐Ÿ˜ฌ. If you use this switch, you must build all modules with the same value, including any libraries, the system libraries, and the startup modules.
  • -mvect8-ret-in-mem โ€” returns 8-byte vectors in memory instead of MMX registers ๐Ÿงบ. This is the default on VxWorks, so it matches the ABI of the Sun Studio compilers up until version 12 ๐Ÿ•ฐ๏ธ. Only use this 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) ๐Ÿ’œ. -mpc80 rounds them to 64 bits (extended double precision), and that's the default ๐Ÿ‘‘. Once you use this option, higher-precision floating-point operations aren't available to the programmer unless you set the FPU control word explicitly ๐Ÿ› ๏ธ.

Rounding to less than the default 80 bits can speed some programs up by 2% or more โšก. BUT, some math libraries assume extended-precision (80-bit) floating-point operations are on by default ๐Ÿ˜ฑ. Routines in those libraries could lose a ton of accuracy, usually through so-called "catastrophic cancellation", if you use this option to drop below extended precision ๐Ÿ’€.

  • -mstackrealign โ€” realigns the stack at entry ๐Ÿชœโœจ. On x86, this option generates an alternate prologue and epilogue that realigns the run-time stack if it's needed ๐Ÿ”ง. It lets legacy code that keeps 4-byte stack alignment play nicely with modern code that keeps 16-byte stack alignment for SSE compatibility ๐Ÿซถ. You can also check out the force_align_arg_pointer attribute, which works on individual functions ๐ŸŽ€.
  • -mpreferred-stack-boundary=num โ€” tries to keep the stack boundary aligned to a 2 raised to num byte boundary ๐Ÿ“. If you don't specify it, the default is 4 (16 bytes or 128 bits) ๐Ÿ’–.
Warning: when you're generating code for the x86-64 architecture with SSE extensions disabled, you can use -mpreferred-stack-boundary=3 to keep the stack boundary aligned to an 8 byte boundary ๐Ÿง. BUT the x86-64 ABI requires 16 byte stack alignment, so this is ABI incompatible ๐Ÿšซ. It's only meant for a controlled environment where stack space is a seriously limited resource ๐Ÿฅฒ.

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 can cause misaligned memory access traps ๐Ÿ˜ต. Variable arguments also get handled incorrectly for 16 byte aligned objects (including x87 long double and __int128), which gives wrong results ๐Ÿ™ƒ. So you MUST build all modules with -mpreferred-stack-boundary=3, including any libraries, the system libraries, and the 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 it, the one set 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 some serious run-time performance hits ๐ŸŒ. On Pentium III, the Streaming SIMD Extension (SSE) data type __m128 may not work properly if it isn't 16-byte aligned ๐Ÿ˜ฌ.

To make sure these values are aligned properly on the stack, the stack boundary has to be as aligned as the most demanding value stored on it ๐Ÿ—๏ธ. Every function also has to be generated so it keeps the stack aligned ๐Ÿซก. That means calling a function compiled with a higher preferred stack boundary from a function compiled with a lower one will most likely misalign the stack ๐Ÿ’ฅ. For libraries that use callbacks, it's recommended to always use the default setting ๐Ÿ’œ.

This extra alignment eats up extra stack space and usually increases code size ๐Ÿ“ˆ. If your code is sensitive to stack usage, like embedded systems and operating system kernels, you might want to lower the preferred alignment to -mpreferred-stack-boundary=2 ๐ŸŒธ.

  • The big ISA squad โ€” these switches turn on the instruction sets listed below, so GCC can use them in your generated code ๐Ÿš€. Each one has a matching -mno- option to turn it off ๐Ÿšซ. Here's the whole lineup, no skipping ๐Ÿ’…:
-mmmx
-msse
-msse2
-msse3
-mssse3
-msse4
-msse4a
-msse4.1
-msse4.2
-mavx
-mavx2
-mavx512f
-mavx512pf
-mavx512er
-mavx512cd
-mavx512vl
-mavx512bw
-mavx512dq
-mavx512ifma
-mavx512vbmi
-msha
-maes
-mpclmul
-mclflushopt
-mclwb
-mfsgsbase
-mptwrite
-mrdrnd
-mf16c
-mfma
-mpconfig
-mwbnoinvd
-mfma4
-mprfchw
-mrdpid
-mprefetchwt1
-mrdseed
-msgx
-mxop
-mlwp
-m3dnow
-m3dnowa
-mpopcnt
-mabm
-madx
-mbmi
-mbmi2
-mlzcnt
-mfxsr
-mxsave
-mxsaveopt
-mxsavec
-mxsaves
-mrtm
-mhle
-mtbm
-mmwaitx
-mclzero
-mpku
-mavx512vbmi2
-mavx512bf16
-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

These turn on the MMX, SSE, SSE2, SSE3, SSSE3, SSE4, SSE4A, SSE4.1, SSE4.2, AVX, AVX2, AVX512F, AVX512PF, AVX512ER, AVX512CD, AVX512VL, AVX512BW, AVX512DQ, AVX512IFMA, AVX512VBMI, SHA, AES, PCLMUL, CLFLUSHOPT, CLWB, FSGSBASE, PTWRITE, RDRND, F16C, FMA, PCONFIG, WBNOINVD, FMA4, PREFETCHW, RDPID, PREFETCHWT1, RDSEED, SGX, XOP, LWP, 3DNow!, enhanced 3DNow!, POPCNT, ABM, ADX, BMI, BMI2, LZCNT, FXSR, XSAVE, XSAVEOPT, XSAVEC, XSAVES, RTM, HLE, TBM, MWAITX, CLZERO, PKU, AVX512VBMI2, GFNI, VAES, WAITPKG, VPCLMULQDQ, AVX512BITALG, MOVDIRI, MOVDIR64B, AVX512BF16, ENQCMD, AVX512VPOPCNTDQ, AVX5124FMAPS, AVX512VNNI, AVX5124VNNIW, SERIALIZE, UINTR, HRESET, AMXTILE, AMXINT8, AMXBF16, KL, WIDEKL, AVXVNNI, AVX512FP16, or CLDEMOTE extended instruction sets ๐ŸŽ‰.

The same extensions also show up as built-in functions ๐Ÿงฉ. Check out x86 Built-in Functions for the details on which functions get enabled and disabled by these switches ๐Ÿ“–.

If you want GCC to generate SSE/SSE2 instructions automatically from floating-point code (instead of 387 instructions), look at -mfpmath=sse ๐Ÿ”ฅ.

Heads up: GCC depresses SSEx instructions when -mavx is used ๐ŸงŠ. Instead, it generates new AVX instructions, or AVX equivalents for all the SSEx instructions, when it needs them ๐Ÿฆ‹.

These options let GCC use these extended instructions in the generated code, even without -mfpmath=sse ๐Ÿ’…. If your app does run-time CPU detection, you need to compile separate files for each supported architecture, using the right flags ๐Ÿซถ. In particular, the file with the CPU detection code should be compiled WITHOUT these options ๐Ÿ™ˆ.

  • -mdump-tune-features โ€” okay bestie, this one makes GCC dump the names of the x86 performance tuning features and their default settings ๐Ÿงš You can use those names with -mtune-ctrl=feature-list.
  • -mtune-ctrl=feature-list โ€” the fine-grain control knob for x86 code generation features โœจ feature-list is a comma-separated list of feature names, and you can look them up with -mdump-tune-features. A feature turns on if it has no ^ in front of it, and turns off if it does.
๐Ÿ’€ This one is really meant for GCC developers. Using it may lead to code paths that testing never covers, and that can potentially result in compiler ICEs or runtime errors. Proceed with caution, bestie.
  • -mno-default โ€” turns off all the tunable features ๐Ÿ™ˆ See also -mtune-ctrl=feature-list and -mdump-tune-features.
  • -mcld โ€” makes GCC emit a cld instruction in the prologue of functions that use string instructions ๐ŸŒธ String instructions depend on the DF flag to pick autoincrement or autodecrement mode. The ABI says DF gets cleared on function entry, but some operating systems don't clear it in their exception dispatchers. So the handler can run with DF set, and string instructions end up going the wrong direction ๐Ÿ˜ญ This option can be enabled by default on 32-bit x86 targets if you configure GCC with the --enable-cld configure option. In that case, you can suppress cld generation with the -mno-cld compiler option.
  • -mvzeroupper โ€” emits a vzeroupper instruction before control flow leaves the function, which minimises the AVX to SSE transition penalty and removes unnecessary zeroupper intrinsics ๐Ÿฆ‹
  • -mprefer-avx128 โ€” the auto-vectorizer uses 128-bit AVX instructions instead of 256-bit AVX instructions ๐Ÿ’œ
  • -mprefer-vector-width=opt โ€” uses opt-bit vector width in instructions instead of the default on the selected platform ๐Ÿ‘‘
  • -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 โ€” sets the maximum number of bits that can be stored to memory efficiently to bits. The valid values are 128, 256 and 512.
    • none โ€” no extra limitations on GCC beyond what the selected platform already defines.
    • 128 โ€” prefers 128-bit vector width for instructions.
    • 256 โ€” prefers 256-bit vector width for instructions.
    • 512 โ€” prefers 512-bit vector width for instructions.

  • -mcx16 โ€” lets GCC generate CMPXCHG16B instructions in 64-bit code for compare-and-exchange on 16-byte aligned 128-bit objects ๐Ÿ’… This is iconic for atomic updates of data structures bigger than one machine word. The compiler uses it to implement __sync builtins. However, __atomic builtins operating on 128-bit integers always go through a library call.
  • -msahf โ€” enables SAHF instructions in 64-bit code ๐ŸŒˆ 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. They're load and store instructions, respectively, for certain status flags. In 64-bit mode, SAHF gets used to optimise the fmod, drem, and remainder built-in functions; see Other Builtins for details.
  • -mmovbe โ€” uses the movbe instruction to implement __builtin_bswap32 and __builtin_bswap64 โœจ
  • -mshstk โ€” enables the shadow stack built-in functions from x86 Control-flow Enforcement Technology (CET) ๐Ÿ›ก๏ธ
  • -mcrc32 โ€” makes the built-in functions __builtin_ia32_crc32qi, __builtin_ia32_crc32hi, __builtin_ia32_crc32si and __builtin_ia32_crc32di generate the crc32 machine instruction ๐ŸŽ€
  • -mmwait โ€” makes the built-in functions __builtin_ia32_monitor and __builtin_ia32_mwait generate the monitor and mwait machine instructions ๐Ÿงš
  • -mrecip โ€” uses RCPSS and RSQRTSS (plus their vectorized versions RCPPS and RSQRTPS) with an extra Newton-Raphson step for precision, instead of DIVSS and SQRTSS (and their vectorized versions) for single-precision floating-point arguments ๐Ÿ”ฅ These instructions only get generated when -funsafe-math-optimizations is enabled together with -ffinite-math-only and -fno-trapping-math. The throughput of the sequence beats the non-reciprocal instruction, but its precision can drop by up to 2 ulp (i.e. the inverse of 1.0 equals 0.99999994).
    • GCC already implements 1.0f/sqrtf(x) in terms of RSQRTSS (or RSQRTPS) with -ffast-math (or the option combination above), so it doesn't need -mrecip for that.
    • GCC also emits the sequence with the extra Newton-Raphson step for vectorized single-float division and vectorized sqrtf(x) already with -ffast-math (or the option combination above), so it doesn't need -mrecip there either.
  • -mrecip=opt โ€” controls which reciprocal estimate instructions may be used ๐Ÿ’– opt is a comma-separated list, and any option can be preceded by a ! to invert it.
    • all โ€” enables all estimate instructions.
    • default โ€” enables the default instructions, equivalent to -mrecip.
    • none โ€” disables all estimate instructions, equivalent to -mno-recip.
    • div โ€” enables the approximation for scalar division.
    • vec-div โ€” enables the approximation for vectorized division.
    • sqrt โ€” enables the approximation for scalar square root.
    • vec-sqrt โ€” enables the approximation for vectorized square root.
    • So, for example, -mrecip=all,!sqrt enables all of the reciprocal approximations except for square root ๐Ÿซถ
  • -mveclibabi=type โ€” specifies the ABI type to use when vectorizing intrinsics with an external library ๐ŸŒธ The supported type values are svml for the Intel short vector math library and acml for the AMD math core library. To use this option, both -ftree-vectorize and -funsafe-math-optimizations have to be enabled, and an SVML or ACML ABI-compatible library must be specified at link time.
    • With -mveclibabi=svml, 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.
    • With -mveclibabi=acml, GCC currently emits calls to __vrd2_sin, __vrd2_cos, __vrd2_exp, __vrd2_log, __vrd2_log2, __vrd2_log10, __vrs4_sinf, __vrs4_cosf, __vrs4_expf, __vrs4_logf, __vrs4_log2f, __vrs4_log10f and __vrs4_powf for the corresponding function type.
  • -mabi=name โ€” generates code for the specified calling convention ๐Ÿ‘‘ The permissible values are sysv for the ABI used on GNU/Linux and other systems, and ms for the Microsoft ABI. The default is the Microsoft ABI when targeting Microsoft Windows, and the SysV ABI on all other systems. You can control this for specific functions with the function attributes ms_abi and sysv_abi.

  • -mforce-indirect-call โ€” forces all calls to functions to be indirect ๐Ÿ” This is useful with Intel Processor Trace, since it gives more precise timing information for function calls.
  • -mmanual-endbr โ€” inserts an ENDBR instruction at function entry only via the cf_check function attribute ๐ŸŽฏ This is useful with -fcf-protection=branch to control ENDBR insertion at function entry.
  • -mcall-ms2sysv-xlogues โ€” because of differences between the 64-bit ABIs, any Microsoft ABI function that calls a System V ABI function must consider RSI, RDI and XMM6-15 as clobbered ๐Ÿ˜ฎโ€๐Ÿ’จ By default, the code that saves and restores these registers is emitted inline, which makes the prologues and epilogues pretty lengthy. With this option, the prologues and epilogues use stubs in the static portion of libgcc to do those saves and restores. That shrinks function size at the cost of a few extra instructions ๐Ÿฆ‹
  • -mtls-dialect=type โ€” generates code to access thread-local storage using the gnu or gnu2 conventions ๐Ÿงต gnu is the conservative default. gnu2 is more efficient, but it may add compile- and run-time requirements that can't be satisfied on all systems.
  • -mpush-args, -mno-push-args โ€” use PUSH operations to store outgoing parameters ๐Ÿ’œ This method is shorter and usually just as fast as the SUB/MOV method, and it's enabled by default. In some cases, disabling it may improve performance because of better scheduling and fewer dependencies.
  • -maccumulate-outgoing-args โ€” if enabled, the maximum amount of space required for outgoing arguments gets computed in the function prologue ๐Ÿš€ This is faster on most modern CPUs thanks to reduced dependencies, improved scheduling, and reduced stack usage when the preferred stack boundary is not equal to 2. The drawback is a notable increase in code size. This switch implies -mno-push-args.
  • -mthreads โ€” supports thread-safe exception handling on MinGW ๐Ÿง Programs that rely on thread-safe exception handling must compile and link all code with the -mthreads option. When compiling, -mthreads defines -D_MT. When linking, it links in a special thread helper library, -lmingwthrd, which cleans up per-thread exception-handling data.
  • -mms-bitfields, -mno-ms-bitfields โ€” enable or disable bit-field layout that's compatible with the native Microsoft Windows compiler ๐ŸชŸ

Okay so, if "packed" gets slapped on a structure, or you use bit-fields, the Microsoft ABI might lay that struct out totally differently from how GCC normally does ๐Ÿ’… This matters a lot when you're passing packed data between GCC-compiled functions and the native Microsoft compiler, whether that's through a function call or as data in a file, because you might need to access either format ๐Ÿซถ

This one is on by default for Microsoft Windows targets ๐ŸชŸ You can also control it locally with variable or type attributes. Check out x86 Variable Attributes and x86 Type Attributes for the deets ๐Ÿ“–

The Microsoft structure layout algorithm is pretty simple, except for bit-field packing. The padding and alignment of structure members, plus whether a bit-field can straddle a storage-unit boundary, are determined by these rules:

  1. Structure members are stored in the order they're declared. The first member sits at the lowest memory address and the last one sits at the highest ๐Ÿ“ˆ
  2. Every data object has an alignment requirement. For everything except structures, unions, and arrays, it's the smaller of the object's size and the current packing size (set with the "aligned" attribute or the "pack" pragma). For structures, unions, and arrays, it's the largest alignment requirement among their members. Every object gets an offset so that offset % alignment_requirement == 0 ๐Ÿ™Œ
  3. Adjacent bit-fields get packed into the same 1-, 2-, or 4-byte allocation unit if their integral types are the same size, and the next bit-field fits in the current allocation unit without crossing the boundary imposed by the common alignment requirements of the bit-fields ๐Ÿงฉ

๐ŸŽ€ MSVC zero-length bit-fields ๐ŸŽ€

Now for the zero-length bit-field drama ๐Ÿ’€ MSVC interprets them in these 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. Like this:

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 ๐Ÿ™ƒ

2. 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. Check these out:

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 that into account, it's important to note the following:

  • If a zero-length bit-field follows a normal bit-field, its type may affect the alignment of the whole structure. For example, t2 has a size of 4 bytes, since the zero-length bit-field follows a normal bit-field and is of type short ๐Ÿ‘‘
  • Even if a zero-length bit-field is not followed by a normal bit-field, it can still affect the alignment of the structure:
struct
 {
   char foo : 6;
   long : 0;
 } t4;

Here, t4 takes up 4 bytes ๐Ÿ’œ

3. 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 โ€” Don't align the destination of inlined string operations. This reduces code size and improves performance 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 one enables more inlining and bigger code, and may speed up code that relies on fast memcpy and memset for short lengths. It also enables inline expansion of strlen for all pointer alignments ๐Ÿ”ฅ
  • -minline-stringops-dynamically โ€” For string operations of unknown size, use run-time checks with inline code for small blocks and a library call for large blocks โœจ
  • -mstringop-strategy=alg โ€” Overrides the internal heuristic for picking the algorithm 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 copy size is known. strategy is a comma-separated list of alg:max_size:dest_align triplets. alg is one of the values from -mstringop-strategy, and max_size is the biggest byte size that alg is allowed to handle. The last triplet must have max_size set to -1. The max_size values in the list must be in increasing order. The minimal byte size for alg is 0 for the first triplet, and max_size + 1 of the preceding range for every triplet after that ๐Ÿ’…
  • -mmemset-strategy=strategy โ€” Works like -mmemcpy-strategy=, except it controls __builtin_memset expansion ๐Ÿงฝ
  • -momit-leaf-frame-pointer โ€” Don't keep the frame pointer in a register for leaf functions. This skips the instructions that save, set up, and restore frame pointers, and frees up an extra register in leaf functions. -fomit-leaf-frame-pointer removes the frame pointer for leaf functions too, but it might make debugging harder ๐Ÿ›
  • -mtls-direct-seg-refs, -mno-tls-direct-seg-refs โ€” Controls whether TLS variables can be accessed with offsets from the TLS segment register (%gs for 32-bit, %fs for 64-bit), or whether the thread base pointer has to be added. Whether or not this is valid depends on the operating system, and on whether it maps the segment to cover the entire TLS area. For systems that use the GNU C Library, the default is on ๐Ÿฆ‹
  • -msse2avx, -mno-sse2avx โ€” Specifies that the assembler should encode SSE instructions with a VEX prefix. The option -mavx turns this on by default ๐Ÿ’–
  • -mfentry, -mno-fentry โ€” If profiling is active (-pg), put the profiling counter call before the prologue. Note: on x86 architectures, the attribute ms_hook_prologue isn't possible at the moment for -mfentry and -pg ๐Ÿ™ˆ
  • -mrecord-mcount, -mno-record-mcount โ€” If profiling is active (-pg), generate a __mcount_loc section that contains pointers to each profiling call. This is useful for automatically patching and out calls ๐ŸŒˆ
  • -mnop-mcount, -mno-nop-mcount โ€” If profiling is active (-pg), generate the calls to the profiling functions as NOPs. This is useful when they should be patched in later, dynamically. This is likely only useful together with -mrecord-mcount ๐Ÿ“
  • -minstrument-return=type โ€” Instruments function exit in -pg -mfentry instrumented functions with a call to the specified function. This only instruments true returns ending with ret, not sibling calls ending with a jump. Valid types are none (don't instrument), call (generate a call to __return__), or nop5 (generate a 5 byte nop) โญ
  • -mrecord-return, -mno-record-return โ€” Generates a __return_loc section pointing to all return instrumentation code ๐ŸŽ€
  • -mfentry-name=name โ€” Sets the name of the __fentry__ symbol called at function entry for -pg -mfentry functions ๐Ÿงš
  • -mfentry-section=name โ€” Sets the name of the section where -mrecord-mcount calls get recorded (default __mcount_loc) ๐Ÿฆ‹
  • -mskip-rax-setup, -mno-skip-rax-setup โ€” When generating code for the x86-64 architecture with SSE extensions disabled, -mskip-rax-setup can be used to skip setting up the RAX register when no variable arguments are passed in vector registers ๐ŸŒธ
Warning: The RAX register is used to avoid unnecessarily saving vector registers on the stack when passing variable arguments, so the impacts of this option are: 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/64-bit integer divide. This option generates a run-time check. If both dividend and divisor are within the range of 0 to 255, 8-bit unsigned integer divide is used instead of 32-bit/64-bit integer divide ๐Ÿ‘‘
  • -mavx256-split-unaligned-load, -mavx256-split-unaligned-store โ€” Split 32-byte AVX unaligned load and store ๐Ÿ’œ
  • -mstack-protector-guard=guard, -mstack-protector-guard-reg=reg, -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 per-thread canary in the TLS block (the default). This option only has an effect when -fstack-protector or -fstack-protector-all is specified ๐Ÿ›ก๏ธ

With that second choice, -mstack-protector-guard-reg=reg and -mstack-protector-guard-offset=offset get to decide which segment register (%fs or %gs) acts as the base for reading the canary ๐Ÿ”, plus how far from that base to look. If you don't set them, you get whatever the relevant ABI says โœจ.

  • -mgeneral-regs-only โ€” bestie, this one keeps the compiler on a short leash ๐Ÿ’…. It only uses general-purpose registers, so floating-point, vector, mask, and bound registers are all off the table.
  • -mrelax-cmpxchg-loop โ€” this is lowkey genius ๐Ÿง . It adds an early load and compare before cmpxchg, and runs pause if the loaded value isn't the one you expected. That cuts down on excessive cache line bouncing, and it works for every atomic logic fetch builtin that builds a compare and swap loop ๐Ÿฆ‹.
  • -mindirect-branch=choice โ€” this one changes how indirect calls and jumps get handled ๐Ÿ”€. The default is keep, which leaves them completely alone ๐ŸŒธ. thunk turns them into call and return thunks, thunk-inline turns them into inlined call and return thunks, and thunk-extern turns them into external call and return thunks that live in a separate object file. You can override this for one specific function with the function attribute "indirect_branch" ๐ŸŽ€.
โš ๏ธ -mcmodel=large doesn't get along with -mindirect-branch=thunk or -mindirect-branch=thunk-extern, because the thunk function might not be reachable in the large code model. Be careful with that combo ๐Ÿ’€.

Good news though: -mindirect-branch=thunk-extern plays nicely with -fcf-protection=branch, since the external thunk can be made to turn on control-flow checking ๐Ÿซถ.

  • -mfunction-return=choice โ€” same energy, but for function returns ๐Ÿฆ‹. The default is keep, which leaves returns unmodified ๐ŸŒˆ. thunk converts function returns to call and return thunks, thunk-inline converts them to inlined call and return thunks, and thunk-extern converts them to external call and return thunks in a separate object file. Per function, you can control this with the function attribute "function_return" โœจ.
โš ๏ธ The -mcmodel=large flag clashes with -mfunction-return=thunk and -mfunction-return=thunk-extern for the same reason as before: the thunk might not be reachable in the large code model ๐Ÿ™ˆ.

Also, -mindirect-return=thunk-extern is compatible with -fcf-protection=branch, since the external thunk can be made to enable control-flow check ๐Ÿ’œ.

  • -mindirect-branch-register โ€” this forces indirect calls and jumps to go through a register ๐Ÿงš.
  • -mharden-sls=choice โ€” this is your anti-speculation shield ๐Ÿ›ก๏ธ. It generates code to mitigate straight line speculation (SLS). The default is none, which turns off all SLS hardening ๐Ÿ™…โ€โ™€๏ธ. return turns it on for function returns, indirect-jmp turns it on for indirect jumps, and all turns on every bit of it ๐Ÿ‘‘.
  • -mindirect-branch-cs-prefix โ€” this one is kinda wild ๐Ÿคฏ. It adds a CS prefix to call and jmp going to an indirect thunk, with the branch target in r8-r15 registers. That makes the call and jmp instructions 6 bytes long, so they can be swapped at run-time for lfence; call *%r8-r15 or lfence; jmp *%r8-r15 ๐Ÿ“.

These -m switches are supported on top of everything above for x86-64 processors in 64-bit environments ๐ŸŒˆ.

  • -m32 โ€” targets a 32-bit environment ๐Ÿ“. It sets int, long, and pointer types to 32 bits, and generates code that runs on any i386 system ๐Ÿ’–.
  • -m64 โ€” targets a 64-bit environment ๐Ÿš€. It sets int to 32 bits, while long and pointer types become 64 bits, and generates code for the x86-64 architecture. On 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 still generates code for the x86-64 architecture ๐Ÿฆ‹.
  • -m16 โ€” basically -m32, with one twist ๐Ÿงšโ€โ™€๏ธ. It outputs the .code16gcc assembly directive at the very 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 needs -m32 turned on too, so don't forget that one ๐Ÿ˜ญ.
  • -mno-red-zone โ€” this turns off the so-called "red zone" for x86-64 code ๐Ÿ™…โ€โ™€๏ธ. The red zone is mandated by the x86-64 ABI, and it's a 128-byte area beyond the stack pointer that signal or interrupt handlers don't touch ๐ŸŒธ. That means it can hold temporary data without adjusting the stack pointer. This flag disables that whole setup ๐Ÿ’….
  • -mcmodel=small โ€” the small code model ๐ŸŒท. The program and its symbols have to be linked in the lower 2 GB of the address space, and pointers are 64 bits. Programs can be statically or dynamically linked. This is the default code model ๐Ÿ‘‘.
  • -mcmodel=kernel โ€” 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 โ€” the medium model ๐ŸŒˆ. The program is linked in the lower 2 GB of the address space, and small symbols are placed there too. Symbols bigger than -mlarge-data-threshold go into large data or BSS sections, and they can live above 2GB. Programs can be statically or dynamically linked ๐Ÿง.
  • -mcmodel=large โ€” the large model ๐ŸŒŒ. It makes no assumptions about addresses and sizes of sections, so it's the most chill about where things end up ๐Ÿ˜Œ.
  • -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 โ€” these control whether the GNU_PROPERTY_X86_ISA_1_NEEDED GNU property gets emitted for Linux targets ๐Ÿ“œ. That property tells you which micro-architecture ISA level the binary needs to run ๐Ÿ”.
  • -mno-direct-extern-access โ€” okay, this one's a bit technical but it matters ๐Ÿง. Without -fpic or -fPIC, it always uses the GOT pointer to access external symbols. With -fpic or -fPIC, it treats access to protected symbols like local symbols. The default is -mdirect-extern-access ๐ŸŽ€.
โš ๏ธ Warning, bestie: shared libraries compiled with -mno-direct-extern-access and executables compiled with -mdirect-extern-access might not be binary compatible if protected symbols are used in both the shared libraries and the executable ๐Ÿ’€.

๐ŸŒธ x86 Windows Options ๐ŸŒธ

These extra options are available for Microsoft Windows targets ๐ŸชŸ:

  • -mconsole โ€” generates a console application by telling the linker to set the PE header subsystem type for console apps ๐Ÿ–ฅ๏ธ. It's available for Cygwin and MinGW targets, and it's on by default there ๐Ÿ’–.
  • -mdll โ€” available for Cygwin and MinGW ๐Ÿฆ‹. It generates a DLL (a dynamic link library), which lets the compiler pick the right runtime startup object and entry point ๐Ÿงš.
  • -mnop-fun-dllimport โ€” available for Cygwin and MinGW ๐Ÿ™ˆ. It makes the compiler ignore the "dllimport" attribute ๐Ÿซ .
  • -mthreads โ€” available for MinGW targets ๐Ÿงต. It uses MinGW-specific thread support ๐Ÿ’….
  • -municode โ€” available for MinGW-w64 targets ๐ŸŒˆ. It predefines the UNICODE preprocessor macro and chooses Unicode-capable runtime startup code ๐ŸŒ.
  • -mwin32 โ€” available for Cygwin and MinGW ๐ŸชŸ. It sets the typical Microsoft Windows predefined macros in the preprocessor, but it doesn't change which runtime library or startup code gets picked โœจ.
  • -mwindows โ€” available for Cygwin and MinGW ๐ŸŽฎ. It generates a GUI application by having the linker set the PE header subsystem type appropriately ๐Ÿช„.
  • -fno-set-stack-executable โ€” available for MinGW targets ๐Ÿ”. It stops the executable flag from being set for the stack used by nested functions. This is necessary for binaries running in kernel mode of Microsoft Windows, since the User32 API (used to set executable privileges) isn't available there ๐Ÿ’€.
  • -fwritable-relocated-rdata โ€” available for MinGW and Cygwin ๐Ÿ“ฆ. It puts relocated data from a read-only section into the ".data" section. This is needed for older runtimes that don't support modifying ".rdata" sections for pseudo-relocation ๐Ÿงธ.
  • -mpe-aligned-commons โ€” available for Cygwin and MinGW ๐ŸŒท. It uses the GNU extension to the PE file format that lets COMMON variables align correctly when generating code. It's enabled by default if GCC detects that the target assembler found during configuration supports the feature ๐Ÿซถ.

See also under x86 Options for standard options ๐Ÿ”—.


๐Ÿฆ– Xstormy16 Options ๐Ÿฆ–

These options are defined for Xstormy16 ๐Ÿ•น๏ธ:

  • -msim โ€” picks startup files and a linker script that work with the simulator ๐ŸŽฎ.

๐ŸŒˆ Xtensa Options ๐ŸŒˆ

These options are supported for Xtensa targets ๐ŸŒŸ:

  • -mconst16, -mno-const16 โ€” enables or disables the use of CONST16 instructions for loading constant values ๐Ÿ”ข. CONST16 isn't a standard option from Tensilica right now ๐Ÿ™ƒ. When it's enabled, CONST16 gets used every time instead of the standard L32R instructions. It's only enabled by default if L32R isn't available ๐Ÿ“.
  • -mfused-madd, -mno-fused-madd โ€” enables or disables fused multiply/add and multiply/subtract instructions in the floating-point option ๐Ÿงฎ. This does nothing if the floating-point option isn't also turned on ๐Ÿ™…โ€โ™€๏ธ. Disabling them makes the compiler use separate instructions for the multiply and the add/subtract ๐Ÿงฉ. That's useful when you need strict IEEE 754-compliant results ๐ŸŽฏ, because fused instructions don't round the intermediate result, so they carry more bits of precision than the IEEE standard specifies ๐Ÿค“. Disabling them also means your program's output won't depend on whether the compiler can combine multiply and add/subtract operations ๐Ÿ’–.
  • -mserialize-volatile, -mno-serialize-volatile โ€” okay so this one is about volatile memory references. When it's on, GCC slides MEMW instructions in front of them to guarantee sequential consistency ๐Ÿ”’โœจ. The default is -mserialize-volatile, and if you want the MEMW instructions gone, use -mno-serialize-volatile ๐Ÿ’…
  • -mforce-no-pic โ€” for targets like GNU/Linux where all user-mode Xtensa code has to be position-independent code (PIC), this one turns PIC off just for compiling kernel code ๐Ÿงš
  • -mtext-section-literals, -mno-text-section-literals โ€” these two control how literal pools get treated ๐ŸŒธ The default is -mno-text-section-literals, which puts literals in their own section in the output file. This 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 improve code size, which is so iconic ๐Ÿ‘‘ With -mtext-section-literals, the literals get interspersed in the text section so they stay as close as possible to their references. That 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 ๐Ÿ’œ The default is -mno-auto-litpools, which puts literals in a separate section in the output file unless -mtext-section-literals is used. With -mauto-litpools, the assembler does the interspersing in the text section. GCC doesn't emit explicit .literal directives, and it loads literals into registers with MOVI instructions instead of L32R, so the assembler can do relaxation and place literals wherever they need to go ๐Ÿซถ This option 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 this is enabled, GCC tells the assembler to auto-align instructions to cut down on branch penalties, at the cost of some code density ๐ŸŽ€ The assembler tries to widen density instructions to align branch targets and the instructions right after call instructions. If there aren't enough preceding safe density instructions to align a target, no widening happens. The default is -mtarget-align. These options don't touch auto-aligned instructions like LOOP, which the assembler always aligns, either by widening density instructions or by inserting NOP instructions ๐ŸŒˆ
  • -mlongcalls, -mno-longcalls โ€” when enabled, GCC tells the assembler to turn direct calls into indirect calls unless it can tell the target of the direct call is in range for the call instruction ๐Ÿ“ This usually happens for calls to functions in other source files. Specifically, the assembler turns a direct CALL into an L32R followed by a CALLX. The default is -mno-longcalls. Use this in programs where the call target could be out of range โญ This option is implemented in the assembler, not the compiler, so the assembly GCC generates still shows direct call instructions---look at the disassembled object code to see the actual instructions ๐Ÿ” Also, the assembler uses an indirect call for every cross-file call, not just the ones that really are out of range ๐Ÿ’€
  • -mabi=name โ€” generates code for the specified ABI. Permissible values are call0 and windowed. The default ABI is chosen by the Xtensa core configuration โœจ
  • -mabi=call0 โ€” when this is on, 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 ABI version is enabled, the C preprocessor symbol __XTENSA_CALL0_ABI__ is defined ๐Ÿฆ‹
  • -mabi=windowed โ€” when this is on, function parameters get passed in registers a10 through a15, and the called function rotates the register window by 8 registers on entry so its arguments are found in registers a2 through a7 ๐ŸŒธ Register a7 may be used as a frame pointer, and the register window gets rotated 8 registers back on return. When this ABI version is enabled, the C preprocessor symbol __XTENSA_WINDOWED_ABI__ is defined ๐Ÿซถ

โœจ zSeries Options โœจ

These are listed under

โœจ ENVIRONMENT โœจ

okay bestie, this section is all about the environment variables that change how GCC behaves ๐ŸŒธ Some of them tell GCC where to hunt for files (directories and prefixes), and some just tweak other parts of the compilation setup ๐Ÿ’…

ngl, you can also tell GCC where to look with options like -B, -I and -L. Those beat environment variables, and environment variables beat the defaults baked into how GCC was configured. Main character hierarchy ๐Ÿ‘‘

LANG, LC_CTYPE, LC_MESSAGES, LC_ALL ๐ŸŒˆ

These four handle localization, which is how GCC copes with different national conventions. GCC checks LC_CTYPE and LC_MESSAGES if it was set up to do that. They can be set to any value your installation supports. A typical one is en_GB.UTF-8, which means English from the United Kingdom encoded in UTF-8 ๐Ÿ‡ฌ๐Ÿ‡ง

  • LC_CTYPE is all about character classification. GCC uses it to figure out where characters start and end in a string. This matters for some multibyte encodings that have quote and escape characters that would otherwise be read as the end of a string or as an escape ๐Ÿซถ
  • LC_MESSAGES picks the language for diagnostic messages (aka the errors and warnings you get back) ๐Ÿ’ฌ
  • LC_ALL is the boss. If it's set, it overrides LC_CTYPE and LC_MESSAGES. If it isn't, then LC_CTYPE and LC_MESSAGES just default to whatever LANG says. And if none of these are set at all, GCC goes with traditional C English behavior ๐Ÿ“

TMPDIR ๐Ÿฆ‹

If TMPDIR is set, that's the directory GCC uses for its temporary files. GCC stashes the output of one stage so the next stage can use it as input. For example, the preprocessor's output becomes the input for the compiler proper ๐Ÿงš

GCC_COMPARE_DEBUG ๐Ÿ”ฅ

Setting GCC_COMPARE_DEBUG is nearly the same as passing -fcompare-debug to the compiler driver. Check that option's docs for the full tea โ˜•

GCC_EXEC_PREFIX โœจ

If GCC_EXEC_PREFIX is set, it's a prefix that gets used in the names of the subprograms GCC runs. No slash gets added when it's combined with a subprogram name, so if you want one, end your prefix with a slash yourself ๐ŸŽ€

  • If it's not set, GCC tries to work out a sensible prefix from the pathname it was invoked with ๐Ÿ”
  • If GCC can't find a subprogram using your prefix, it falls back to the usual places ๐Ÿ 
  • The default is prefix/lib/gcc/, where prefix is the prefix of the installed compiler. Most of the time that's whatever you passed as "prefix" when you ran the configure script โš™๏ธ
  • Prefixes given with -B beat this one ๐Ÿ‘‘
  • This prefix also helps GCC find files like crt0.o that get used for linking ๐Ÿ”—

It's also used in a sneaky way for header files ๐Ÿซฃ For each standard directory that normally starts with /usr/local/lib/gcc (or more precisely, with the value of GCC_INCLUDE_DIR), GCC swaps that beginning for your prefix to make an alternate directory name. So with -Bfoo/, GCC searches foo/bar just before it checks the standard /usr/local/lib/bar. And if a standard directory starts with the configured prefix, GCC swaps in the value of GCC_EXEC_PREFIX when looking for headers ๐Ÿ’–

COMPILER_PATH ๐Ÿ›ค๏ธ

The value of COMPILER_PATH is a colon-separated list of directories, very much like PATH. GCC checks these 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. On a native compiler, GCC checks these when hunting for special linker files, but only if GCC_EXEC_PREFIX didn't find them first. Linking also searches these directories for ordinary libraries used with the -l option, although any directories given with -L come first ๐Ÿฆ‹

LANG (round two) ๐ŸŒธ

This LANG is about passing locale info to the compiler. One thing it affects is which character set gets used when character literals, string literals and comments are parsed in C and C++ ๐Ÿง When the compiler is set up to allow multibyte characters, these LANG values are recognized:

  • C-JIS โ€” recognizes JIS characters ๐Ÿ‡ฏ๐Ÿ‡ต
  • C-SJIS โ€” recognizes SJIS characters ๐Ÿ‡ฏ๐Ÿ‡ต
  • C-EUCJP โ€” recognizes EUCJP characters ๐Ÿ‡ฏ๐Ÿ‡ต

If LANG isn't defined, or it's set to something else, the compiler uses "mblen" and "mbtowc" from the default locale to recognize and translate multibyte characters ๐ŸŒ

GCC_EXTRA_DIAGNOSTIC_OUTPUT ๐Ÿฉน

If GCC_EXTRA_DIAGNOSTIC_OUTPUT is set to one of the values below, GCC prints extra text to stderr whenever it emits fix-it hints. Heads up: -fdiagnostics-parseable-fixits and -fno-diagnostics-parseable-fixits win over this environment variable ๐Ÿ™…โ€โ™€๏ธ

  • fixits-v1 โ€” emits parseable fix-it hints, same as -fdiagnostics-parseable-fixits. Columns are counted in bytes, starting at byte 1 for the first column ๐Ÿ”ข
  • fixits-v2 โ€” same as fixits-v1, except columns are counted as display columns, like with -fdiagnostics-column-unit=display ๐Ÿ“

Some more environment variables affect the preprocessor too ๐Ÿงšโ€โ™€๏ธ

CPATH, C_INCLUDE_PATH, CPLUS_INCLUDE_PATH, OBJC_INCLUDE_PATH ๐Ÿ’œ

Each of these holds a list of directories to search for header files, separated by a special character, like PATH. That special character, "PATH_SEPARATOR", depends on the target and gets decided when GCC is built. On Microsoft Windows-based targets it's a semicolon, and on almost every other target it's a colon ๐ŸชŸ

  • CPATH directories get searched as if you'd used -I, but after any paths from -I options on the command line. This one is used no matter which language is being preprocessed ๐ŸŒˆ
  • The rest only apply when preprocessing their particular language. Each one's directories get searched as if you'd used -isystem, but after any paths from -isystem options on the command line ๐Ÿซถ

In all of these, an empty element tells the compiler to search its current working directory. Empty elements can go at the start or end of a path. For example, if CPATH is ":/special/include", that has the exact same effect as -I. -I/special/include ๐Ÿ“

DEPENDENCIES_OUTPUT ๐Ÿงฉ

If this variable is set, its value says how to output dependencies for Make, based on the non-system header files the compiler processes. System header files get ignored in the dependency output ๐Ÿ™ˆ

The value can just be a file name. In that case the Make rules get written to that file, and the target name is guessed from the source file name. Or the value can look like file target, in which case the rules get written to file and use target as the target name ๐ŸŽฏ

Put simply, this environment variable works like combining the options -MM and -MF, with an optional -MT switch too ๐Ÿ’…

SUNPRO_DEPENDENCIES ๐ŸŒ™

This one is the same as DEPENDENCIES_OUTPUT (see above), with one big difference: system header files are not ignored. That means 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 that replaces the current date and time in the "__DATE__" and "__TIME__" macros. That way the embedded timestamps stay reproducible โœจ

The value has to be a UNIX timestamp, which is the number of seconds (leap seconds excluded) since 01 Jan 1970 00:00:00, written in ASCII. It's the same as what date +%s prints on GNU/Linux and other systems that support the %s extension in the date command ๐Ÿงฎ

Pick a known timestamp, like the last modification time of the source or package, and let your build process set it ๐Ÿ› ๏ธ


๐Ÿ› BUGS ๐Ÿ›

For instructions on reporting bugs, see <file:///usr/share/doc/gcc-12/README.Bugs> ๐Ÿ’Œ

๐Ÿ“ FOOTNOTES ๐Ÿ“

  1. On some systems, gcc -shared needs to build supplementary stub code for constructors to work. On multi-libbed systems, gcc -shared must select the correct support libraries to link against. Failing to supply the correct flags may lead to subtle defects. Supplying them in cases where they are not necessary is innocuous. ๐Ÿ™ˆ

๐Ÿ”— SEE ALSO ๐Ÿ”—

gpl(7), gfdl(7), fsf-funding(7), cpp(1), gcov(1), as(1), ld(1), gdb(1), dbx(1) and the Info entries for gcc, cpp, as, ld, binutils and gdb ๐Ÿ“–

๐Ÿ‘ฉโ€๐Ÿ’ป AUTHOR ๐Ÿ‘ฉโ€๐Ÿ’ป

See the Info entry for gcc, or <https://gcc.gnu.org/onlinedocs/gcc/Contributors.html>, for contributors to GCC ๐Ÿซถ

Copyright (c) 1988-2022 Free Software Foundation, Inc. ๐ŸŒธ

Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.3 or any later version published by the Free Software Foundation. The Invariant Sections are "GNU General Public License" and "Funding Free Software", the Front-Cover texts are (a) (see below), and the Back-Cover Texts are (b) (see below). A copy of the license is included in the gfdl(7) man page ๐Ÿ“œ

(a) The FSF's Front-Cover Text is:

A GNU Manual

(b) The FSF's Back-Cover Text is:

You have freedom to copy and modify this GNU Manual, like GNU software. Copies published by the Free Software Foundation raise funds for GNU development. ๐Ÿ’œ


That's the whole page, bestie! ๐ŸŽ€ Thanks for hanging with me through all 116 parts ๐Ÿฅน This one was gcc-12, last updated 2022-03-02, and we are SO done ๐Ÿ’…โœจ

๐Ÿ“ฆ where this page comes from