GCC(1)

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

๐Ÿ’– GCC(1) ยท GNU manual ๐Ÿ’–

๐ŸŽ€ NAME ๐ŸŽ€

gcc - GNU project C and C++ compiler ๐Ÿ’–

๐ŸŒธ SYNOPSIS ๐ŸŒธ

Here's the vibe check for how you call it โœจ

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

Only the MVP options made the cut here, so the rest are down below ๐Ÿ‘€. g++ takes pretty much the same options as gcc ๐Ÿงš.

๐Ÿ’… DESCRIPTION ๐Ÿ’…

Okay so when you invoke GCC, it normally runs through preprocessing, compilation, assembly, and linking all in one go ๐Ÿ”ฅ. The "overall options" let you stop the process at an intermediate stage. Like, -c says don't bother running the linker, so what you get back is the object files the assembler spat out ๐Ÿฆ‹.

Other options get passed along to one or more stages of processing ๐Ÿ’…. Some control the preprocessor, some control the compiler itself, and yet more control the assembler and linker. Most of those linker and assembler ones aren't documented here, since you hardly ever 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 explicitly ๐Ÿ’–. If an option's description doesn't mention a source language, you can use it with all supported languages โœจ.

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

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

You can mix options and other arguments ๐ŸŽ€. For the most part the order doesn't matter, but it does when you use several options of the same kind. For example, if you specify -L more than once, the directories get searched in the order you gave them. Also, where you place the -l option is significant ๐Ÿ‘€.

Tons of options have long names starting with -f or with -W---for, for example -fmove-loop-invariants, -Wformat, and so on ๐Ÿ’…. Most of them come in positive and negative forms, and the negative form of -ffoo is -fno-foo. This manual only documents one of the two forms, whichever one isn't the default ๐Ÿฆ‹.

Some options take one or more arguments, usually separated from the option name by either a space or an equals sign (=) ๐Ÿซถ. Unless it says otherwise, an argument can be numeric or a string ๐Ÿ”ฅ. Numeric arguments are typically small unsigned decimal or hexadecimal integers, and hex ones must begin with the 0x prefix ๐Ÿ’œ.

Arguments to options that set a size threshold can be arbitrarily large decimal or hexadecimal integers, followed by a byte size suffix ๐ŸŒˆ. Those suffixes stand for multiples of bytes: "kB" and "KiB" for kilobyte and kibibyte, "MB" and "MiB" for megabyte and mebibyte, "GB" and "GiB" for gigabyte and gigibyte, and so on. In the following text these are called byte-size arguments. For the full listing and explanation of the binary and decimal byte size prefixes, refer to the NIST, IEC, and other relevant national and international standards ๐Ÿงš.

โœจ OPTIONS โœจ

๐Ÿฆ‹ Option Summary ๐Ÿฆ‹

Here's the whole squad of options, sorted by type ๐Ÿ’–. The explanations come later on in the page โœจ.

Overall Options

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

C Language Options

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

C++ Language Options

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

Objective-C and Objective-C++ Language Options

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

Diagnostic Message Formatting Options

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

โœจ Warning Options โœจ

okay bestie, this is the whole warning squad ๐Ÿšจ๐Ÿ’… these are just the names, no descriptions in this part, so grab the ones you need and go ๐Ÿซถ

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

โœจ Static Analyzer Options โœจ

the analyzer era ๐Ÿ”๐Ÿฆ‹ these are the static analyzer flags, all lined up and ready to be used, no cap

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

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

these ones are for the C and Objective-C crowd only ๐ŸŒธ๐Ÿ’œ if you're not writing those languages, you can skip this one, no judgment ๐Ÿ™ˆ

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

the debugging era is here ๐Ÿงš๐Ÿ”ฅ this is where you go when things are being weird and you need the receipts ๐Ÿงพโœจ every flag from the debugging list is right below, bestie ๐Ÿ’–

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

โœจ Optimization Options โœจ

okay bestie, buckle up ๐Ÿ˜ญ๐Ÿ”ฅ this optimization menu is HUGE and honestly the vibes are immaculate ๐Ÿ’…

  • -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
  • -fno-branch-count-reg
  • -fno-defer-pop
  • -fno-fp-int-builtin-inexact
  • -fno-function-cse
  • -fno-guess-branch-probability
  • -fno-inline
  • -fno-math-errno
  • -fno-peephole
  • -fno-peephole2
  • -fno-printf-return-value
  • -fno-sched-interblock
  • -fno-sched-spec
  • -fno-signed-zeros
  • -fno-toplevel-reorder
  • -fno-trapping-math
  • -fno-zero-initialized-in-bss
  • -fomit-frame-pointer
  • -foptimize-sibling-calls
  • -fpartial-inlining
  • -fpeel-loops
  • -fpredictive-commoning
  • -fprefetch-loop-arrays
  • -fprofile-correction
  • -fprofile-use
  • -fprofile-use=path
  • -fprofile-partial-training
  • -fprofile-values
  • -fprofile-reorder-functions
  • -freciprocal-math
  • -free
  • -frename-registers
  • -freorder-blocks
  • -freorder-blocks-algorithm=algorithm
  • -freorder-blocks-and-partition
  • -freorder-functions
  • -frerun-cse-after-loop
  • -freschedule-modulo-scheduled-loops
  • -frounding-math
  • -fsave-optimization-record
  • -fsched2-use-superblocks
  • -fsched-pressure
  • -fsched-spec-load
  • -fsched-spec-load-dangerous
  • -fsched-stalled-insns-dep[=n]
  • -fsched-stalled-insns[=n]
  • -fsched-group-heuristic
  • -fsched-critical-path-heuristic
  • -fsched-spec-insn-heuristic
  • -fsched-rank-heuristic
  • -fsched-last-insn-heuristic
  • -fsched-dep-count-heuristic
  • -fschedule-fusion
  • -fschedule-insns
  • -fschedule-insns2
  • -fsection-anchors
  • -fselective-scheduling
  • -fselective-scheduling2
  • -fsel-sched-pipelining
  • -fsel-sched-pipelining-outer-loops
  • -fsemantic-interposition
  • -fshrink-wrap
  • -fshrink-wrap-separate
  • -fsignaling-nans
  • -fsingle-precision-constant
  • -fsplit-ivs-in-unroller
  • -fsplit-loops
  • -fsplit-paths
  • -fsplit-wide-types
  • -fsplit-wide-types-early
  • -fssa-backprop
  • -fssa-phiopt
  • -fstdarg-opt
  • -fstore-merging
  • -fstrict-aliasing
  • -fthread-jumps
  • -ftracer
  • -ftree-bit-ccp
  • -ftree-builtin-call-dce
  • -ftree-ccp
  • -ftree-ch
  • -ftree-coalesce-vars
  • -ftree-copy-prop
  • -ftree-dce
  • -ftree-dominator-opts
  • -ftree-dse
  • -ftree-forwprop
  • -ftree-fre
  • -fcode-hoisting
  • -ftree-loop-if-convert
  • -ftree-loop-im
  • -ftree-phiprop
  • -ftree-loop-distribution
  • -ftree-loop-distribute-patterns
  • -ftree-loop-ivcanon
  • -ftree-loop-linear
  • -ftree-loop-optimize
  • -ftree-loop-vectorize
  • -ftree-parallelize-loops=n
  • -ftree-pre
  • -ftree-partial-pre
  • -ftree-pta
  • -ftree-reassoc
  • -ftree-scev-cprop
  • -ftree-sink
  • -ftree-slsr
  • -ftree-sra
  • -ftree-switch-conversion
  • -ftree-tail-merge
  • -ftree-ter
  • -ftree-vectorize
  • -ftree-vrp
  • -funconstrained-commons
  • -funit-at-a-time
  • -funroll-all-loops
  • -funroll-loops
  • -funsafe-math-optimizations
  • -funswitch-loops
  • -fipa-ra
  • -fvariable-expansion-in-unroller
  • -fvect-cost-model
  • -fvpt
  • -fweb
  • -fwhole-program
  • -fwpa
  • -fuse-linker-plugin
  • -fzero-call-used-regs
  • --param name=value
  • -O
  • -O0
  • -O1
  • -O2
  • -O3
  • -Os
  • -Ofast
  • -Og

โœจ Program Instrumentation Options โœจ

the detective squad ๐Ÿ•ต๏ธ๐Ÿ’œ these ones are all about watching the code do its thing, iykyk

  • -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]
  • -fstack-protector
  • -fstack-protector-all
  • -fstack-protector-strong
  • -fstack-protector-explicit
  • -fstack-check
  • -fstack-limit-register=reg
  • -fstack-limit-symbol=sym
  • -fno-stack-limit
  • -fsplit-stack
  • -fvtable-verify=[std|preinit|none]
  • -fvtv-counts
  • -fvtv-debug
  • -finstrument-functions
  • -finstrument-functions-exclude-function-list=sym,sym,...
  • -finstrument-functions-exclude-file-list=file,file,...

โœจ Preprocessor Options โœจ

preprocessor era ๐ŸŒธ๐ŸŽ€ everything gets lined up before the main show, it's giving prep school

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

tiny section, big energy ๐Ÿฆ‹

  • -Wa,option
  • -Xassembler option

โœจ Linker Options โœจ

the linking era ๐Ÿ”—๐Ÿ’š this is where all the pieces finally click together ๐Ÿซถ

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

โœจ Directory Options โœจ

where everything lives ๐Ÿ—‚๏ธโœจ it's giving GPS, bestie ๐Ÿงญ

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

โœจ Code Generation Options โœจ

the glow-up section ๐ŸŒˆ๐Ÿ’… this one is literally so extra

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

for the people who love peeking under the hood ๐Ÿ‘‘๐Ÿ’œ ngl I'm obsessed with this whole section

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

every target gets its own VIP list ๐Ÿค–๐Ÿ‘‘ the hardware is giving main character energy

AArch64 Options

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

โœจ Adapteva Epiphany Options โœจ

okay bestie, this part is basically a big sparkly list of machine-specific flags, and the page just names them without explaining what they do. so I'm not gonna make stuff up ๐Ÿซถ
  • -mhalf-reg-file ๐Ÿ’–
  • -mprefer-short-insn-regs โœจ
  • -mbranch-cost=num ๐ŸŽ€
  • -mcmove ๐Ÿฆ‹
  • -mnops=num ๐ŸŒธ
  • -msoft-cmpsf ๐Ÿ’…
  • -msplit-lohi ๐Ÿซถ
  • -mpost-inc ๐Ÿ”ฅ
  • -mpost-modify ๐Ÿ‘‘
  • -mstack-offset=num ๐ŸŒˆ
  • -mround-nearest โญ
  • -mlong-calls ๐Ÿ“
  • -mshort-calls ๐Ÿงš
  • -msmall16 ๐Ÿ’œ
  • -mfp-mode=mode ๐Ÿ’–
  • -mvect-double โœจ
  • -max-vect-align=num ๐ŸŽ€
  • -msplit-vecmove-early ๐Ÿฆ‹
  • -m1reg-reg ๐ŸŒธ

โœจ AMD GCN Options โœจ

  • -march=gpu ๐Ÿ’…
  • -mtune=gpu ๐Ÿซถ
  • -mstack-size=bytes ๐Ÿ”ฅ

โœจ ARC Options โœจ

  • -mbarrel-shifter ๐Ÿ‘‘
  • -mjli-always ๐ŸŒˆ
  • -mcpu=cpu โญ
  • -mA6 ๐Ÿ“
  • -mARC600 ๐Ÿงš
  • -mA7 ๐Ÿ’œ
  • -mARC700 ๐Ÿ’–
  • -mdpfp โœจ
  • -mdpfp-compact ๐ŸŽ€
  • -mdpfp-fast ๐Ÿฆ‹
  • -mno-dpfp-lrsr ๐ŸŒธ
  • -mea ๐Ÿ’…
  • -mno-mpy ๐Ÿซถ
  • -mmul32x16 ๐Ÿ”ฅ
  • -mmul64 ๐Ÿ‘‘
  • -matomic ๐ŸŒˆ
  • -mnorm โญ
  • -mspfp ๐Ÿ“
  • -mspfp-compact ๐Ÿงš
  • -mspfp-fast ๐Ÿ’œ
  • -msimd ๐Ÿ’–
  • -msoft-float โœจ
  • -mswap ๐ŸŽ€
  • -mcrc ๐Ÿฆ‹
  • -mdsp-packa ๐ŸŒธ
  • -mdvbf ๐Ÿ’…
  • -mlock ๐Ÿซถ
  • -mmac-d16 ๐Ÿ”ฅ
  • -mmac-24 ๐Ÿ‘‘
  • -mrtsc ๐ŸŒˆ
  • -mswape โญ
  • -mtelephony ๐Ÿ“
  • -mxy ๐Ÿงš
  • -misize ๐Ÿ’œ
  • -mannotate-align ๐Ÿ’–
  • -marclinux โœจ
  • -marclinux_prof ๐ŸŽ€
  • -mlong-calls ๐Ÿฆ‹
  • -mmedium-calls ๐ŸŒธ
  • -msdata ๐Ÿ’…
  • -mirq-ctrl-saved ๐Ÿซถ
  • -mrgf-banked-regs ๐Ÿ”ฅ
  • -mlpc-width=width ๐Ÿ‘‘
  • -G num ๐ŸŒˆ
  • -mvolatile-cache โญ
  • -mtp-regno=regno ๐Ÿ“
  • -malign-call ๐Ÿงš
  • -mauto-modify-reg ๐Ÿ’œ
  • -mbbit-peephole ๐Ÿ’–
  • -mno-brcc โœจ
  • -mcase-vector-pcrel ๐ŸŽ€
  • -mcompact-casesi ๐Ÿฆ‹
  • -mno-cond-exec ๐ŸŒธ
  • -mearly-cbranchsi ๐Ÿ’…
  • -mexpand-adddi ๐Ÿซถ
  • -mindexed-loads ๐Ÿ”ฅ
  • -mlra ๐Ÿ‘‘
  • -mlra-priority-none ๐ŸŒˆ
  • -mlra-priority-compact โญ
  • mlra-priority-noncompact ๐Ÿ“
  • -mmillicode ๐Ÿงš
  • -mmixed-code ๐Ÿ’œ
  • -mq-class ๐Ÿ’–
  • -mRcq โœจ
  • -mRcw ๐ŸŽ€
  • -msize-level=level ๐Ÿฆ‹
  • -mtune=cpu ๐ŸŒธ
  • -mmultcost=num ๐Ÿ’…
  • -mcode-density-frame ๐Ÿซถ
  • -munalign-prob-threshold=probability ๐Ÿ”ฅ
  • -mmpy-option=multo ๐Ÿ‘‘
  • -mdiv-rem ๐ŸŒˆ
  • -mcode-density โญ
  • -mll64 ๐Ÿ“
  • -mfpu=fpu ๐Ÿงš
  • -mrf16 ๐Ÿ’œ
  • -mbranch-index ๐Ÿ’–
the original is missing the leading dash on mlra-priority-noncompact, so I kept it exactly as written ๐Ÿ™ˆ

โœจ ARM Options โœจ

  • -mapcs-frame โœจ
  • -mno-apcs-frame ๐ŸŽ€
  • -mabi=name ๐Ÿฆ‹
  • -mapcs-stack-check ๐ŸŒธ
  • -mno-apcs-stack-check ๐Ÿ’…
  • -mapcs-reentrant ๐Ÿซถ
  • -mno-apcs-reentrant ๐Ÿ”ฅ
  • -mgeneral-regs-only ๐Ÿ‘‘
  • -msched-prolog ๐ŸŒˆ
  • -mno-sched-prolog โญ
  • -mlittle-endian ๐Ÿ“
  • -mbig-endian ๐Ÿงš
  • -mbe8 ๐Ÿ’œ
  • -mbe32 ๐Ÿ’–
  • -mfloat-abi=name โœจ
  • -mfp16-format=name ๐ŸŽ€
  • -mthumb-interwork ๐Ÿฆ‹
  • -mno-thumb-interwork ๐ŸŒธ
  • -mcpu=name ๐Ÿ’…
  • -march=name ๐Ÿซถ
  • -mfpu=name ๐Ÿ”ฅ
  • -mtune=name ๐Ÿ‘‘
  • -mprint-tune-info ๐ŸŒˆ
  • -mstructure-size-boundary=n โญ
  • -mabort-on-noreturn ๐Ÿ“
  • -mlong-calls ๐Ÿงš
  • -mno-long-calls ๐Ÿ’œ
  • -msingle-pic-base ๐Ÿ’–
  • -mno-single-pic-base โœจ
  • -mpic-register=reg ๐ŸŽ€
  • -mnop-fun-dllimport ๐Ÿฆ‹
  • -mpoke-function-name ๐ŸŒธ
  • -mthumb ๐Ÿ’…
  • -marm ๐Ÿซถ
  • -mflip-thumb ๐Ÿ”ฅ
  • -mtpcs-frame ๐Ÿ‘‘
  • -mtpcs-leaf-frame ๐ŸŒˆ
  • -mcaller-super-interworking โญ
  • -mcallee-super-interworking ๐Ÿ“
  • -mtp=name ๐Ÿงš
  • -mtls-dialect=dialect ๐Ÿ’œ
  • -mword-relocations ๐Ÿ’–
  • -mfix-cortex-m3-ldrd โœจ
  • -munaligned-access ๐ŸŽ€
  • -mneon-for-64bits ๐Ÿฆ‹
  • -mslow-flash-data ๐ŸŒธ
  • -masm-syntax-unified ๐Ÿ’…
  • -mrestrict-it ๐Ÿซถ
  • -mverbose-cost-dump ๐Ÿ”ฅ
  • -mpure-code ๐Ÿ‘‘
  • -mcmse ๐ŸŒˆ
  • -mfix-cmse-cve-2021-35465 โญ
  • -mfdpic ๐Ÿ“

โœจ AVR Options โœจ

  • -mmcu=mcu ๐Ÿงš
  • -mabsdata ๐Ÿ’œ
  • -maccumulate-args ๐Ÿ’–
  • -mbranch-cost=cost โœจ
  • -mcall-prologues ๐ŸŽ€
  • -mgas-isr-prologues ๐Ÿฆ‹
  • -mint8 ๐ŸŒธ
  • -mdouble=bits ๐Ÿ’…
  • -mlong-double=bits ๐Ÿซถ
  • -mn_flash=size ๐Ÿ”ฅ
  • -mno-interrupts ๐Ÿ‘‘
  • -mmain-is-OS_task ๐ŸŒˆ
  • -mrelax โญ
  • -mrmw ๐Ÿ“
  • -mstrict-X ๐Ÿงš
  • -mtiny-stack ๐Ÿ’œ
  • -mfract-convert-truncate ๐Ÿ’–
  • -mshort-calls โœจ
  • -nodevicelib ๐ŸŽ€
  • -nodevicespecs ๐Ÿฆ‹
  • -Waddr-space-convert ๐ŸŒธ
  • -Wmisspelled-isr ๐Ÿ’…

โœจ Blackfin Options โœจ

  • -mcpu=cpu[-sirevision] ๐Ÿซถ
  • -msim ๐Ÿ”ฅ
  • -momit-leaf-frame-pointer ๐Ÿ‘‘
  • -mno-omit-leaf-frame-pointer ๐ŸŒˆ
  • -mspecld-anomaly โญ
  • -mno-specld-anomaly ๐Ÿ“
  • -mcsync-anomaly ๐Ÿงš
  • -mno-csync-anomaly ๐Ÿ’œ
  • -mlow-64k ๐Ÿ’–
  • -mno-low64k โœจ
  • -mstack-check-l1 ๐ŸŽ€
  • -mid-shared-library ๐Ÿฆ‹
  • -mno-id-shared-library ๐ŸŒธ
  • -mshared-library-id=n ๐Ÿ’…
  • -mleaf-id-shared-library ๐Ÿซถ
  • -mno-leaf-id-shared-library ๐Ÿ”ฅ
  • -msep-data ๐Ÿ‘‘
  • -mno-sep-data ๐ŸŒˆ
  • -mlong-calls โญ
  • -mno-long-calls ๐Ÿ“
  • -mfast-fp ๐Ÿงš
  • -minline-plt ๐Ÿ’œ
  • -mmulticore ๐Ÿ’–
  • -mcorea โœจ
  • -mcoreb ๐ŸŽ€
  • -msdram ๐Ÿฆ‹
  • -micplb ๐ŸŒธ

โœจ C6X Options โœจ

  • -mbig-endian ๐Ÿ’…
  • -mlittle-endian ๐Ÿซถ
  • -march=cpu ๐Ÿ”ฅ
  • -msim ๐Ÿ‘‘
  • -msdata=sdata-type ๐ŸŒˆ

โœจ CRIS Options โœจ

  • -mcpu=cpu โญ
  • -march=cpu ๐Ÿ“
  • -mtune=cpu ๐Ÿงš
  • -mmax-stack-frame=n ๐Ÿ’œ
  • -metrax4 ๐Ÿ’–
  • -metrax100 โœจ
  • -mpdebug ๐ŸŽ€
  • -mcc-init ๐Ÿฆ‹
  • -mno-side-effects ๐ŸŒธ
  • -mstack-align ๐Ÿ’…
  • -mdata-align ๐Ÿซถ
  • -mconst-align ๐Ÿ”ฅ
  • -m32-bit ๐Ÿ‘‘
  • -m16-bit ๐ŸŒˆ
  • -m8-bit โญ
  • -mno-prologue-epilogue ๐Ÿ“
  • -melf ๐Ÿงš
  • -maout ๐Ÿ’œ
  • -sim ๐Ÿ’–
  • -sim2 โœจ
  • -mmul-bug-workaround ๐ŸŽ€
  • -mno-mul-bug-workaround ๐Ÿฆ‹

โœจ CR16 Options โœจ

  • -mmac ๐ŸŒธ
  • -mcr16cplus ๐Ÿ’…
  • -mcr16c ๐Ÿซถ
  • -msim ๐Ÿ”ฅ
  • -mint32 ๐Ÿ‘‘
  • -mbit-ops ๐ŸŒˆ
  • -mdata-model=model โญ

โœจ C-SKY Options โœจ

  • -march=arch ๐Ÿ“
  • -mcpu=cpu ๐Ÿงš
  • -mbig-endian ๐Ÿ’œ
  • -EB ๐Ÿ’–
  • -mlittle-endian โœจ
  • -EL ๐ŸŽ€
  • -mhard-float ๐Ÿฆ‹
  • -msoft-float ๐ŸŒธ
  • -mfpu=fpu ๐Ÿ’…
  • -mdouble-float ๐Ÿซถ
  • -mfdivdu ๐Ÿ”ฅ
  • -mfloat-abi=name ๐Ÿ‘‘
  • -melrw ๐ŸŒˆ
  • -mistack โญ
  • -mmp ๐Ÿ“
  • -mcp ๐Ÿงš
  • -mcache ๐Ÿ’œ
  • -msecurity ๐Ÿ’–
  • -mtrust โœจ
  • -mdsp ๐ŸŽ€
  • -medsp ๐Ÿฆ‹
  • -mvdsp ๐ŸŒธ
  • -mdiv ๐Ÿ’…
  • -msmart ๐Ÿซถ
  • -mhigh-registers ๐Ÿ”ฅ
  • -manchor ๐Ÿ‘‘
  • -mpushpop ๐ŸŒˆ
  • -mmultiple-stld โญ
  • -mconstpool ๐Ÿ“
  • -mstack-size ๐Ÿงš
  • -mccrt ๐Ÿ’œ
  • -mbranch-cost=n ๐Ÿ’–
  • -mcse-cc โœจ
  • -msched-prolog ๐ŸŽ€
  • -msim ๐Ÿฆ‹

โœจ Darwin Options โœจ

  • -all_load ๐ŸŒธ
  • -allowable_client ๐Ÿ’…
  • -arch ๐Ÿซถ
  • -arch_errors_fatal ๐Ÿ”ฅ
  • -arch_only ๐Ÿ‘‘
  • -bind_at_load ๐ŸŒˆ
  • -bundle โญ
  • -bundle_loader ๐Ÿ“
  • -client_name ๐Ÿงš
  • -compatibility_version ๐Ÿ’œ
  • -current_version ๐Ÿ’–
  • -dead_strip โœจ
  • -dependency-file ๐ŸŽ€
  • -dylib_file ๐Ÿฆ‹
  • -dylinker_install_name ๐ŸŒธ
  • -dynamic ๐Ÿ’…
  • -dynamiclib ๐Ÿซถ
  • -exported_symbols_list ๐Ÿ”ฅ
  • -filelist ๐Ÿ‘‘
  • -flat_namespace ๐ŸŒˆ
  • -force_cpusubtype_ALL โญ
  • -force_flat_namespace ๐Ÿ“
  • -headerpad_max_install_names ๐Ÿงš
  • -iframework ๐Ÿ’œ
  • -image_base ๐Ÿ’–
  • -init โœจ
  • -install_name ๐ŸŽ€
  • -keep_private_externs ๐Ÿฆ‹
  • -multi_module ๐ŸŒธ
  • -multiply_defined ๐Ÿ’…
  • -multiply_defined_unused ๐Ÿซถ
  • -noall_load ๐Ÿ”ฅ
  • -no_dead_strip_inits_and_terms ๐Ÿ‘‘
  • -nofixprebinding ๐ŸŒˆ
  • -nomultidefs โญ
  • -noprebind ๐Ÿ“
  • -noseglinkedit ๐Ÿงš
  • -pagezero_size ๐Ÿ’œ
  • -prebind ๐Ÿ’–
  • -prebind_all_twolevel_modules โœจ
  • -private_bundle ๐ŸŽ€
  • -read_only_relocs ๐Ÿฆ‹
  • -sectalign ๐ŸŒธ
  • -sectobjectsymbols ๐Ÿ’…
  • -whyload ๐Ÿซถ
  • -seg1addr ๐Ÿ”ฅ
  • -sectcreate ๐Ÿ‘‘
  • -sectorder ๐ŸŒˆ
  • -segaddr โญ
  • -segs_read_only_addr ๐Ÿ“
  • -segs_read_write_addr ๐Ÿงš
  • -seg_addr_table ๐Ÿ’œ
  • -seg_addr_table_filename ๐Ÿ’–
  • -seglinkedit โœจ
  • -segprot ๐ŸŽ€
  • -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 ๐ŸŒธ
-sectobjectsymbols, -segs_read_only_addr and -segs_read_write_addr each show up twice in the original, so I listed them once each here ๐Ÿ™ˆ

โœจ DEC Alpha Options โœจ

  • -mno-fp-regs ๐Ÿ’…
  • -msoft-float ๐Ÿซถ
  • -mieee ๐Ÿ”ฅ
  • -mieee-with-inexact ๐Ÿ‘‘
  • -mieee-conformant ๐ŸŒˆ
  • -mfp-trap-mode=mode โญ
  • -mfp-rounding-mode=mode ๐Ÿ“
  • -mtrap-precision=mode ๐Ÿงš
  • -mbuild-constants ๐Ÿ’œ
  • -mcpu=cpu-type ๐Ÿ’–
  • -mtune=cpu-type โœจ
  • -mbwx ๐ŸŽ€
  • -mmax ๐Ÿฆ‹
  • -mfix ๐ŸŒธ
  • -mcix ๐Ÿ’…
  • -mfloat-vax ๐Ÿซถ
  • -mfloat-ieee ๐Ÿ”ฅ
  • -mexplicit-relocs ๐Ÿ‘‘
  • -msmall-data ๐ŸŒˆ
  • -mlarge-data โญ
  • -msmall-text ๐Ÿ“
  • -mlarge-text ๐Ÿงš
  • -mmemory-latency=time ๐Ÿ’œ

โœจ eBPF Options โœจ

  • -mbig-endian ๐Ÿ’–
  • -mlittle-endian โœจ
  • -mkernel=version ๐ŸŽ€
  • -mframe-limit=bytes ๐Ÿฆ‹
  • -mxbpf ๐ŸŒธ

โœจ FR30 Options โœจ

  • -msmall-model ๐Ÿ’…
  • -mno-lsim ๐Ÿซถ

โœจ FT32 Options โœจ

  • -msim ๐Ÿ”ฅ
  • -mlra ๐Ÿ‘‘
  • -mnodiv ๐ŸŒˆ
  • -mft32b โญ
  • -mcompress ๐Ÿ“
  • -mnopm ๐Ÿงš

โœจ FRV Options โœจ

  • -mgpr-32 ๐Ÿ’œ
  • -mgpr-64 ๐Ÿ’–
  • -mfpr-32 โœจ
  • -mfpr-64 ๐ŸŽ€
  • -mhard-float ๐Ÿฆ‹
  • -msoft-float ๐ŸŒธ
  • -malloc-cc ๐Ÿ’…
  • -mfixed-cc ๐Ÿซถ
  • -mdword ๐Ÿ”ฅ
  • -mno-dword ๐Ÿ‘‘
  • -mdouble ๐ŸŒˆ
  • -mno-double โญ
  • -mmedia ๐Ÿ“
  • -mno-media ๐Ÿงš
  • -mmuladd ๐Ÿ’œ
  • -mno-muladd ๐Ÿ’–
  • -mfdpic โœจ
  • -minline-plt ๐ŸŽ€
  • -mgprel-ro ๐Ÿฆ‹
  • -multilib-library-pic ๐ŸŒธ
  • -mlinked-fp ๐Ÿ’…
  • -mlong-calls ๐Ÿซถ
  • -malign-labels ๐Ÿ”ฅ
  • -mlibrary-pic ๐Ÿ‘‘
  • -macc-4 ๐ŸŒˆ
  • -macc-8 โญ
  • -mpack ๐Ÿ“
  • -mno-pack ๐Ÿงš
  • -mno-eflags ๐Ÿ’œ
  • -mcond-move ๐Ÿ’–
  • -mno-cond-move โœจ
  • -moptimize-membar ๐ŸŽ€
  • -mno-optimize-membar ๐Ÿฆ‹
  • -mscc ๐ŸŒธ
  • -mno-scc ๐Ÿ’…
  • -mcond-exec ๐Ÿซถ
  • -mno-cond-exec ๐Ÿ”ฅ
  • -mvliw-branch ๐Ÿ‘‘
  • -mno-vliw-branch ๐ŸŒˆ
  • -mmulti-cond-exec โญ
  • -mno-multi-cond-exec ๐Ÿ“
  • -mnested-cond-exec ๐Ÿงš
  • -mno-nested-cond-exec ๐Ÿ’œ
  • -mtomcat-stats ๐Ÿ’–
  • -mTLS โœจ
  • -mtls ๐ŸŽ€
  • -mcpu=cpu ๐Ÿฆ‹

โœจ GNU/Linux Options โœจ

  • -mglibc ๐ŸŒธ
  • -muclibc ๐Ÿ’…
  • -mmusl ๐Ÿซถ
  • -mbionic ๐Ÿ”ฅ
  • -mandroid ๐Ÿ‘‘
  • -tno-android-cc ๐ŸŒˆ
  • -tno-android-ld โญ

โœจ H8/300 Options โœจ

  • -mrelax ๐Ÿ“
  • -mh ๐Ÿงš
  • -ms ๐Ÿ’œ
  • -mn ๐Ÿ’–
  • -mexr โœจ
  • -mno-exr ๐ŸŽ€
  • -mint32 ๐Ÿฆ‹
  • -malign-300 ๐ŸŒธ

โœจ HPPA Options โœจ

  • -march=architecture-type ๐Ÿ’…
  • -mcaller-copies ๐Ÿซถ
  • -mdisable-fpregs ๐Ÿ”ฅ
  • -mdisable-indexing ๐Ÿ‘‘
  • -mfast-indirect-calls ๐ŸŒˆ
  • -mgas โญ
  • -mgnu-ld ๐Ÿ“
  • -mhp-ld ๐Ÿงš
  • -mfixed-range=register-range ๐Ÿ’œ
  • -mjump-in-delay ๐Ÿ’–
  • -mlinker-opt โœจ
  • -mlong-calls ๐ŸŽ€
  • -mlong-load-store ๐Ÿฆ‹
  • -mno-disable-fpregs ๐ŸŒธ
  • -mno-disable-indexing ๐Ÿ’…
  • -mno-fast-indirect-calls ๐Ÿซถ
  • -mno-gas ๐Ÿ”ฅ
  • -mno-jump-in-delay ๐Ÿ‘‘
  • -mno-long-load-store ๐ŸŒˆ
  • -mno-portable-runtime โญ
  • -mno-soft-float ๐Ÿ“
  • -mno-space-regs ๐Ÿงš
  • -msoft-float ๐Ÿ’œ
  • -mpa-risc-1-0 ๐Ÿ’–
  • -mpa-risc-1-1 โœจ
  • -mpa-risc-2-0 ๐ŸŽ€
  • -mportable-runtime ๐Ÿฆ‹
  • -mschedule=cpu-type ๐ŸŒธ
  • -mspace-regs ๐Ÿ’…
  • -msio ๐Ÿซถ
  • -mwsio ๐Ÿ”ฅ
  • -munix=unix-std ๐Ÿ‘‘
  • -nolibdld ๐ŸŒˆ
  • -static โญ
  • -threads ๐Ÿ“

โœจ IA-64 Options โœจ

  • -mbig-endian ๐Ÿงš
  • -mlittle-endian ๐Ÿ’œ
  • -mgnu-as ๐Ÿ’–
  • -mgnu-ld โœจ
  • -mno-pic ๐ŸŽ€
  • -mvolatile-asm-stop ๐Ÿฆ‹
  • -mregister-names ๐ŸŒธ
  • -msdata ๐Ÿ’…
  • -mno-sdata ๐Ÿซถ
  • -mconstant-gp ๐Ÿ”ฅ
  • -mauto-pic ๐Ÿ‘‘
  • -mfused-madd ๐ŸŒˆ
  • -minline-float-divide-min-latency โญ
  • -minline-float-divide-max-throughput ๐Ÿ“
  • -mno-inline-float-divide ๐Ÿงš
  • -minline-int-divide-min-latency ๐Ÿ’œ
  • -minline-int-divide-max-throughput ๐Ÿ’–
  • -mno-inline-int-divide โœจ
  • -minline-sqrt-min-latency ๐ŸŽ€
  • -minline-sqrt-max-throughput ๐Ÿฆ‹
  • -mno-inline-sqrt ๐ŸŒธ
  • -mdwarf2-asm ๐Ÿ’…
  • -mearly-stop-bits ๐Ÿซถ
  • -mfixed-range=register-range ๐Ÿ”ฅ
  • -mtls-size=tls-size ๐Ÿ‘‘
  • -mtune=cpu-type ๐ŸŒˆ
  • -milp32 โญ
  • -mlp64 ๐Ÿ“
  • -msched-br-data-spec ๐Ÿงš
  • -msched-ar-data-spec ๐Ÿ’œ
  • -msched-control-spec ๐Ÿ’–
  • -msched-br-in-data-spec โœจ
  • -msched-ar-in-data-spec ๐ŸŽ€
  • -msched-in-control-spec ๐Ÿฆ‹
  • -msched-spec-ldc ๐ŸŒธ
  • -msched-spec-control-ldc ๐Ÿ’…
  • -msched-prefer-non-data-spec-insns ๐Ÿซถ
  • -msched-prefer-non-control-spec-insns ๐Ÿ”ฅ
  • -msched-stop-bits-after-every-cycle ๐Ÿ‘‘
  • -msched-count-spec-in-critical-path ๐ŸŒˆ
  • -msel-sched-dont-check-control-spec โญ
  • -msched-fp-mem-deps-zero-cost ๐Ÿ“
  • -msched-max-memory-insns-hard-limit ๐Ÿงš
  • -msched-max-memory-insns=max-insns ๐Ÿ’œ

โœจ LM32 Options โœจ

  • -mbarrel-shift-enabled ๐Ÿ’–
  • -mdivide-enabled โœจ
  • -mmultiply-enabled ๐ŸŽ€
  • -msign-extend-enabled ๐Ÿฆ‹
  • -muser-enabled ๐ŸŒธ

โœจ M32R/D Options โœจ

  • -m32r2 ๐Ÿ’…
  • -m32rx ๐Ÿซถ
  • -m32r ๐Ÿ”ฅ
  • -mdebug ๐Ÿ‘‘
  • -malign-loops ๐ŸŒˆ
  • -mno-align-loops โญ
  • -missue-rate=number ๐Ÿ“
  • -mbranch-cost=number ๐Ÿงš
  • -mmodel=code-size-model-type ๐Ÿ’œ
  • -msdata=sdata-type ๐Ÿ’–
  • -mno-flush-func โœจ
  • -mflush-func=name ๐ŸŽ€
  • -mno-flush-trap ๐Ÿฆ‹
  • -mflush-trap=number ๐ŸŒธ
  • -G num ๐Ÿ’…

โœจ M32C Options โœจ

  • -mcpu=cpu ๐Ÿซถ
  • -msim ๐Ÿ”ฅ
  • -memregs=number ๐Ÿ‘‘

โœจ M680x0 Options โœจ

  • -march=arch ๐ŸŒˆ
  • -mcpu=cpu โญ
  • -mtune=tune ๐Ÿ“
  • -m68000 ๐Ÿงš
  • -m68020 ๐Ÿ’œ
  • -m68020-40 ๐Ÿ’–
  • -m68020-60 โœจ
  • -m68030 ๐ŸŽ€
  • -m68040 ๐Ÿฆ‹
  • -m68060 ๐ŸŒธ
  • -mcpu32 ๐Ÿ’…
  • -m5200 ๐Ÿซถ
  • -m5206e ๐Ÿ”ฅ
  • -m528x ๐Ÿ‘‘
  • -m5307 ๐ŸŒˆ
  • -m5407 โญ
  • -mcfv4e ๐Ÿ“
  • -mbitfield ๐Ÿงš
  • -mno-bitfield ๐Ÿ’œ
  • -mc68000 ๐Ÿ’–
  • -mc68020 โœจ
  • -mnobitfield ๐ŸŽ€
  • -mrtd ๐Ÿฆ‹
  • -mno-rtd ๐ŸŒธ
  • -mdiv ๐Ÿ’…
  • -mno-div ๐Ÿซถ
  • -mshort ๐Ÿ”ฅ
  • -mno-short ๐Ÿ‘‘
  • -mhard-float ๐ŸŒˆ
  • -m68881 โญ
  • -msoft-float ๐Ÿ“
  • -mpcrel ๐Ÿงš
  • -malign-int ๐Ÿ’œ
  • -mstrict-align ๐Ÿ’–
  • -msep-data โœจ
  • -mno-sep-data ๐ŸŽ€
  • -mshared-library-id=n ๐Ÿฆ‹
  • -mid-shared-library ๐ŸŒธ
  • -mno-id-shared-library ๐Ÿ’…
  • -mxgot ๐Ÿซถ
  • -mno-xgot ๐Ÿ”ฅ
  • -mlong-jump-table-offsets ๐Ÿ‘‘

โœจ MCore Options โœจ

  • -mhardlit ๐ŸŒˆ
  • -mno-hardlit โญ
  • -mdiv ๐Ÿ“
  • -mno-div ๐Ÿงš
  • -mrelax-immediates ๐Ÿ’œ
  • -mno-relax-immediates ๐Ÿ’–
  • -mwide-bitfields โœจ
  • -mno-wide-bitfields ๐ŸŽ€
  • -m4byte-functions ๐Ÿฆ‹
  • -mno-4byte-functions ๐ŸŒธ
  • -mcallgraph-data ๐Ÿ’…
  • -mno-callgraph-data ๐Ÿซถ
  • -mslow-bytes ๐Ÿ”ฅ
  • -mno-slow-bytes ๐Ÿ‘‘
  • -mno-lsim ๐ŸŒˆ
  • -mlittle-endian โญ
  • -mbig-endian ๐Ÿ“
  • -m210 ๐Ÿงš
  • -m340 ๐Ÿ’œ
  • -mstack-increment ๐Ÿ’–

โœจ MeP Options โœจ

  • -mabsdiff โœจ
  • -mall-opts ๐ŸŽ€
  • -maverage ๐Ÿฆ‹
  • -mbased=n ๐ŸŒธ
  • -mbitops ๐Ÿ’…
  • -mc=n ๐Ÿซถ
  • -mclip ๐Ÿ”ฅ
  • -mconfig=name ๐Ÿ‘‘
  • -mcop ๐ŸŒˆ
  • -mcop32 โญ
  • -mcop64 ๐Ÿ“
  • -mivc2 ๐Ÿงš
  • -mdc ๐Ÿ’œ
  • -mdiv ๐Ÿ’–
  • -meb โœจ
  • -mel ๐ŸŽ€
  • -mio-volatile ๐Ÿฆ‹
  • -ml ๐ŸŒธ
  • -mleadz ๐Ÿ’…
  • -mm ๐Ÿซถ
  • -mminmax ๐Ÿ”ฅ
  • -mmult ๐Ÿ‘‘
  • -mno-opts ๐ŸŒˆ
  • -mrepeat โญ
  • -ms ๐Ÿ“
  • -msatur ๐Ÿงš
  • -msdram ๐Ÿ’œ
  • -msim ๐Ÿ’–
  • -msimnovec โœจ
  • -mtf ๐ŸŽ€
  • -mtiny=n ๐Ÿฆ‹

โœจ MicroBlaze Options โœจ

  • -msoft-float ๐ŸŒธ
  • -mhard-float ๐Ÿ’…
  • -msmall-divides ๐Ÿซถ
  • -mcpu=cpu ๐Ÿ”ฅ
  • -mmemcpy ๐Ÿ‘‘
  • -mxl-soft-mul ๐ŸŒˆ
  • -mxl-soft-div โญ
  • -mxl-barrel-shift ๐Ÿ“
  • -mxl-pattern-compare ๐Ÿงš
  • -mxl-stack-check ๐Ÿ’œ
  • -mxl-gp-opt ๐Ÿ’–
  • -mno-clearbss โœจ
  • -mxl-multiply-high ๐ŸŽ€
  • -mxl-float-convert ๐Ÿฆ‹
  • -mxl-float-sqrt ๐ŸŒธ
  • -mbig-endian ๐Ÿ’…
  • -mlittle-endian ๐Ÿซถ
  • -mxl-reorder ๐Ÿ”ฅ
  • -mxl-mode-app-model ๐Ÿ‘‘
  • -mpic-data-is-text-relative ๐ŸŒˆ

๐Ÿฆ‹ MIPS Options ๐Ÿฆ‹

Bestie, this is the whole MIPS squad. The page just lists them here without a deep dive, so we're vibing with the names ๐Ÿ’…

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

๐ŸŒˆ MMIX Options ๐ŸŒˆ

Next up, the MMIX crew ๐Ÿงš Same deal, just the names on this page.

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

The MN10300 options, bestie ๐ŸŽ€

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

Moxie gets four flags, and they're all right here ๐Ÿซถ

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

๐ŸŒธ MSP430 Options ๐ŸŒธ

MSP430 is giving a whole buffet of flags ๐Ÿฐ

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

NDS32, the squad is big and I'm obsessed ๐Ÿ”ฅ

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

Nios II, the longest list of the bunch and still slaying ๐Ÿ’…

  • -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 ๐Ÿ‘‘

Three flags, very power-move energy โญ

  • -m64
  • -mmainkernel
  • -moptimize

๐ŸŽ€ OpenRISC Options ๐ŸŽ€

OpenRISC, let's go ๐ŸŒˆ

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

๐Ÿฆ– PDP-11 Options ๐Ÿฆ–

PDP-11, a whole retro era, iykyk ๐Ÿ’€

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

picoChip, four flags and a whole vibe ๐Ÿฆ‹

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

โšก PowerPC Options โšก

No list of its own, bestie. PowerPC is all tucked into the RS/6000 section

See RS/6000 and PowerPC Options.

๐Ÿชฒ PRU Options ๐Ÿชฒ

PRU, small but mighty ๐Ÿ”ฅ

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

๐ŸŒฟ RISC-V Options ๐ŸŒฟ

RISC-V is a whole main character with a long list of flags, and I'm here for it ๐Ÿ’…

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

๐Ÿฌ RL78 Options ๐Ÿฌ

RL78 has its own little lineup, and it's sweet ๐Ÿญ

  • -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, the main event, the whole PowerPC universe โœจ

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

RX is the next stop on the train, choo choo ๐Ÿ’–

  • -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 ๐Ÿ›๏ธ

S/390 and zSeries, a classic with a long guest list ๐ŸŽฉ

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

Score, nine flags and a sunny attitude โ˜€๏ธ

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

๐Ÿš SH Options ๐Ÿš

SH has a huge lineup and every single one is giving ๐Ÿ’…

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

โ˜€๏ธ Solaris 2 Options โ˜€๏ธ

Solaris 2, a short and sweet set ๐ŸŒž

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

๐Ÿ‘ SPARC Options ๐Ÿ‘

SPARC has a huge closet of flags and I'm obsessed ๐Ÿ’–

  • -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 ๐Ÿ

System V, the classic finale of this bunch ๐ŸŽ€

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

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

TILE-Gx, out of this world and totally iconic ๐Ÿ›ธ

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

๐Ÿ’ TILEPro Options ๐Ÿ’

Last but not least, TILEPro, the cherry on top ๐Ÿ’๐Ÿ’…

  • -mcpu=cpu
  • -m32

๐Ÿฆ‹ V850 Options ๐Ÿฆ‹

Okay so the V850 squad is up first, bestie ๐Ÿ’… Here's the whole lineup:

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

Three little flags, and they're all giving main character energy โœจ

-mg -mgnu -munix

๐Ÿ“ Visium Options ๐Ÿ“

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

๐Ÿ‘‘ VMS Options ๐Ÿ‘‘

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

๐ŸŒˆ VxWorks Options ๐ŸŒˆ

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

๐Ÿ’œ x86 Options ๐Ÿ’œ

Okay this one is LONG, bestie ๐Ÿ˜ญ Grab a snack, it's a whole buffet of flags:

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

๐Ÿซถ x86 Windows Options ๐Ÿซถ

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

โญ Xstormy16 Options โญ

-msim

๐ŸŒธ Xtensa Options ๐ŸŒธ

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

See S/390 and zSeries Options. The zSeries flags live over there, bestie, so go check them out ๐Ÿ’–


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

Okay so compilation can involve up to four stages: preprocessing, compilation proper, assembly and linking, always in that order โœจ GCC can preprocess and compile several files into several assembler input files, or into one assembler input file. Then each assembler input file produces an object file, and linking combines all the object files (the ones newly compiled and the ones you passed in) into an executable file. It's giving teamwork ๐Ÿซถ

For any given input file, the file name suffix decides what kind of compilation happens. Here's the cheat sheet:

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

You can also spell out the input language yourself with the -x option, which is honestly so handy ๐Ÿ’–

  • -x language โ€” Explicitly sets the language for the following input files, instead of letting the compiler pick a default based on the file name suffix. This applies to all following input files until the next -x option. The possible values for language are:
c  c-header  cpp-output
c++  c++-header  c++-system-header c++-user-header c++-cpp-output
objective-c  objective-c-header  objective-c-cpp-output
objective-c++ objective-c++-header objective-c++-cpp-output
assembler  assembler-with-cpp
ada
d
f77  f77-cpp-input f95  f95-cpp-input
go
brig
  • -x none โ€” Turns off any language specification, so later files are handled by their file name suffixes, just like they would be if -x had never been used at all.

If you only want some of the stages, use -x (or the filename suffixes) to tell gcc where to start, and one of the options -c, -S, or -E to say where gcc should stop. Be careful, though: some combinations, like -x cpp-output -E, instruct gcc to do nothing at all ๐Ÿ˜ญ

  • -c โ€” Compiles or assembles the source files, but does not link. The linking stage simply doesn't happen, so the final 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 stage and does not assemble. The output is an assembler code file for each non-assembler input file you specify.

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

Input files that don't require compilation are ignored.

  • -E โ€” Stops after the preprocessing stage and does not run the compiler proper. The output is preprocessed source code, which gets sent to the standard output.

Input files that don't require preprocessing are ignored.

  • -o file โ€” Places the primary output in file. This works for whatever you're producing, whether that's an executable file, an object file, an assembler file, or preprocessed C code ๐Ÿ’…

If you don't specify -o, the default is to put an executable file in a.out, the object file for source.suffix in source.o, its assembler file in source.s, a precompiled header file in source.suffix.gch, and all preprocessed C source on standard output ๐ŸŽ€

Okay so, even though -o only names the main output, it's also secretly in charge of naming the aux and dump outputs ๐Ÿ‘€๐ŸŽ€ Unless you override it, those extras get parked in the same folder as your primary output ๐Ÿ’… For aux outputs, the input file's suffix gets swapped out for the aux file type's suffix. For dump outputs, the dump file's suffix gets tacked onto the input file's suffix โœจ In compilation commands, both aux and dump outputs borrow the base name of the primary output. In compile-and-link commands, the primary output name (minus the executable suffix) gets combined with the input file name ๐Ÿฆ‹ If both end up with the same base name (ignoring the suffix), the result is just that base name. If they don't match, they get joined with a dash.

gcc -c foo.c ...

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

If you explicitly specify a non-linker output file, the aux and dump files take the same base name by default ๐Ÿ’œ

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

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

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

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

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

There's one exception, and it's iconic. If the executable shares its base name with the single input, the naming goes back to normal ๐Ÿ‘‘

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

In that case the aux outputs are named dir/foo.* and the dump outputs are named dir/foo.c.* ๐Ÿ’–

You can tweak the location and names of the aux and dump outputs with the options -dumpbase, -dumpbase-ext, -dumpdir, -save-temps=cwd, and -save-temps=obj โœจ

๐ŸŽ€ -dumpbase dumpbase

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

gcc -save-temps -S foo.c

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

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

This preprocesses into save-foo.i, compiles to save-foo.s (which is now an intermediate, and therefore an aux output), and then assembles to the (implied) output file foo.o ๐ŸŒˆ

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

You can get similar suffix differentiation for dump and aux outputs with an explicit -dumpbase basename.suf by also specifying -dumpbase-ext .suf ๐Ÿ’œ

If dumpbase is explicitly given with any directory component, then any dumppfx specification (like -dumpdir or -save-temps=*) gets ignored. The dumpbase fully overrides it instead of getting appended to it ๐Ÿ‘‘

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

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

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

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

This creates foo.o and bar.o as primary outputs. It also avoids overwriting the aux and dump outputs by using the dumpbase as a prefix, so you get aux and dump outputs named main-foo.* and main-bar.* ๐Ÿซถ

An empty string given as the dumpbase keeps the output basename from influencing 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 the aux outputs dir/foo.* and the dump outputs dir/foo.c.*. Notice how their 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 ๐Ÿฆ‹

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

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

๐Ÿ’– -dumpbase-ext auxdropsuf

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

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

This creates dir/foo.o as the main output. It generates aux outputs in dir/x-foo.*, using the location of the primary output and dropping the .c suffix from the dumpbase. Dump outputs keep the suffix, so you get dir/x-foo.c.* ๐Ÿฆ‹

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

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

This creates main.out as the primary output. It avoids overwriting the aux and dump outputs by using the executable name minus auxdropsuf as a prefix. That gives you aux outputs named main-foo.* and main-bar.*, and dump outputs named main-foo.c.* and main-bar.c.* ๐Ÿ’œ

๐ŸŒธ -dumpdir dumppfx

When forming the name of an auxiliary or dump output file, this option 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 named pfx-foo.c.* ๐Ÿซถ

If you want to use dumppfx as a directory name, it has to end with a directory separator ๐Ÿ“

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

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

By default, the dumppfx is the location of the output file. The exception is when the output is a special file like "/dev/null". The options -save-temps=cwd and -save-temps=obj override this default, just like an explicit -dumpdir option does. If you give several of these, 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 give -dumpbase, the dumpbase (minus an auxdropsuf suffix) and a dash get appended to the explicit or defaulted dumppfx. If the dumpbase contains any directory components, it overrides the dumppfx instead. Either way, each of the multiple compilations ends up with differently-named aux and dump outputs ๐Ÿฆ‹

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

This sends the auxiliary dumps to dir/pfx-main-foo.* and dir/pfx-main-bar.*, appending dumpbase- to the dumppfx. Dump outputs keep the input file suffix, so you get dir/pfx-main-foo.c.* and dir/pfx-main-bar.c.*, respectively ๐Ÿ’–

Now contrast that with the single-input version:

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

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

When you compile and then link from multiple input files, a defaulted or explicit dumppfx also goes through the dumpbase- transformation from above. The example would be the compilation of foo.c and bar.c from earlier, just without -c. If you give neither -dumpdir nor -dumpbase, then the linker output base name gets appended to the default dumppfx instead. Before that happens, the base name has the auxdropsuf removed if you specified one. Otherwise the executable suffix gets removed. Then a dash gets added ๐Ÿซถ

Here's the twist, though. Unlike the earlier linking cases, this one doesn't work the same way:

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

This does not append the output name main to the dumppfx, because -dumpdir was explicitly specified. The idea is that an explicitly specified dumppfx can include the output name as part of its prefix, if you want that. Only an explicitly specified -dumpbase gets combined with it, so you don't accidentally throw away a meaningful option ๐Ÿ‘‘

When you compile and then link from a single input file, the linker output base name gets appended to the default dumppfx (as described above) only if it doesn't share its base name with the single input file name. That covers the single-input linking cases from earlier. It doesn't cover an explicit -dumpdir that stops the combination from happening, even if -save-temps=* overrides it later:

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

In this case, the auxiliary outputs are named foo.* and the dump outputs are named foo.c.*. They end up in the current working directory, as -save-temps=cwd ultimately requests ๐ŸŒธ

Okay so, here's the naming situation all in one place (it's a little simplified, but it gets the vibe across ๐Ÿ’…). The main output name gets split into a directory part and a basename part ๐Ÿฆ‹. The directory part becomes dumppfx, unless you've overridden it with -dumpdir or -save-temps=*. The basename becomes dumpbase, unless you've overridden it with -dumpbase ๐Ÿซถ. If there are multiple inputs or you're linking, dumpbase can get combined with dumppfx and pulled from each input file โœจ. Auxiliary output names for each input are built by smooshing together dumppfx, dumpbase minus its suffix, and the auxiliary output suffix ๐ŸŽ€. Dump output names are almost the same thing, except the suffix from dumpbase gets to stay ๐Ÿ’–.

Now for LTO recompilation ๐ŸŒˆ. A combo of dumppfx and dumpbase gets passed down to lto-wrapper as a -dumpdir option, with a trailing period swapped in for the compiler-added dash (if there is one). This happens whether that combo is the one you gave, or one derived from the linker output name and not from the inputs, and even when it wouldn't normally be used that way ๐Ÿงš. Since gcc is involved in linking, it doesn't normally get any -dumpbase or -dumpbase-ext, and it ignores them if they show up ๐Ÿ™ˆ.

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

  • -v โ€” Prints the commands run for each stage of compilation ๐Ÿ“œ (on standard error output, bestie). It also shows the version number of the compiler driver program, plus the version of the preprocessor and the compiler proper ๐Ÿ”ฅ.
  • -### โ€” Basically -v, except nothing actually runs ๐Ÿ™…โ€โ™€๏ธ. Arguments get wrapped in quotes unless they only contain alphanumeric characters or "./-_". This is super useful for shell scripts that want to capture the command lines the driver generates ๐Ÿ“.
  • --help โ€” Prints (on standard output) a rundown of the command-line options gcc understands ๐Ÿ“–. If -v is also there, --help gets passed on to the other processes gcc invokes, so they can show the options they accept ๐ŸŒธ. If -Wextra was specified before --help, then options with no documentation get shown too โœจ.
  • --target-help โ€” Prints (on standard output) the target-specific command-line options for each tool ๐ŸŽฏ. For some targets, extra target-specific info might get printed too ๐Ÿฆ‹.
  • --help={class|[^]qualifier}[,...] โ€” Prints (on standard output) the options that fit into all the classes and qualifiers you list ๐Ÿ”. Here are the classes:
    • optimizers โ€” every optimization option the compiler supports ๐Ÿš€.
    • warnings โ€” every option that controls warning messages ๐Ÿšจ.
    • target โ€” target-specific options ๐ŸŽ€. Unlike --target-help, the linker's and assembler's target options don't show up here, since those tools don't support the extended --help= syntax yet ๐Ÿ™ˆ.
    • params โ€” the values --param recognizes ๐Ÿ’œ.
    • language โ€” the options for language, which is any one of the languages this GCC version supports ๐ŸŒˆ. If an option works with every language, you need to pick the common class instead.
    • common โ€” the options shared by all languages ๐Ÿซถ.

And here are the qualifiers:

  • undocumented โ€” only the options with no documentation ๐Ÿซฅ.
  • joined โ€” options that take an argument right after an equal sign, in the same chunk of text, like --help=target ๐Ÿงฉ.
  • separate โ€” options that take an argument as a separate word after the original option, like -o output-file ๐Ÿ“Ž.

Want every undocumented target-specific switch the compiler supports? Use:

--help=target,undocumented

You can flip a qualifier by putting ^ in front of it. So to show all the binary warning options (the ones that are either on or off and don't take an argument) that do have a description, use:

--help=warnings,^joined,^undocumented

The argument to --help= can't be made up only of inverted qualifiers, so don't try that ๐Ÿ™…โ€โ™€๏ธ. Combining several classes is possible, but it usually narrows the output so much there's nothing left to show ๐Ÿ˜ญ. One combo that actually works is pairing target with another class. To see all the target-specific optimization options, use:

--help=target,optimizers

You can repeat --help= on the command line. Each use displays its requested class and skips anything already shown ๐Ÿ”. If --help is also anywhere on the command line, it beats any --help= option ๐Ÿ‘‘.

If -Q shows up on the command line before --help=, the descriptive text changes ๐Ÿช„. Instead of describing the options, it tells you whether each one is enabled, disabled, or set to a specific value (as long as the compiler knows that at the point where --help= is used). Here's a truncated example from the ARM port of gcc:

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

The output depends on earlier options, so you can find out which optimizations are enabled at -O2 with:

-Q -O2 --help=optimizers

Or, if you want to see which binary optimizations -O3 enables, you can do:

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 โ€” Shows the version number and copyright info of the GCC you invoked ๐ŸŽ‰.
  • -pass-exit-codes โ€” Normally gcc exits with code 1 if any phase of the compiler returns a non-success code ๐Ÿ˜ฌ. With -pass-exit-codes, it instead returns the numerically highest error from any phase that gave back an error indication ๐Ÿ“ˆ. The C, C++, and Fortran front ends return 4 if they run into an internal compiler error ๐Ÿ’€.
  • -pipe โ€” Uses pipes instead of temporary files to pass stuff between compilation stages ๐Ÿšฐ. This fails on some systems where the assembler can't read from a pipe, but the GNU assembler has zero trouble with it ๐Ÿ’….
  • -specs=file โ€” Processes file after the compiler reads in the standard specs file ๐Ÿ“‘. This lets you override the defaults that the gcc driver uses when figuring out which switches to pass to cc1, cc1plus, as, ld, and so on ๐Ÿ”ง. You can use more than one -specs=file, and they get processed in order, from left to right โžก๏ธ.
  • -wrapper โ€” Runs all subcommands under a wrapper program ๐ŸŽ. The wrapper's name and its parameters go in as a comma-separated list. For example:
gcc -c t.c -wrapper gdb,--args

That runs every gcc subprogram under gdb --args, so the cc1 invocation becomes gdb --args cc1 .... ๐Ÿ›.

  • -ffile-prefix-map=old=new โ€” When you compile files living in directory old, any references to them in the compilation result get recorded as if those files lived in directory new instead ๐Ÿ—บ๏ธ. Using this is the same as specifying all the individual -f*-prefix-map options. It's handy for reproducible, location-independent builds ๐Ÿซถ. See also -fmacro-prefix-map and -fdebug-prefix-map ๐Ÿ‘€.
  • -fplugin=name.so โ€” Loads the plugin code from name.so, which is assumed to be a shared object the compiler will dlopen ๐Ÿงฉ. The base name of the shared object file is what identifies the plugin when arguments get parsed (see -fplugin-arg-name-key=value below). Each plugin should define the callback functions listed in the Plugins API ๐Ÿ“š.
  • -fplugin-arg-name-key=value โ€” Defines an argument called key with a value of value for the plugin called name ๐ŸŽ€.
  • -fdump-ada-spec[-slim] โ€” For C and C++ source and include files, generates the matching Ada specs ๐ŸŒท.
  • -fada-spec-parent=unit โ€” Used together with -fdump-ada-spec[-slim] above, this generates the Ada specs as child units of the parent unit ๐Ÿ‘ถ.
  • -fdump-go-spec=file โ€” For input files in any language, generates the matching Go declarations in file ๐Ÿน. That means Go const, type, var, and func declarations, which can be a great way to kick off writing a Go interface to code written in another language ๐ŸŒˆ.
  • @file โ€” Reads command-line options from file โœ๏ธ. The options read get inserted right where the original @file option was, and that @file is no longer there. If file doesn't exist or can't be read, then @file gets treated literally and is not removed ๐Ÿ™ƒ.

Options inside file are separated by whitespace. To include a whitespace character in an option, wrap the entire option in single or double quotes. To include any character (even a backslash), put a backslash in front of it. The file can contain more @file options too, and those get processed recursively ๐Ÿ”.


โœจ Compiling C++ Programs โœจ

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

However, using gcc doesn't pull in the C++ library, bestie ๐Ÿ™ˆ That's where g++ comes in. It's a program that calls GCC and automatically links against the C++ library ๐Ÿ’– It treats .c, .h and .i files as C++ source files instead of C source files, unless you use -x. It's also super useful for precompiling a C header file with a .h extension for use in C++ compilations ๐Ÿงš On many systems, g++ is also installed under the name c++ โœจ

When you compile C++ programs, you can use lots of the same command-line options you'd use for any language ๐ŸŒˆ You can also use options meant for C and related languages, or options that only matter for C++ programs. Main character energy, honestly ๐Ÿ‘‘

๐ŸŽ€ Options Controlling C Dialect ๐ŸŽ€

The following options control the dialect of C (or languages derived from C, like C++, Objective-C and Objective-C++) that the compiler accepts ๐Ÿ’…

  • -ansi โ€” okay, this one's a whole vibe. In C mode it's 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, plus predefined macros like unix and vax that tell you what kind of system you're on ๐Ÿ™ˆ It also turns on the undesirable, rarely used ISO trigraph feature. For the C compiler, it also disables recognition of C++ style // comments and the inline keyword.
    • The alternate keywords __asm__, __extension__, __inline__ and __typeof__ still work with -ansi โœจ You wouldn't want them in an ISO C program, obviously, but they're handy in header files that might get included in compilations done with -ansi. The alternate predefined macros __unix__ and __vax__ are available with or without -ansi ๐Ÿฆ‹
    • -ansi doesn't reject non-ISO programs out of nowhere. 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 the ISO standard doesn't ask for, so they don't mess with programs using those names for other stuff ๐Ÿซถ
    • Functions that are normally built in but don't have ISO C semantics, like alloca and ffs, are not built-in functions when -ansi is used ๐Ÿ”ฅ
  • -std= โ€” determines the language standard. This is only supported when compiling C or C++ ๐Ÿ‘‘
    • The compiler can accept base standards like c90 or c++98, plus GNU dialects of those, like gnu90 or gnu++98 ๐ŸŒˆ With a base standard, it accepts all programs following that standard plus GNU extensions that don't contradict it. For example, -std=c90 turns off GCC features that are incompatible with ISO C90, like asm and typeof, but keeps other GNU extensions that don't mean anything in ISO C90, like omitting 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. As a result, some strictly conforming programs may be rejected ๐Ÿ˜ญ
    • -Wpedantic uses the 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 <http://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). It's the same as C11 except for corrections of defects (all of which are also applied with -std=c11) and a new value of __STDC_VERSION__, so it's supported to the same extent as C11 โœจ
      • c2x โ€” the next version of the ISO C standard, still under development. Support for this version is experimental and incomplete ๐Ÿงช
      • gnu90, gnu89 โ€” GNU dialect of ISO C90 (including some C99 features) ๐ŸŒธ
      • gnu99, gnu9x โ€” GNU dialect of ISO C99. The name gnu9x is deprecated.
      • gnu11, gnu1x โ€” GNU dialect of ISO C11. The name gnu1x is deprecated.
      • gnu17, gnu18 โ€” GNU dialect of ISO C17. This is the default for C code ๐Ÿ’–
      • gnu2x โ€” the next version of the ISO C standard, still under development, plus GNU extensions. Support for this version is experimental and incomplete.
      • c++98, c++03 โ€” the 1998 ISO C++ standard plus the 2003 technical corrigendum and some additional defect reports. Same as -ansi for C++ code.
      • gnu++98, gnu++03 โ€” GNU dialect of -std=c++98.
      • c++11, c++0x โ€” the 2011 ISO C++ standard plus amendments. The name c++0x is deprecated.
      • gnu++11, gnu++0x โ€” GNU dialect of -std=c++11. The name gnu++0x is deprecated.
      • c++14, c++1y โ€” the 2014 ISO C++ standard plus amendments. The name c++1y is deprecated.
      • gnu++14, gnu++1y โ€” GNU dialect of -std=c++14. The name gnu++1y is deprecated.
      • c++17, c++1z โ€” the 2017 ISO C++ standard plus amendments. The name c++1z is deprecated.
      • gnu++17, gnu++1z โ€” GNU dialect of -std=c++17. This is the default for C++ code. The name gnu++1z is deprecated.
      • c++20, c++2a โ€” the 2020 ISO C++ standard plus amendments. Support is experimental and could change in incompatible ways in future releases. The name c++2a is deprecated.
      • gnu++20, gnu++2a โ€” GNU dialect of -std=c++20. Support is experimental and could change in incompatible ways in future releases. The name gnu++2a is deprecated.
      • c++2b, c++23 โ€” the next revision of the ISO C++ standard, planned for 2023. Support is highly experimental and will almost certainly change in incompatible ways in future releases โš ๏ธ
      • gnu++2b, gnu++23 โ€” GNU dialect of -std=c++2b. Support is highly experimental, and will almost certainly change in incompatible ways in future releases.
  • -fgnu89-inline โ€” tells GCC to use the traditional GNU semantics for inline functions when in C99 mode ๐Ÿฆ‹
    • Using this option is roughly equivalent to adding the gnu_inline function attribute to all inline functions.
    • The option -fno-gnu89-inline explicitly tells GCC to use the C99 semantics for inline when in C99 or gnu99 mode (i.e., it specifies the default behavior). This option is not supported in -std=c90 or -std=gnu90 mode.
    • The preprocessor macros __GNUC_GNU_INLINE__ and __GNUC_STDC_INLINE__ may be used to check which semantics are in effect for inline functions ๐Ÿ”
  • -fpermitted-flt-eval-methods=style โ€” okay, this one's a brain-melt, but stay with me ๐Ÿง  ISO/IEC TS 18661-3 defines new permissible values for FLT_EVAL_METHOD that indicate 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. These new values are a superset of those permitted under C99/C11, which doesn't specify the meaning of other positive values of FLT_EVAL_METHOD. So code conforming to C11 may not have been written expecting the new values ๐Ÿฅบ
    • -fpermitted-flt-eval-methods specifies whether the compiler should allow only the FLT_EVAL_METHOD values specified in C99/C11, or the extended set of values specified in ISO/IEC TS 18661-3.
    • style is either c11 or ts-18661-3, as appropriate.
    • The default in a standards-compliant mode (-std=c11 or similar) is -fpermitted-flt-eval-methods=c11. The default in a GNU dialect (-std=gnu11 or similar) is -fpermitted-flt-eval-methods=ts-18661-3.
  • -aux-info filename โ€” outputs to the given filename prototyped declarations for all functions declared and/or defined in a translation unit, including those in header files ๐Ÿ“ This option is silently ignored in any language other than C.
    • Besides declarations, the file indicates, in comments, the origin of each declaration (source file and line), whether the declaration was implicit, prototyped or unprototyped (I, N for new or O for old, respectively, in the first character after the line number and the colon), and whether it came from a declaration or a definition (C or F, respectively, in the following character).
    • For function definitions, a K&R-style list of arguments followed by their declarations is also provided, inside comments, after the declaration ๐Ÿ’œ
  • -fallow-parameterless-variadic-functions โ€” accepts variadic functions without named parameters ๐ŸŒŸ
    • Sure, you can define one, but it's not very useful since you can't read the arguments ๐Ÿ™ƒ This is only supported for C, since C++ already allows this construct.
  • -fno-asm: okay bestie, this one's giving "let me use your words." It stops GCC from treating asm, inline or typeof as keywords, so your code can use those words as identifiers ๐Ÿซถ. If you still want the keyword powers, use __asm__, __inline__ and __typeof__ instead ๐Ÿ’…. -ansi implies -fno-asm.

In C++, this switch only affects the typeof keyword, since asm and inline are standard keywords ๐Ÿงš. You may want to use the -fno-gnu-keywords flag instead, which has the same effect โœจ. 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: don't recognize built-in functions that don't start with __builtin_ as a prefix ๐Ÿ™ˆ.

Okay so 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 show up as calls, you cannot set a breakpoint on them, nor can you change how the functions behave by linking with a different library ๐Ÿ’€. Also, when a function is recognized as a built-in, GCC may use info about it to warn you about sketchy calls, or to generate more efficient code, even if the result still contains calls to that function ๐Ÿ‘‘. For example, you get warnings with -Wformat for bad calls to printf when printf is built in, and when strlen is known not to modify global memory ๐Ÿฆ‹.

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

#define abs(n)          __builtin_abs ((n))
#define strcpy(d, s)    __builtin_strcpy ((d), (s))
  • -fgimple: enables parsing of function definitions marked with __GIMPLE. This is an experimental feature for unit testing GIMPLE passes ๐Ÿงช.
  • -fhosted: asserts that compilation targets a hosted environment, and this implies -fbuiltin. A hosted environment is one where the entire standard library is available, and where main has a return type of int. Examples are basically everything except a kernel ๐Ÿ“. This is equivalent to -fno-freestanding.
  • -ffreestanding: asserts that compilation targets a freestanding environment, and this implies -fno-builtin. A freestanding environment is one where the standard library may not exist, and program startup may not necessarily begin at main. The most obvious example is an OS kernel ๐Ÿง . This is equivalent to -fno-hosted.
  • -fopenacc: enables handling of OpenACC directives, #pragma acc in C/C++ and !$acc in Fortran ๐Ÿš€. When you use -fopenacc, the compiler generates accelerated code according to the OpenACC Application Programming Interface v2.6 at https://www.openacc.org. This option implies -pthread, so it's only supported on targets that support -pthread ๐Ÿงต.
  • -fopenacc-dim=geom: sets default compute dimensions for parallel offload regions that don't explicitly specify their own ๐Ÿ“. The geom value is a triple of :-separated sizes, in the order 'gang', 'worker' and 'vector'. You can leave a size out to use a target-specific default value ๐Ÿซง.
  • -fopenmp: enables handling of OpenMP directives, #pragma omp in C/C++ and !$omp in Fortran ๐ŸŽ€. When you use -fopenmp, the compiler generates parallel code according to the OpenMP Application Program Interface v4.5 at https://www.openmp.org. This option implies -pthread, so it's only supported on targets that support -pthread. -fopenmp also implies -fopenmp-simd ๐Ÿ’œ.
  • -fopenmp-simd: enables handling of OpenMP's SIMD directives written with #pragma omp in C/C++ and !$omp in Fortran. Other OpenMP directives get ignored ๐Ÿ™ƒ.
  • -fgnu-tm: when you specify -fgnu-tm, the compiler generates code for the Linux variant of Intel's current Transactional Memory ABI specification document (Revision 1.1, May 6 2009). This is an experimental feature whose interface may change in future versions of GCC, as the official specification changes ๐Ÿงช. Please note that not every architecture supports 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) ๐Ÿšซ.
  • -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;
};

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 x86 targets using ms-abi.

  • -fplan9-extensions: accepts some non-standard constructs used in Plan 9 code ๐Ÿš.

This enables -fms-extensions, allows passing pointers to structures with anonymous fields to functions that expect pointers to elements of the field's type, and allows referring to anonymous fields declared using a typedef. This is only supported for C, not C++ ๐Ÿ™…โ€โ™€๏ธ.

  • -fcond-mismatch: allows conditional expressions with mismatched types in the second and third arguments. The value of such an expression is void. This option is not supported for C++ ๐Ÿซ .
  • -flax-vector-conversions: allows implicit conversions between vectors with differing numbers of elements and/or incompatible element types. This option should not be used for new code ๐Ÿ˜ฌ.
  • -funsigned-char: lets the type char be unsigned, like unsigned char ๐ŸŒ™.

Every kind of machine has a default for what char should be. It's either like unsigned char by default or like signed char by default ๐Ÿคทโ€โ™€๏ธ.

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

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

  • -fsigned-char: lets the type char be signed, like signed char โญ.

This is equivalent to -fno-unsigned-char, which is the negative form of -funsigned-char. Likewise, the option -fno-signed-char is equivalent to -funsigned-char ๐Ÿ”„.

  • -fsigned-bitfields, -funsigned-bitfields, -fno-signed-bitfields, -fno-unsigned-bitfields: these control whether a bit-field is signed or unsigned when the declaration doesn't use either signed or unsigned ๐ŸŽฏ. By default, such a bit-field is signed, because that's consistent: basic integer types like int are signed types ๐Ÿ’–.
  • -fsso-struct=endianness: sets the default scalar storage order of structures and unions to the specified endianness. The accepted values are big-endian, little-endian and native (the default), where native means the native endianness of the target. 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 only matter for C++ programs ๐Ÿ’œ. You can also use most of the GNU compiler options no matter what language your program is in ๐ŸŒธ. For example, you might compile a file firstClass.C like this:

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

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

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

Here 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. That means the ABI you get from version 0 will change in different versions of G++ as ABI bugs get fixed ๐Ÿ› ๏ธ.

Version 1 is the version of the C++ ABI that first appeared in G++ 3.2 ๐ŸŒฑ.

Version 2 is the version of the C++ ABI that first appeared in G++ 3.4, and it was the default through G++ 4.9 ๐Ÿ‘‘.

Version 3 corrects an error in mangling a constant address as a template argument ๐Ÿ”ง.

Version 4, which first appeared in G++ 4.5, implements a standard mangling for vector types ๐Ÿ“ฆ.

Version 5, which first appeared in G++ 4.6, corrects the mangling of attribute const/volatile on function pointer types, decltype of a plain decl, and use of a function parameter in the declaration of another parameter ๐Ÿงฉ.

Version 6, which first appeared in G++ 4.7, corrects the promotion behavior of C++11 scoped enums and the mangling of template argument packs, const/static_cast, prefix ++ and --, and a class scope function used as a template argument ๐ŸŽ€.

Version 7, which first appeared in G++ 4.8, that treats nullptr_t as a builtin type and corrects the mangling of lambdas in default argument scope ๐Ÿญ.

Version 8, which first appeared in G++ 4.9, corrects the substitution behavior of function types with function-cv-qualifiers ๐Ÿ’….

Version 9, which first appeared in G++ 5.2, corrects the alignment of nullptr_t โœจ.

Version 10, which first appeared in G++ 6.1, adds mangling of attributes that affect type identity, such as ia32 calling convention attributes (e.g. stdcall) ๐Ÿฆ‹.

  • Version 11 ๐ŸŽ€ (first showed up in G++ 7) fixes how sizeof... expressions and operator names get mangled. Okay so for multiple entities with the same name inside one function that are declared in different scopes, the mangling changes starting with the twelfth occurrence ๐Ÿ’… It also implies -fnew-inheriting-ctors.
  • Version 12 ๐Ÿ˜ญ (first showed up in G++ 8) fixes calling conventions for empty classes on the x86_64 target and for classes with only deleted copy/move constructors. Bestie, it also accidentally changes the calling convention for classes with a deleted copy constructor and a trivial move constructor.
  • Version 13 ๐Ÿซถ (first showed up in G++ 8.2) fixes that accidental change from version 12. Iconic redemption arc.
  • Version 14 โœจ (first showed up in G++ 10) corrects the mangling of the nullptr expression.
  • Version 15 ๐Ÿฆ‹ (first showed up in G++ 11) makes the mangling of __alignof__ distinct from alignof, and also changes the mangling of dependent operator names.

Also, see -Wabi ๐Ÿ‘€


โœจ OPTIONS โœจ (continued)

  • -fabi-compat-version=n ๐ŸŒธ โ€” On targets that support strong aliases, G++ works around mangling changes by creating an alias with the correct mangled name whenever it defines a symbol with an incorrect mangled name. This switch picks which ABI version the alias uses.
    • With -fabi-version=0 (the default), this defaults to 11 (GCC 7 compatibility). If you explicitly pick a different ABI version, it defaults to 0.
    • For compatibility with GCC versions 3.2 through 4.9, use -fabi-compat-version=2.
    • If this option isn't provided but -Wabi=n is, that version is used for the compatibility aliases. If this option is provided along with -Wabi (without a version), the version from this option is used for the warning.
  • -fno-access-control ๐Ÿ”“ โ€” Turns off all access checking. Mainly useful for working around bugs in the access control code, so it's a lowkey lifesaver for that specific situation.
  • -faligned-new ๐Ÿ“ โ€” Enables support for C++17 new of types that need more alignment than void* ::operator new(std::size_t) provides. You can pass a number like -faligned-new=32 to say how much alignment (in bytes) that function provides, but few users will need to override the default of alignof(std::max_align_t). This flag is enabled by default for -std=c++17.
  • -fchar8_t, -fno-char8_t ๐Ÿ’œ โ€” Enables support for char8_t, as adopted for C++20. This brings a new char8_t fundamental type, changes to the types of UTF-8 string and character literals, new signatures for user-defined literals, associated standard library updates, and the new __cpp_char8_t and __cpp_lib_char8_t feature test macros.

This option lets functions be overloaded 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;
The change to the types of UTF-8 string and character literals introduces incompatibilities with ISO C++11 and later standards. For example, the following code is well-formed under ISO C++11, but is ill-formed when -fchar8_t is specified.
        char ca[] = u8"xx";     // error: char-array initialized from wide
                                //        string
        const char *cp = u8"xx";// error: invalid conversion from
                                //        `const char8_t*' to `const char*'
        int f(const char*);
        auto v = f(u8"xx");     // error: invalid conversion from
                                //        `const char8_t*' to `const char*'
        std::string s{u8"xx"};  // error: no matching function for call to
                                //        `std::basic_string<char>::basic_string()'
        using namespace std::literals;
        s = u8"xx"s;            // error: conversion from
                                //        `basic_string<char8_t>' to non-scalar
                                //        type `basic_string<char>' requested
  • -fcheck-new ๐Ÿ™ˆ โ€” Checks that the pointer returned by operator new is non-null before it tries to modify the storage it allocated. This check is normally unnecessary, because the C++ standard says operator new only returns 0 if it's declared throw(). In that case the compiler always checks the return value, even without this option. In 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's specification of Concepts differs significantly from the TS, so some constructs that were allowed in the TS but didn't make it into the standard can still be enabled with -fconcepts-ts.

  • -fconstexpr-depth=n ๐ŸŒ€ โ€” Sets the maximum nested evaluation depth for C++11 constexpr functions to n. A limit is needed to catch endless recursion during constant expression evaluation. The minimum the standard specifies is 512.
  • -fconstexpr-cache-depth=n ๐Ÿง  โ€” Sets the maximum nested evaluation depth for C++11 constexpr functions that will be cached to n. This is a heuristic that trades compilation speed (when the cache avoids repeated calculations) against memory consumption (when the cache grows huge from highly recursive evaluations). The default is 8. Very few users are likely to want to adjust it, but if your code does heavy constexpr calculations, you might want to experiment to find which value works best for you.
  • -fconstexpr-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 of a single loop is capped by the limit above, several nested loops that each have lots of iterations (but still fewer than that limit), or too many expressions to evaluate in a loop body or even outside a loop, can make the constexpr evaluation take too long. The default is 33554432 (1<<25).
  • -fcoroutines ๐Ÿงต โ€” Enables support for the C++ coroutines extension. This one is experimental, so proceed with main character energy and a little caution ๐Ÿ’€
  • -fno-elide-constructors ๐Ÿšซ โ€” The C++ standard lets an implementation skip creating a temporary that's only used to initialize another object of the same type. Specifying this option disables that optimization and forces G++ to call the copy constructor in all cases. It also causes G++ to call trivial member functions that would otherwise be expanded inline.

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

  • -fno-enforce-eh-specs โš ๏ธ โ€” Don't generate code that checks for violations of exception specifications at run time. This option violates the C++ standard, but it may be useful for shrinking code size in production builds, kind of like defining NDEBUG. It does not give your code permission to throw exceptions in violation of the exception specifications. The compiler still optimizes based on the specifications, so throwing an unexpected exception results in undefined behavior at run time.
Bestie, this is a "don't throw the unexpected exception" situation. Undefined behavior is not a vibe.
  • -fextern-tls-init, -fno-extern-tls-init ๐Ÿงต โ€” The C++11 and OpenMP standards let thread_local and threadprivate variables have dynamic (runtime) initialization. To support that, any use of such a variable goes through a wrapper function that does any necessary initialization. When the use and definition are in the same translation unit, this overhead can be optimized away. But when the use is in a different translation unit, there's significant overhead even if the variable doesn't actually need dynamic initialization. If the programmer can be sure that no use of the variable in a non-defining TU needs to trigger dynamic initialization (either because the variable is statically initialized, or because a use in the defining TU will run before any uses in another TU), they can avoid this overhead with -fno-extern-tls-init.

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

  • -fno-gnu-keywords ๐Ÿ”ค โ€” Stops typeof from being recognized as a keyword, so your code can use that word as an identifier. You can use the keyword __typeof__ instead. This option is implied by the strict ISO C++ dialects: -ansi, -std=c++98, -std=c++11, etc.
  • -fno-implicit-templates ๐Ÿ›‘ โ€” Never emits code for non-inline templates that are instantiated implicitly (that is, by use). Only explicit instantiations get code. If you use this option, you must be careful to structure your code so it includes all the necessary explicit instantiations, 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 that compiles with and without optimization need the same set of explicit instantiations.
  • -fno-implement-inlines ๐Ÿชถ โ€” To save space, doesn't emit out-of-line copies of inline functions controlled by #pragma implementation. This causes linker errors if these functions aren't inlined everywhere they're called.
  • -fmodules-ts, -fno-modules-ts ๐Ÿ“ฆ โ€” Enables support for C++20 modules. The -fno-modules-ts option is usually not needed, since that's the default. Even though this is a C++20 feature, selecting that standard version does not currently implicitly enable it.
  • -fmodule-header, -fmodule-header=user, -fmodule-header=system โ€” okay bestie, these take a header file and compile it into an importable header unit ๐ŸŽ€ So you can import it later and skip the whole #include circus ๐Ÿ’…
  • -fmodule-implicit-inline โ€” ngl this one is a lil tricky ๐Ÿ™ˆ Member functions defined inside their class definitions are not implicitly inline for modular code. That's different from traditional C++ behavior, and there are good reasons for it ๐Ÿงš But it can be a headache when you're porting code. This option makes those function definitions implicitly inline. Just know it creates an ABI incompatibility, so you have to use it everywhere or nowhere, no cap ๐Ÿ˜ญ (Definitions outside of a named module stay implicitly inline either way, regardless ๐Ÿ’…)
  • -fno-module-lazy โ€” Turns off lazy module importing and module mapper creation ๐Ÿฆ‹
  • -fmodule-mapper=[hostname]:port[?ident], -fmodule-mapper=|program[?ident] args..., -fmodule-mapper==socket[?ident], -fmodule-mapper=<>[inout][?ident], -fmodule-mapper=<in>out[?ident], -fmodule-mapper=file[?ident] โ€” The module mapper is an oracle ๐Ÿ”ฎ that answers "which filename goes with this module name?" ๐Ÿ“ If you don't set one, the CXX_MODULE_MAPPER environment variable gets used, and if that's unset too, you get an in-process default ๐Ÿ’œ
  • -fmodule-only โ€” Only emit the Compiled Module Interface, and skip any object file ๐ŸŒธ
  • -fms-extensions โ€” Turns off Wpedantic warnings for MFC-style stuff ๐Ÿ’… like implicit int and grabbing a pointer to a member function with non-standard syntax. It's giving "I know what I'm doing" energy ๐Ÿ‘‘
  • -fnew-inheriting-ctors โ€” Turns on the P0136 tweak to how C++11 constructor inheritance works ๐Ÿ”ฅ It's part of C++17, but it's also considered a Defect Report against C++11 and C++14 ๐Ÿค“ This flag is on by default unless you specify -fabi-version=10 or lower ๐ŸŒˆ
  • -fnew-ttp-matching โ€” Enables the P0522 resolution to Core issue 150, which covers template template parameters and default arguments โœจ It lets a template with default template arguments be an argument for a template template parameter with fewer template parameters ๐Ÿ‘‘ This is on by default for -std=c++17 ๐Ÿ’–
  • -fno-nonansi-builtins โ€” Disables built-in declarations of functions that ANSI/ISO C doesn't mandate ๐Ÿ™ˆ Think ffs, alloca, _exit, index, bzero, conjf, and other related functions.
  • -fnothrow-opt โ€” Treats a throw() exception specification as if it were noexcept ๐Ÿงš so the text size overhead drops compared to a function with no exception specification. Lowkey clever: if the function has local variables with non-trivial destructors, the spec actually makes the function smaller, because the EH cleanups for those variables can get optimized away ๐Ÿซถ Heads up: an exception thrown out of a function with this spec results in a call to terminate rather than unexpected ๐Ÿ’€
  • -fno-operator-names โ€” Don't treat the operator name keywords and, bitand, bitor, compl, not, or, and xor as synonyms for keywords ๐Ÿ™…
  • -fno-optional-diags โ€” Turns off diagnostics the standard says a compiler doesn't need to issue ๐Ÿฅบ Right now the only one G++ issues in that category is the one for a name having multiple meanings within a class.
  • -fpermissive โ€” Downgrades some diagnostics about nonconformant code from errors to warnings ๐ŸŽ€ So -fpermissive lets some nonconforming code compile. Use with a little caution, bestie ๐Ÿซถ
  • -fno-pretty-templates โ€” When an error message refers to a function template specialization, the compiler normally prints the template signature followed by the template arguments and any typedefs or typenames in the signature. So you get void f(T) [with T = int] instead of void f(int), which makes it clear which template is involved ๐Ÿ” For class template specializations, the compiler leaves out any template arguments that match the default template arguments. If either of these makes the error harder to understand instead of easier, use -fno-pretty-templates to turn them off ๐Ÿ’…
  • -fno-rtti โ€” Disables generating info about every class with virtual functions for the C++ run-time type identification features (dynamic_cast and typeid) ๐Ÿ’œ If you don't use those parts of the language, you can save some space with this flag. Exception handling uses the same information, but G++ generates it as needed. The dynamic_cast operator can still be used for casts that don't need run-time type information, i.e., casts to void * or to unambiguous base classes.
Mixing code compiled with -frtti with code compiled with -fno-rtti may not work. For example, programs may fail to link if a class compiled with -fno-rtti is used as a base for a class compiled with -frtti. ๐Ÿ˜ฌ
  • -fsized-deallocation โ€” Turns on the built-in global declarations ๐ŸŽ€
void operator delete (void *, std::size_t) noexcept;
void operator delete[] (void *, std::size_t) noexcept;

These 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 โšก 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 can be represented in the minimum number of bits needed to represent all the enumerators.)
This assumption may not be valid if the 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 in left-to-right order, and assignment in right-to-left order, 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 value is 10.
  • -ftemplate-depth=n โ€” Sets the maximum instantiation depth for template classes to n ๐ŸŒ€ The limit is needed to detect 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 value 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 the C++ ABI specifies for thread-safe initialization of local statics ๐Ÿงต You can use this to shave a little code size in code that doesn't need to be thread-safe.
  • -fuse-cxa-atexit โ€” Registers destructors for objects with static storage duration with the __cxa_atexit function instead of atexit โšก This option 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. Heads up: this makes std::uncaught_exception incorrect, but it's necessary if the runtime routine isn't available ๐Ÿ˜ญ
  • -fvisibility-inlines-hidden โ€” This switch declares that you don't try to compare pointers to inline functions or methods where the addresses of the two functions are taken in different shared objects ๐Ÿฆ‹

So GCC may effectively mark inline methods with __attribute__ ((visibility ("hidden"))), so they don't appear in the export table of a DSO and don't need PLT indirection when used within the DSO. Turning this on can have a dramatic effect on load and link times of a DSO, because it massively reduces the size of the dynamic export table when the library makes heavy use of templates ๐Ÿคฏ

This isn't quite the same as marking methods hidden directly, because it doesn't affect static variables local to the function, and it doesn't cause the compiler to deduce that the function is defined in only one shared object ๐Ÿค“

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

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

  • -fvisibility-ms-compat โ€” This flag attempts to use visibility settings to make GCC's C++ linkage model compatible with Microsoft Visual Studio's ๐ŸชŸ It makes these changes to GCC's linkage model:
    1. It sets the default visibility to hidden, like -fvisibility=hidden.
    2. Types, but not their members, are not hidden by default.
    3. The One Definition Rule is relaxed for types without explicit visibility specifications that are defined in more than one shared object: those declarations are permitted if they are permitted when this option is not used.

In new code it's better to use -fvisibility=hidden and export those classes that are intended to be externally visible. Unfortunately, it's possible for code to rely, perhaps accidentally, on the Visual Studio behavior ๐Ÿ˜ฌ

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

  • -fno-weak โ€” Doesn't use weak symbol support, even if the linker provides it. By default, G++ uses weak symbols if they're available.
This option exists only for testing, and should not be used by end-users; it results in inferior code and has no benefits. It may be removed in a future release of G++. ๐Ÿšซ
  • -fext-numeric-literals (C++ and Objective-C++ only): okay so this one lets you use imaginary, fixed-point, or machine-defined literal number suffixes as GNU extensions ๐Ÿ’… When it's 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++: bestie, this one skips the C++-specific standard directories when it's searching for headers ๐Ÿ™… but it still checks the other standard directories โœจ (It's used when building the C++ library, so it's kind of a big deal ๐Ÿ“š)
  • -flang-info-include-translate, -flang-info-include-translate-not, -flang-info-include-translate=header: this is the info-tea on include translation events ๐Ÿต The first one reports accepted include translations, and the second one reports declined ones. The header form only gives you the scoop on that one specific header. If header is "user" or "<system>", it gets resolved to a specific user or system header using the include path ๐Ÿงš
  • -flang-info-module-cmi, -flang-info-module-cmi=module: this one's all about Compiled Module Interface pathnames ๐ŸŒธ The first option notes every CMI pathname that gets read. The module form notes when a specific module's CMI is read. module can be a named module or a header-unit, and you can tell it's a header-unit when the pathname has directory separators or is 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, G++'s native C++ runtime) and libc++, which is the C++ runtime installed on some operating systems (like Darwin versions from Darwin11 onwards). This option switches G++ to the headers from whichever library you pick, and it emits -lstdc++ or -lc++ respectively when a C++ runtime is needed for linking ๐Ÿ‘‘

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

  • -Wabi-tag (C++ and Objective-C++ only): this warns when a type with an ABI tag gets used in a context that doesn't have that ABI tag ๐ŸŽ€ Check out C++ Attributes for more info about ABI tags.
  • -Wcomma-subscript (C++ and Objective-C++ only): this one warns about comma expressions used inside a subscripting expression ๐Ÿ™ˆ That usage was deprecated in C++20, but a comma expression wrapped in ( ) is not deprecated. Example:
void f(int *a, int b, int c) {
    a[b,c];     // deprecated
    a[(b,c)];   // OK
}

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

  • -Wctad-maybe-unsupported (C++ and Objective-C++ only): this warns when you do class template argument deduction (CTAD) on a type that has no explicitly written deduction guides ๐Ÿง It points out cases where CTAD only worked because the compiler synthesized the implicit deduction guides, which might not be what you meant. Some style guides only allow CTAD on types that specifically "opt-in," meaning types designed to support CTAD. You can suppress this warning with this 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): this warns when a class seems totally unusable because all of its constructors or destructors are private, and it has neither friends nor public static member functions ๐Ÿ”’ It also warns if there are no non-private methods and there's at least one private member function that isn't a constructor or destructor.
  • -Wdelete-non-virtual-dtor (C++ and Objective-C++ only): this warns when delete is used to destroy an instance of a class that has virtual functions and a non-virtual destructor ๐Ÿ’€ It's unsafe to delete a derived class instance through a base class pointer if the base class doesn't have a virtual destructor. This warning is enabled by -Wall.
  • -Wdeprecated-copy (C++ and Objective-C++ only): this warns that the implicit declaration of a copy constructor or copy assignment operator is deprecated when the class has a user-provided copy constructor or copy assignment operator, in C++11 and up ๐Ÿ“ This warning is enabled by -Wextra. With -Wdeprecated-copy-dtor, it also deprecates the implicit copy when the class has a user-provided destructor.
  • -Wno-deprecated-enum-enum-conversion (C++ and Objective-C++ only): this turns off the warning for when the usual arithmetic conversions get applied to operands where one is an enumeration type and the other is a different enumeration type ๐Ÿ™… This conversion was deprecated in C++20. For example:
enum E1 { e };
enum E2 { f };
int k = f - e;

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

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

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

  • -Wno-init-list-lifetime (C++ and Objective-C++ only): this stops the warning about uses of std::initializer_list that are likely to end up with dangling pointers ๐Ÿ˜ญ The underlying array for an initializer_list is handled like a normal C++ temporary object, so it's super easy to accidentally keep a pointer to the array after its lifetime has ended. Some examples:
    • If a function returns a temporary initializer_list, or a local initializer_list variable, the array's lifetime ends at the end of the return statement, so the returned value has a dangling pointer.
    • If a new-expression creates an initializer_list, the array only lives until the end of the enclosing full-expression, so the initializer_list on the heap has a dangling pointer.
    • When an initializer_list variable is assigned from a brace-enclosed initializer list, the temporary array created for the right side of the assignment only lives until the end of the full-expression. So at the next statement, the initializer_list variable has a dangling pointer.
    • When a list constructor stores the begin pointer from the initializer_list argument, this doesn't extend the lifetime of the array. So if a class variable is constructed from a temporary initializer_list, the pointer is left dangling by the end of the variable declaration statement.
// 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
  • -Winvalid-imported-macros: this verifies that all imported macro definitions are valid at the end of compilation ๐Ÿงฉ It's not enabled by default, since it needs some extra processing to figure out. It can be super useful when you're preparing sets of header-units and want consistent macros ๐Ÿ’–
  • -Wno-literal-suffix (C++ and Objective-C++ only): this stops the warning when a string or character literal is followed by a ud-suffix that doesn't begin with an underscore ๐ŸŽ€ As a conforming extension, GCC treats those suffixes as separate preprocessing tokens so that older code using formatting macros from <inttypes.h> keeps working. For example:
#define __STDC_FORMAT_MACROS
#include <inttypes.h>
#include <stdio.h>

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

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

This option also controls warnings when a user-defined literal operator is declared with a literal suffix identifier that doesn't begin with an underscore. Literal suffix identifiers that don't begin with an underscore are reserved for future standardization โš ๏ธ These warnings are enabled by default.

  • -Wno-narrowing (C++ and Objective-C++ only): for C++11 and later standards, narrowing conversions get diagnosed by default, because the standard requires it ๐Ÿšซ A narrowing conversion from a constant produces an error, and a narrowing conversion from a non-constant produces a warning, but -Wno-narrowing suppresses the diagnostic. This doesn't change the meaning of well-formed code, since narrowing conversions are still ill-formed in SFINAE contexts. With -Wnarrowing in C++98, you get a warning when a narrowing conversion prohibited by C++11 happens within { }, for example:
int i = { 2.2 }; // error: narrowing from double to int

This flag is included in -Wall and -Wc++11-compat.

  • -Wnoexcept (C++ and Objective-C++ only): this warns when a noexcept-expression evaluates to false because of a call to a function that doesn't have a non-throwing exception specification (that is, throw() or noexcept), but that the compiler knows will never throw an exception ๐Ÿฆ‹
  • -Wnoexcept-type (C++ and Objective-C++ only): this warns if the C++17 feature that makes noexcept part of a function type changes the mangled name of a symbol compared to C++14 โœจ It's enabled by -Wabi and -Wc++17-compat. As an example:
template <class T> void f(T t) { t(); };
void g() noexcept;
void h() { f(g); }

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

  • -Wclass-memaccess (C++ and Objective-C++ only) โ€” okay so this one yells when you hand a raw memory function like memset or memcpy a destination that's an object of class type ๐Ÿ˜ญ. The danger is that writing into it can skip a non-trivial or deleted constructor or copy assignment, break const-correctness or encapsulation, or corrupt virtual table pointers. Messing with the guts of these objects can violate invariants the class's member functions depend on ๐Ÿ’…. Like, the memset call below is undefined because it modifies a non-trivial class object, so it gets flagged ๐Ÿ™ˆ. The safe way to initialize or clear storage for these types is to use the appropriate constructor or assignment operator, if one exists โœจ. -Wclass-memaccess is enabled by -Wall. Casting the pointer to the class object to void *, or to a type the raw memory function can safely access, suppresses the warning ๐Ÿซถ.
std::string str = "abc";
memset (&str, 0, sizeof str);
  • -Wnon-virtual-dtor (C++ and Objective-C++ only) โ€” this one catches a class that has virtual functions but an accessible non-virtual destructor, either on itself or in an accessible polymorphic base class ๐Ÿ‘€. That combo means deleting a derived instance through a pointer to the class or base class is possible but unsafe ๐Ÿ’€. It turns on automatically if -Weffc++ is specified ๐ŸŒธ.
  • -Wregister (C++ and Objective-C++ only) โ€” warns on uses of the register storage class specifier, unless it's part of the GNU Explicit Register Variables extension ๐Ÿฆ‹. Fun fact, the register keyword got deprecated in C++11 and fully removed in C++17 ๐Ÿฅ€. It's enabled by default with -std=c++17 ๐Ÿ’œ.
  • -Wreorder (C++ and Objective-C++ only) โ€” warns when the order of your member initializers doesn't match the order they actually have to run in ๐Ÿงš. For instance:
struct A {
  int i;
  int j;
  A(): j (0), i (1) { }
};

The compiler quietly rearranges the member initializers for i and j to match the declaration order of the members, and it emits a warning about it โš ๏ธ. This warning is enabled by -Wall.

  • -Wno-pessimizing-move (C++ and Objective-C++ only) โ€” this warning pops up when a call to std::move blocks copy elision ๐Ÿ™…โ€โ™€๏ธ. A typical copy elision situation is returning from a function with a class return type, where the returned expression is the name of a non-volatile automatic object (not a function parameter) with the same type as the return type ๐Ÿ‘‘. But in this example, the std::move call prevents copy elision:
struct T {
...
};
T fn()
{
  T t;
  ...
  return std::move (t);
}

This warning is enabled by -Wall.

  • -Wno-redundant-move (C++ and Objective-C++ only) โ€” this one warns about redundant calls to std::move, aka the times a move would've happened even without the std::move call ๐Ÿ”. It happens because the compiler gets forced to treat the object as an rvalue in certain spots, like returning a local variable where copy elision doesn't apply ๐ŸŽ€. Consider:
struct T {
...
};
T fn(T t)
{
  ...
  return std::move (t);
}

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

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

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

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

It does not warn when the type being copied is trivially-copyable and smaller than 64 bytes ๐Ÿ“.

It also warns when a loop variable in a range-based for-loop gets 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 creates and destroys a temporary value of type double, which the reference const double & is bound to ๐Ÿ”ฅ. This warning is enabled by -Wall.

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

On the other hand, this example gets no warning:

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 differs in each translation unit ๐Ÿ˜ฌ. If A only shows up in a single translation unit, the best way to silence the warning is to give it internal linkage by putting it in an anonymous namespace too ๐Ÿซถ. The compiler doesn't warn for types defined in the main .C file, since those are unlikely to have multiple definitions ๐Ÿ’…. -Wsubobject-linkage is enabled by default.
  • -Weffc++ (C++ and Objective-C++ only) โ€” this one warns about violations of the style guidelines from Scott Meyers' Effective C++ series of books ๐Ÿ“š. The guidelines it checks are:
    • Define a copy constructor and an assignment operator for classes with dynamically-allocated memory.
    • Prefer initialization to assignment in constructors.
    • Have operator= return a reference to *this.
    • Don't try to return a reference when you must return an object.
    • Distinguish between prefix and postfix forms of increment and decrement operators.
    • Never overload &&, ||, or ,.

This option also turns on -Wnon-virtual-dtor, which is one of the Effective C++ recommendations too ๐ŸŒธ. The check is extended, though, to warn about a missing virtual destructor in accessible non-polymorphic base classes as well ๐Ÿงš.

Heads up, bestie: the standard library headers don't obey all of these guidelines ๐Ÿ˜ญ. When you select this option, use grep -v to filter out those warnings.
  • -Wno-exceptions (C++ and Objective-C++ only) โ€” disables the warning for when an exception handler is shadowed by another handler, which can point out a wrong ordering of exception handlers ๐Ÿ™ˆ.
  • -Wstrict-null-sentinel (C++ and Objective-C++ only) โ€” warns about using an uncasted NULL as a sentinel ๐Ÿง. When compiling only with GCC, this is a valid sentinel, 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 ๐Ÿ’€.
  • -Wno-non-template-friend (C++ and Objective-C++ only) โ€” disables warnings when non-template friend functions are declared within a template ๐Ÿฆ‹. Very old versions of GCC, from before the ISO standard was implemented, could interpret declarations like friend int foo(int) (where the friend's name is an unqualified-id) as a particular specialization of a template function. The warning exists to diagnose those compatibility problems, and it's enabled by default ๐Ÿ•ฐ๏ธ.
  • -Wold-style-cast (C++ and Objective-C++ only) โ€” warns if an old-style (C-style) cast to a non-void type is used in a C++ program ๐Ÿ™…โ€โ™€๏ธ. The new-style casts (dynamic_cast, static_cast, reinterpret_cast, and const_cast) are less vulnerable to unintended effects and way easier to search for ๐Ÿ”.
  • -Woverloaded-virtual (C++ and Objective-C++ only) โ€” warns when a function declaration hides virtual functions from a base class ๐Ÿซฃ. For example:
struct A {
  virtual void f();
};

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

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

B* b;
b->f();

fails to compile ๐Ÿ’”.

  • -Wno-pmf-conversions (C++ and Objective-C++ only) โ€” disables the diagnostic for converting a bound pointer to member function 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 ๐Ÿ“œ.
  • -Wtemplates (C++ and Objective-C++ only) โ€” warns when a primary template declaration is encountered ๐Ÿงฉ. Some coding rules disallow templates, and this can be used to enforce that rule ๐Ÿ“. The warning is inactive inside a system header file, such as the STL, so you can still use the STL ๐Ÿ’–. You're also still allowed to instantiate or specialize templates โœจ.
  • -Wno-mismatched-new-delete (C++ and Objective-C++ only) โ€” okay bestie, this one is all about catching mismatched new and delete calls ๐Ÿ”ฅ It warns when operator new or operator delete gets paired with the wrong corresponding allocation or deallocation call ๐Ÿ’… That includes C++ operator delete being used on pointers from mismatched forms of operator new, or from other functions that allocate objects where operator delete isn't a suitable deallocator ๐Ÿ˜ญ It also covers other deallocation functions being called on pointers returned from operator new when that deallocation function isn't suitable.

Check out this example ๐Ÿ‘€ The delete expression in the function below gets flagged because it doesn't match the array form of the new expression its pointer came from. The free call gets flagged too:

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

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

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

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

  • -Wmismatched-tags (C++ and Objective-C++ only) โ€” this one yells at you if you declare a struct, class, or class template (or one of its specializations) using a class-key that doesn't match the definition, or the first declaration when no definition exists ๐Ÿง

For example, the declaration of struct Object in the argument list of draw sets it off. To make it stop, either drop the extra class-key struct or swap it for class so it matches the definition ๐Ÿ’–

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

Using struct to declare a class is totally not wrong, as the example shows ๐Ÿฆ‹ -Wmismatched-tags is really about keeping your class declarations looking consistent. If you're writing code meant to be portable to Windows-based compilers, this warning helps you avoid unresolved references caused by different class-keys mangling symbols differently ๐Ÿซถ You can use the option on its own or alongside -Wredundant-tags.

  • -Wmultiple-inheritance (C++ and Objective-C++ only) โ€” warns when a class is defined with multiple direct base classes ๐ŸŽ€ Some coding rules ban multiple inheritance, and this can enforce that rule. The warning goes quiet inside system header files like the STL, so you can still use the STL ๐Ÿ’œ You can also define classes that use multiple inheritance indirectly.
  • -Wvirtual-inheritance โ€” warns when a class is defined with a virtual direct base class ๐ŸŒˆ Some coding rules ban multiple inheritance, and this can enforce that rule. It's also inactive inside system header files like the STL, so the STL is still fair game ๐Ÿงš You can still define classes that use virtual inheritance indirectly.
  • -Wno-virtual-move-assign โ€” suppresses warnings about inheriting from a virtual base with a non-trivial C++11 move assignment operator ๐Ÿ’…
โš ๏ธ This is dangerous, bestie! If the virtual base is reachable along more than one path, it gets moved multiple times, which can leave both objects in the moved-from state. If your move assignment operator is written so it avoids moving from a moved-from object, you can safely disable this warning.
  • -Wnamespaces โ€” warns when a namespace definition is opened โญ Some coding rules ban namespaces, and this can enforce that rule. The warning is inactive inside system header files like the STL, so the STL still works ๐Ÿซถ You can also use using directives and qualified names.
  • -Wno-terminate (C++ and Objective-C++ only) โ€” turns off the warning about a throw-expression that will immediately lead to 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++ says it has to be read as a function declaration. For instance:
void f(double a) {
  int i();        // extern int i (void);
  int n(int(a));  // extern int n (int);
}

Another example:

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

The warning will suggest ways to deal with the ambiguity, like removing the parentheses or using braces instead ๐ŸŒธ

This warning is enabled by default ๐Ÿ’œ

  • -Wno-class-conversion (C++ and Objective-C++ only) โ€” don't warn when a conversion function converts an object to the same type, to a base class of that type, or to void ๐Ÿฆ‹ Such a conversion function will never be called anyway.
  • -Wvolatile (C++ and Objective-C++ only) โ€” warns about deprecated uses of the volatile qualifier ๐Ÿฅ€ This covers postfix and prefix ++ and -- expressions on volatile-qualified types, simple assignments where the left operand is a volatile-qualified non-class type (for their value), compound assignments where the left operand is a volatile-qualified non-class type, a volatile-qualified function return type, a volatile-qualified parameter type, and structured bindings of a volatile-qualified type. This usage was deprecated in C++20 ๐Ÿ“‰

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

  • -Wzero-as-null-pointer-constant (C++ and Objective-C++ only) โ€” warns when a literal 0 is used as a null pointer constant ๐Ÿ“ This can be handy for moving over to nullptr in C++11.
  • -Waligned-new โ€” warns about a new-expression of a type that needs greater alignment than alignof(std::max_align_t) but uses an allocation function without an explicit alignment parameter ๐ŸŒˆ This option is enabled by -Wall.

Normally this only warns about global allocation functions, but -Waligned-new=all also warns about class member allocation functions โœจ

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

This warning is enabled by default ๐Ÿ’…

-Wplacement-new=1

This is the default warning level for -Wplacement-new ๐Ÿงš At this level, the warning isn't issued for some strictly undefined constructs that GCC allows as extensions for compatibility with legacy code. For example, the 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]();

-Wplacement-new=2

At this level you get all the same diagnostics as level 1, plus a diagnostic for placement new expressions that construct an object in the last member of a structure, where that member is an array of a single element and the size is less than the size of the object being constructed ๐Ÿ”ฅ The previous example would be diagnosed here, but the following construct uses the flexible member array extension to avoid the warning at level 2:

struct S { int n, a[]; };
S *s = (S *)malloc (sizeof *s + 32 * sizeof s->a[0]);
new (s->a)int [32]();
  • -Wcatch-value, -Wcatch-value=n (C++ and Objective-C++ only) โ€” warns about catch handlers that don't catch via reference ๐Ÿ‘€ With -Wcatch-value=1 (or -Wcatch-value for short), you get warnings about polymorphic class types caught by value. With -Wcatch-value=2, you get warnings about all class types caught by value. With -Wcatch-value=3, you get warnings about all types that aren't caught by reference. -Wcatch-value is enabled by -Wall ๐ŸŽ€
  • -Wconditionally-supported (C++ and Objective-C++ only) โ€” warns for conditionally-supported (C++11 [intro.defs]) constructs ๐Ÿฆ‹
  • -Wno-delete-incomplete (C++ and Objective-C++ only) โ€” don't warn when deleting a pointer to an incomplete type, which may cause undefined behavior at runtime ๐Ÿ™ˆ This warning is enabled by default.
  • -Wextra-semi (C++, Objective-C++ only) โ€” warns about redundant semicolons after in-class function definitions ๐Ÿซถ
  • -Wno-inaccessible-base (C++, Objective-C++ only) โ€” controls warnings when a base class is inaccessible in a derived class because of ambiguity ๐Ÿง The warning is enabled by default. Note that the warning for ambiguous virtual bases is enabled by the -Wextra option. Here's the example:
struct A { int a; };

struct B : A { };

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

The restrictions on offsetof may be relaxed in a future version of the C++ standard โœจ

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

Okay so this one's about mismatched deallocators ๐Ÿ™ˆ GCC gets suspicious when you write one of these unsized operator delete versions and skip the sized bestie that goes with it:

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

...without a matching sized deallocation function defined right next to it. โœจ The sized ones look like this:

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

Or it's the other way around, so you've got the sized one and no unsized one. Either way GCC's gonna flag it ๐Ÿ’… Enabled by -Wextra along with -fsized-deallocation. ๐ŸŽ€

  • -Wsuggest-final-types โ€” Okay this one is giving "glow up your class hierarchy" ๐Ÿฆ‹ It warns about types with virtual methods that would be cleaner if they were declared with the C++11 "final" specifier, or, if it's possible, put inside an anonymous namespace. Doing that lets GCC devirtualize the polymorphic calls more aggressively, which is so iconic ๐Ÿ‘‘ This warning hits harder with link-time optimization, because that's when GCC has the full class hierarchy graph and knows way more about what's going on.
  • -Wsuggest-final-methods โ€” Same energy, but at the method level ๐Ÿ’œ It warns about virtual methods that would be better off declared with the C++11 "final" specifier. If it's possible, the method's type could go into an anonymous namespace or get the "final" specifier instead. Like the previous one, this is more effective with link-time optimization, since the class hierarchy graph is more complete then. Bestie tip from the original: consider the -Wsuggest-final-types suggestions first, then rebuild with the new annotations ๐ŸŒธ
  • -Wsuggest-override โ€” GCC will side-eye any virtual function you override without marking it with the "override" keyword ๐Ÿ‘€ Add that keyword, it's literally free slay โœจ
  • -Wuseless-cast (C++ and Objective-C++ only) โ€” Warns when an expression gets cast to its own type. Like, why are we even doing that ๐Ÿ’€
  • -Wno-conversion-null (C++ and Objective-C++ only) โ€” Turns off warnings for conversions between NULL and non-pointer types. Heads up though, -Wconversion-null is already on by default, so this is you saying "chill, I got this" ๐Ÿซถ

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

NOTE: This manual does not describe the Objective-C and Objective-C++ languages themselves. ๐Ÿ™ˆ

This section is all about the command-line options that only matter for Objective-C and Objective-C++ programs ๐ŸŒˆ You can also use most of the language-independent GNU compiler options too. For example, you could compile a file called some_class.m like this:

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

In this example, -fgnu-runtime is an Objective-C-only option ๐Ÿ’– You can use the other options with any language GCC supports.

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

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

  • -fconstant-string-class=class-name โ€” This picks the class that gets instantiated for each literal string written with the @"..." syntax. The default is NXConstantString when the GNU runtime is in use, and NSConstantString when the NeXT runtime is in use (more on that below) ๐Ÿ’… On Darwin (macOS, MacOS X) platforms, if -fconstant-cfstrings is also present, it overrides -fconstant-string-class and makes @"..." literals get laid out as constant CoreFoundation strings. Also, -fconstant-cfstrings is an alias for the target-specific -mconstant-cfstrings equivalent.
  • -fgnu-runtime โ€” Generates object code that's compatible with the standard GNU Objective-C runtime. This is the default for most systems ๐Ÿ“
  • -fnext-runtime โ€” Generates output compatible with the NeXT runtime. This is the default for NeXT-based systems, including Darwin and Mac OS X. The macro __NEXT_RUNTIME__ is predefined if, and only if, this option is used ๐Ÿฆ‹
  • -fno-nil-receivers โ€” Tells the compiler to assume every Objective-C message dispatch ([receiver message:arg]) in this translation unit makes sure the receiver is not nil. That lets the runtime use more efficient entry points โšก This option is only available together with the NeXT runtime and ABI version 0 or 1.
  • -fobjc-abi-version=n โ€” Uses version n of the Objective-C ABI for the selected runtime. Right now this is only supported for the NeXT runtime ๐ŸŒธ In that case, Version 0 is the traditional (32-bit) ABI without support for properties and other Objective-C 2.0 additions. Version 1 is the traditional (32-bit) ABI with support for properties and other Objective-C 2.0 additions. Version 2 is the modern (64-bit) ABI. If you don't specify anything, the default is Version 0 on 32-bit target machines, and Version 2 on 64-bit target machines.
  • -fobjc-call-cxx-cdtors โ€” For each Objective-C class, GCC checks whether any of its instance variables is a C++ object with a non-trivial default constructor. If so, it synthesizes a special - (id) .cxx_construct instance method that runs those non-trivial default constructors on the instance variables, in order, and then returns self. It also checks whether any instance variable is a C++ object with a non-trivial destructor, and if so, synthesizes a special - (void) .cxx_destruct method that runs all those default destructors in reverse order ๐ŸŽ€

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

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

  • -fobjc-direct-dispatch โ€” 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++ has ๐Ÿซถ You need this option to use the Objective-C keywords @try, @throw, @catch, @finally and @synchronized. It works with both the GNU runtime and the NeXT runtime, but it's not available with the NeXT runtime on Mac OS X 10.2 and earlier.
  • -fobjc-gc โ€” Enables garbage collection (GC) in Objective-C and Objective-C++ programs. This is only available with the NeXT runtime. The GNU runtime has its own, different garbage collection implementation that doesn't need any special compiler flags ๐Ÿงน
  • -fobjc-nilcheck โ€” For the NeXT runtime with version 2 of the ABI, GCC checks for a nil receiver in method invocations before doing the actual method call. This is the default, and you can turn it off with -fno-objc-nilcheck. Class methods and super calls are never checked for nil this way, no matter what this flag is set to. Right now this flag does nothing when the GNU runtime, or an older version of the NeXT runtime ABI, is used ๐Ÿ™ˆ
  • -fobjc-std=objc1 โ€” Conforms to the language syntax of Objective-C 1.0, the language GCC 4.0 recognized. This only affects the Objective-C additions to the C/C++ language. It doesn't change conformance to C/C++ standards, which is controlled by the separate C/C++ dialect option flags. When you use this with the Objective-C or Objective-C++ compiler, any Objective-C syntax that GCC 4.0 didn't recognize gets rejected. This is handy if you need to make sure your Objective-C code can compile with older versions of GCC ๐Ÿ•ฐ๏ธ
  • -freplace-objc-classes โ€” Emits a special marker that tells ld(1) not to statically link the resulting object file, and lets dyld(1) load it at run time instead. This is used with the Fix-and-Continue debugging mode, where the object file might get recompiled and dynamically reloaded while the program is running, no restart needed ๐Ÿ”ฅ For now, Fix-and-Continue only works with the NeXT runtime on Mac OS X 10.3 and later.
  • -fzero-link โ€” When compiling for the NeXT runtime, the compiler normally swaps calls to objc_getClass("...") (when the class name is known at compile time) for static class references that get initialized at load time, which makes run-time performance better ๐Ÿš€ This flag stops that and keeps the objc_getClass("...") calls. It's useful in Zero-Link debugging mode, since you can modify individual class implementations while the program runs. The GNU runtime always keeps calls to objc_get_class("...") no matter what command-line options you pass.
  • -fno-local-ivars โ€” By default, instance variables in Objective-C can be accessed as if they were local variables inside the methods of the class they're declared in. That can cause shadowing between instance variables and other variables declared locally inside a class method, or globally, with the same name. Passing -fno-local-ivars turns this off and avoids those shadowing issues ๐Ÿ’…
  • -fivar-visibility=[public|protected|private|package] โ€” Sets the default instance variable visibility to the option you pick, so instance variables declared outside the scope of any access modifier directives default to that visibility ๐Ÿ‘‘
  • -gen-decls โ€” Dumps interface declarations for all classes seen in the source file to 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) โ€” Doesn't warn if a property for an Objective-C object has no assign semantics specified. It's giving "I trust you" energy ๐Ÿซถ
  • -Wno-protocol (Objective-C and Objective-C++ only) โ€” okay so if a class says it implements a protocol, GCC warns about every protocol method the class doesn't implement ๐Ÿ™…โ€โ™€๏ธ. The default is even stricter: it warns about every method not explicitly implemented in the class, even when the superclass already has it ๐Ÿ’€. With -Wno-protocol, inherited methods count as implemented, so no warning for them โœจ.
  • -Wobjc-root-class (Objective-C and Objective-C++ only) โ€” warns if a class interface has no superclass ๐Ÿ‘€. Most classes inherit from "NSObject" (or "Object"), so this is for the rare case. If you're intentionally making a root class, mark its interface with __attribute__((objc_root_class)) and the warning gets suppressed ๐Ÿซถ.
  • -Wselector (Objective-C and Objective-C++ only) โ€” warns if multiple methods with different types share the same selector during compilation ๐Ÿ”. This check runs on the method list at the very end of compilation. It also checks each selector used in a @selector(...) expression, if a matching method was found during compilation. Since these checks only happen at the end, the warnings won't show up if the final stage never runs, like when an error stops compilation early or when -fsyntax-only is being used ๐Ÿฅฒ.
  • -Wstrict-selector-match (Objective-C and Objective-C++ only) โ€” warns if a selector has several methods with different argument and/or return types, when you send a message with that selector to a receiver of type id or Class ๐Ÿง. This flag is off by default. When it's off, the compiler skips these warnings if the only differences are between types that share the same size and alignment ๐Ÿ˜Œ.
  • -Wundeclared-selector (Objective-C and Objective-C++ only) โ€” warns if you use a @selector(...) expression for a selector that was never declared ๐Ÿ“ฃ. A selector counts as undeclared if no method with that name was declared before the @selector(...) expression, either explicitly in an @interface or @protocol declaration, or implicitly in an @implementation section. This option checks right away when it hits a @selector(...) expression, while -Wselector waits until the final stage of compilation. It also enforces the vibe that methods and selectors must be declared before they're used ๐Ÿ’….
  • -print-objc-runtime-info โ€” generates a C header describing the largest structure that gets passed by value, if there is one ๐Ÿงพ.

๐ŸŽ€ Options to Control Diagnostic Messages Formatting ๐ŸŽ€

Traditionally, diagnostic messages were formatted without caring what the output device looked like (its width and stuff) ๐Ÿ“บ. These options let you control the formatting, like how many characters fit on a line and how often the source location gets reported ๐ŸŒธ. Heads up that some language front ends might not respect these options ๐Ÿ™ˆ.

  • -fmessage-length=n โ€” tries to format error messages so they fit on lines about n characters long โœ‚๏ธ. If n is zero, no line-wrapping happens and each error message sits on a single line. This is the default for all front ends ๐Ÿ’–.

Note: this option also affects the display of the #error and #warning preprocessor directives, and the deprecated function/type/variable attribute ๐Ÿ“. It does not affect pragma GCC warning and pragma GCC error ๐Ÿ™…โ€โ™€๏ธ.

  • -fdiagnostics-plain-output โ€” makes diagnostic output look as plain as possible ๐Ÿค. This is handy when you're running dejagnu or other tools that parse the diagnostics and need them to stay stable over time ๐Ÿ”ง. Right now, -fdiagnostics-plain-output is the same as all of these together: -fno-diagnostics-show-caret -fno-diagnostics-show-line-numbers -fdiagnostics-color=never -fdiagnostics-urls=never -fdiagnostics-path-format=separate-events. If GCC ever changes the default look of its diagnostics, the matching option to turn off that new behavior will get added to this list ๐Ÿ”ฎ.
  • -fdiagnostics-show-location=once โ€” only matters in line-wrapping mode ๐ŸŒ€. It tells the reporter to show source location information just once. So if a message is too long and gets wrapped, the location doesn't get repeated as a prefix on every continuation line ๐Ÿ™Œ. This is the default behavior โœ….
  • -fdiagnostics-show-location=every-line โ€” also only matters in line-wrapping mode ๐ŸŒŠ. It tells the reporter to put the same source location prefix on every physical line that comes from breaking up a message that's too long ๐Ÿ“.
  • -fdiagnostics-color[=WHEN], -fno-diagnostics-color โ€” turns color on in diagnostics ๐ŸŒˆ. WHEN can be never, always, or auto ๐ŸŽจ. The default depends on how the compiler was configured. It can be any of those WHEN options, or never if the GCC_COLORS environment variable isn't in the environment, and auto otherwise ๐Ÿง . auto only uses color when standard error is a terminal, and when you're not running in an emacs shell ๐Ÿ–ฅ๏ธ. -fdiagnostics-color and -fno-diagnostics-color are just aliases for -fdiagnostics-color=always and -fdiagnostics-color=never, respectively ๐Ÿ’œ.

The colors come from the environment variable GCC_COLORS ๐ŸŽจ. Its value is a colon-separated list of capabilities and Select Graphic Rendition (SGR) substrings ๐Ÿช„. SGR commands get interpreted by your terminal or terminal emulator. (Check the section in your text terminal's documentation for the permitted values and what they mean as character attributes ๐Ÿ“š.) These substring values are decimal integers, and you can join them with semicolons ๐Ÿ”ข. Common values people combine include 1 for bold, 4 for underline, 5 for blink, 7 for inverse, 39 for default foreground color, 30 to 37 for foreground colors, 90 to 97 for 16-color mode foreground colors, 38;5;0 to 38;5;255 for 88-color and 256-color mode foreground colors, 49 for default background color, 40 to 47 for background colors, 100 to 107 for 16-color mode background colors, and 48;5;0 to 48;5;255 for 88-color and 256-color mode background colors ๐ŸŒท.

The default GCC_COLORS is:

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

Here, 01;31 is bold red, 01;35 is bold magenta, 01;36 is bold cyan, 32 is green, 34 is blue, 01 is bold, and 31 is red ๐Ÿ“. Setting GCC_COLORS to the empty string turns colors off ๐Ÿšซ. These are the capabilities you can set ๐Ÿ‘‡:

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

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

The default depends on how the compiler was configured, and it can be any of the WHEN options above ๐Ÿ› ๏ธ. GCC can also be configured with the --with-diagnostics-urls=auto-if-env configure-time option, so the default depends on environment variables ๐ŸŒ. In that setup, GCC defaults to auto if either the GCC_URLS or TERM_URLS environment variables are present and non-empty in the compiler's environment, and never if neither is ๐Ÿงš.

Even with -fdiagnostics-urls=always, the behavior still depends on those environment variables ๐Ÿคฏ. If GCC_URLS is set to empty or no, URLs don't get embedded in diagnostics. If it's set to st, URLs use ST escape sequences. If it's set to bel, which is the default, URLs use BEL escape sequences. Any other non-empty value turns the feature on ๐Ÿ’œ. If GCC_URLS isn't set, GCC falls back to TERM_URLS ๐Ÿ”.

Quick glossary, bestie ๐Ÿ“š: ST is an ANSI escape sequence whose string terminator is ESC \. BEL is an ASCII character, CTRL-G, which usually makes a beep ๐Ÿ””.

So GCC also tries to sniff out a few terminals that don't play nice with URL escapes ๐Ÿ™ˆ. These are terminals that don't implement the URL feature, or that have bugs (or had bugs in versions people still use) where the escapes misbehave and print garbage all over your screen ๐Ÿ’€. Right now that list is xfce4-terminal, certain known-buggy gnome-terminal versions, the linux console, and mingw. If you're sure your terminal is fine, you can skip this check with -fdiagnostics-urls=always. ๐Ÿฆ‹

๐Ÿ’… -fno-diagnostics-show-option

By default, every diagnostic includes a little note naming the command-line option that directly controls it, as long as the diagnostic machinery knows which option that is ๐ŸŽ€. Add -fno-diagnostics-show-option and that note gets suppressed โœจ.

๐ŸŽฏ -fno-diagnostics-show-caret

By default, each diagnostic comes with the original source line and a caret ^ pointing at the column ๐Ÿ“. This option suppresses all of that. If you also pass -fmessage-length=n, the source line gets truncated to n characters. When the output goes to the terminal, the width is limited by the COLUMNS environment variable or, if that isn't set, the actual terminal width ๐Ÿ“.

๐Ÿท๏ธ -fno-diagnostics-show-labels

By default, when GCC prints source code (via -fdiagnostics-show-caret), diagnostics can label ranges of code with pertinent info, like the types of expressions ๐Ÿ’–:

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

This option suppresses the labels ๐Ÿ™…โ€โ™€๏ธ, so the vertical bars and the "char *" and "long int" text in the example above disappear.

๐Ÿ”— -fno-diagnostics-show-cwe

Diagnostics can optionally have an associated CWE identifier, which links to https://cwe.mitre.org/index.html ๐Ÿงฉ. GCC itself only provides this metadata for some of the -fanalyzer diagnostics, and GCC plugins may also provide diagnostics with it. By default, if this info is present, it gets printed with the diagnostic. This option suppresses that metadata ๐Ÿค.

๐Ÿ”ข -fno-diagnostics-show-line-numbers

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

๐Ÿ“ -fdiagnostics-minimum-margin-width=width

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

๐Ÿค– -fdiagnostics-parseable-fixits

This emits fix-it hints in a machine-parseable format, so IDEs can gobble them right up ๐Ÿซถ. 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 things like this ๐Ÿงผ: backslash becomes "\\", tab becomes "\t", newline becomes "\n", double quotes become "\"", and non-printable characters come out as octal, so a vertical tab shows up as "\013".

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

๐Ÿ“œ -fdiagnostics-generate-patch

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

In the C++ frontend, when diagnostics show mismatching template types, like this ๐Ÿ‘€:

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

the -fdiagnostics-show-template-tree flag turns on a tree-like structure showing the common and differing parts of the types, like so ๐ŸŒฒ:

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

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

๐Ÿงน -fno-elide-type

By default, when the C++ frontend prints diagnostics showing mismatching template types, the common parts get printed as "[...]" to keep the error message simple ๐Ÿงน. For example:

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

Specifying -fno-elide-type suppresses that behavior ๐Ÿ™…. This flag also affects the output of -fdiagnostics-show-template-tree.

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

This specifies how to print paths of control-flow events for diagnostics that have one associated with them โœจ.

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

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

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

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

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

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

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

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

๐Ÿง  -fdiagnostics-show-path-depths

This option adds extra info when printing control-flow paths associated with a diagnostic ๐Ÿ”. If it's provided, the stack depth gets printed for each run of events within -fdiagnostics-path-format=separate-events. It's intended for GCC developers and plugin developers debugging diagnostics that report interprocedural control flow ๐Ÿง‘โ€๐Ÿ’ป.

๐Ÿ™ˆ -fno-show-column

This stops column numbers from being printed in diagnostics ๐Ÿ™ˆ. It may be necessary if diagnostics are being scanned by a program that doesn't understand column numbers, such as dejagnu ๐Ÿค–.

๐Ÿ“ -fdiagnostics-column-unit=UNIT

This selects the units for the column number ๐Ÿ“. It affects traditional diagnostics (in the absence of -fno-show-column), as well as JSON format diagnostics if requested ๐Ÿงพ.

โœจ OPTIONS โœจ

Okay so the default UNIT is display ๐Ÿ’–, which counts the number of display columns each character actually takes up on screen. That can be bigger than the bytes needed to encode it (hello, tab characters ๐Ÿ“) or smaller (hello, multibyte characters ๐Ÿฆ‹). For example, "GREEK SMALL LETTER PI (U+03C0)" takes up one display column but needs two bytes in UTF-8 ๐Ÿ’…. Meanwhile "SLIGHTLY SMILING FACE (U+1F642)" takes up two display columns and needs four bytes in UTF-8 ๐Ÿ™ˆ.

Setting UNIT to byte ๐Ÿงš switches the column number to the raw byte count in every case. That's how GCC used to output it before version 11.1.0, so if you're nostalgic, this is your move โœจ.

  • -fdiagnostics-column-origin=ORIGIN โ€” Picks where column numbering starts, aka the number given to the very first column ๐ŸŽ€. The default of 1 is the classic GCC behavior and matches the GNU style guide, so it's the iconic choice. Some utilities may vibe better with an origin of 0, and honestly any non-negative value works ๐ŸŒˆ.
  • -fdiagnostics-format=FORMAT โ€” Lets you switch up how diagnostics get printed ๐Ÿ’œ. FORMAT is either text or json, and the default is text, no cap ๐Ÿ’….

When you go with json, you get a top-level JSON array full of JSON objects, one for each diagnostic ๐Ÿซถ. It's emitted all on one line with zero formatting, so it looks kinda messy, but the examples below have been prettified so you can actually read them ๐Ÿ˜ญ.

Diagnostics can also have child diagnostics ๐Ÿ‘‘. Check out this error and its 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;
      |     ^

In JSON form (after formatting, obviously) it might look like this ๐Ÿฆ‹:

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

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 telling you which command-line option is controlling the warning ๐Ÿ”ฅ.

A diagnostic can hold zero or more locations ๐ŸŒธ. Each location can have an optional "label" string and up to three positions: a "caret" position plus optional "start" and "finish" positions. Every position is described by a "file" name, a "line" number, and three numbers for the column position ๐Ÿ’…:

  • "display-column" counts display columns, accounting for tabs and multibyte characters ๐Ÿ“.
  • "byte-column" counts raw bytes ๐Ÿงš.
  • "column" is equal to one of the previous two, depending on what the -fdiagnostics-column-unit option says ๐Ÿ’œ.

All three columns are relative to the origin set by -fdiagnostics-column-origin, which is usually 1 but could be set to 0 for compatibility with utilities that count columns from zero ๐ŸŒˆ. The origin gets recorded in the JSON output under the "column-origin" tag โญ. In the rest of the examples, the extra column outputs got left out to keep things short ๐Ÿซถ.

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 ๐Ÿ˜ญ. The primary one is at the + token, column 23 ๐Ÿ‘‘. It also has two secondary locations, one for the left-hand side and one for the right-hand side of the expression, and both of those come with labels ๐ŸŽ€. It might be printed in JSON form as:

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

If a diagnostic has fix-it hints, it gets a "fixits" array ๐Ÿ› ๏ธโœจ. Those are half-open intervals, kinda like what you'd get from -fdiagnostics-parseable-fixits ๐Ÿฆ‹. Here's a diagnostic with a replacement fix-it hint:

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

It might come out in JSON form like this ๐Ÿ’…:

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

So the fix-it hint says to replace the text from "start" up to, but not including, "next" with the value of "string" ๐ŸŒธ. Deletions are written as an empty "string" value, and insertions are written by making "start" equal "next" ๐Ÿ’œ.

If the diagnostic has a path of control-flow events attached to it ๐Ÿงš, it gets a "path" array of event objects ๐ŸŒˆ. Each event has a "description" string, a "location" object, a "function" string, and a "depth" number, which is how interprocedural paths get represented ๐Ÿ‘‘. The "function" tells you the current function at that event, and the "depth" shows the stack depth compared to some baseline: the higher the number, the more frames are sitting 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
        }
    }
]

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

okay so warnings are GCC going "hmm, sus ๐Ÿง" about stuff that isn't technically broken, but is risky or might mean you messed up somewhere ๐Ÿ’€

these next few are language-independent, so they work across the board ๐ŸŒˆ they don't switch on any specific warning, they just control what kind of diagnostics GCC spits out ๐Ÿ’…

  • -fsyntax-only โ€” checks your code for syntax errors and then stops there. no extra nonsense ๐Ÿซถ
  • -fmax-errors=n โ€” caps the number of error messages at n. once it hits that number, GCC bails instead of trying to keep going through your source code ๐Ÿ˜ญ if n is 0 (the default), there's no limit on how many errors it'll print. if -Wfatal-errors is also specified, then -Wfatal-errors takes precedence over this option ๐Ÿ‘‘
  • -w โ€” inhibits all warning messages. silence is golden โœจ
  • -Werror โ€” turns every single warning into an error ๐Ÿ”ฅ
  • -Werror= โ€” turns one specific warning into an error. you just tack on the warning's name, so for example -Werror=switch makes the warnings controlled by -Wswitch into errors ๐Ÿ“ this one 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 ๐Ÿ™ˆ
    • every controllable warning message includes the option that controls it, and you can use that option with -Werror= and -Wno-error= like we just talked about. (printing the option in the warning message can be disabled using the -fno-diagnostics-show-option flag ๐Ÿ’œ)
    • note that specifying -Werror=foo automatically implies -Wfoo. however, -Wno-error=foo does not imply anything ๐Ÿ‘€
  • -Wfatal-errors โ€” makes the compiler abort compilation on the very first error it hits, instead of trying to keep going and printing more error messages ๐Ÿ’€

you can request a bunch 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 them off, like -Wno-implicit. this manual only lists one of the two forms, whichever one isn't the default ๐Ÿงš for further language-specific options, also refer to C++ Dialect Options and Objective-C and Objective-C++ Dialect Options. additional warnings can be produced by enabling the static analyzer;

okay so some options, like -Wall and -Wextra, turn on other options, like -Wunused, which may then turn on even more options, like -Wunused-value. the combined effect of positive and negative forms is that more specific options have priority over less specific ones, no matter where they sit on the command line ๐ŸŒธ for options of the same specificity, the last one takes effect. options enabled or disabled via pragmas take effect as if they appeared at the end of the command line ๐ŸŽ€

when you request an unrecognized warning option (e.g., -Wunknown-warning), GCC emits a diagnostic saying the option isn't recognized. but if the -Wno- form is used, it's a little different: no diagnostic is produced for -Wno-unknown-warning unless other diagnostics are being produced. this lets you use new -Wno- options with old compilers, but if something goes wrong, the compiler warns that an unrecognized option is present ๐Ÿซถ

the effectiveness of some warnings depends on optimizations also being enabled. for example, -Wsuggest-final-types is more effective with link-time optimization, and -Wmaybe-uninitialized does not warn at all unless optimization is enabled ๐Ÿ˜ญ

  • -Wpedantic, -pedantic โ€” issues all the warnings demanded by strict ISO C and ISO C++, rejects all programs that use forbidden extensions, and rejects some other programs that don't follow ISO C and ISO C++ ๐Ÿ’… for ISO C, it follows the version of the ISO C standard specified by any -std option used.
    • valid ISO C and ISO C++ programs should compile properly with or without this option (though a rare few require -ansi or a -std option specifying the required version of ISO C). however, without this option, certain GNU extensions and traditional C and C++ features are supported too. with this option, they get rejected ๐Ÿ™…โ€โ™€๏ธ
    • -Wpedantic does not cause warning messages for use of the alternate keywords whose names begin and end with __. this alternate format can also be used to disable warnings for non-ISO __intN types, i.e. __intN__. pedantic warnings are also disabled in the expression that follows "__extension__". however, only system header files should use these escape routes; application programs should avoid them ๐Ÿšซ
    • some users try to use -Wpedantic to check programs for strict ISO C conformance. they soon find that it doesn't quite do what they want: it finds some non-ISO practices, but not all---only the ones for which ISO C requires a diagnostic, plus some others that have had diagnostics added ๐Ÿฅฒ
    • a feature to report any failure to conform to ISO C might be useful in some instances, but it would require a ton of additional work and would be quite different from -Wpedantic. there are no plans to support such a feature in the near future ๐Ÿงƒ
    • where the standard specified with -std represents a GNU extended dialect of C, such as gnu90 or gnu99, there's a corresponding base standard: the version of ISO C that the GNU extended dialect is based on. warnings from -Wpedantic are given where they're required by the base standard. (it doesn't make sense for those warnings to only cover features that aren't in the specified GNU C dialect, since by definition the GNU dialects of C include all features the compiler supports with the given option, and there would be nothing to warn about ๐Ÿคทโ€โ™€๏ธ)
  • -pedantic-errors โ€” gives an error whenever the base standard (see -Wpedantic) requires a diagnostic, 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 equivalent to -Werror=pedantic, since there are errors enabled by this option that the latter doesn't enable, and vice versa ๐Ÿ™ƒ
  • -Wall โ€” enables all the warnings about constructions that some users consider questionable and that are easy to avoid (or modify to prevent the warning), even in conjunction with macros ๐ŸŒˆ this also enables some language-specific warnings described in C++ Dialect Options and Objective-C and Objective-C++ Dialect Options.

-Wall turns on the following warning flags:

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

note that some warning flags are not implied by -Wall ๐Ÿ‘€ some of them warn about constructions that users generally don't consider questionable, but which 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 modify the code to suppress the warning. some of them are enabled by -Wextra, but many of them have to be enabled individually ๐ŸŽ€

  • -Wextra โ€” enables some extra warning flags that are not enabled by -Wall. (this option used to be called -W. the older name is still supported, but the newer name is more descriptive ๐Ÿงš)

the extra flags it turns on are:

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

Okay so -Wextra is lowkey not done yet ๐Ÿ’… it also yells about these bad boys ๐Ÿ”ฅ:

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

-Wabi (C, Objective-C, C++ and Objective-C++ only)

Ohh, this one is all about ABI changes ๐Ÿซถ It warns about code that's affected by ABI changes, including code that might not be compatible with the vendor-neutral C++ ABI, and code that might not match the psABI for your particular target.

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

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

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

GCC tried really hard to warn about every case ๐Ÿ˜ญ but there are probably some cases that go unwarned, even though G++ is generating incompatible code. There may also be cases where warnings pop up even though the generated code is actually compatible.

You should rewrite your code to avoid these warnings if you're worried that code generated by G++ might not be binary compatible with code generated by other compilers. ๐ŸŽ€

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 didn't allow for overloading of functions taking vectors of different sizes. The mangling was changed in -fabi-version=4.

๐Ÿ› __attribute ((const)) and noreturn were mangled as type qualifiers, and decltype of a plain declaration got folded away. These mangling issues were fixed in -fabi-version=5.

๐Ÿ› Scoped enumerators passed as arguments to a variadic function get promoted like unscoped enumerators, which makes va_arg complain. On most targets this doesn't actually affect the parameter passing ABI, since there's no way to pass an argument smaller than int. The ABI also changed the mangling of template argument packs, const_cast, static_cast, prefix increment/decrement, and a class scope function used as a template argument. These issues were corrected in -fabi-version=6.

๐Ÿ› Lambdas in default argument scope were mangled incorrectly, and the ABI changed the mangling of nullptr_t. These issues were corrected in -fabi-version=7.

๐Ÿ› Function types with function-cv-qualifiers: when mangling one, the un-qualified function type was incorrectly treated as a substitution candidate. This was fixed in -fabi-version=8, the default for GCC 5.1.

๐Ÿ› decltype(nullptr) incorrectly had an alignment of 1, leading to unaligned accesses. This didn't affect the ABI of a function with a nullptr_t parameter, since parameters have a minimum alignment. This was fixed in -fabi-version=9, the default for GCC 5.2.

๐Ÿ› Target-specific attributes that affect the identity of a type, like ia32 calling conventions on a function type (stdcall, regparm, etc.), didn't affect the mangled name. That caused name collisions when function pointers were used as template arguments. This was fixed in -fabi-version=10, the default for GCC 6.1.

This option also enables warnings about psABI-related changes. The known psABI changes at this point include:

  • For SysV/x86-64, unions with long double members are passed in memory as specified in psABI. Prior to GCC 4.4, this was not the case. For example:
union U {
  long double ld;
  int i;
};

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


-Wchar-subscripts

Warns if an array subscript has type char. This is a common cause of errors, because programmers often 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 using the -fprofile-use option. If a source file is changed between compiling with -fprofile-generate and with -fprofile-use, the files with the profile feedback can fail to match the source file, and GCC can't use the profile feedback information. By default, this warning is enabled and is treated as an error. -Wno-coverage-mismatch can be used to disable the warning, or -Wno-error=coverage-mismatch can be used to disable the error. Disabling the error for this warning can result in poorly optimized code, and it's only useful for very minor changes, like bug fixes to an existing code-base. Completely disabling the warning is not recommended. ๐Ÿšจ

-Wno-cpp (C, Objective-C, C++, Objective-C++ and Fortran only)

Suppresses 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 computations with double values is much more expensive because of the overhead required for software emulation. ๐Ÿ˜ค

It's super easy to accidentally do computations with double, 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 supplied have types that fit 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've selected, 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, as well as features from the Single Unix Specification and some BSD and GNU extensions. Other library implementations may not support all of these, and GCC doesn't warn about features that go beyond a particular library's limitations. However, if -Wpedantic is used with -Wformat, warnings are given 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 equivalent to -Wformat=1, and -Wno-format is equivalent to -Wformat=0. Since -Wformat also checks for null format arguments for several functions, it also implies -Wnonnull. Some aspects of this level of format checking can be disabled with these options: -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. Currently 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 such arguments are ignored. ๐Ÿ™ƒ

Where the unused arguments lie between used arguments that are specified with $ operand number specifications, warnings are normally still given, since the implementation couldn't know what type to pass to va_arg to skip the unused arguments. However, for scanf formats, this option suppresses the warning if the unused arguments are all pointers, since the Single Unix Specification says such unused arguments are allowed.

-Wformat-overflow, -Wformat-overflow=level

Warns about calls to formatted input/output functions, such as 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. Enabling optimization will in most cases improve the accuracy of the warning, but it may also result in false positives. Watch out for those false alarms ๐Ÿ”ฅ

  • -Wformat-overflow, -Wformat-overflow=1 โ€” okay bestie, this is the chill level ๐Ÿ’… Level 1 is switched on by -Wformat and it's super conservative, so it only yells about calls that most likely overflow the buffer ๐Ÿ™ˆ Numeric arguments with unknown values get treated as 1, and strings of unknown length get treated as empty. Numeric arguments known to be bounded to a subrange of their type, or string arguments whose output is bounded by the directive's precision or by a finite set of string literals, are assumed to take whatever value in that range gives the most bytes of output. So the sprintf call below gets flagged because even with a and b both zero, the terminating NUL character ('\0') that the function tacks onto the destination buffer gets written past its end ๐Ÿ˜ญ Making the buffer just one byte bigger is enough to dodge the warning โœจ, though that might not be enough to actually stop 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 is the "okay but what if" level ๐Ÿ”ฅ It warns about calls that might overflow the destination buffer if an argument is long enough or big enough in magnitude. At level 2, unknown numeric arguments are assumed to have the minimum representable value for signed types with a precision greater than 1, and the maximum representable value otherwise. Unknown string arguments that can't be assumed bounded (by the directive's precision, 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 size of the buffer in an informational note after the warning, so you don't have to guess ๐Ÿซถ

An alternative to making the buffer bigger is to constrain 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 can be assumed to be bounded by less than the precision of their type, picking an appropriate length modifier for the format specifier will shrink the 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 size of the buffer to 24 bytes.

void f (int a, int b)
{
  char buf [23];
  sprintf (buf, "a = %hi, b = %i\n", a, (short)b);
}
  • -Wno-format-zero-length โ€” if -Wformat is specified, don't warn about zero-length formats ๐ŸŒธ The C standard says zero-length formats are allowed, so no drama needed.
  • -Wformat-nonliteral โ€” if -Wformat is specified, also warn if the format string isn't a string literal and therefore can't be checked ๐Ÿง The exception is when the format function takes its format arguments as a va_list.
  • -Wformat-security โ€” if -Wformat is specified, also warn about format function uses that could be security problems ๐Ÿšจ Right now it warns about calls to printf and scanf where the format string isn't a string literal and there are no format arguments, like printf (foo);. That can be a security hole if the format string came from untrusted input and contains %n. (This is currently a subset of what -Wformat-nonliteral warns about, but future warnings may be added to -Wformat-security that aren't included in -Wformat-nonliteral.)
  • -Wformat-signedness โ€” if -Wformat is specified, also warn if the format string requires an unsigned argument and the argument is signed, and vice versa ๐Ÿ”ข
  • -Wformat-truncation, -Wformat-truncation=level โ€” warn about calls to formatted input/output functions like snprintf and vsnprintf that might result in output truncation โœ‚๏ธ When the exact number of bytes written by a format directive can't be figured out at compile time, it's estimated using heuristics that depend on the level argument and on optimization. Turning on optimization will usually make the warning more accurate, but it can also cause false positives. Except where noted otherwise, this option uses the same logic as -Wformat-overflow.
    • -Wformat-truncation, -Wformat-truncation=1 โ€” level 1 of -Wformat-truncation is enabled by -Wformat and is conservative ๐Ÿซง It only warns about calls to bounded functions whose return value is unused and that will most likely result in output truncation.
    • -Wformat-truncation=2 โ€” level 2 also warns about calls to bounded functions whose return value is used and that might result in truncation, 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 ๐Ÿ“… Y2K vibes, not it ๐Ÿ’€
  • -Wnonnull โ€” warn about passing a null pointer for arguments marked as requiring a non-null value by the nonnull function attribute ๐Ÿšซ -Wnonnull is included in -Wall and -Wformat, and it can be disabled with the -Wno-nonnull option.
  • -Wnonnull-compare โ€” warn when comparing an argument marked with the nonnull function attribute against null inside the function ๐Ÿ‘€ -Wnonnull-compare is included in -Wall, and it can be disabled with the -Wno-nonnull-compare option.
  • -Wnull-dereference โ€” warn if the compiler detects paths that trigger erroneous or undefined behavior due to dereferencing a null pointer ๐Ÿ•ณ๏ธ This option is only active when -fdelete-null-pointer-checks is active, which is enabled by optimizations on most targets. How precise the warnings are depends on the optimization options you use.
  • -Winit-self (C, C++, Objective-C and Objective-C++ only) โ€” warn about uninitialized variables that get initialized with themselves ๐Ÿชž Note this option can only be used together with the -Wuninitialized option.

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

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

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

  • -Wno-implicit-int (C and Objective-C only) โ€” this option controls warnings when a declaration doesn't specify a type ๐Ÿงฉ The 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) โ€” this option controls warnings when a function is used before it's declared ๐Ÿ“ฃ The warning is enabled by default in C99 and later dialects of C, and also by -Wall. It gets upgraded to an error by -pedantic-errors, so be careful ๐Ÿ™ˆ
  • -Wimplicit (C and Objective-C only) โ€” same as -Wimplicit-int and -Wimplicit-function-declaration ๐ŸŒˆ This warning is enabled by -Wall.
  • -Wimplicit-fallthrough โ€” same as -Wimplicit-fallthrough=3, and -Wno-implicit-fallthrough is the same as -Wimplicit-fallthrough=0 ๐Ÿฆ‹
  • -Wimplicit-fallthrough=n โ€” warn 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, like ifs, into account, and only warns when it's appropriate. E.g.

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

Sometimes a switch case falling through is actually desirable ๐Ÿซ  For that, GCC provides an attribute, __attribute__ ((fallthrough)), which is used along with a null statement to suppress the warning that would normally happen:

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

C++17 gives you a standard way to suppress the -Wimplicit-fallthrough warning using [[fallthrough]]; instead of the GNU attribute ๐ŸŽ€ In C++11 or C++14, you can use [[gnu::fallthrough]];, which is a GNU extension. Instead of these attributes, you can also add a fallthrough comment to silence the warning ๐Ÿ’ฌ The whole body of the C or C++ style comment has to match the regular expressions listed below. The option argument n specifies what 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:

Okay so the =3 lineup keeps going, and these are all the comment patterns GCC will accept as a fallthrough note ๐Ÿ’…

"-fallthrough"
"@fallthrough@"
"lint -fallthrough[ \t]*"
"[ \t.!]*(ELSE,? |INTENTIONAL(LY)? )?FALL(S | |-)?THR(OUGH|U)[ \t.!]*(-[^\n\r]*)?"
"[ \t.!]*(Else,? |Intentional(ly)? )?Fall((s | |-)[Tt]|t)hr(ough|u)[ \t.!]*(-[^\n\r]*)?"
"[ \t.!]*([Ee]lse,? |[Ii]ntentional(ly)? )?fall(s | |-)?thr(ough|u)[ \t.!]*(-[^\n\r]*)?"

The -Wimplicit-fallthrough=4 level is way pickier ๐Ÿ™ˆ It's case sensitive and only matches one of these four patterns:

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

And -Wimplicit-fallthrough=5 is the no-nonsense one ๐Ÿ”ฅ It doesn't recognise any comments as fallthrough comments. Only attributes can shut the warning up.

The comment has to be followed, after optional whitespace and other comments, by a case or default keyword, or by a user label that sits in front of a case or default label. Like this:

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

The -Wimplicit-fallthrough=3 warning is turned on by -Wextra โœจ


  • -Wno-if-not-aligned (C, C++, Objective-C and Objective-C++ only) โ€” lets you decide whether warnings triggered by the warn_if_not_aligned attribute actually get issued. They're on by default ๐ŸŒธ
  • -Wignored-qualifiers (C and C++ only) โ€” warns if a function's return type has a qualifier like const. In ISO C that qualifier does nothing, since a function's return value isn't an lvalue. In C++ the warning only fires for scalar types or void. ISO C bans qualified void return types on function definitions, so those always get a warning, even without this option. This one's also enabled by -Wextra ๐ŸŽ€
  • -Wno-ignored-attributes (C and C++ only) โ€” controls warnings for when an attribute gets ignored. It's different from -Wattributes, because this one speaks up whenever the compiler decides to drop an attribute. -Wattributes cares about whether the attribute is unknown or in the wrong spot. It's on by default ๐Ÿฆ‹
  • -Wmain โ€” warns if the type of main is sus. main should be a function with external linkage that returns int, and takes either zero arguments, two, or three arguments of the appropriate types. It's enabled by default in C++, and by either -Wall or -Wpedantic ๐Ÿ‘‘
  • -Wmisleading-indentation (C and C++ only) โ€” warns when the indentation doesn't match the real block structure. Specifically, it fires for if, else, while, and for clauses with a guarded statement that has no braces, followed by an unguarded statement at the same indent. Look at the call to bar below. It looks guarded by the if, but it totally isn't ๐Ÿ™ˆ
if (some_condition ())
  foo ();
  bar ();  /* Gotcha: this is not guarded by the "if".  */

If you mix tabs and spaces, the warning uses -ftabstop= to figure out whether the statements line up. That defaults to 8.

It won't warn about multiline preprocessor logic like this:

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

It also skips anything after a #line directive, because that usually means autogenerated code, and you can't make any assumptions about the layout of the file that directive points to. This one's enabled by -Wall in C and C++ โœจ

  • -Wmissing-attributes โ€” warns when a function declaration is missing one or more attributes that a related function is declared with, and that absence could hurt the correctness or efficiency of the generated code. A classic example is an alias declaration that uses attributes to ask for less strict requirements than its target. That's usually a potential optimisation opportunity ๐Ÿ’– By contrast, -Wattribute-alias=2 warns when the alias is more restrictive than the target, which could lead to incorrect code generation. The attributes it checks are alloc_align, alloc_size, cold, const, hot, leaf, malloc, nonnull, noreturn, nothrow, pure, returns_nonnull, and returns_twice.

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

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

-Wmissing-attributes is enabled by -Wall.

For example, the primary function template below uses both the malloc and alloc_size attributes. That means the explicit specialisation is flagged, because it's missing one of them:

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

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

This warning is enabled by -Wall.

  • -Wmissing-include-dirs (C, C++, Objective-C and Objective-C++ only) โ€” warns if a user-supplied include directory doesn't exist ๐Ÿ“
  • -Wno-missing-profile โ€” controls warnings when feedback profiles are missing while you're using -fprofile-use. It catches the 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 information at all. In every one of these cases, you get warnings telling you a profile generation step is due ๐Ÿ˜ญ Ignoring them can result in poorly optimised code. You can use -Wno-missing-profile to switch the warning off, but that's not recommended, and it should only happen when non-existent profile data is actually justified.
  • -Wno-mismatched-dealloc โ€” warns for calls to deallocation functions with pointer arguments that came from allocation functions the deallocator isn't suitable for. You can link a pair of functions as matching allocator and deallocator with the malloc attribute. Unless -fno-builtin turns it off, the standard functions calloc, malloc, realloc, and free, along with the matching C++ forms of operator new and operator delete, are implicitly treated as matching allocators and deallocators. In the example, mydealloc is the deallocator for pointers returned from myalloc ๐Ÿ‘‘
void mydealloc (void*);

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

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

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

Option -Wmismatched-dealloc is enabled by default.

  • -Wmultistatement-macros โ€” warns about unsafe multi-statement macros that look guarded by a clause like if, else, for, switch, or while, when only the first statement is actually guarded once the macro expands ๐Ÿ’€

For example:

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

This will increment y unconditionally, not just when c holds. You can usually fix it by wrapping the macro in a do-while loop:

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

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

  • -Wparentheses โ€” warns if parentheses are left out in certain spots, like when there's an assignment where a truth value is expected, or when operators are nested in a way people often mix up the precedence of ๐Ÿ™ƒ

It also warns if you write a comparison like x<=y<=z. That's equivalent to (x<=y ? 1 : 0) <= z, which is a different reading from normal maths notation ๐Ÿ˜ญ

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

For C++, this also warns about some unnecessary parentheses in declarations, which can mean you meant to make a function call instead of a declaration:

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

This warning is enabled by -Wall.

  • -Wsequence-point โ€” warns about code that might have undefined semantics because it breaks the sequence point rules in the C and C++ standards. Be careful with this one, bestie ๐Ÿซถ

The C and C++ standards define the order that expressions run in using sequence points ๐ŸŽ€. Think of them as checkpoints in your program: everything before a checkpoint is finished, and nothing after it has started yet. A sequence point happens after a full expression (one that isn't part of a bigger expression) โœจ, after the first operand of a &&, ||, ? :, or , (comma) operator ๐Ÿ’…, before a function is called (but after its arguments and the expression naming the function are evaluated) ๐Ÿฆ‹, and in a few other spots too. Apart from what the sequence point rules say, the order in which subexpressions get evaluated is unspecified ๐Ÿ™ˆ. The rules only give a partial order, not a total one. For example, if two functions get called inside one expression with no sequence point between them, the order of those calls is unspecified. The standards committee did rule that function calls never overlap, though ๐Ÿ’œ.

It's also unspecified when, between sequence points, changes to an object's value actually take effect ๐Ÿ˜ญ. Programs that depend on this have undefined behavior. The standards say: "Between the previous and next sequence point an object shall have its stored value modified at most once by the evaluation of an expression. Furthermore, the prior value shall be read only to determine the value to be stored.". If your program breaks these rules, the results on any given implementation are totally unpredictable ๐Ÿ’€. Bestie, don't do that.

Examples of code with undefined behavior include a = a++;, a[n] = b[n++], and a[i++] = i; ๐Ÿ™ˆ. Some trickier cases won't get caught by this option, and it might occasionally give a false positive โš ๏ธ. Overall though, it's been pretty effective at catching this kind of problem ๐Ÿ”ฅ.

The C++17 standard defines 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 ๐Ÿ‘‘. This option will still warn about them anyway ๐Ÿซถ, to help people avoid writing code that's undefined in C and in earlier revisions of C++.

The standard is worded super confusingly, so people genuinely debate the exact meaning of the sequence point rules in subtle cases ๐Ÿ˜ญ. Links to discussions of the problem, including proposed formal definitions, can be found on the GCC readings page at http://gcc.gnu.org/readings.html ๐Ÿ“š.

This warning is enabled by -Wall for C and C++ ๐ŸŒˆ.

  • -Wno-return-local-addr โ€” Don't warn about returning a pointer (or, in C++, a reference) to a variable that goes out of scope once the function returns ๐Ÿงš.
  • -Wreturn-type โ€” Warn whenever a function gets defined with a return type that defaults to int ๐Ÿ“. It also warns about any return statement with no return value inside a function whose return type isn't void (falling off the end of the function body counts as returning without a value ๐Ÿ™ˆ).
    • For C only, it warns about a return statement with an expression inside a function whose return type is void, unless the expression's type is also void. As a GNU extension, that latter case is accepted without a warning unless -Wpedantic is used ๐Ÿค“.
    • Using the return value of a non-void function (other than main) that flows off the end by reaching the closing curly brace is undefined behavior ๐Ÿ’€.
    • Unlike C, in C++ flowing off the end of a non-void function (other than main) results in undefined behavior even if the function's value never gets used ๐Ÿ˜ญ.
    • This warning is enabled by default in C++ and by -Wall otherwise โœจ.
  • -Wno-shift-count-negative โ€” Controls warnings for when a shift count is negative ๐ŸŒธ. This warning is enabled by default ๐Ÿ’–.
  • -Wno-shift-count-overflow โ€” Controls warnings for when a shift count is greater than or equal to the bit width of the type ๐Ÿฆ‹. This warning is enabled by default ๐Ÿ’–.
  • -Wshift-negative-value โ€” Warn if you left shift a negative value ๐Ÿซฃ. This warning is enabled by -Wextra in C99 (and newer) and in C++11 through C++17 modes ๐ŸŒˆ.
  • -Wno-shift-overflow, -Wshift-overflow=n โ€” These options control warnings about left shift overflows ๐Ÿ‘‘.
    • -Wshift-overflow=1 โ€” This is the warning level of -Wshift-overflow, and it's enabled by default in C99 and C++11 modes (and newer) โœจ. This level doesn't warn about left-shifting 1 into the sign bit. (However, in C, that kind of overflow is still rejected in contexts where an integer constant expression is required ๐Ÿ™….) No warning is emitted in C++20 mode (and newer), since signed left shifts always wrap ๐ŸŽ€.
    • -Wshift-overflow=2 โ€” This level also warns about left-shifting 1 into the sign bit, unless C++14 mode (or newer) is active ๐Ÿ”ฅ.
  • -Wswitch โ€” Warn whenever a switch statement has an index of enumerated type and is missing a case for one or more of that enumeration's named codes ๐Ÿ’…. (Having a default label stops this warning from firing ๐Ÿ™Œ.) case labels outside the enumeration's range also set off warnings with this option, even if there's a default label ๐Ÿซถ. This warning is enabled by -Wall โœจ.
  • -Wswitch-default โ€” Warn whenever a switch statement doesn't have a default case ๐Ÿงš.
  • -Wswitch-enum โ€” Warn whenever a switch statement has an index of enumerated type and is missing a case for one or more of that enumeration's named codes ๐Ÿฆ‹. case labels outside the enumeration's range also trigger warnings with this option ๐Ÿ’œ. The only difference between -Wswitch and this option is that this one warns about an omitted enumeration code even when there's a default label ๐Ÿ‘€.
  • -Wno-switch-bool โ€” Don't warn when a switch statement has an index of boolean type and the case values fall outside the range of a boolean type ๐ŸŒˆ. You can suppress this warning by casting the controlling expression to a type other than bool ๐Ÿ“. For example:
switch ((int) (a == 4))
  {
  ...
  }

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

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

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

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

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

  • -Wsync-nand (C and C++ only) โ€” Warn when the __sync_fetch_and_nand and __sync_nand_and_fetch built-in functions are used ๐Ÿšจ. These functions changed semantics in GCC 4.4 ๐Ÿ˜ญ.
  • -Wunused-but-set-parameter โ€” Warn whenever a function parameter gets assigned to but is otherwise unused (aside from its declaration) ๐Ÿฅบ. To suppress this warning, use the unused attribute ๐Ÿซถ. This warning is also enabled by -Wunused together with -Wextra ๐ŸŒˆ.
  • -Wunused-but-set-variable โ€” Warn whenever a local variable gets assigned to but is otherwise unused (aside from its declaration) ๐ŸŽ€. This warning is enabled by -Wall โœจ. To suppress it, use the unused attribute ๐Ÿ™Œ. This warning is also enabled by -Wunused, which is itself enabled by -Wall ๐Ÿ’œ.
  • -Wunused-function โ€” Warn whenever a static function is declared but not defined, or a non-inline static function goes unused ๐Ÿฆ‹. This warning is enabled by -Wall ๐Ÿ’–.
  • -Wunused-label โ€” Warn whenever a label is declared but never used ๐Ÿท๏ธ. This warning is enabled by -Wall โœจ. To suppress it, use the unused attribute ๐Ÿซถ.
  • -Wunused-local-typedefs (C, Objective-C, C++ and Objective-C++ only) โ€” Warn when a typedef defined locally inside a function isn't used ๐Ÿ“. This warning is enabled by -Wall ๐ŸŒธ.
  • -Wunused-parameter โ€” Warn whenever a function parameter is unused, aside from its declaration ๐Ÿงš. To suppress this warning, use the unused attribute ๐Ÿซถ.
  • -Wno-unused-result โ€” Don't warn if a caller of a function marked with the attribute warn_unused_result doesn't use its return value ๐Ÿ™ˆ. The default is -Wunused-result ๐Ÿ’….
  • -Wunused-variable โ€” Warn whenever a local or static variable is unused, aside from its declaration ๐Ÿ‘€. For C, this option implies -Wunused-const-variable=1, but for C++ it doesn't ๐ŸŒˆ. This warning is enabled by -Wall โœจ. To suppress it, use the unused attribute ๐Ÿ™Œ.
  • -Wunused-const-variable, -Wunused-const-variable=n โ€” Warn whenever a constant static variable is unused, aside from its declaration ๐Ÿ’–. -Wunused-const-variable=1 is enabled by -Wunused-variable for C, but not for C++ ๐Ÿซถ. In C this declares variable storage, but in C++ it isn't an error, since const variables take the place of #defines ๐Ÿค“. To suppress this warning, use the unused attribute ๐ŸŽ€.
    • -Wunused-const-variable=1 โ€” This is the warning level that -Wunused-variable enables for C ๐Ÿ’œ. It only warns about unused static const variables defined in the main compilation unit, not about static const variables declared in any included header ๐Ÿงธ.
    • -Wunused-const-variable=2 โ€” This warning level also warns about unused constant static variables in headers (excluding system headers) ๐Ÿ”. This is the warning level of -Wunused-const-variable, and it must be explicitly requested, since in C++ this isn't an error and in C it can be harder to clean up every header that gets included ๐Ÿ˜ญ.
  • -Wunused-value โ€” ๐Ÿ’… Warns whenever a statement computes a result that's explicitly not used. Rude. To shut it up, cast the unused expression to void. This also covers an expression-statement or the left-hand side of a comma expression that has no side effects. So x[i,j] gets flagged, but x[(void)i,j] is totally fine ๐Ÿซถ

This warning is enabled by -Wall. โœจ

  • -Wunused โ€” the whole squad of -Wunused options combined ๐Ÿ‘‘

To get a warning about an unused function parameter, you have to either specify -Wextra -Wunused (note that -Wall already implies -Wunused), or specify -Wunused-parameter separately. ๐ŸŽ€

  • -Wuninitialized โ€” ๐Ÿฅบ Warns if an object with automatic or allocated storage duration gets used without having been initialized. In C++, it also warns if a non-static reference or non-static const member shows up in a class that has no constructors.

Passing a pointer (or in C++, a reference) to an uninitialized object into a const-qualified argument of a built-in function known to read that object gets diagnosed by this warning too. (-Wmaybe-uninitialized is the one for ordinary functions.)

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

These warnings pop up for individual uninitialized elements of structure, union, or array variables, as well as for variables that are uninitialized as a whole. They do not 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 version of GCC you're using. ๐ŸŒˆ

โš ๏ธ Heads up: there may be no warning about a variable that's only used to compute a value that's never used itself, because those computations can get deleted by data flow analysis before the warnings are printed. ๐Ÿ™ˆ
  • -Wno-invalid-memory-model โ€” This one controls warnings for invocations of __atomic Builtins, __sync Builtins, 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, the __atomic_store and __atomic_store_n built-ins are only defined for the relaxed, release, and sequentially consistent memory orders, so the following code gets diagnosed:
void store (int *i)
{
  __atomic_store_n (i, 0, memory_order_consume);
}

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

  • -Wmaybe-uninitialized โ€” ๐ŸŒธ For an object with automatic or allocated storage duration, if there's a path from the function entry to a use of the object where it is initialized, but some other paths leave it uninitialized, 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 is also diagnosed by this warning. (-Wuninitialized is issued for built-in functions known to read the object.) Annotating the function with attribute access (none) says the argument isn't used to access the object, and that avoids the warning. โœจ

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

These warnings are optional because GCC may not be able to tell when code is correct even though it looks like an error. Here's one example of how that can happen:

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

If the value of y is always 1, 2 or 3, then x is always initialized, but GCC doesn't know that. To suppress the warning, you need to provide a default case with assert(0) or similar code. ๐Ÿซถ

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

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

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

  • -Wunknown-pragmas โ€” ๐Ÿ”ฎ Warns when a #pragma directive shows up that GCC doesn't understand. If this command-line option is used, warnings are even issued for unknown pragmas in system header files. That's not the case if the warnings are only enabled by the -Wall command-line option.
  • -Wno-pragmas โ€” ๐Ÿ™…โ€โ™€๏ธ Don't warn about misuses of pragmas, like incorrect parameters, invalid syntax, or conflicts between pragmas. 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 assign a priority to control their order of execution before main is called or after it returns. The priority values must be greater than 100, because the compiler reserves priority values between 0--100 for the implementation. ๐ŸŽ€
  • -Wstrict-aliasing โ€” ๐Ÿฆ‹ This option is only active when -fstrict-aliasing is active. It warns about code that might break the strict aliasing rules the compiler uses for optimization. It doesn't catch every case, but it does try to catch the more common pitfalls. It's included in -Wall. It's equivalent to -Wstrict-aliasing=3.
  • -Wstrict-aliasing=n โ€” Same deal: only active when -fstrict-aliasing is active, and it warns about code that might break those strict aliasing rules. Higher levels mean higher accuracy (fewer false positives), and they also take more effort, kind of like how -O works. -Wstrict-aliasing is equivalent to -Wstrict-aliasing=3. Here are the levels:
    • Level 1 โ€” the most aggressive, quick, and least accurate option ๐Ÿƒโ€โ™€๏ธ. It's possibly useful when higher levels don't warn but -fstrict-aliasing still breaks the code, since it has very few false negatives. However, it has many false positives. It warns for all pointer conversions between possibly incompatible types, even if the pointer is never dereferenced. It runs in the front end only.
    • Level 2 โ€” aggressive 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) โ€” ๐Ÿ‘‘ 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. It does not warn about incomplete types.
  • -Wstrict-overflow, -Wstrict-overflow=n โ€” ๐Ÿง This option is only active when signed overflow is undefined. It warns about cases where the compiler optimizes based on the assumption that signed overflow doesn't occur. It doesn't warn about every case where 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 happen is perfectly safe if the values involved are such that overflow never actually occurs. That means this warning can easily give a false positive, which is a warning about code that isn't actually a problem. To help you focus on the important stuff, several warning levels are defined. No warnings are issued for uses of undefined signed overflow when estimating how many iterations a loop requires, in particular when determining whether a loop will be executed at all. ๐Ÿ’–

  • -Wstrict-overflow=1 โ€” Warns about cases that are both questionable and easy to avoid. For example, the compiler simplifies x + 1 > x to 1. This level is enabled by -Wall; higher levels aren't, and must be explicitly requested. ๐ŸŒธ
  • -Wstrict-overflow=2 โ€” Also warns about other cases where a comparison is simplified to a constant. For example: abs (x) >= 0. This can only be simplified when signed integer overflow is undefined, because abs (INT_MIN) overflows to INT_MIN, which is less than zero. -Wstrict-overflow (with no level) is the same as -Wstrict-overflow=2. โœจ
  • -Wstrict-overflow=3 โ€” Also warns about other cases where a comparison is simplified. For example: x + 1 > 1 is simplified to x > 0. ๐Ÿฆ‹
  • -Wstrict-overflow=4 โ€” Also warns about other simplifications not covered by the above cases. For example: (x * 10) / 5 is simplified to x * 2. ๐Ÿ”ฅ
  • -Wstrict-overflow=5 โ€” Also warns about cases where the compiler reduces the magnitude of a constant involved in a comparison. For example: x + 2 > y is simplified to x + 1 >= y. This is only reported at the highest warning level, because this simplification applies to many comparisons, so this level gives a very large number of false positives. ๐Ÿ’€

โœจ -Wstring-compare โœจ

okay so bestie, this one watches strcmp and strncmp ๐Ÿซถ It warns when a comparison result is basically decided before it even starts, because one argument is longer than the array the other one lives in (or the bound, for strncmp). Like, the answer is already locked in ๐Ÿ’€ and those calls could be mistakes, so GCC flags them. no cap, it's a lifesaver ๐ŸŒธ

Here's the example: the strcmp call below gets flagged because its result is necessarily non-zero no matter what's inside the array a ๐Ÿ”ฅ

extern char a[4];
void f (char *d)
{
  strcpy (d, "string");
  ...
  if (0 == strcmp (a, d))   // cannot be true
    puts ("a and d are the same");
}

-Wstring-compare comes on automatically with -Wextra โœจ


๐Ÿ’– -Wno-stringop-overflow, -Wstringop-overflow, -Wstringop-overflow=type ๐Ÿ’–

this one is all about catching string functions like memcpy and strcpy when they're about to overflow the destination buffer ๐Ÿ˜ญ The optional number you pass is one bigger than the Object Size Checking type GCC uses to figure out how big the destination is. That number only matters for functions that work on character arrays. Raw memory functions like memcpy always use Object Size type-0, so no vibe shift there ๐Ÿฆ‹

It also warns when a call asks for a size bigger than the largest possible object, or more than SIZE_MAX / 2 bytes. The best results happen with optimization turned on, but it can still catch a small set of simple overflows without optimization, in calls to GCC built-ins like __builtin_memcpy that match the standard functions ๐Ÿงš Either way, it only catches a subset of what the matching overflow checking built-ins can find, so don't get too comfy ๐Ÿ‘€

Check this one out: the strcpy below gets a warning because it copies at least 5 characters ("blue" plus the terminating NUL) into a buffer of size 4 ๐Ÿ’…

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

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

Option -Wstringop-overflow=2 is the default setting โœจ

  • -Wstringop-overflow, -Wstringop-overflow=1 โ€” this setting uses type-zero Object Size Checking to size destinations ๐ŸŒˆ At this level it doesn't warn about writes past the end of subobjects inside larger objects accessed through pointers, unless the size of the largest surrounding object is known. If the destination could be one of several objects, GCC assumes it's the biggest one. On Linux, when optimization is on at this level, it warns for the same code that would be flagged when _FORTIFY_SOURCE is defined to a non-zero value ๐Ÿซถ
  • -Wstringop-overflow=2 โ€” this one uses type-one Object Size Checking ๐Ÿ”ฅ It warns about overflows when writing to members of the largest complete objects whose exact size is known. It won't warn about excessive writes to the same members of unknown objects reached through pointers, since those might point to arrays with an unknown number of elements. This is the default setting, so you're already on it ๐Ÿ’–
  • -Wstringop-overflow=3 โ€” type-two Object Size Checking, and it's the strictest setting that might warn about safe code ๐Ÿ˜ญ It warns about overflowing the smallest object or data member.
  • -Wstringop-overflow=4 โ€” type-three Object Size Checking ๐Ÿ’€ It warns about overflowing any data members. When the destination could be one of several objects, it uses the size of the largest one to decide whether to warn. Just like -Wstringop-overflow=3, this setting may produce warnings for benign code ๐Ÿ™ˆ

๐ŸŒธ -Wno-stringop-overread ๐ŸŒธ

this one warns about string functions like memchr or strcpy that get determined to read past the end of the source sequence ๐Ÿ‘€ it's on by default, so you get this protection for free โœจ

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


๐Ÿฆ‹ -Wno-stringop-truncation ๐Ÿฆ‹

okay so this flag tells GCC to not warn about bounded string functions like strncat, strncpy, and stpncpy that might truncate the copied string or leave the destination unchanged ๐Ÿ“ Not warning is the whole point of -Wno-, so yeah, babe, it's a choice ๐Ÿ’…

Here, the strncat call gets flagged because its bound is smaller than the length of the source string. That means the copy gets truncated ๐Ÿ’€ To dodge the warning, use bufsize - strlen (buf) - 1) as the bound.

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

Next up, the strncpy below only copies the characters before the terminating NUL, so the NUL never gets added to the end of d ๐Ÿ˜ญ Assuming the result is always NUL-terminated is a super common mistake, so this one gets diagnosed. If you're not expecting a NUL-terminated result, call memcpy instead ๐Ÿซถ

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

Last one! Here the bound for strncpy is the size of the destination buffer. If the source is equal to or longer than that size, the result won't be NUL-terminated, so it gets flagged too ๐Ÿ™ˆ To avoid the warning, use 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);
  ...
}

Sometimes a character array is meant to hold bytes with no terminating NUL. In that case you can annotate the array with the attribute nonstring to skip this warning โœจ Heads up though, those arrays aren't suitable for functions that expect NUL-terminated strings ๐Ÿ’€ To help catch accidental misuse, GCC still warns about them unless it can prove the use is safe ๐Ÿ”ฅ


๐Ÿงš -Wsuggest-attribute=[pure|const|noreturn|format|cold|malloc] ๐Ÿงš

this is GCC giving you friendly attribute suggestions ๐Ÿ’– It warns when 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 โ€” this part warns about functions that might be candidates for the attributes pure, const, noreturn, or malloc ๐Ÿ‘‘ GCC only warns about functions visible in other compilation units, or (for pure and const) if it can't prove the function returns normally. A function returns normally if it doesn't contain an infinite loop or return abnormally by throwing, calling abort, or trapping. This analysis needs the option -fipa-pure-const, which is enabled by default at -O and higher. Higher optimization levels make the analysis more accurate ๐ŸŒˆ
  • -Wsuggest-attribute=format, -Wmissing-format-attribute โ€” this warns about function pointers that might be candidates for format attributes ๐ŸŽ€ These are only possible candidates, not 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. So the left-hand side of the assignment or initialization, the type of the parameter variable, or the return type of the containing function, respectively, should also have a format attribute to avoid the warning. GCC also warns about function definitions that might be candidates for format attributes, again just as possible candidates ๐Ÿฆ‹ It guesses that a format attribute might fit any function that calls something like vprintf or vscanf, but that might not always be true, and some functions that really do want format attributes may not get detected ๐Ÿ™ˆ
  • -Wsuggest-attribute=cold โ€” this warns about functions that might be candidates for the cold attribute ๐ŸงŠ It's based on static detection, and it usually only warns about functions that always lead to a call to another cold function, like wrappers of C++ throw or fatal error reporting functions that lead to abort ๐Ÿ’…

๐Ÿ“ -Walloc-zero ๐Ÿ“

this one warns about calls to allocation functions decorated with the attribute alloc_size that ask for zero bytes ๐Ÿ˜ญ That includes the built-in forms of aligned_alloc, alloca, calloc, malloc, and realloc.

Heads up, bestie: how these functions behave 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 ๐Ÿ‘‘

this one warns about calls to functions decorated with alloc_size that try to allocate objects bigger than the number of bytes you specify ๐Ÿ’… It also catches cases where the size computation, done in an integer type with infinite precision, would go over the value of PTRDIFF_MAX on the target ๐Ÿ”ฅ -Walloc-size-larger-than=PTRDIFF_MAX is enabled by default โœจ

To turn these warnings off, you can either specify a byte-size of SIZE_MAX or more, or use -Wno-alloc-size-larger-than ๐Ÿซถ

  • -Wno-alloc-size-larger-than โ€” okay bestie, this one switches off the -Walloc-size-larger-than= warnings ๐Ÿ™ˆ Doing it is the same as -Walloc-size-larger-than=SIZE_MAX or anything bigger, so you're basically telling GCC to chill โœจ
  • -Walloca โ€” warns on every single use of alloca in your source. Literally all of them ๐Ÿ’€
  • -Walloca-larger-than=byte-size โ€” the big one ๐Ÿ”ฅ It warns on calls to alloca where the integer argument is zero, or where it isn't bounded by a controlling predicate that caps it at byte-size. It also yells when the bound is unknown. Heads up: arguments of non-integer types count as unbounded, even if they look like they're in range ๐Ÿ‘€

For example, a bounded case of alloca could be:

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

In the above example, passing -Walloca-larger-than=1000 would not issue a warning because the call to alloca is known to be at most 1000 bytes. However, if -Walloca-larger-than=500 were passed, the compiler would emit a warning โœจ

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

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

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

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

void func (signed int n)
{
  if (n < 500)
    {
      p = alloca (n);
      f (p);
    }
}
Watch out! In the above example, n could be negative, causing a larger than expected argument to be implicitly cast into the alloca call ๐Ÿ˜ญ

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

-Walloca-larger-than=PTRDIFF_MAX is enabled by default but is usually only effective when -ftree-vrp is active (default for -O2 and above).

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

  • -Wno-alloca-larger-than โ€” disables the -Walloca-larger-than= warnings. It's the same as -Walloca-larger-than=SIZE_MAX or larger, so it's a full mute ๐Ÿ”‡
  • -Warith-conversion โ€” main character energy ๐Ÿ‘‘ This one makes sure GCC warns about implicit conversions coming from arithmetic operations, even when converting the operands to the same type can't actually change their values. It affects warnings from -Wconversion, -Wfloat-conversion, and -Wsign-conversion.
void f (char c, int i)
{
  c = c + i; // warns with B<-Wconversion>
  c = c + 1; // only warns with B<-Warith-conversion>
}
  • -Warray-bounds, -Warray-bounds=n โ€” only active when -ftree-vrp is active (default for -O2 and above) ๐Ÿง It warns about subscripts to arrays that are always out of bounds. This warning is enabled by -Wall.
    • -Warray-bounds=1 โ€” this is the warning level of -Warray-bounds and it's on with -Wall. The higher levels aren't, so you have to explicitly ask for them ๐Ÿ™‹โ€โ™€๏ธ
    • -Warray-bounds=2 โ€” also warns about out of bounds access for arrays at the end of a struct and for arrays accessed through pointers. It can give way more false positives, so it's deactivated by default ๐Ÿฅด
  • -Warray-parameter, -Warray-parameter=n โ€” warns about redeclarations of functions where the array or pointer arguments are inconsistent in kind or form. It also turns on the detection of out-of-bounds accesses to those parameters through warnings like -Warray-bounds ๐Ÿฆ‹

If the first function declaration uses the array form, the bound in the array is assumed to be the minimum number of elements expected in calls to the function and the maximum number of elements it accesses. Not passing enough elements or touching more than the max can get flagged by warnings like -Warray-bounds. At level 1, the warning diagnoses inconsistencies involving array parameters declared with the T[static N] form.

For example, the warning triggers for the following redeclarations, because the first one allows an array of any size to be passed to f, while the second one, with the keyword static, says the array argument must have at least four elements:

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

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

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

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

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

  • -Wattribute-alias=n, -Wno-attribute-alias โ€” warns about declarations using the alias and similar attributes whose target is incompatible with the type of the alias ๐ŸŒธ
    • -Wattribute-alias=1 โ€” the default level. It diagnoses incompatibilities between the type of the alias declaration and the type of its target. These are usually signs of bugs ๐Ÿ›
    • -Wattribute-alias=2 โ€” at this level, -Wattribute-alias also diagnoses cases where the alias declaration's attributes are more restrictive than the attributes on its target. Those mismatches can potentially lead to incorrect code generation. In other cases they may be harmless and could be fixed by simply adding the missing attribute to the target. For comparison, see the -Wmissing-attributes option, which controls diagnostics when the alias declaration is less restrictive than the target, rather than more restrictive ๐Ÿ”

Attributes considered include alloc_align, alloc_size, cold, const, hot, leaf, malloc, nonnull, noreturn, nothrow, pure, returns_nonnull, and returns_twice.

-Wattribute-alias is equivalent to -Wattribute-alias=1. This is the default. You can disable these warnings with either -Wno-attribute-alias or -Wattribute-alias=0 ๐Ÿ™…โ€โ™€๏ธ

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

This warning is enabled by -Wall ๐Ÿ’–

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

This warning is enabled by -Wall.

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

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

int i = x ? *p : *p;
  • -Wduplicated-cond โ€” warns about duplicated conditions in an if-else-if chain. For instance, it'll warn for this code:
if (p->q != NULL) { ... }
else if (p->q != NULL) { ... }
  • -Wframe-address โ€” warns when __builtin_frame_address or __builtin_return_address is called with an argument greater than 0. Such calls may return indeterminate values or crash the program ๐Ÿ’€ This warning is included in -Wall.
  • -Wno-discarded-qualifiers (C and Objective-C only) โ€” stops the warning about type qualifiers on pointers being discarded. Usually GCC complains if a const char * variable gets passed to a function that takes a char * parameter. Use this option to mute that ๐Ÿคซ
  • -Wno-discarded-array-qualifiers (C and Objective-C only) โ€” same vibe, but for arrays that are pointer targets. Usually GCC complains if a const int (*)[] variable is passed to a function that takes an int (*)[] parameter. This option lets you suppress that warning ๐ŸŽ€
  • -Wno-incompatible-pointer-types (C and Objective-C only) โ€” no warning when there's a conversion between pointers with incompatible types. This is for cases not covered by -Wno-pointer-sign, which warns about pointer argument passing or assignment with different signedness ๐Ÿงš
  • -Wno-int-conversion (C and Objective-C only) โ€” stops the warnings about incompatible integer-to-pointer and pointer-to-integer conversions. This warning is about implicit conversions. For explicit conversions, you can use -Wno-int-to-pointer-cast and -Wno-pointer-to-int-cast instead ๐Ÿ“
  • -Wzero-length-bounds โ€” warns about accesses to elements of zero-length array members that might overlap other members of the same object ๐ŸŒˆ Declaring interior zero-length arrays is discouraged, because accesses to them are undefined. See
Undefined behaviour alert! ๐Ÿšจ Interior zero-length arrays are undefined territory, so don't go poking around in them.

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

struct X { int a[0]; int b, c; };
struct X x;

Okay so this is the rest of the -Wzero-length-bounds vibe check ๐Ÿ‘€

void bad (void)
{
  x.a[0] = 0;   // -Wzero-length-bounds
  x.a[1] = 1;   // -Wzero-length-bounds
  x.a[2] = 2;   // -Warray-bounds
}

Option -Wzero-length-bounds is enabled by -Warray-bounds ๐Ÿ’…โœจ

  • -Wno-div-by-zero โ€” Bestie, this one tells GCC to chill ๐Ÿ™…โ€โ™€๏ธ and stop warning about compile-time integer division by zero. Floating-point division by zero doesn't get flagged either, because it can be a legit way to get infinities and NaNs ๐ŸŒˆ
  • -Wsystem-headers โ€” This one prints warnings for constructs in system header files ๐Ÿงน. Normally those get muted, because they usually aren't real problems and would just make your compiler output harder to read. Turning this on makes GCC treat system header warnings like they came from your own code ๐Ÿ’–. Heads up though: using -Wall with this doesn't warn about unknown pragmas in system headers. For that, you also need -Wunknown-pragmas ๐Ÿ™ˆ
  • -Wtautological-compare โ€” Warns if a self-comparison is always true or always false. It catches mistakes like this one ๐Ÿ’€:
int i = 1;
...
if (i > i) { ... }

Bitwise comparisons that always come out true or false get flagged too. Check this one out:

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

That if will always be false, so it's giving nothing ๐Ÿ˜ญ This warning is enabled by -Wall ๐ŸŽ€

  • -Wtrampolines โ€” Warns about trampolines generated for pointers to nested functions ๐Ÿงš. A trampoline is a small piece of data or code that gets created at run time on the stack when the address of a nested function is taken. It's used to call that nested function indirectly. On some targets it's just data and needs no special treatment. On most targets, though, it's made of code, so the stack has to be made executable for the program to work properly ๐Ÿ˜ฌ
  • -Wfloat-equal โ€” Warns when floating-point values are used in equality comparisons ๐Ÿซ . The thinking is that sometimes it's convenient to treat floats as approximations of infinitely precise real numbers. If you're doing that, you need to figure out the maximum or likely maximum error the computation introduces (by analyzing the code, or some other way) and allow for it in comparisons. Output is a different problem, too ๐Ÿ™ƒ. Instead of testing for equality, check whether the two values have ranges that overlap. That's done with the relational operators, so equality comparisons are probably 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. It's a whole vibe, so here's what it catches:
    • Macro parameters that show up inside string literals in the macro body. Traditional C does macro replacement inside string literals, but ISO C doesn't ๐Ÿ™…โ€โ™€๏ธ
    • In traditional C, some preprocessor directives didn't exist. Traditional preprocessors only treated a line as a directive if the # was in column 1. So -Wtraditional warns about directives that traditional C understands but ignores, because the # isn't the first character on the line. It also suggests hiding directives like #pragma (which traditional C doesn't understand) by indenting them. Some traditional implementations don't recognize #elif, so this option suggests avoiding it altogether ๐ŸŒธ
    • A function-like macro that appears without arguments
    • The unary plus operator
    • The U integer constant suffix, or the F or L floating-point constant suffixes. (Traditional C does support the L suffix on integer constants.) These suffixes show up in macros defined in the system headers of most modern systems, like the _MIN/_MAX macros in <limits.h>. Using those macros in user code might normally lead to spurious warnings, but GCC's integrated preprocessor has enough context to avoid warning in these cases โœจ
    • A function declared external in one block and then used after the end of that block
    • A switch statement with an operand of type long
    • A non-static function declaration that follows a static one. Some traditional C compilers don't accept this ๐Ÿ™ˆ
    • The ISO type of an integer constant has a different width or signedness from its traditional type. This warning is only issued if the base of the constant is ten. Hexadecimal or octal values, which usually represent bit patterns, aren't warned about ๐Ÿ”ข
    • ISO string concatenation usage gets detected ๐Ÿงต
    • Initialization of automatic aggregates
    • Identifier conflicts with labels. Traditional C doesn't have a separate namespace for labels ๐Ÿท๏ธ
    • Initialization of unions. If the initializer is zero, the warning gets skipped. This is done on the assumption that a zero initializer in user code is conditioned on something like __STDC__ to avoid missing-initializer warnings, and it relies on default initialization to zero in the traditional C case ๐Ÿซถ
    • Conversions by prototypes between fixed-point and floating-point values, and vice versa. Leaving these prototypes out when compiling with traditional C causes serious problems ๐Ÿ’€. This is only a subset of the possible conversion warnings. For the full set, use -Wtraditional-conversion
    • Use of ISO C style function definitions. This warning intentionally isn't issued for prototype declarations or variadic functions, because those ISO C features show up in your code when you use libiberty's traditional C compatibility macros, PARAMS and VPARAMS. It's also skipped for nested functions, since that's already a GCC extension and 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 ๐Ÿ”„. That includes conversions of fixed-point to floating-point and vice versa, and conversions that change the width or signedness of a fixed-point argument, except when that matches the default promotion.
  • -Wdeclaration-after-statement (C and Objective-C only) โ€” Warns when a declaration shows up after a statement in a block ๐Ÿ“. This construct comes from C++, was introduced with ISO C99, and is allowed by default in GCC. It isn't supported by ISO C90.
  • -Wshadow โ€” Warns whenever a local variable or type declaration shadows another variable, parameter, type, class member (in C++), or instance variable (in Objective-C). It also warns whenever a built-in function gets shadowed ๐ŸŽญ. In C++, the compiler warns if a local variable shadows an explicit typedef, but not if it shadows a struct/class/enum. When this warning is enabled, it also includes all instances of local shadowing. That means -Wno-shadow=local and -Wno-shadow=compatible-local are ignored when -Wshadow is used. Same as -Wshadow=global ๐Ÿ’œ
  • -Wno-shadow-ivar (Objective-C only) โ€” Don't warn when a local variable shadows an instance variable in an Objective-C method ๐Ÿ™…โ€โ™€๏ธ
  • -Wshadow=global โ€” Warns for any shadowing. Same as -Wshadow ๐ŸŒ
  • -Wshadow=local โ€” Warns when a local variable shadows another local variable or parameter ๐Ÿ 
  • -Wshadow=compatible-local โ€” Warns when a local variable shadows another local variable or parameter whose type is compatible with the type of the shadowing variable. In C++, type compatibility here means the shadowing variable's type can be converted to the shadowed variable's type ๐Ÿง . This flag exists (on top of -Wshadow=local) because when a local variable shadows another one of incompatible type, it's most likely on purpose, not a bug or typo. Here's an example:
for (SomeIterator i = SomeObj.begin(); i != SomeObj.end(); ++i)
{
  for (int i = 0; i < N; ++i)
  {
    ...
  }
  ...
}

Since the two i variables in the example above have incompatible types, enabling only -Wshadow=compatible-local doesn't 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 reduce the number of warnings triggered by intentional shadowing. Note that this also means shadowing const char *i with char *i doesn't 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. It also warns for calls to bounded functions such as memchr or strnlen that specify a bound greater than the largest possible object, which is PTRDIFF_MAX bytes by default ๐Ÿงฎ. These 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 โ€” okay so this one is bestie's personal bodyguard ๐Ÿ’– It warns you if a function's stack frame gets bigger than byte-size โœจ BUT the math used to guess the frame size is rough and not conservative, so the real needs might be a little bigger than byte-size even when you get zero warnings ๐Ÿ™ˆ Also, any space grabbed by alloca, variable-length arrays, or related constructs is NOT counted when the compiler decides whether to warn ๐Ÿ’€ -Wframe-larger-than=PTRDIFF_MAX is on by default ๐ŸŒธ To shut these warnings up, give it a byte-size of SIZE_MAX or more, or just use -Wno-frame-larger-than.
  • -Wno-frame-larger-than โ€” the lazy-girl-but-make-it-iconic option ๐Ÿ’… It turns off the -Wframe-larger-than= warnings, and it's the same thing as -Wframe-larger-than=SIZE_MAX or bigger.
  • -Wno-free-nonheap-object โ€” okay this one is giving "why is free() yelling at me" ๐Ÿ˜ญ It warns when you try to deallocate an object that either wasn't allocated on the heap, or was reached through a pointer that didn't come back from a previous call to the matching allocation function. Like, stpcpy hands you back a pointer to the terminating nul character instead of the start of your object, so calling free on it gets flagged ๐Ÿ“ Check it out:
void f (char *p)
{
  p = stpcpy (p, "abc");
  // ...
  free (p);   // warning
}

-Wfree-nonheap-object is enabled by default ๐Ÿฆ‹

  • -Wstack-usage=byte-size โ€” the stack-usage detective ๐Ÿ•ต๏ธโ€โ™€๏ธโœจ It warns if a function's stack usage might go over byte-size. This one is conservative, so it's way more careful than the frame one. Any space from alloca, variable-length arrays, or related constructs DOES get counted when it decides whether to warn ๐Ÿ‘‘

The message is totally in line with what -fstack-usage spits out ๐ŸŒˆ Here's how the vibes change:

  • If the stack usage is fully static but goes over the amount you set, it's:
warning: stack usage is 1120 bytes
  • If the stack usage is (partly) dynamic but bounded, it's:
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

-Wstack-usage=PTRDIFF_MAX is enabled by default ๐Ÿ”ฅ You can disable these warnings by giving a byte-size of SIZE_MAX or more, or by using -Wno-stack-usage.

  • -Wno-stack-usage โ€” the off switch for -Wstack-usage= warnings ๐Ÿซถ It's the same as -Wstack-usage=SIZE_MAX or larger.
  • -Wunsafe-loop-optimizations โ€” this one watches your loops ๐Ÿงš It warns if a loop can't be optimized because the compiler can't assume anything about the bounds of the loop indices. And with -funsafe-loop-optimizations turned on, it warns when the compiler makes those assumptions anyway ๐Ÿ™ˆ
  • -Wno-pedantic-ms-format (MinGW targets only) โ€” for my Windows bestie ๐ŸŽ€ When you use it together with -Wformat and -pedantic (without GNU extensions), this kills the warnings about the non-ISO printf / scanf format width specifiers I32, I64, and I that get used on Windows targets. Those depend on the MS runtime, so they're not really a crime ๐ŸŒธ
  • -Wpointer-arith โ€” warns about anything that depends on the "size of" a function type or of void ๐Ÿ‘€ GNU C gives these types a size of 1, which is super handy for math with void * pointers and pointers to functions. In C++, it also warns when an arithmetic operation involves NULL ๐Ÿ’… This warning is also enabled by -Wpedantic.
  • -Wno-pointer-compare โ€” don't warn if a pointer gets compared with a zero character constant โœจ That usually means the pointer was supposed to be dereferenced, so the comparison is kinda sus. For example:
const char *p = foo ();
if (p == '\0')
  return 42;
Heads up bestie: the code above is invalid in C++11 ๐Ÿ’€

This warning is enabled by default ๐Ÿ’–

  • -Wtsan โ€” the ThreadSanitizer check-in ๐Ÿงต It warns about features ThreadSanitizer doesn't support. Like, it doesn't support std::atomic_thread_fence, and it can report false positives, so it's giving "I can't be trusted here" ๐Ÿ˜ญ This warning is enabled by default โœจ
  • -Wtype-limits โ€” the "wait, that's literally impossible" warning ๐Ÿฆ‹ It 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 warns if an unsigned variable gets compared against zero with < or >= ๐Ÿ’œ This warning is also enabled by -Wextra.
  • -Wabsolute-value (C and Objective-C only) โ€” the "you picked the wrong math function, sis" warning ๐ŸŽ€ It warns on calls to standard functions that compute the absolute value of an argument when there's a better standard function for the job. For example, calling abs(3.14) gets flagged, because fabs is the right one for a double argument ๐ŸŒˆ It also fires when the argument in a call like that has an unsigned type. You can suppress it with an explicit type cast, and it's also enabled by -Wextra ๐Ÿซถ
  • -Wcomment, -Wcomments โ€” warns whenever a comment-start sequence /* shows up inside a /* comment, or whenever a backslash-newline shows up in a // comment ๐Ÿ™ˆ This warning is enabled by -Wall.
  • -Wtrigraphs โ€” warns if any trigraphs get encountered that might change what the program means ๐Ÿ‘‘ Trigraphs inside comments don't get warned about, except the ones that would form escaped newlines. This option is implied by -Wall. If you don't give -Wall, it's still enabled unless trigraphs are enabled. Want trigraph conversion without the warnings but still get the other -Wall warnings? Use -trigraphs -Wall -Wno-trigraphs ๐Ÿ“
  • -Wundef โ€” warns if an undefined identifier gets evaluated in an #if directive ๐Ÿงš Those identifiers get replaced with zero, so keep an eye out โœจ
  • -Wexpansion-to-defined โ€” warns whenever defined shows up in the expansion of a macro, including when the macro is expanded by an #if directive ๐Ÿ’… That usage isn't portable, so it's a major no-no. This warning is also enabled by -Wpedantic and -Wextra.
  • -Wunused-macros โ€” warns about macros that are defined in the main file but never used ๐Ÿฆ‹ A macro counts as used if it's expanded or tested for existence at least once. The preprocessor also warns if the macro hasn't been used by the time it gets redefined or undefined ๐Ÿ’œ Built-in macros, macros defined on the command line, and macros defined in include files don't get warned about.
Note: if a macro is actually used, but only inside skipped conditional blocks, the preprocessor still reports it as unused ๐Ÿ’€ To dodge the warning, you could improve the scope of the macro's definition, like moving it into the first skipped block. Or you could give it a dummy use with something like this:
#if defined the_macro_causing_the_warning
#endif
  • -Wno-endif-labels โ€” no warning when an #else or an #endif has text after it ๐ŸŒธ This happens sometimes in older programs with code like this:
#if FOO
...
#else FOO
...
#endif FOO

The second and third FOO should be in comments, bestie ๐Ÿซถ 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 aren't in ISO C90 but do show up in ISO C99 โœจ Think variable length arrays, the long long type, the bool type, compound literals, designated initializers, and so on. This option doesn't care about the standards mode. Warnings get turned off in the expression that follows __extension__.
  • -Wc99-c11-compat (C and Objective-C only) โ€” warns about features that aren't in ISO C99 but are in ISO C11 ๐Ÿฆ‹ Like anonymous structures and unions, the _Atomic type qualifier, the _Thread_local storage-class specifier, the _Alignas specifier, the Alignof operator, the _Generic keyword, and so on. Again, it doesn't care about the standards mode, and warnings are turned off in the expression that follows __extension__.
  • -Wc11-c2x-compat (C and Objective-C only) โ€” warns about features that aren't in ISO C11 but are in ISO C2X ๐Ÿ’œ For instance, omitting the string in _Static_assert, using [[]] syntax for attributes, using decimal floating-point types, and so on. It's independent of the standards mode, and warnings are disabled in the expression that follows __extension__.
  • -Wc++-compat (C and Objective-C only) โ€” warns about ISO C constructs that live outside the common subset of ISO C and ISO C++ ๐ŸŒˆ For example, requesting an implicit conversion from void * to a pointer to a non-void type.
  • -Wc++11-compat (C++ and Objective-C++ only) โ€” warns about C++ constructs whose meaning is different between ISO C++ 1998 and ISO C++ 2011 ๐Ÿงš For example, identifiers in ISO C++ 1998 that are keywords in ISO C++ 2011. This warning turns on -Wnarrowing and is enabled by -Wall.
  • -Wc++14-compat (C++ and Objective-C++ only) โ€” warns about C++ constructs whose meaning is different 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 is different 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 is different between ISO C++ 2017 and ISO C++ 2020 ๐Ÿ‘‘ This warning is enabled by -Wall.
  • -Wcast-qual โ€” warns whenever a pointer gets cast so it 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 โ€” ๐ŸŽ€ Okay so this one warns whenever a pointer cast makes the target's required alignment stricter, no matter what machine you're on. Like casting a char * to an int * is giving trouble, bestie ๐Ÿ˜ญโœจ.
  • -Wcast-function-type โ€” ๐Ÿฆ‹ This one side-eyes you when a function pointer gets cast to an incompatible function pointer type. Here's the tea ๐Ÿต:
    • When the function type has a variable argument list, only the types of the initial arguments you actually pass get checked ๐Ÿ’….
    • Any pointer-type parameter matches any other pointer-type ๐Ÿ’œ.
    • Benign integral differences get ignored, like int vs. long on ILP32 targets ๐ŸŒธ.
    • Type qualifiers get ignored too, no judgment ๐Ÿซถ.
    • The function type void (*) (void) is super special because it matches everything, so you can use it to shut this warning up ๐Ÿคซ๐Ÿ‘‘.
    • For casts involving pointer to member types, it warns whenever the cast changes the pointer to member type ๐Ÿ”ฅ.
    • This warning is enabled by -Wextra โญ.
  • -Wwrite-strings โ€” ๐Ÿ“ When you're compiling C, string constants get the type const char[length], so copying one's address into a non-const char * pointer gets flagged. This is super useful for catching code at compile time that might try to write into a string constant ๐Ÿ‘€, but only if you've been really careful with const in your declarations and prototypes. Otherwise it's just a nuisance ๐Ÿ™„, which is exactly why -Wall doesn't ask for these warnings ๐Ÿšซ. When you're compiling C++, it warns about the deprecated conversion from string literals to char * ๐Ÿ’€. This warning is enabled by default for C++ programs ๐Ÿงš.
  • -Wclobbered โ€” ๐ŸŒˆ Warns for variables that might get changed by longjmp or vfork. Also enabled by -Wextra ๐Ÿ’–.
  • -Wconversion โ€” ๐Ÿ‘‘ Warns for implicit conversions that might alter a value. That includes:
    • conversions between real and integer, like abs (x) when x is a double ๐Ÿ”ข,
    • conversions between signed and unsigned, like unsigned ui = -1 ๐Ÿ™ˆ,
    • and conversions to smaller types, like sqrtf (M_PI) ๐Ÿ“‰. It does not warn for explicit casts like abs ((int) x) and ui = (unsigned) -1, or when the value doesn't actually change, like abs (2.0) โœจ. Warnings about signed/unsigned conversions can be turned off with -Wno-sign-conversion ๐Ÿซถ. For C++, it also warns about confusing overload resolution for user-defined conversions ๐ŸŒ€, and about conversions that never use a type conversion operator: conversions to void, to the same type, to a base class, or to a reference to them ๐Ÿงš. Signed/unsigned conversion warnings are disabled by default in C++ unless you explicitly turn on -Wsign-conversion ๐Ÿ’…. Warnings about conversion from arithmetic on a small type back to that same type only show up with -Warith-conversion ๐Ÿฆ‹.
  • -Wdangling-else โ€” ๐Ÿ˜ญ Warns about constructions where it's unclear which if an else branch belongs to. Here's an example of the drama:
{
  if (a)
    if (b)
      foo ();
  else
    bar ();
}

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

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

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

  • -Wdate-time โ€” โฐ Warns when the macros __TIME__, __DATE__, or __TIMESTAMP__ show up, since they might prevent bit-wise-identical reproducible compilations ๐Ÿ”.
  • -Wempty-body โ€” ๐Ÿซฅ Warns if an empty body shows up in an if, else, or do while statement. Also enabled by -Wextra ๐ŸŒธ.
  • -Wno-endif-labels โ€” ๐Ÿ™…โ€โ™€๏ธ Tells GCC to chill and not warn about stray tokens after #else and #endif ๐Ÿ’œ.
  • -Wenum-compare โ€” ๐Ÿงฉ Warns about a comparison between values of different enumerated types. In C++, enumerated type mismatches in conditional expressions get diagnosed too, and this warning is enabled by default there ๐Ÿ’…. In C, it's enabled by -Wall โœจ.
  • -Wenum-conversion โ€” ๐Ÿ”„ Warns when a value of one enumerated type gets implicitly converted to a different enumerated type. This warning is enabled by -Wextra in C ๐ŸŒˆ.
  • -Wjump-misses-init (C, Objective-C only) โ€” ๐Ÿฆ˜ Warns if a goto or switch statement jumps forward across the initialization of a variable, or jumps backward to a label after the variable has already been initialized. It only cares about variables that are initialized when they're declared ๐ŸŽฏ. This warning is only supported for C and Objective-C. In C++, this sort of branch is an error anyway ๐Ÿ™…โ€โ™€๏ธ. -Wjump-misses-init is included in -Wc++-compat ๐Ÿ’–. You can turn it off with the -Wno-jump-misses-init option ๐Ÿซถ.
  • -Wsign-compare โ€” โš–๏ธ Warns when a comparison between signed and unsigned values could give an incorrect result because the signed value gets converted to unsigned. In C++, this warning is also enabled by -Wall ๐Ÿ’œ. In C, it's also enabled by -Wextra ๐ŸŒธ.
  • -Wsign-conversion โ€” ๐Ÿซ  Warns for implicit conversions that may change the sign of an integer value, like assigning a signed integer expression to an unsigned integer variable ๐Ÿ™ƒ. An explicit cast silences the warning ๐Ÿคซ. In C, this option is also enabled by -Wconversion ๐Ÿ”ฅ.
  • -Wfloat-conversion โ€” ๐Ÿ“ Warns for implicit conversions that reduce the precision of a real value. That includes conversions from real to integer, and from higher precision real to lower precision real values ๐Ÿ’€. This option is also enabled by -Wconversion โœจ.
  • -Wno-scalar-storage-order โ€” ๐Ÿ™ˆ Tells GCC not to warn on suspicious constructs involving reverse scalar storage order ๐Ÿ’….
  • -Wsizeof-array-div โ€” ๐Ÿงฎ Warns about divisions of two sizeof operators when the first one is applied to an array and the divisor doesn't equal the size of the array element. In that case, the computation won't give you the number of elements in the array, which is probably not what you meant ๐Ÿ˜ฌ. This warning goes off for stuff like this:
int fn ()
{
  int arr[10];
  return sizeof (arr) / sizeof (short);
}

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

  • -Wsizeof-pointer-div โ€” ๐Ÿšฉ Warns about suspicious divisions of two sizeof expressions that divide the pointer size by the element size. That's the usual way to compute an array size, but it won't work out correctly with pointers ๐Ÿ™ƒ. For example, it warns about sizeof (ptr) / sizeof (ptr[0]) if ptr is not an array but a pointer ๐Ÿง. 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. For example, it triggers on memset (ptr, 0, sizeof (ptr)); if ptr is a pointer rather than an array, and suggests a possible fix ๐Ÿ”ง. It also triggers on things like memcpy (&foo, ptr, sizeof (&foo)); ๐Ÿ˜ต. On top of that, it warns about calls to bounded string copy functions like strncat or strncpy that use a sizeof expression of the source array as the bound. In the example below, the call to strncat uses the size of the source string as its bound. That's almost certainly a mistake, so the call gets diagnosed ๐Ÿšจ.
void make_file (const char *name)
{
  char path[PATH_MAX];
  strncpy (path, name, sizeof path - 1);
  strncat (path, ".text", sizeof ".text");
  ...
}

The -Wsizeof-pointer-memaccess option is enabled by -Wall ๐ŸŒŸ.

  • -Wno-sizeof-array-argument โ€” ๐Ÿ™… Tells GCC not to warn when the sizeof operator is applied to a parameter that's declared as an array in a function definition. This warning is enabled by default for C and C++ programs ๐ŸŒธ.
  • -Wmemset-elt-size โ€” ๐Ÿช„ Warns about suspicious calls to the memset built-in function. It goes off 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 means you probably forgot to multiply by the element size ๐Ÿ“. This warning is enabled by -Wall ๐Ÿ’….
  • -Wmemset-transposed-args โ€” ๐Ÿ”€ Warns about suspicious memset calls where the second argument isn't zero and the third argument is zero ๐Ÿ˜ณ. For example, memset (buf, sizeof buf, 0) gets diagnosed, because memset (buf, 0, sizeof buf) was what was meant ๐Ÿ’ก. The diagnostic is only emitted if the third argument is a literal zero ๐Ÿ”ข. If it's an expression that folds to zero, or a cast of zero to some type, the arguments are far less likely to have been mixed up by mistake, so no warning is emitted ๐Ÿซถ. This warning is enabled by -Wall โœจ.
  • -Waddress โ€” ๐Ÿ  Warns about suspicious uses of memory addresses. These include using the address of a function in a conditional expression, like void func(void); if (func), and comparisons against the memory address of a string literal, like if (x == "abc") ๐Ÿง. These uses usually point to a programmer error. The address of a function always evaluates to true, so using it in a conditional usually means you forgot the parentheses in a function call ๐Ÿคฆโ€โ™€๏ธ. Comparisons against string literals give unspecified behavior and aren't portable in C, so they usually mean you meant to use strcmp ๐Ÿ’…. This warning is enabled by -Wall ๐ŸŽ€.
  • -Wno-address-of-packed-member โ€” ๐Ÿ“ฆ Tells GCC not to warn when the address of a packed member of a struct or union is taken, which usually results in an unaligned pointer value ๐Ÿ™ˆ. This is enabled by default ๐Ÿ’–.
  • -Wlogical-op โ€” ๐Ÿง  Warns about suspicious uses of logical operators in expressions. That includes using logical operators in contexts where a bit-wise operator is likely expected ๐Ÿ”. It also warns when the operands of a logical operator are the same:
extern int a;
if (a < 0 && a < 0) { ... }
  • -Wlogical-not-parentheses โ€” okay so this one warns when you use logical not on the left side of a comparison ๐Ÿ‘€. It stays quiet if the right operand is a boolean expression. The whole point is catching sus code like this:
int a;
...
if (!a > 1) { ... }

You can keep the warning from firing by wrapping the left side in parentheses:

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

This warning is enabled by -Wall. โœจ

  • -Waggregate-return โ€” warns if any functions that return structures or unions are defined or called. (In languages where you can return an array, this also triggers a warning ๐Ÿ’…)
  • -Wno-aggressive-loop-optimizations โ€” warns if, inside a loop with a constant number of iterations, the compiler spots undefined behavior in some statement during one or more of those iterations ๐Ÿ”ฅ
  • -Wno-attributes โ€” no warning if an unexpected __attribute__ shows up, like unrecognized attributes, function attributes slapped onto variables, etc. ๐Ÿ™ˆ This does not stop errors for incorrect use of supported attributes, so don't get it twisted.
  • -Wno-builtin-declaration-mismatch โ€” this one catches built-in functions declared with an incompatible signature, or declared as a non-function. It also warns when a built-in function declared without a prototype gets called with arguments whose promoted types don't match what the function expects. With -Wextra, it also warns when a built-in function that takes arguments is declared without a prototype. The -Wbuiltin-declaration-mismatch warning is enabled by default. To dodge it, include the right header so the built-in prototypes are in scope ๐ŸŽ€

Take memset below. The call gets flagged because the function expects a value of type size_t as its argument, but the type of 32 is int. With -Wextra, the declaration gets flagged too:

extern void* memset ();
void f (void *d)
{
  memset (d, '\0', 32);
}
  • -Wno-builtin-macro-redefined โ€” no warning if certain built-in macros get redefined. This silences the warnings for redefining __TIMESTAMP__, __TIME__, __DATE__, __FILE__, and __BASE_FILE__ ๐Ÿฆ‹
  • -Wstrict-prototypes (C and Objective-C only) โ€” warns if a function is declared or defined without specifying its argument types. (An old-style function definition gets a pass with no 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. It warns even if there's a previous prototype. A definition using () is not considered old-style in C2X mode, since it's equivalent to (void) there, but it is considered old-style for older standards ๐Ÿ’€
  • -Wmissing-parameter-type (C and Objective-C only) โ€” warns when a function parameter is declared without a type specifier in K&R-style functions:
void foo(bar) { }

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

  • -Wmissing-prototypes (C and Objective-C only) โ€” warns if a global function is defined without a previous prototype declaration. It fires even if the definition itself provides a prototype. Use this to catch global functions that don't have a matching prototype declaration in a header file. This option is not valid for C++, because all function declarations provide prototypes there, and a non-matching declaration declares an overload rather than conflicting with an earlier one. For missing declarations in C++, use -Wmissing-declarations instead ๐Ÿ“
  • -Wmissing-declarations โ€” warns if a global function is defined without a previous declaration, even if the definition itself provides a prototype. Use this to catch global functions that aren't declared in header files. In C, no warnings are issued for functions with previous non-prototype declarations, so use -Wmissing-prototypes for those. In C++, no warnings are issued for function templates, inline functions, or functions in anonymous namespaces ๐Ÿ‘‘
  • -Wmissing-field-initializers โ€” warns if a structure's initializer is missing some fields. In this example, x.h is implicitly zero, so it triggers a warning:
struct s { int f, g, h; };
struct s x = { 3, 4 };

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

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

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

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

Likewise, in C++ it 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-multichar โ€” no warning if a multicharacter constant ('FOOF') is used. These usually point to a typo in your code, since they have implementation-defined values and shouldn't be used in portable code ๐Ÿ™…โ€โ™€๏ธ
  • -Wnormalized=[none|id|nfc|nfkc] โ€” okay this one is lowkey deep ๐Ÿง  In ISO C and ISO C++, two identifiers are different if they're different sequences of characters. But when you use characters outside basic ASCII, you can end up with two different character sequences that look exactly the same. To stop that confusion, the ISO 10646 standard sets normalization rules that turn look-alike sequences into the same sequence. GCC can warn you if your identifiers haven't been normalized, and this option controls that warning.

There are four levels:

  • The default is -Wnormalized=nfc, which warns about any identifier that isn't in the ISO 10646 "C" normalized form, NFC. NFC is the recommended form for most uses. It's equivalent to -Wnormalized.
  • Some characters allowed in identifiers by ISO C and ISO C++ stop being allowed once they're turned into NFC. So there's no way to use these symbols in portable ISO C or C++ and keep all your identifiers in NFC. -Wnormalized=id suppresses the warning for these characters. Future versions of the standards may fix this, which is why this isn't the default.
  • You can switch the warning off for all characters with -Wnormalized=none or -Wno-normalized. Only do this if you're using some other normalization scheme (like "D"), because otherwise you can easily create bugs that are literally impossible to see ๐Ÿ˜ญ
  • -Wnormalized=nfkc goes further. Some characters in ISO 10646 have distinct meanings but look identical in some fonts or display methods, especially once formatting is applied. For instance, "\u207F" (SUPERSCRIPT LATIN SMALL LETTER N) displays just like a regular "n" placed in a superscript. ISO 10646 defines the NFKC normalization scheme to convert all of these into a standard form too, and GCC warns if your code isn't in NFKC when you use -Wnormalized=nfkc. This warning is comparable to warning about every identifier that contains the letter O because it might be confused with the digit 0. So it isn't the default, but it can be a useful local coding convention if your programming environment can't be fixed to display these characters distinctly ๐ŸŒˆ
  • -Wno-attribute-warning โ€” no warning about using functions declared with the warning attribute. By default this warning is enabled. Use -Wno-attribute-warning to disable the warning, or -Wno-error=attribute-warning to disable the error when compiling with the -Werror flag ๐Ÿซถ
  • -Wno-deprecated โ€” no warning about using deprecated features ๐Ÿฅ€
  • -Wno-deprecated-declarations โ€” no warning about uses of functions, variables, and types marked as deprecated with the deprecated attribute ๐Ÿ’…
  • -Wno-overflow โ€” no warning about compile-time overflow in constant expressions โœจ
  • -Wno-odr โ€” warns about One Definition Rule violations during link-time optimization. Enabled by default. Yes, the name says -Wno-, but it's the warning itself ๐Ÿ˜ญ iykyk
  • -Wopenmp-simd โ€” warns if the vectorizer cost model overrides the OpenMP simd directive set by the user. The -fsimd-cost-model=unlimited option can be used to relax the cost model ๐ŸŒธ
  • -Woverride-init (C and Objective-C only) โ€” warns if an initialized field without side effects gets overridden when using designated initializers.

This warning is included in -Wextra. To get the other -Wextra warnings without this one, use -Wextra -Wno-override-init ๐Ÿงš

  • -Wno-override-init-side-effects (C and Objective-C only) โ€” no warning if an initialized field with side effects gets overridden when using designated initializers. This warning is enabled by default ๐ŸŽ€
  • -Wpacked โ€” warns if a structure is given the packed attribute, but that attribute has no effect on the layout or size of the structure. These structures may end up misaligned for little benefit. For instance, in this code, the variable f.x in struct bar is misaligned, even though struct bar doesn't itself have the packed attribute ๐Ÿ’€
struct foo {
  int x;
  char a, b, c, d;
} __attribute__((packed));
struct bar {
  char z;
  struct foo f;
};
  • -Wnopacked-bitfield-compat โ€” okay so the 4.1, 4.2, and 4.3 series of GCC just ignored the packed attribute on char bit-fields ๐Ÿ’€. That got fixed in GCC 4.4, but the fix can shift your struct layout around, so GCC will tell you when the offset of one of these fields changes ๐Ÿซถ. Like in this struct, the 4-bit padding between a and b is just gone now โœจ:
struct foo
{
  char a:4;
  char b:8;
} __attribute__ ((packed));

This one is on by default ๐ŸŒธ. If you want it quiet, use -Wno-packed-bitfield-compat to shush it ๐Ÿคซ.

  • -Wpacked-not-aligned (C, C++, Objective-C and Objective-C++ only) โ€” this one warns you if a struct field has an explicitly set alignment inside a packed struct or union, and that field ends up misaligned ๐Ÿ™ˆ. Like, you'll get warning: alignment 1 of 'struct S' is less than 8 for this code ๐Ÿ‘€:
struct __attribute__ ((aligned (8))) S8 { char a[8]; };
struct __attribute__ ((packed)) S {
  struct S8 s8;
};

It's enabled by -Wall ๐Ÿ’….

  • -Wpadded โ€” warns when padding gets slipped into a struct, whether that's to line up one element or to line up the whole struct ๐Ÿงš. Sometimes you can shuffle the fields around to cut down on the padding and make the struct smaller, which is literally the dream ๐Ÿ“.
  • -Wredundant-decls โ€” warns if something gets declared more than once in the same scope. This happens even when multiple declarations are allowed and don't change anything, so it's giving "why are you doing this" energy ๐Ÿ’€๐Ÿ’œ.
  • -Wrestrict โ€” warns when an object that a restrict-qualified parameter points to (or a __restrict-qualified one in C++) gets aliased by another argument, or when copies between those objects overlap ๐Ÿšจ. Check out this strcpy call, which tries to chop the string by overwriting its start with its last four characters. Because it 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 can catch some simple overlap even without optimization, but it works best at -O2 and above โญ. It's included in -Wall โœจ.

  • -Wnested-externs (C and Objective-C only) โ€” warns if an extern declaration shows up inside a function ๐Ÿ™…โ€โ™€๏ธ.
  • -Winline โ€” warns if a function declared as inline can't actually be inlined ๐Ÿฆ‹. Even with this on, the compiler won't warn about failed inlining for functions in system headers ๐Ÿค. GCC uses a bunch of heuristics to decide whether to inline something, like how big the function is and how much inlining has already happened in the current function ๐Ÿง . So tiny changes in your source can make -Winline warnings show up or disappear, which is chaotic but iykyk ๐ŸŒ€.
  • -Wint-in-bool-context โ€” warns about sketchy uses of integer values where booleans are expected ๐Ÿ‘€. Examples are conditional expressions (?:) with non-boolean integer constants in a boolean context, like if (a <= b ? 2 : 3), or left-shifting signed integers in a boolean context, like for (a = 0; 1 << a; a++);. It also covers all kinds of multiplications, no matter the data type ๐Ÿ’–. This warning is enabled by -Wall ๐ŸŽ€.
  • -Wno-int-to-pointer-cast โ€” suppresses warnings for casts to a pointer type from an integer of a different size ๐Ÿ™ˆ. In C++, casting to a pointer type of smaller size is an error, so this one is not a vibe ๐Ÿšซ. The Wint-to-pointer-cast warning is enabled by default ๐Ÿ‘.
  • -Wno-pointer-to-int-cast (C and Objective-C only) โ€” suppresses warnings for casts from a pointer to an integer type of a different size ๐ŸŒˆ.
  • -Winvalid-pch โ€” warns if a precompiled header shows up in the search path but can't be used ๐Ÿ’€.
  • -Wlong-long โ€” warns if the long long type gets used ๐Ÿ“ฃ. This is enabled by either -Wpedantic or -Wtraditional in ISO C90 and C++98 modes. To make the warning messages go away, use -Wno-long-long ๐Ÿซง.
  • -Wvariadic-macros โ€” warns if variadic macros are used in ISO C90 mode, or if the GNU alternate syntax is used in ISO C99 mode ๐ŸŒธ. This is enabled by either -Wpedantic or -Wtraditional. To silence it, use -Wno-variadic-macros ๐Ÿคซ.
  • -Wno-varargs โ€” tells GCC to stop warning about questionable usage of the macros that handle variable arguments, like va_start ๐Ÿงš. These warnings are enabled by default, so this is the opt-out ๐Ÿฆ‹.
  • -Wvector-operation-performance โ€” warns if a vector operation isn't implemented using the SIMD capabilities of the architecture ๐Ÿ”ฅ. It's mainly useful for performance tuning ๐Ÿ“ˆ. A vector operation can be done three ways: "piecewise", meaning the scalar operation runs on every vector element; "in parallel", meaning it's implemented with scalars of a wider type, which is usually more performance efficient; and "as a single scalar", meaning the vector fits into a scalar type ๐Ÿ’….
  • -Wvla โ€” warns if a variable-length array shows up in the code ๐Ÿ“. -Wno-vla stops the -Wpedantic warning about variable-length arrays ๐Ÿ™…โ€โ™€๏ธ.
  • -Wvla-larger-than=byte-size โ€” if you use this, GCC warns about variable-length array declarations whose size is either unbounded, or bounded by an argument that lets the array exceed byte-size bytes ๐Ÿ“. It works like -Walloca-larger-than=byte-size, just for variable-length arrays ๐ŸŽ€. Heads up though, GCC may optimize small variable-length arrays of a known value into plain arrays, so this warning might not trigger for those ๐Ÿ™ˆ. -Wvla-larger-than=PTRDIFF_MAX is enabled by default but usually only does anything when -ftree-vrp is active, which is the default for -O2 and above ๐ŸŒŸ. See also -Walloca-larger-than=byte-size ๐Ÿ”—.
  • -Wno-vla-larger-than โ€” disables the -Wvla-larger-than= warnings ๐Ÿ™…. It's the same as -Wvla-larger-than=SIZE_MAX or larger ๐Ÿ’œ.
  • -Wvla-parameter โ€” warns about redeclarations of functions that have arguments of Variable Length Array types with inconsistent kinds or forms ๐Ÿ“. It also turns on detection of out-of-bounds accesses to those parameters through warnings like -Warray-bounds ๐Ÿ‘‘. If the first function declaration uses the VLA form, the bound in the array is assumed to be the minimum number of elements expected in calls to the function, and also the maximum number of elements it accesses ๐Ÿง . If you don't pass enough elements, or it accesses more than that maximum, you may get a diagnostic ๐Ÿ’€.

In this example, the warning triggers on those redeclarations because the first one lets any size of array get passed to f, while the second one says the array argument must have at least n elements. Calling f with the associated VLA bound parameter larger than the actual VLA bound also triggers a warning ๐Ÿ˜ญ:

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

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

-Wvla-parameter is included in -Wall ๐Ÿ’–. The -Warray-parameter option does the same kind of thing for regular array arguments ๐Ÿฆ‹.

  • -Wvolatile-register-var โ€” warns if a register variable is declared volatile ๐Ÿ™…โ€โ™€๏ธ. The volatile modifier doesn't stop every optimization that might eliminate reads or writes to register variables, so it's not the safety net you think it is ๐Ÿซ . This warning is enabled by -Wall ๐ŸŽ€.
  • -Wdisabled-optimization โ€” warns if a requested optimization pass gets disabled ๐Ÿ› ๏ธ. This doesn't usually mean your code is wrong, just that GCC's optimizers can't handle it effectively ๐Ÿคทโ€โ™€๏ธ. Often the issue is that your code is too big or too complex, and GCC refuses to optimize programs when the optimization would likely take an absurd amount of time ๐Ÿข.
  • -Wpointer-sign (C and Objective-C only) โ€” warns for pointer argument passing or assignment with different signedness ๐Ÿง. This option is only supported for C and Objective-C. It's implied by -Wall and by -Wpedantic, and you can turn it off with -Wno-pointer-sign ๐Ÿ™….
  • -Wstack-protector โ€” this one is only active when -fstack-protector is active ๐Ÿ›ก๏ธ. It warns about functions that aren't protected against stack smashing ๐Ÿ˜ฑ.
  • -Woverlength-strings โ€” warns about string constants longer than the "minimum maximum" length the C standard specifies ๐Ÿ“œ. Modern compilers usually allow string constants way longer than that minimum, but very portable programs should 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 raised to 4095 ๐Ÿ“ˆ. C++98 doesn't specify a normative minimum maximum, so GCC doesn't diagnose overlength strings in C++ ๐Ÿ™Œ. This option is implied by -Wpedantic, and you can disable it with -Wno-overlength-strings ๐Ÿซถ.
  • -Wunsuffixed-float-constants (C and Objective-C only) โ€” warns about any floating constant that doesn't have a suffix ๐Ÿ”ข. When you use it together with -Wsystem-headers, it also warns about those constants in system header files ๐Ÿงพ. This is super useful when you're prepping code to use with the FLOAT_CONST_DECIMAL64 pragma from the decimal floating-point extension to C99 ๐Ÿ’œ.
  • -Wno-lto-type-mismatch โ€” during link-time optimization, this stops GCC from warning about type mismatches in global declarations from different compilation units ๐Ÿ”—. It requires -flto to be enabled ๐ŸŽฌ. Enabled by default ๐Ÿ‘.
  • -Wno-designated-init (C and Objective-C only) โ€” suppresses warnings when a positional initializer is used to initialize a struct that's been marked with the designated_init attribute ๐Ÿ™ˆ.

โœจ Options That Control Static Analysis โœจ

  • -fanalyzer โ€” enables a static analysis of program flow ๐Ÿ”. It looks for "interesting" interprocedural paths through the code, and issues warnings for problems it finds on them ๐Ÿ•ต๏ธโ€โ™€๏ธ๐Ÿ‘‘.

This analysis is lowkey expensive compared to other GCC warnings, so heads up ๐Ÿ’ธ๐Ÿ™ˆ

Turning this on also switches on all of these warnings ๐Ÿ‘‘:

  • -Wanalyzer-double-fclose
  • -Wanalyzer-double-free
  • -Wanalyzer-exposure-through-output-file
  • -Wanalyzer-file-leak
  • -Wanalyzer-free-of-non-heap
  • -Wanalyzer-malloc-leak
  • -Wanalyzer-mismatching-deallocation
  • -Wanalyzer-possible-null-argument
  • -Wanalyzer-possible-null-dereference
  • -Wanalyzer-null-argument
  • -Wanalyzer-null-dereference
  • -Wanalyzer-shift-count-negative
  • -Wanalyzer-shift-count-overflow
  • -Wanalyzer-stale-setjmp-buffer
  • -Wanalyzer-tainted-array-index
  • -Wanalyzer-unsafe-call-within-signal-handler
  • -Wanalyzer-use-after-free
  • -Wanalyzer-use-of-pointer-in-stale-stack-frame
  • -Wanalyzer-write-to-const
  • -Wanalyzer-write-to-string-literal

This only works if GCC was configured with analyzer support enabled ๐Ÿซถ


-Wanalyzer-too-complex

When -fanalyzer is on, the analyzer uses a bunch of heuristics to poke around the control flow and data flow in your program. Honestly though, sufficiently complicated code can totally outsmart it ๐Ÿ˜ญ

By default, the analysis quietly gives up if the code is too complicated and it hits an internal limit. -Wanalyzer-too-complex is the one that actually warns you when that happens โœจ


-Wno-analyzer-double-fclose

This one needs -fanalyzer to turn it on, and you can use -Wno-analyzer-double-fclose to turn it off ๐Ÿ’…

It warns about code paths where a FILE * can have fclose called on it more than once.

-Wno-analyzer-double-free

This one needs -fanalyzer to turn it on, and -Wno-analyzer-double-free turns it off ๐Ÿฆ‹

It warns about code paths where a pointer can have a deallocator called on it more than once. That deallocator is either free, or one referenced by attribute malloc.

-Wno-analyzer-exposure-through-output-file

This one needs -fanalyzer to turn it on, and -Wno-analyzer-exposure-through-output-file turns it off ๐Ÿ”

It warns about code paths where a security-sensitive value gets written to an output file, like writing a password to a log file. Yikes ๐Ÿ™ˆ

-Wno-analyzer-file-leak

This one needs -fanalyzer to turn it on, and -Wno-analyzer-file-leak turns it off ๐ŸŒธ

It warns about code paths where a FILE * stream object from <stdio.h> gets leaked.

-Wno-analyzer-free-of-non-heap

This one needs -fanalyzer to turn it on, and -Wno-analyzer-free-of-non-heap turns it off ๐Ÿงš

It warns about code paths where free gets called on a non-heap pointer. For example, an on-stack buffer or a global.

-Wno-analyzer-malloc-leak

This one needs -fanalyzer to turn it on, and -Wno-analyzer-malloc-leak turns it off ๐Ÿ’ง

It warns about code paths where a pointer allocated through an allocator gets leaked. The allocator is either malloc, or a function marked with attribute malloc.

-Wno-analyzer-mismatching-deallocation

This one needs -fanalyzer to turn it on, and -Wno-analyzer-mismatching-deallocation turns it off ๐Ÿ“

It warns about code paths where the wrong deallocation function gets called on a pointer value. The check depends on which function allocated that pointer in the first place. It'll flag mismatches between free, scalar delete, and vector delete[], plus anything marked as an allocator/deallocator pair using attribute malloc.

-Wno-analyzer-possible-null-argument

This one needs -fanalyzer to turn it on, and -Wno-analyzer-possible-null-argument turns it off ๐ŸŽ€

It warns about code paths where a possibly-NULL value gets passed to a function argument marked with __attribute__((nonnull)), which means that argument needs a non-NULL value.

-Wno-analyzer-possible-null-dereference

This one needs -fanalyzer to turn it on, and -Wno-analyzer-possible-null-dereference turns it off ๐Ÿซง

It warns about code paths where a possibly-NULL value gets dereferenced.

-Wno-analyzer-null-argument

This one needs -fanalyzer to turn it on, and -Wno-analyzer-null-argument turns it off ๐Ÿšซ

It warns about code paths where a value known to be NULL gets passed to a function argument marked with __attribute__((nonnull)), which needs a non-NULL value.

-Wno-analyzer-null-dereference

This one needs -fanalyzer to turn it on, and -Wno-analyzer-null-dereference turns it off ๐Ÿ’–

It warns about code paths where a value known to be NULL gets dereferenced.

-Wno-analyzer-shift-count-negative

This one needs -fanalyzer to turn it on, and -Wno-analyzer-shift-count-negative turns it off ๐ŸŒˆ

It warns about code paths where a shift is attempted with a negative count. It's the analyzer's cousin of -Wshift-count-negative, which lives in the C/C++ front ends. The difference is that this one works by analyzing interprocedural paths instead of just parsing the syntax tree. Still, the analyzer doesn't prioritize catching these, so false negatives are more likely compared to other warnings ๐Ÿฅฒ

-Wno-analyzer-shift-count-overflow

This one needs -fanalyzer to turn it on, and -Wno-analyzer-shift-count-overflow turns it off โญ

It warns about code paths where a shift is attempted with a count greater than or equal to the precision of the operand's type. It's analogous to -Wshift-count-overflow in the C/C++ front ends, but it's based on analyzing interprocedural paths rather than merely parsing the syntax tree. The analyzer doesn't prioritize detecting these paths, so false negatives are more likely relative to other warnings.

-Wno-analyzer-stale-setjmp-buffer

This one needs -fanalyzer to turn it on, and -Wno-analyzer-stale-setjmp-buffer turns it off ๐Ÿงธ

It warns about code paths where longjmp is called to rewind to a jmp_buf tied to a setjmp call in a function that has already returned.

Here's the tea: when setjmp is called on a jmp_buf to record a rewind location, it records the stack frame. That stack frame becomes invalid once the function containing the setjmp call returns. Trying to rewind to it via longjmp would reference a stack frame that no longer exists, and that's likely to lead to a crash (or worse) ๐Ÿ’€

Rewinding with longjmp into a stale stack frame can lead to a crash (or worse). Don't do it bestie ๐Ÿ™…โ€โ™€๏ธ

-Wno-analyzer-tainted-array-index

This warning needs both -fanalyzer and -fanalyzer-checker=taint to turn it on. Use -Wno-analyzer-tainted-array-index to turn it off ๐Ÿ›ก๏ธ

It warns about code paths where a value that could be under an attacker's control gets used as the index of an array access without being sanitized.

-Wno-analyzer-unsafe-call-within-signal-handler

This one needs -fanalyzer to turn it on, and -Wno-analyzer-unsafe-call-within-signal-handler turns it off ๐Ÿšจ

It warns about code paths where a function known to be async-signal-unsafe (like fprintf) gets called from a signal handler.

-Wno-analyzer-use-after-free

This one needs -fanalyzer to turn it on, and -Wno-analyzer-use-after-free turns it off ๐Ÿ—‘๏ธ

It warns about code paths where a pointer gets used after a deallocator has been called on it. That deallocator is either free, or one referenced by attribute malloc.

-Wno-analyzer-use-of-pointer-in-stale-stack-frame

This one needs -fanalyzer to turn it on, and -Wno-analyzer-use-of-pointer-in-stale-stack-frame turns it off ๐Ÿ•ฐ๏ธ

It warns about code paths where a pointer gets dereferenced while pointing to a variable in a stale stack frame.

-Wno-analyzer-write-to-const

This one needs -fanalyzer to turn it on, and -Wno-analyzer-write-to-const turns it off ๐Ÿ”’

It warns about code paths where the analyzer detects an attempt to write through a pointer to a const object. The analyzer doesn't prioritize catching these, so false negatives are more likely relative to other warnings.

-Wno-analyzer-write-to-string-literal

This one needs -fanalyzer to turn it on, and -Wno-analyzer-write-to-string-literal turns it off ๐Ÿ“œ

It warns about code paths where the analyzer detects an attempt to write through a pointer to a string literal. Same deal: the analyzer doesn't prioritize these, so false negatives are more likely relative to other warnings.


Pertinent parameters for controlling the exploration are these four โœจ:

  • --param analyzer-bb-explosion-factor=value
  • --param analyzer-max-enodes-per-program-point=value
  • --param analyzer-max-recursion-depth=value
  • --param analyzer-min-snodes-for-call-summary=value

The following options control the analyzer ๐Ÿ’…

-fanalyzer-call-summaries

This one simplifies interprocedural analysis by computing the effect of certain calls, instead of exploring every path through the function from the callsite to each possible return. Iconic efficiency ๐Ÿง 

If it's enabled, call summaries only get used for functions with more than one call site, and that are sufficiently complicated (as per --param analyzer-min-snodes-for-call-summary=value).

-fanalyzer-checker=name

This one restricts the analyzer to run just the named checker, and enables it ๐ŸŽฏ

Some checkers are disabled by default, even with -fanalyzer. The taint checker is one of them. It's the one that implements -Wanalyzer-tainted-array-index, and you need this option to turn it on.

-fno-analyzer-feasibility

This option is intended for analyzer developers ๐Ÿง‘โ€๐Ÿ’ป

By default, the analyzer checks that there's a feasible control flow path for each diagnostic it emits. In other words, the conditions that hold can't be mutually exclusive. Diagnostics with no feasible path get rejected. You can suppress this filtering with -fno-analyzer-feasibility, which is handy for debugging issues in this code ๐Ÿ”ง

-fanalyzer-fine-grained

This option is intended for analyzer developers ๐Ÿง‘โ€๐Ÿ’ป

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

By default, an edge in this graph can hold the effects of a whole run of statements inside one basic block ๐Ÿง . With -fanalyzer-fine-grained, every single statement gets its own edge ๐Ÿ” (so much more detail, no cap).

  • -fanalyzer-show-duplicate-count โ€” ๐Ÿ‘ฏ Dev-only vibes! If a bunch of diagnostics get flagged as duplicates of each other, GCC drops a note on the best one saying how many extra diagnostics the dedup logic quietly suppressed ๐Ÿคซ.
  • -fno-analyzer-state-merge โ€” ๐Ÿซ  Dev-only! By default the analyzer keeps things simple by merging states that are similar enough at each program point while it builds the "exploded graph." With -fno-analyzer-state-merge, that merging gets switched off so you can debug state-handling issues ๐Ÿ”ง.
  • -fno-analyzer-state-purge โ€” ๐Ÿงน Dev-only! Normally the analyzer tidies up by purging bits of state at a program point that seem irrelevant anymore, like the values of locals that never get touched later in the function and don't matter for leak analysis. With -fno-analyzer-state-purge, that purging is suppressed, which is handy for debugging state-handling issues ๐Ÿ™ˆ.
  • -fanalyzer-transitivity โ€” ๐Ÿ”— Enables transitivity of constraints within the analyzer.
  • -fanalyzer-verbose-edges โ€” ๐Ÿ“œ Dev-only! Turns on more verbose, lower-level detail in the descriptions of control flow inside diagnostic paths.
  • -fanalyzer-verbose-state-changes โ€” ๐ŸŽข Dev-only! Turns on more verbose, lower-level detail in the descriptions of state machine events inside diagnostic paths.
  • -fanalyzer-verbosity=level โ€” ๐ŸŽš๏ธ Controls how complex the control flow paths are that get emitted for analyzer diagnostics. The level can be one of:
    • 0 โ€” ๐Ÿ“ž Shows interprocedural call and return events, plus the most pertinent state-change events for a diagnostic. For example, for a double-"free" diagnostic, both calls to free get shown.
    • 1 โ€” ๐Ÿšช Same as level 0, but also shows events for the entry to each function.
    • 2 โ€” ๐ŸŒŸ Same as level 1, but also shows control flow events that are significant to triggering the issue (like "true path taken" at a conditional). This is the default!
    • 3 โ€” ๐ŸŒŠ Same as level 2, but shows all control flow events, not just the significant ones.
    • 4 โ€” ๐Ÿงช Dev-only! Adds various other events meant for debugging the analyzer.
  • -fdump-analyzer โ€” ๐Ÿ—‚๏ธ Dumps internal details about what the analyzer is doing to file.analyzer.txt. This option gets overridden by -fdump-analyzer-stderr.
  • -fdump-analyzer-stderr โ€” ๐Ÿ–ฅ๏ธ Dumps internal details about what the analyzer is doing to stderr. This option overrides -fdump-analyzer.
  • -fdump-analyzer-callgraph โ€” ๐ŸŒณ Dumps a representation of the call graph that's suitable for viewing with GraphViz to file.callgraph.dot.
  • -fdump-analyzer-exploded-graph โ€” ๐ŸŽจ Dumps a representation of the "exploded graph" suitable for viewing with GraphViz to file.eg.dot. The nodes are color-coded based on state-machine states so state changes pop out ๐Ÿ’–.
  • -fdump-analyzer-exploded-nodes โ€” ๐Ÿ“ Emits diagnostics showing where nodes in the "exploded graph" sit in relation to the program source.
  • -fdump-analyzer-exploded-nodes-2 โ€” ๐Ÿ“ Dumps a textual representation of the "exploded graph" to file.eg.txt.
  • -fdump-analyzer-exploded-nodes-3 โ€” ๐Ÿ“š Dumps a textual representation of the "exploded graph" with one dump file per node, named file.eg-id.txt. Heads up, this is typically a large number of dump files ๐Ÿ˜ญ.
  • -fdump-analyzer-feasibility โ€” ๐Ÿ”Ž Dumps internal details about the analyzer's search for feasible paths. The details are written in a form suitable for viewing with 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. The precise format is subject to change, so don't build your whole life around it ๐Ÿซถ.
  • -fdump-analyzer-state-purge โ€” ๐Ÿ—บ๏ธ Same vibe as -fdump-analyzer-supergraph: dumps a "supergraph" representation suitable for GraphViz, but annotates the graph with info on what state will be purged at each node. The graph gets written to file.state-purge.dot.
  • -fdump-analyzer-supergraph โ€” ๐Ÿ•ธ๏ธ Dumps representations of the "supergraph" suitable for GraphViz to file.supergraph.dot and to file.supergraph-eg.dot. These show all of the control flow graphs in the program, with interprocedural edges for calls and returns. The second dump has annotations showing nodes in the "exploded graph" and any diagnostics tied to them ๐Ÿ’œ.

๐Ÿ› Options for Debugging Your Program

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

GCC lets you use -g with -O too ๐Ÿ”ฅ. Fair warning though, the shortcuts optimized code takes can be lowkey 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 execute in different places because they got moved out of loops. Even so, it's totally possible to debug optimized output โœจ. That makes it reasonable to use the optimizer for programs that might have bugs.

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

  • -g โ€” ๐ŸŒธ Produces debugging information in the operating system's native format (stabs, COFF, XCOFF, or DWARF). GDB can work with this debugging information.
    • On most systems that use stabs format, -g turns on extra debugging info that only GDB can use. That makes debugging better in GDB but probably makes other debuggers crash or refuse to read the program ๐Ÿ’€. If you want to be certain whether the extra info gets generated, use -gstabs+, -gstabs, -gxcoff+, -gxcoff, or -gvms (see below).
  • -ggdb โ€” ๐Ÿงธ Produces debugging information for use by GDB. This means using the most expressive format available (DWARF, stabs, or the native format if neither of those are supported), including GDB extensions if at all possible ๐Ÿ‘‘.
  • -gdwarf, -gdwarf-version โ€” ๐Ÿฆ‹ Produces debugging information in DWARF format (if that's supported). The value of version can be 2, 3, 4 or 5. The default version for most targets is 5, except VxWorks, TPF and Darwin/Mac OS X, which default to version 2, and AIX, which defaults to version 4.
    • With DWARF Version 2, some ports require and always use some non-conflicting DWARF 3 extensions in the unwind tables.
    • Version 4 may require GDB 7.0 and -fvar-tracking-assignments for maximum benefit. Version 5 requires GDB 8.0 or higher.
    • GCC no longer supports DWARF Version 1, which is substantially different from Version 2 and later. For historical reasons, some other DWARF-related options such as -fno-dwarf2-cfi-asm) keep a reference to DWARF Version 2 in their names, but they apply to all currently-supported versions of DWARF ๐Ÿฅน.
  • -gstabs โ€” ๐Ÿง Produces debugging information in stabs format (if that's supported), without GDB extensions. This is the format DBX uses on most BSD systems. On MIPS, Alpha and System V Release 4 systems, this option produces stabs debugging output that DBX doesn't understand. On System V Release 4 systems, this option requires the GNU assembler.
  • -gstabs+ โ€” ๐Ÿงƒ Produces debugging information in stabs format (if that's supported), using GNU extensions that only the GNU debugger (GDB) understands.
โš ๏ธ Using these extensions is likely to make other debuggers crash or refuse to read the program.
  • -gxcoff โ€” ๐ŸŽ‹ Produces debugging information in XCOFF format (if that's supported). This is the format DBX uses on IBM RS/6000 systems.
  • -gxcoff+ โ€” ๐Ÿญ Produces debugging information in XCOFF format (if that's supported), using GNU extensions that only the GNU debugger (GDB) understands.
โš ๏ธ Using these extensions is likely to make other debuggers crash or refuse to read the program, and may cause assemblers other than the GNU assembler (GAS) to fail with an error.
  • -gvms โ€” ๐Ÿ›ธ Produces debugging information in Alpha/VMS debug format (if that's supported). This is the format DEBUG uses on Alpha/VMS systems.
  • -glevel, -ggdblevel, -gstabslevel, -gxcofflevel, -gvmslevel โ€” ๐ŸŽš๏ธ Requests debugging information and also uses level to decide how much info you get. The default level is 2.
    • Level 0 produces no debug information at all. So -g0 negates -g ๐Ÿ™….
    • Level 1 produces minimal information, enough for making backtraces in parts of the program you don't plan to debug. This includes descriptions of functions and external variables, and line number tables, but no information about local variables.
    • Level 3 includes extra information, 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's effective ๐Ÿซถ.
    • -gdwarf doesn't accept a concatenated debug level, to avoid confusion with -gdwarf-level. Instead, use an additional -glevel option to change the debug level for DWARF.
  • -fno-eliminate-unused-debug-symbols โ€” ๐Ÿงน By default, no debug information is produced for symbols that aren't actually used. Use this option if you want debug information for all symbols ๐ŸŒˆ.
  • -femit-class-debug-always: okay so instead of dropping the debug info for a C++ class into just one object file, this one puts it in every object file that uses the class ๐Ÿ’…. Only reach for it if your debugger literally can't handle the normal way GCC emits class debug info ๐Ÿ˜ญ, because it can make the debug info up to a factor of two bigger ๐Ÿซ .
  • -fno-merge-debug-strings: tells the linker to NOT squish together identical strings in the debug info across different object files ๐Ÿ™…โ€โ™€๏ธ. Not every assembler or linker can merge, btw. Merging shrinks the output's debug info but makes linking take longer โณ. Merging is on by default โœจ.
  • -fdebug-prefix-map=old=new: when you compile files that live in directory old, the debug info will describe them as if they lived in new instead ๐Ÿ—บ๏ธ. Use it to swap a build-time path for an install-time path, or turn an absolute path into a relative one by using . as new. It can give more reproducible, location-independent builds ๐ŸŒธ, but you might need an extra command to tell GDB where the source files are ๐Ÿ”. See also -ffile-prefix-map.
  • -fvar-tracking: runs the variable tracking pass ๐Ÿ•ต๏ธโ€โ™€๏ธ, which figures out where variables are stored at each position in the code. The result is better debug info, as long as your debug format supports it ๐Ÿ’–. It's enabled by default when you optimize (-Os, -O, -O2, ...) and have debug info (-g) and the format supports it.
  • -fvar-tracking-assignments: annotates assignments to user variables early in compilation and tries to carry those annotations all the way to the end ๐ŸŽ€, all to improve debug info while optimizing. Using -gdwarf-4 alongside it is recommended. It can be enabled even if var-tracking is disabled, in which case the annotations get created and maintained but tossed at the end. By default this is enabled together with -fvar-tracking, except when selective scheduling is enabled.
  • -gsplit-dwarf: if DWARF debug info is enabled, it shoves as much of that info as possible into a separate output file with the extension .dwo ๐Ÿ“ฆ. This lets the build system skip linking files that have debug info ๐Ÿ™Œ. To be useful, you need a debugger that can read .dwo files.
  • -gdwarf32, -gdwarf64: if DWARF debug info is enabled, -gdwarf32 picks the 32-bit DWARF format and -gdwarf64 picks the 64-bit one ๐Ÿงฎ. The default is target specific, though on most targets it's -gdwarf32 ๐Ÿคทโ€โ™€๏ธ. The 32-bit format is smaller but can't support more than 2GiB of debug info in any of the DWARF debug info sections ๐Ÿ˜ฌ. The 64-bit format allows larger debug info, but not all consumers support it well yet.
  • -gdescribe-dies: adds description attributes to some DWARF DIEs that have no name attribute, like artificial variables, external references, and call site parameter DIEs ๐Ÿงš.
  • -gpubnames: generates the DWARF .debug_pubnames and .debug_pubtypes sections ๐Ÿ“š.
  • -ggnu-pubnames: generates .debug_pubnames and .debug_pubtypes in a format that's suitable for converting into a GDB index ๐Ÿ”ฅ. This is only useful with a linker that can produce GDB index version 7.
  • -fdebug-types-section: when using DWARF Version 4 or higher, type DIEs can get their own .debug_types section instead of living in .debug_info ๐Ÿ—‚๏ธ. It's more efficient to put them in a separate comdat section, since the linker can then remove duplicates. BUT not all DWARF consumers support .debug_types yet, and on some objects it actually produces larger debug info instead of smaller ๐Ÿ’€.
  • -grecord-gcc-switches, -gno-record-gcc-switches: the command-line options used to invoke the compiler that may affect code generation get appended to the DW_AT_producer attribute in DWARF debug info ๐Ÿ“. The options are joined with spaces, separating them from each other and from the compiler version. It's enabled by default. See also -frecord-gcc-switches for another way to store compiler options in the object file.
  • -gstrict-dwarf: disallows using extensions from a later DWARF standard version than the one picked with -gdwarf-version ๐Ÿšซ. On most targets, though, using non-conflicting DWARF extensions from later standard versions is allowed anyway.
  • -gno-strict-dwarf: allows using extensions from a later DWARF standard version than the one selected with -gdwarf-version ๐Ÿฆ‹.
  • -gas-loc-support: tells the compiler that the assembler supports .loc directives, so it may use them to have the assembler generate DWARF2+ line number tables ๐Ÿ“. This is generally desirable, because assembler-generated line-number tables are a lot more compact than the ones the compiler can make itself. It's enabled by default if, at GCC configure time, the assembler was found to support these directives.
  • -gno-as-loc-support: forces GCC to generate DWARF2+ line number tables internally, if DWARF2+ line number tables are to be generated at all ๐Ÿ™…โ€โ™€๏ธ.
  • -gas-locview-support: tells the compiler that the assembler supports "view" assignment and reset assertion checking in .loc directives ๐Ÿ‘€. It's enabled by default if, at GCC configure time, the assembler was found to support them.
  • -gno-as-locview-support: forces GCC to assign view numbers internally, if -gvariable-location-views is explicitly requested ๐Ÿ”ง.
  • -gcolumn-info, -gno-column-info: emits location column info into DWARF debug info, instead of just file and line ๐Ÿ“. This option is enabled by default.
  • -gstatement-frontiers, -gno-statement-frontiers: makes GCC create markers in the internal representation at the beginning of statements, keep them roughly in place throughout compilation ๐Ÿ“Œ, and use them to guide the output of "is_stmt" markers in the line number table. It's enabled by default when you optimize (-Os, -O, -O2, ...) and output DWARF 2 debug info at the normal level ๐Ÿ’….
  • -gvariable-location-views, -gvariable-location-views=incompat5, -gno-variable-location-views: augments variable location lists with progressive view numbers implied by the line number table โœจ. This lets debug info consumers inspect state at certain points of the program, even if no instructions for the matching source locations exist there. If the assembler lacks view number support in line number tables, the compiler will emit the line number table itself, which makes them somewhat less compact. The augmented tables and lists are fully backward-compatible, so consumers that don't know about the augmentations can still read them, but they won't get any benefit from them either.

This is 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. When assembler support isn't available it may still be enabled, but it 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 view number representation 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 a reference implementation of the proposed representation. Debug info consumers aren't expected to support this extended format, so they'd be unable to decode location lists that use it.
  • -ginternal-reset-location-views, -gno-internal-reset-location-views: attempts to figure out which location views can be omitted from location view lists ๐Ÿง . This requires the compiler to have very accurate insn length estimates, which isn't always the case, and it may silently generate incorrect view lists when 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 the capabilities of the assembler and linker used. type may be one of none (don't compress debug sections), zlib (use zlib compression in ELF gABI format), or zlib-gnu (use zlib compression in traditional GNU format). If the linker doesn't support writing compressed debug sections, the option is 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 one substantially shrinks debug info, but the debugger can lose a significant amount of type information. For a less aggressive option, see -femit-struct-debug-reduced, and for more detailed control, see -femit-struct-debug-detailed. It only works with DWARF debug output.

Okay so bestie, the -femit-struct-debug-* flags are all about keeping your debug info lean ๐Ÿงนโœจ. Here's the rest of that gang:

  • -femit-struct-debug-reduced โ€” ๐Ÿฆ‹ Only emit debug info for struct-like types when the base name of your compile source matches the base name of the file where the type lives. The exceptions are templates and anything defined in a system header, which get skipped. This makes your debug info way smaller, but the debugger might lose a bit of type info. For something more aggressive, check out -femit-struct-debug-baseonly, and for finer control, -femit-struct-debug-detailed. This one only works with DWARF debug output ๐Ÿ’œ
  • -femit-struct-debug-detailed[=spec-list] โ€” ๐Ÿ’… This is the power-user version. You tell the compiler exactly which struct-like types get debug info, so you don't get the same struct duplicated across different object files in one program. It's a detailed version of -femit-struct-debug-reduced and -femit-struct-debug-baseonly, and honestly it covers most needs ๐Ÿ”ฅ

A spec looks like this:

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

The first word is optional and narrows things down to structs used directly (dir:) or indirectly (ind:). A struct is used directly when it's the type of a variable, member. Indirect use happens through pointers to structs, so when using an incomplete struct is valid, the use counts as indirect. For example, struct one direct; is direct and struct two * indirect; is indirect ๐Ÿงš

The second word is optional too and picks ordinary structs (ord:) or generic structs (gen:). Generic structs are a little tricky ngl. In C++, these are non-explicit specializations of template classes, or non-template classes within the above. Other languages have generics, but -femit-struct-debug-detailed doesn't implement them yet ๐Ÿ™ˆ

The third word is the one that picks the source files. none and any mean what you'd expect. base means the base name of the file where the type is declared has to match the base name of the main compilation file. 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 satisfy base or are declared in system or compiler headers ๐ŸŒธ

You might need to experiment a bit to find the best settings for your app, no shame in that ๐Ÿซถ

The default is -femit-struct-debug-detailed=all. This one also only works with DWARF debug output.

  • -fno-dwarf2-cfi-asm โ€” ๐ŸŽ€ Instead of using GAS .cfi_* directives, this puts the DWARF unwind info into a compiler-generated .eh_frame section.
  • -fno-eliminate-unused-debug-types โ€” ๐Ÿง  Normally, when making DWARF output, GCC skips debug symbols for types that never get used in the file being compiled. Sometimes you want debug info for every type declared in a compilation unit, even unused ones. Like, if you want to cast a value to a type that's declared but never actually used in your program while you're debugging. But honestly, most of the time this just wastes a ton of space ๐Ÿ˜ญ

โšก Options That Control Optimization ๐Ÿš€

These options control different kinds of optimization, and they're the main vibe for making your code faster or smaller ๐Ÿ’–

Without any optimization option, the compiler's main goal is to keep compile time low and make debugging behave the way you'd 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 another 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 compile time and might make debugging less predictable ๐Ÿ”ฅ

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

Not every optimization has its own 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. Similarly, -Og suppresses a lot of optimization passes ๐Ÿ’€

Depending on the target and how GCC was configured, the set of optimizations enabled at each -O level might be a bit different from what's listed here. To see the exact set enabled at each level, run -Q --help=optimizers ๐ŸŒˆ

  • -O, -O1 โ€” โœจ Optimize. Optimizing compilation takes a bit more time, and a lot more memory for a large function.

With -O, the compiler tries to shrink code size and speed up execution, but it skips any optimizations that take a long time to compile ๐Ÿ’…

-O turns on the following optimization flags:

-fauto-inc-dec -fbranch-count-reg -fcombine-stack-adjustments
-fcompare-elim -fcprop-registers -fdce -fdefer-pop -fdelayed-branch
-fdse -fforward-propagate -fguess-branch-probability -fif-conversion
-fif-conversion2 -finline-functions-called-once -fipa-modref
-fipa-profile -fipa-pure-const -fipa-reference
-fipa-reference-addressable -fmerge-constants -fmove-loop-invariants
-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 runs nearly every supported optimization that doesn't involve a space-speed tradeoff. Compared to -O, this increases both compile time and the performance of the generated code ๐Ÿ“ˆ

-O2 turns on every optimization flag that -O does. It also turns on 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-pre
-ftree-switch-conversion  -ftree-tail-merge -ftree-vrp
โš ๏ธ Heads up: please check the warning under -fgcse about using -O2 on programs that use computed gotos. It's important ๐Ÿ™ˆ
๐Ÿ“ฃ NOTE: In Ubuntu 8.10 and later, -D_FORTIFY_SOURCE=2 is set by default. In Ubuntu 24.04 and later, -D_FORTIFY_SOURCE=3 is set by default instead. It turns on when -O is set to 2 or higher, and it adds extra compile-time and run-time checks for several libc functions. To turn it off, use either -U_FORTIFY_SOURCE or -D_FORTIFY_SOURCE=0 ๐Ÿ›ก๏ธ
  • -O3 โ€” ๐Ÿš€ Optimize yet more. -O3 turns on everything -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-loop-vectorize -ftree-partial-pre -ftree-slp-vectorize
-funswitch-loops -fvect-cost-model -fvect-cost-model=dynamic
-fversion-loops-for-strides
  • -O0 โ€” ๐Ÿงธ Reduce compile time and keep debugging predictable. This is the default.
  • -Os โ€” ๐Ÿ“ Optimize for size. -Os enables all the -O2 optimizations except the ones that often make code bigger:
-falign-functions  -falign-jumps -falign-labels  -falign-loops
-fprefetch-loop-arrays  -freorder-blocks-algorithm=stc

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

  • -Ofast โ€” ๐ŸŒช๏ธ Disregard strict standards compliance. -Ofast enables all -O3 optimizations, plus optimizations that aren't valid for every standard-compliant program. It turns on -ffast-math, -fallow-store-data-races, and the Fortran-specific -fstack-arrays (unless -fmax-stack-var-size is specified), and -fno-protect-parens ๐Ÿ’€
  • -Og โ€” ๐Ÿ” Optimize the debugging experience. -Og is the go-to level for the standard 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 debuggable code, because some compiler passes that collect debug info are disabled at -O0 ๐Ÿ’–

Like -O0, -Og fully disables a bunch of optimization passes, so the individual options that control them do nothing. Otherwise, -Og enables all the -O1 optimization flags except the ones that could get in the way of debugging:

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

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

Options written as -fflag are machine-independent. Most flags come in both positive and negative forms, and the negative form of -ffoo is -fno-foo. The table below only lists one form, the one you'd typically use. To figure out the other, just remove no- or add it ๐ŸŒท

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

  • -fno-defer-pop โ€” ๐Ÿ’… okay bestie, on machines that have to pop arguments after a function call, this makes the compiler pop them right away as each function returns. At levels -O1 and higher, -fdefer-pop is the default, which lets arguments pile up on the stack across several calls so they can all get popped at once โœจ
  • -fforward-propagate โ€” ๐Ÿฆ‹ this runs a forward propagation pass on RTL. It tries to combine two instructions and then checks whether the result can be simplified. If loop unrolling is active, two passes happen, and the second one gets scheduled after loop unrolling.
    • Enabled by default at optimization levels -O, -O2, -O3, -Os.
  • -ffp-contract=*style* โ€” ๐Ÿงฎ this one is giving options, so let's break it down:
    • -ffp-contract=off disables floating-point expression contraction.
    • -ffp-contract=fast enables contraction, like forming fused multiply-add operations, if the target has native support for them.
    • -ffp-contract=on enables contraction if the language standard allows it. This is currently not implemented and is treated the same as -ffp-contract=off ๐Ÿ™ˆ
    • The default is -ffp-contract=fast.
  • -fomit-frame-pointer โ€” ๐ŸŒธ omits the frame pointer in functions that don't need one. This skips the instructions for saving, setting up, and restoring the frame pointer, and on many targets it also frees up an extra register.
    • On some targets this flag has no effect ๐Ÿ˜ญ because the standard calling sequence always uses a frame pointer, so it can't be left out.
    • -fno-omit-frame-pointer doesn't guarantee the frame pointer is used in every function. Several targets always omit it in leaf functions.
    • Enabled by default at -O and higher.
  • -foptimize-sibling-calls โ€” โœจ optimizes sibling and tail recursive calls.
    • Enabled at levels -O2, -O3, -Os.
  • -foptimize-strlen โ€” ๐Ÿ“ optimizes various standard C string functions (e.g. "strlen", "strchr" or "strcpy") and their "_FORTIFY_SOURCE" counterparts into faster alternatives.
    • Enabled at levels -O2, -O3.
  • -fno-inline โ€” ๐Ÿ›‘ don't expand any functions inline, except the ones marked with the "always_inline" attribute. This is the default when you're not optimizing.
    • Single functions can opt out of inlining by marking them with the "noinline" attribute.
  • -finline-small-functions โ€” ๐Ÿ”ฅ integrates functions into their callers when their body is smaller than the function call code, so the overall program gets smaller. The compiler heuristically decides which functions are simple enough, and this applies to all functions, even ones not declared inline.
    • Enabled at levels -O2, -O3, -Os.
  • -findirect-inlining โ€” ๐Ÿ‘‘ also inlines indirect calls that are known at compile time thanks to previous inlining. This only does anything when inlining is already turned on by -finline-functions or -finline-small-functions.
    • Enabled at levels -O2, -O3, -Os.
  • -finline-functions โ€” ๐ŸŽ€ considers all functions for inlining, even ones not declared inline. The compiler heuristically decides which ones are worth it.
    • If every call to a given function gets integrated and the function is declared "static", it's normally not output as assembler code on its own.
    • Enabled at levels -O2, -O3, -Os. Also enabled by -fprofile-use and -fauto-profile.
  • -finline-functions-called-once โ€” ๐Ÿงš considers all "static" functions called once for inlining into their caller, even if they aren't marked "inline". If a call gets integrated, the function isn't output as assembler code on its own.
    • Enabled at levels -O1, -O2, -O3 and -Os, but not -Og.
  • -fearly-inlining โ€” ๐Ÿฆ‹ inlines functions marked "always_inline", plus functions whose body seems smaller than the function call overhead, early on. This happens before the -fprofile-generate instrumentation and the real inlining pass. Doing it this way makes profiling significantly cheaper and usually makes inlining faster in programs with large chains of nested wrapper functions.
    • Enabled by default.
  • -fipa-sra โ€” ๐Ÿ’– performs interprocedural scalar replacement of aggregates, removes unused parameters, and swaps parameters passed by reference for parameters passed by value.
    • Enabled at levels -O2, -O3 and -Os.
  • -finline-limit=*n* โ€” ๐Ÿ“ by default GCC limits the size of functions that can be inlined. This flag gives you coarse control over that limit. n is the size of functions that can be inlined, measured in pseudo instructions.
    • Inlining is actually controlled by a bunch of parameters, which you can set one at a time with --param name=value. The -finline-limit=n option sets some of them like this:
      • max-inline-insns-single is set to n/2.
      • max-inline-insns-auto is set to n/2.
    • See below for documentation of the individual inlining parameters and their defaults.
    • Note: there may be no value of -finline-limit that results in default behavior.
    • Note: in this context, a pseudo instruction is an abstract measurement of a function's size. It in no way represents a count of assembly instructions, so its exact meaning might change from one release to another ๐Ÿ™ˆ
  • -fno-keep-inline-dllexport โ€” ๐Ÿซถ a more fine-grained version of -fkeep-inline-functions, which only applies to functions declared with the "dllexport" attribute or declspec.
  • -fkeep-inline-functions โ€” ๐Ÿ’œ in C, emits "static" functions declared "inline" into the object file, even if the function has been inlined into all of its callers. This switch doesn't affect functions using the "extern inline" extension in GNU C90. In C++, it emits any and all inline functions into the object file.
  • -fkeep-static-functions โ€” ๐ŸŒˆ emits "static" functions into the object file, even if the function is never used.
  • -fkeep-static-consts โ€” ๐Ÿ“ emits variables declared "static const" when optimization isn't turned on, even if the variables aren't referenced.
    • GCC enables this by default. If you want the compiler to check whether a variable is referenced regardless of optimization, use -fno-keep-static-consts instead.
  • -fmerge-constants โ€” ๐Ÿงฉ attempts to merge identical constants (string constants and floating-point constants) across compilation units.
    • This is the default for optimized compilation if the assembler and linker support it. Use -fno-merge-constants to inhibit this behavior.
    • Enabled at levels -O, -O2, -O3, -Os.
  • -fmerge-all-constants โ€” ๐Ÿคฏ attempts to merge identical constants and identical variables.
    • This option implies -fmerge-constants. On top of that, it considers things like constant initialized arrays or initialized constant variables with integral or floating-point types. Languages like C or C++ require each variable, including multiple instances of the same variable in recursive calls, to have distinct locations, so using this option results in non-conforming behavior.
๐Ÿšจ Bestie, heads up: -fmerge-all-constants results in non-conforming behavior, so think carefully before you reach for it ๐Ÿ’€
  • -fmodulo-sched โ€” ๐ŸŽข performs swing modulo scheduling immediately before the first scheduling pass. It looks at innermost loops and reorders their instructions by overlapping different iterations.
  • -fmodulo-sched-allow-regmoves โ€” ๐ŸŽ๏ธ performs more aggressive SMS-based modulo scheduling with register moves allowed. Setting this flag deletes certain anti-dependence edges, which triggers the generation of reg-moves based on life-range analysis. This option is only effective with -fmodulo-sched enabled.
  • -fno-branch-count-reg โ€” ๐Ÿ”ข disables the optimization pass that scans for chances to use "decrement and branch" instructions on a count register, instead of instruction sequences that decrement a register, compare it against zero, and then branch based on the result. This is only meaningful on architectures that support such instructions, which include x86, PowerPC, IA-64 and S/390. Note that -fno-branch-count-reg doesn't remove the decrement and branch instructions introduced by other optimization passes.
    • The default is -fbranch-count-reg at -O1 and higher, except for -Og.
  • -fno-function-cse โ€” ๐Ÿ™…โ€โ™€๏ธ doesn't put function addresses in registers. Instead, each instruction that calls a constant function contains the function's address explicitly.
    • This gives you less efficient code, but some strange hacks that alter the assembler output may get confused by the optimizations performed when this option isn't used.
    • The default is -ffunction-cse
  • -fno-zero-initialized-in-bss โ€” ๐Ÿ›๏ธ if the target supports a BSS section, GCC by default puts variables that are initialized to zero into BSS, which can save space in the resulting code. This option turns that off, because some programs explicitly rely on variables going to the data section, e.g. so the resulting executable can find the beginning of that section and/or make assumptions based on that.
    • The default is -fzero-initialized-in-bss.
  • -fthread-jumps โ€” ๐Ÿงต performs optimizations that check whether a jump branches to a location where another comparison, subsumed by the first, is found. If so, the first branch is redirected either to the destination of the second branch or to a point immediately after it, depending on whether the condition is known to be true or false.
    • Enabled at levels -O2, -O3, -Os.
  • -fsplit-wide-types โ€” ๐Ÿฐ when using a type that occupies multiple registers, like "long long" on a 32-bit system, splits the registers apart and allocates them independently. This normally generates better code for those types, but it may make debugging more difficult.
    • Enabled at levels -O, -O2, -O3, -Os.
  • -fsplit-wide-types-early โ€” โฐ fully splits wide types early, instead of very late. This option has no effect unless -fsplit-wide-types is turned on.
    • This is the default on some targets.
  • -fcse-follow-jumps โ€” okay so during common subexpression elimination (CSE), GCC peeks through jump instructions as long as no other path reaches the jump's target. Like, when CSE hits an if with an else clause, it follows the jump when the tested condition is false ๐Ÿ‘€
    • Enabled at levels -O2, -O3, -Os. ๐Ÿ’–
  • -fcse-skip-blocks โ€” this is basically -fcse-follow-jumps's bestie ๐Ÿซถ It makes CSE follow jumps that conditionally skip over blocks. So when it sees a simple if with no else, it hops right over the body of the if. Iconic ๐Ÿฆ‹
    • Enabled at levels -O2, -O3, -Os. โœจ
  • -frerun-cse-after-loop โ€” runs common subexpression elimination again after the loop optimizations are done. Second glow-up, no cap ๐Ÿ’…
    • Enabled at levels -O2, -O3, -Os. ๐ŸŒธ
  • -fgcse โ€” turns on a global common subexpression elimination pass. This one also does global constant and copy propagation, so it's doing a lot, periodt ๐Ÿ”ฅ
    • Enabled at levels -O2, -O3, -Os.
Note: if you're compiling a program that uses computed gotos (a GCC extension), you might get better run-time performance by turning off this global CSE pass. Just add -fno-gcse to your command line. Not every program is gonna love the same vibe, so test it, bestie ๐Ÿ™ˆ
  • -fgcse-lm โ€” when this is on, global CSE tries to move loads that only get killed by stores into themselves. So a loop with a load/store sequence can get reshaped: the load moves outside the loop, and a copy/store stays inside it. Very main character energy ๐Ÿ‘‘
    • Enabled by default when -fgcse is enabled. ๐ŸŽ€
  • -fgcse-sm โ€” after global CSE runs, a store motion pass kicks in. It tries to move stores out of loops. Team it up with -fgcse-lm and loops with a load/store sequence can turn into a load before the loop and a store after it ๐Ÿงš
    • Not enabled at any optimization level. ๐Ÿฅฒ
  • -fgcse-las โ€” the global CSE pass gets rid of redundant loads that come right after stores to the same memory location. It catches both partial and full redundancies. Main character cleanup ๐Ÿงนโœจ
    • Not enabled at any optimization level.
  • -fgcse-after-reload โ€” runs a redundant load elimination pass after reload. Its whole job is to tidy up redundant spilling ๐Ÿงฝ
    • Enabled by -fprofile-use and -fauto-profile. ๐Ÿ’œ
  • -faggressive-loop-optimizations โ€” this tells the loop optimizer to lean on language constraints to figure out bounds for how many times a loop runs. It assumes your loop code never triggers undefined behavior, like signed integer overflows or out-of-bound array accesses (so please don't ๐Ÿ’€). Those bounds guide loop unrolling, loop peeling, and loop exit test optimizations.
    • This option is enabled by default. ๐ŸŒˆ
  • -funconstrained-commons โ€” tells the compiler that variables declared in common blocks (like in Fortran) might get overridden later with longer trailing arrays. This stops certain optimizations that rely on knowing the array bounds, so it's a little bit of a trade-off ๐Ÿฆ‹
  • -fcrossjumping โ€” performs the cross-jumping transformation. It unifies equivalent code and saves code size. The result may or may not perform better than without cross-jumping, so it's a vibe check ๐Ÿคทโ€โ™€๏ธ
    • Enabled at levels -O2, -O3, -Os. ๐Ÿ“
  • -fauto-inc-dec โ€” combines increments or decrements of addresses with memory accesses. This pass always gets skipped on architectures that don't have instructions to support it.
    • Enabled by default at -O and higher on architectures that support this. ๐Ÿ”ฅ
  • -fdce โ€” performs dead code elimination (DCE) on RTL. Bye bye, useless code ๐Ÿ‘‹๐Ÿ’€
    • Enabled by default at -O and higher.
  • -fdse โ€” performs dead store elimination (DSE) on RTL. Same energy as -fdce, but for stores nobody reads ๐Ÿงน
    • Enabled by default at -O and higher.
  • -fif-conversion โ€” tries to transform conditional jumps into branch-less equivalents. This includes conditional moves, min, max, set flags and abs instructions, plus some tricks you can do with standard arithmetic ๐Ÿงฎ Whether conditional execution gets used on chips that have it is controlled by -fif-conversion2.
    • Enabled at levels -O, -O2, -O3, -Os, but not with -Og. ๐Ÿ’…
  • -fif-conversion2 โ€” uses conditional execution (where the chip has it) to turn conditional jumps into branch-less equivalents. Smooth ๐Ÿซง
    • Enabled at levels -O, -O2, -O3, -Os, but not with -Og. ๐ŸŒธ
  • -fdeclone-ctor-dtor โ€” okay this one's a whole saga ๐Ÿ˜ญ 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. For a hierarchy with virtual bases, the base and complete variants are clones, meaning you get two copies of the function. With this option, those base and complete variants become thunks that call a common implementation. Less duplicate code, more slay โœจ
    • Enabled by -Os. ๐Ÿงš
  • -fdelete-null-pointer-checks โ€” assumes programs can't safely dereference null pointers, and that no code or data element lives at address zero. This turns on simple constant folding optimizations at all levels. On top of that, other GCC optimization 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 ๐Ÿ™ˆ
    • Note: 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, this option is completely disabled. ๐Ÿซ 
    • Passes that use the dataflow information are enabled independently at different optimization levels. ๐Ÿ’œ
  • -fdevirtualize โ€” tries to convert calls to virtual functions into direct calls. This happens both within a procedure and interprocedurally, as part of indirect inlining (-findirect-inlining) and interprocedural constant propagation (-fipa-cp).
    • Enabled at levels -O2, -O3, -Os. ๐Ÿ‘‘
  • -fdevirtualize-speculatively โ€” tries to convert calls to virtual functions into speculative direct calls. Using 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 one. Speculative calls unlock more optimizations, like inlining. If they seem useless after further optimization, they get converted back to their original form ๐Ÿ”„
  • -fdevirtualize-at-ltrans โ€” streams extra information needed for aggressive devirtualization when the link-time optimizer runs in local transformation mode. You get more devirtualization, but the streamed data gets way bigger. So it's disabled by default, bestie ๐Ÿฅฒ
  • -fexpensive-optimizations โ€” performs a bunch of minor optimizations that are kinda pricey to run ๐Ÿ’ธ
    • Enabled at levels -O2, -O3, -Os. ๐Ÿ“
  • -free โ€” tries to remove redundant extension instructions. This is especially helpful for the x86-64 architecture, which implicitly zero-extends into 64-bit registers after writing to the lower 32-bit half. Clean and tidy ๐Ÿงผ
    • Enabled for Alpha, AArch64 and x86 at levels -O2, -O3, -Os.
  • -fno-lifetime-dse โ€” in C++, an object's value only gets affected by changes made within its lifetime. The object has an indeterminate value when its constructor begins, and any changes during its lifetime are dead once it's destroyed. Normally, dead store elimination takes advantage of that. But if your code relies on the object's storage value sticking around past the object's lifetime, use this flag to disable the optimization. ๐Ÿ™…โ€โ™€๏ธ
    • To keep stores before the constructor starts (say, because your operator new clears the object storage) but still treat the object as dead after the destructor, use -flifetime-dse=1.
    • The default behavior can be explicitly selected with -flifetime-dse=2.
    • -flifetime-dse=0 is equivalent to -fno-lifetime-dse. ๐Ÿง 
  • -flive-range-shrinkage โ€” tries to lower register pressure by shrinking register live ranges. It's a big help for fast processors with small or moderate-sized register sets ๐ŸŽ๏ธ
  • -fira-algorithm=algorithm โ€” picks the coloring algorithm for the integrated register allocator. The algorithm argument can be priority, which means Chow's priority coloring, or CB, which means Chaitin-Briggs coloring. Chaitin-Briggs 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 โ€” tells the integrated register allocator which regions to use. The region argument should be one of these:
    • 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 the ones with small register pressure as 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 โ€” uses IRA to evaluate register pressure in the code hoisting pass when deciding whether to hoist expressions. This usually results in smaller code, but it can slow the compiler down ๐Ÿข
    • This option is enabled at level -Os for all targets.
  • -fira-loop-pressure โ€” uses IRA to evaluate register pressure in loops when deciding whether to move loop invariants. This usually generates faster and smaller code on machines with large register files (>= 32 registers), but it can slow the compiler down too ๐ŸŒ
    • This option is enabled at level -O3 for some targets. ๐Ÿ’–

-fno-ira-share-save-slots

Okay so this one is about stack slots for saving call-used hard registers that stay alive across a call ๐Ÿงš. Turning it off with -fno-ira-share-save-slots means every hard register gets its very own stack slot, and bestie, that makes your function stack frames bigger ๐Ÿ“ฆ๐Ÿ’€. Not the vibe, but sometimes you need it.

-fno-ira-share-spill-slots

Same energy, different target ๐Ÿฆ‹. This one disables sharing of stack slots for pseudo-registers. Any pseudo-register that doesn't get a hard register is given a separate stack slot, so again, the function stack frames end up larger ๐Ÿฅฒ.

-flra-remat

Okay this is giving optimization โœจ. It enables CFG-sensitive rematerialization in LRA. Instead of loading the values of spilled pseudos, LRA tries to rematerialize (recalculate) them whenever that's profitable ๐Ÿงฎ๐Ÿ’….

Enabled at levels -O2, -O3, -Os. ๐ŸŒธ

-fdelayed-branch

If the target machine supports it, GCC will try to reorder instructions so they fill the instruction slots available after delayed branch instructions ๐Ÿ“. Lowkey clever.

Enabled at levels -O, -O2, -O3, -Os, but not at -Og. ๐Ÿซถ

-fschedule-insns

If the target supports it, GCC attempts to reorder instructions to avoid execution stalls caused by data that isn't ready yet โณ. This is a lifesaver for machines with slow floating point or memory load instructions, because other instructions can get issued while the load or float op is still cooking ๐Ÿ”ฅ.

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

-fschedule-insns2

This is basically -fschedule-insns but with an extra scheduling pass after register allocation is done ๐Ÿ‘‘. It's especially useful on machines with a pretty small number of registers, where memory loads take more than one cycle ๐Ÿ’œ.

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

-fno-sched-interblock

Disables instruction scheduling across basic blocks ๐Ÿ™…โ€โ™€๏ธ. Normally this is on when scheduling happens before register allocation, meaning with -fschedule-insns or at -O2 or higher.

-fno-sched-spec

Disables speculative motion of non-load instructions ๐Ÿ™ˆ. Normally this is on when scheduling happens before register allocation, meaning with -fschedule-insns or at -O2 or higher.

-fsched-pressure

Enables register-pressure-sensitive insn scheduling before register allocation ๐ŸŽ€. This only makes sense if pre-allocation scheduling is on, so with -fschedule-insns or at -O2 or higher. Using it can improve the generated code and shrink its size, because it stops register pressure from going above the number of available hard registers, which would otherwise lead to spills during allocation ๐Ÿง .

-fsched-spec-load

Allows speculative motion of some load instructions ๐ŸŒท. Only makes sense when scheduling before register allocation, meaning with -fschedule-insns or at -O2 or higher.

-fsched-spec-load-dangerous

Allows speculative motion of more load instructions ๐Ÿ˜ฌ. Same deal: only makes sense when scheduling before register allocation, meaning with -fschedule-insns or at -O2 or higher.

-fsched-stalled-insns -fsched-stalled-insns=n

This controls how many insns (if any) can be moved early from the queue of stalled insns into the ready list during the second scheduling pass ๐Ÿšฆ. -fno-sched-stalled-insns means none get moved early, and -fsched-stalled-insns=0 means there's no limit on how many queued insns can be moved early. Just -fsched-stalled-insns with no value is the same as -fsched-stalled-insns=1 ๐ŸŽฏ.

-fsched-stalled-insns-dep -fsched-stalled-insns-dep=n

This defines 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 used. -fno-sched-stalled-insns-dep is the same as -fsched-stalled-insns-dep=0, and -fsched-stalled-insns-dep with no value is the same as -fsched-stalled-insns-dep=1 ๐Ÿ’–.

-fsched2-use-superblocks

When scheduling after register allocation, this uses superblock scheduling ๐ŸŒŠ. That lets instructions move across basic block boundaries, which can give faster schedules โšก. Heads up though: this option is experimental, because not all machine descriptions model the CPU closely enough to avoid unreliable results ๐Ÿ™ƒ.

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

-fsched-group-heuristic

Enables the group heuristic in the scheduler ๐Ÿซง. This one favors the instruction that belongs to a schedule group. It's on by default when scheduling is enabled, meaning with -fschedule-insns or -fschedule-insns2 or at -O2 or higher ๐Ÿ’….

-fsched-critical-path-heuristic

Enables the critical-path heuristic in the scheduler ๐Ÿ›ฃ๏ธ. This one favors instructions on the critical path. It's on by default when scheduling is enabled, meaning with -fschedule-insns or -fschedule-insns2 or at -O2 or higher ๐Ÿ‘‘.

-fsched-spec-insn-heuristic

Enables the speculative instruction heuristic in the scheduler ๐Ÿ”ฎ. It favors speculative instructions with greater dependency weakness. On by default when scheduling is enabled, meaning with -fschedule-insns or -fschedule-insns2 or at -O2 or higher ๐ŸŒธ.

-fsched-rank-heuristic

Enables the rank heuristic in the scheduler ๐Ÿ“Š. It favors the instruction in a basic block with greater size or frequency. On by default when scheduling is enabled, meaning with -fschedule-insns or -fschedule-insns2 or at -O2 or higher ๐Ÿฆ‹.

-fsched-last-insn-heuristic

Enables the last-instruction heuristic in the scheduler ๐ŸŽฏ. It favors the instruction that depends less on the last instruction scheduled. On by default when scheduling is enabled, meaning with -fschedule-insns or -fschedule-insns2 or at -O2 or higher โœจ.

-fsched-dep-count-heuristic

Enables the dependent-count heuristic in the scheduler ๐Ÿง. It favors the instruction that has more instructions depending on it. On by default when scheduling is enabled, meaning with -fschedule-insns or -fschedule-insns2 or at -O2 or higher ๐Ÿ’œ.

-freschedule-modulo-scheduled-loops

Modulo scheduling happens before traditional scheduling ๐Ÿ”. If a loop gets modulo scheduled, later scheduling passes may change its schedule, and this option is how you control that behavior ๐ŸŽ›๏ธ.

-fselective-scheduling

Schedules instructions using the selective scheduling algorithm ๐Ÿงฉ. Selective scheduling runs instead of the first scheduler pass.

-fselective-scheduling2

Schedules instructions using the selective scheduling algorithm again ๐Ÿ”„. This time it runs instead of the second scheduler pass.

-fsel-sched-pipelining

Enables software pipelining of innermost loops during selective scheduling ๐Ÿฅ. This option has no effect unless -fselective-scheduling or -fselective-scheduling2 is turned on.

-fsel-sched-pipelining-outer-loops

When pipelining loops during selective scheduling, this also pipelines outer loops ๐ŸŒ€. It has no effect unless -fsel-sched-pipelining is turned on.

-fsemantic-interposition

Okay this one is a whole saga ๐ŸŽญ. Some object formats, like ELF, let the dynamic linker interpose symbols. That means for symbols exported from the DSO, the compiler can't do interprocedural propagation, inlining, or other optimizations, because the function or variable might get swapped out later ๐Ÿ˜ค. It's useful, for example, for 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 happens for functions, the overwriting function will have precisely the same semantics (and side effects). Similarly, if interposition happens for variables, the constructor of the variable will be the same. This flag has no effect on functions explicitly declared inline (where interposition is never allowed to change semantics), or on symbols explicitly declared weak ๐Ÿซถ.

-fshrink-wrap

Emits function prologues only before the parts of the function that need them, instead of at the top of the function ๐ŸŽ. This flag is enabled by default at -O and higher.

-fshrink-wrap-separate

Shrink-wraps the separate parts of the prologue and epilogue separately, so those parts only run when needed ๐Ÿช„. This option is on by default, but it has no effect unless -fshrink-wrap is also turned on and the target supports this.

-fcaller-saves

Enables allocating values to registers that get clobbered by function calls ๐Ÿงบ. GCC does this by emitting extra instructions to save and restore those registers around such calls. This allocation only happens when it seems to result in better code ๐ŸคŒ.

This option is always enabled by default on certain machines, usually the ones that don't have call-preserved registers to use instead ๐Ÿ’….

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

-fcombine-stack-adjustments

Tracks stack adjustments (pushes and pops) and stack memory references, then tries to find ways to combine them ๐Ÿฅž.

Enabled by default at -O1 and higher. โœจ

-fipa-ra

Uses caller-save registers for allocation if those registers aren't used by any called function ๐Ÿง . In that case there's no need to save and restore them around calls. This only works if the called functions are part of the same compilation unit as the current function and get compiled before it ๐Ÿ“š.

Enabled at levels -O2, -O3, -Os, but it's disabled if the generated code will be instrumented for profiling (-p or -pg), or if the callee's register usage can't be known exactly (which happens on targets that don't expose prologues and epilogues in RTL) ๐Ÿšซ.

-fconserve-stack

Attempts to minimize stack usage ๐Ÿชถ. The compiler tries to use less stack space, even if that makes the program slower ๐Ÿข. This option implies setting the large-stack-frame parameter to 100 and the large-stack-frame-growth parameter to 400 ๐Ÿ’œ.

-ftree-reassoc

Performs reassociation on trees ๐ŸŒณ. Enabled by default at -O and higher โœจ.

-fcode-hoisting

Performs code hoisting ๐Ÿช. Code hoisting tries to move the evaluation of expressions executed on all paths to the function exit as early as possible. This is especially useful as a code size optimization, but it often helps code speed too ๐ŸŽ๏ธ. This flag is enabled by default at -O2 and higher ๐ŸŽ€.

  • -ftree-pre โ€” okay so this one does partial redundancy elimination (PRE) on trees ๐ŸŒธ It's switched on by default at -O2 and -O3 โœจ
  • -ftree-partial-pre โ€” this makes PRE way more aggressive ๐Ÿ”ฅ It's only on by default at -O3 ๐Ÿ’…
  • -ftree-forwprop โ€” forward propagation on trees, very clean-up-your-room energy ๐Ÿงน On by default at -O and higher.
  • -ftree-fre โ€” full redundancy elimination (FRE) on trees ๐Ÿ’– The tea is that FRE only looks at expressions that get computed on all paths leading to the redundant computation. It's faster than PRE but catches fewer redundancies, so it's the chill sibling ๐Ÿฆ‹ On by default at -O and higher.
  • -ftree-phiprop โ€” hoists loads from conditional pointers on trees ๐ŸŽ€ This pass is on by default at -O and higher.
  • -fhoist-adjacent-loads โ€” speculatively hoists loads from both branches of an if-then-else, but only when the loads come from adjacent spots in the same structure and the target architecture has a conditional move instruction ๐Ÿซถ On by default at -O2 and higher.
  • -ftree-copy-prop โ€” copy propagation on trees, which gets rid of unnecessary copy operations ๐Ÿงผ On by default at -O and higher.
  • -fipa-pure-const โ€” figures out which functions are pure or constant ๐Ÿ”ฎ On by default at -O and higher.
  • -fipa-reference โ€” figures out which static variables don't escape the compilation unit ๐Ÿ‘€ On by default at -O and higher.
  • -fipa-reference-addressable โ€” finds read-only, write-only and non-addressable static variables ๐Ÿฆ‹ On by default at -O and higher.
  • -fipa-stack-alignment โ€” reduces stack alignment on call sites whenever it's possible โœจ On by default.
  • -fipa-pta โ€” interprocedural pointer analysis plus interprocedural modification and reference analysis ๐Ÿง  It's not enabled by default at any optimization level.
๐Ÿ’€ Heads up bestie: -fipa-pta can cause excessive memory and compile-time usage on large compilation units, so it's not a casual add-on.
  • -fipa-profile โ€” interprocedural profile propagation ๐Ÿ“Š Functions called only from cold functions get marked as cold, and functions executed once (such as "cold", "noreturn", static constructors or destructors) get identified. Cold functions and loop less parts of functions executed once then get optimized for size ๐ŸงŠ On by default at -O and higher.
  • -fipa-modref โ€” interprocedural mod/ref analysis ๐ŸŒˆ It analyzes the side effects of functions (memory locations that are modified or referenced), which means better optimization across the function call boundary ๐Ÿซง On by default at -O and higher.
  • -fipa-cp โ€” interprocedural constant propagation ๐Ÿ’œ It checks when values passed to functions are constants, then optimizes accordingly. It can substantially increase performance if your app has constants passed to functions ๐Ÿš€ On by default at -O2, -Os and -O3. It's also enabled by -fprofile-use and -fauto-profile.
  • -fipa-cp-clone โ€” function cloning to make interprocedural constant propagation stronger ๐Ÿงฌ When enabled, it clones functions when an externally visible function can be called with constant arguments. Because this can create multiple copies of functions, it may significantly increase code size (see --param ipa-cp-unit-growth=value) ๐Ÿ“ˆ On by default at -O3. It's also enabled by -fprofile-use and -fauto-profile.
  • -fipa-bit-cp โ€” interprocedural bitwise constant propagation ๐Ÿ”ข On by default at -O2 and by -fprofile-use and -fauto-profile. It requires that -fipa-cp is enabled.
  • -fipa-vrp โ€” interprocedural propagation of value ranges ๐Ÿ“ On by default at -O2. It requires that -fipa-cp is enabled.
  • -fipa-icf โ€” Identical Code Folding for functions and read-only variables ๐Ÿช„ It reduces code size, but it may disturb unwind stacks by swapping a function out for an equivalent one with a different name. It works more effectively with link-time optimization turned on.
    • It's similar to the Gold Linker's ICF optimization, but GCC ICF works on different levels, so the optimizations aren't the same. There are equivalences only GCC finds, and equivalences only Gold finds ๐Ÿค“
    • On by default at -O2 and -Os.
  • -flive-patching=level โ€” tweaks GCC's optimizations so the output is suitable for live-patching ๐Ÿฉน Quick vocab: if an optimization uses a function's body (or info pulled from that body) to optimize or change another function, that other one is called an impacted function of the first. If a function gets patched, its impacted functions should get patched too ๐Ÿ”
    • Which functions are impacted depends on the interprocedural optimizations. For example, a caller is impacted when a function gets inlined into it, when a function gets cloned and its caller is changed to call the new clone, or when a function's pureness/constness info gets extracted to optimize its direct or indirect callers, etc.
    • Usually, the more IPA optimizations are enabled, the more impacted functions each function has. To keep that number under control and make the list easier to compute, IPA optimizations can be partially enabled at two different levels.
    • The level argument should be one of the following:
      • inline-clone โ€” only enables inlining and cloning optimizations, which covers inlining, cloning, interprocedural scalar replacement of aggregates and partial inlining ๐Ÿงฉ So when you patch a function, all its callers and its clones' callers are impacted and need patching too.
        • -flive-patching=inline-clone disables 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 ๐ŸŽฏ So when you patch a static function, all its callers are impacted and need patching too.
        • On top of everything -flive-patching=inline-clone disables, -flive-patching=inline-only-static also disables: -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).
โš ๏ธ -flive-patching and link-time optimization (-flto) don't get along, so this combo is a no-go.
  • -fisolate-erroneous-paths-dereference โ€” detects paths that trigger erroneous or undefined behavior due to dereferencing a null pointer ๐Ÿšจ It isolates those paths from the main control flow and turns the statement with erroneous or undefined behavior into a trap. On by default at -O2 and higher, and it depends on -fdelete-null-pointer-checks also being enabled.
  • -fisolate-erroneous-paths-attribute โ€” detects paths that trigger erroneous or undefined behavior because a null value gets used in a way forbidden by a "returns_nonnull" or "nonnull" attribute ๐Ÿ™ˆ Same vibe as above: those paths get isolated from the main control flow and the statement becomes a trap. This is not currently enabled, but it may be enabled by -O2 in the future ๐Ÿ”ฎ
  • -ftree-sink โ€” forward store motion on trees ๐Ÿ›‹๏ธ On by default at -O and higher.
  • -ftree-bit-ccp โ€” sparse conditional bit constant propagation on trees, and it propagates pointer alignment info too ๐Ÿงฎ It only operates on local scalar variables. On by default at -O1 and higher, except for -Og. It requires that -ftree-ccp is enabled.
  • -ftree-ccp โ€” sparse conditional constant propagation (CCP) on trees ๐Ÿ’ซ It only operates on local scalar variables. On by default at -O and higher.
  • -fssa-backprop โ€” propagates info about uses of a value up the definition chain so the definitions get simplified ๐Ÿ”™ For example, this pass strips sign operations if the sign of a value never matters ๐Ÿงน On by default at -O and higher.
  • -fssa-phiopt โ€” pattern matching on SSA PHI nodes to optimize conditional code ๐Ÿงฉ On by default at -O1 and higher, except for -Og.
  • -ftree-switch-conversion โ€” turns simple initializations in a switch into initializations from a scalar array ๐ŸŽ€ On by default at -O2 and higher.
  • -ftree-tail-merge โ€” looks for identical code sequences and, when it finds them, replaces one with a jump to the other ๐Ÿชž This is known as tail merging or cross jumping. On 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 ๐Ÿ—‘๏ธ On by default at -O and higher.
  • -ftree-builtin-call-dce โ€” conditional DCE for calls to built-in functions that may set errno but are otherwise free of side effects ๐ŸŒ™ On by default at -O2 and higher, if -Os isn't also specified.
  • -ffinite-loops โ€” assumes that a loop with an exit will eventually take the exit and won't loop indefinitely โ™พ๏ธ That lets the compiler remove loops that otherwise have no side effects, since it doesn't count eventual endless looping as such ๐ŸŒ€ This option is enabled by default at -O2 for C++ with -std=c++11 or higher.
  • -ftree-dominator-opts โ€” a bunch of simple scalar cleanups (constant/copy propagation, redundancy elimination, range propagation and expression simplification) based on a dominator tree traversal ๐Ÿงผ It also does jump threading (to reduce jumps to jumps) โ›“๏ธ On by default at -O and higher.
  • -ftree-dse โ€” Okay so this is dead store elimination (DSE) on trees ๐Ÿ’… A dead store is a store into a memory location that gets overwritten later by another store with no loads in between, so the earlier store can be deleted ๐Ÿ—‘๏ธ Enabled by default at -O and higher โœจ
  • -ftree-ch โ€” Loop header copying on trees ๐Ÿฆ‹ It's lowkey iconic because it boosts code motion optimizations and saves one jump. Enabled by default at -O and higher, but not for -Os, since it usually bloats code size ๐Ÿ™ˆ
  • -ftree-loop-optimize โ€” Loop optimizations on trees ๐ŸŒธ Enabled by default at -O and higher.
  • -ftree-loop-linear, -floop-strip-mine, -floop-block โ€” Loop nest optimizations ๐Ÿงš These are the same as -floop-nest-optimize. To actually use this transformation, GCC has to be configured with --with-isl so the Graphite loop transformation infrastructure gets enabled. Don't skip that part, it's giving config drama ๐Ÿ’€
  • -fgraphite-identity โ€” Enables the identity transformation for Graphite ๐Ÿ” For every SCoP, GCC builds the polyhedral representation and transforms it back to GIMPLE. This lets you check the costs or benefits of the GIMPLE -> GRAPHITE -> GIMPLE round trip. The isl code generator also does some minimal optimizations, like index splitting and dead code elimination in loops.
  • -floop-nest-optimize โ€” Enables the isl-based loop nest optimizer ๐Ÿ‘‘ It's a generic one based on the Pluto optimization algorithms, and it calculates a loop structure optimized for data locality and parallelism.
โš ๏ธ Heads up bestie: this option is experimental, so use it with care ๐Ÿซถ
  • -floop-parallelize-all โ€” Uses Graphite data dependence analysis to find loops that can be parallelized ๐Ÿงต It parallelizes every loop that can be analyzed as not containing loop carried dependences, without checking whether parallelizing is profitable first.
  • -ftree-coalesce-vars โ€” When transforming the program out of SSA representation, this tries to cut down copying by coalescing versions of different user-defined variables, not just compiler temporaries ๐Ÿ’œ
๐Ÿ™ˆ This may severely limit your ability to debug an optimized program compiled with -fno-var-tracking-assignments. The negated form of 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 vibe is to remove control flow from the innermost loops so the vectorization pass can handle them better. Enabled by default if vectorization is enabled.
  • -ftree-loop-distribution โ€” Performs loop distribution ๐Ÿ“ This can improve cache performance on big loop bodies and lets further loop optimizations, like parallelization or vectorization, take place. For example, the 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 โ€” Distributes loops over 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, the 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 can improve cache performance on loop nests and allow further loop optimizations, like vectorization, to take place. For example, the 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. Enabled by default at -O3. It is also enabled by -fprofile-use and -fauto-profile.
  • -ftree-loop-im โ€” Performs loop invariant motion on trees ๐ŸŽ€ It 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 that out takes 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 on exit can be determined using only its initial value and the number of loop iterations, uses of the final value get replaced by that computation, as long as it's sufficiently cheap. This reduces data dependencies and may allow further simplifications. Enabled by default at -O and higher.
  • -fivopts โ€” Performs induction variable optimizations on trees ๐Ÿ” That includes strength reduction, induction variable merging, and induction variable elimination.
  • -ftree-parallelize-loops=n โ€” Parallelizes loops by splitting their iteration space to run in n threads ๐Ÿงต This is only possible for loops whose iterations are independent and can be arbitrarily reordered. The optimization is only profitable on multiprocessor machines, for CPU-intensive loops rather than loops constrained by, e.g., memory bandwidth. This option implies -pthread, so it's only supported on targets that have support for -pthread ๐Ÿซถ
  • -ftree-pta โ€” Performs function-local points-to analysis on trees ๐ŸŽฏ Enabled by default at -O1 and higher, except for -Og.
  • -ftree-sra โ€” Performs scalar replacement of aggregates ๐Ÿงธ It replaces structure references with scalars so structures don't get committed to memory too early. Enabled by default at -O1 and higher, except for -Og.
  • -fstore-merging โ€” Merges narrow stores to consecutive memory addresses ๐Ÿ“ฆ It merges contiguous stores of immediate values that are narrower than a word into fewer, wider stores to reduce the number of instructions. 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 are replaced at their use location with their defining expression. This results in non-GIMPLE code, but gives the expanders much more complex trees to work on, which means better RTL generation. Enabled by default at -O 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. Enabled by default at -O 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 ๐Ÿ’ช Enabled by default at -O3, and by -ftree-vectorize, -fprofile-use, and -fauto-profile.
  • -ftree-slp-vectorize โ€” Performs basic block vectorization on trees โœจ Enabled by default at -O3, and by -ftree-vectorize, -fprofile-use, and -fauto-profile.
  • -fvect-cost-model=model โ€” Alters the cost model used for vectorization ๐Ÿ’ฐ The model argument should be one of the following:
    • unlimited โ€” the vectorized code path is assumed to be profitable.
    • dynamic โ€” a runtime check guards the vectorized code path, so it only runs for iteration counts that will likely execute faster than the original scalar loop.
    • cheap โ€” disables vectorization of loops where doing so would be cost prohibitive, for example due to required runtime checks for data dependence or alignment. Otherwise it's equal to dynamic.
    • very-cheap โ€” only allows vectorization if the vector code would entirely replace the scalar code being vectorized. For example, if each iteration of a vectorized loop could only handle exactly four iterations of the scalar loop, very-cheap would only allow vectorization if the scalar iteration count is known to be a multiple of four.

The default cost model depends on other optimization flags and is either dynamic or cheap ๐ŸŒท

  • -fsimd-cost-model=model โ€” Alters the cost model used for vectorization of loops marked with the OpenMP simd directive ๐ŸŒˆ The model argument should be one of unlimited, dynamic, cheap. All values of model have the same meaning as described in -fvect-cost-model, and by default a cost model defined with -fvect-cost-model is used ๐Ÿ’œ

โœจ OPTIONS โœจ (continued, bestie ๐ŸŽ€)

  • -ftree-vrp ๐ŸŒธ โ€” okay so this one runs Value Range Propagation on trees ๐ŸŒณ. It's basically the cousin of constant propagation, except it tracks whole ranges of values instead of single values ๐Ÿ“. That means the optimizers can ditch pointless checks like array bound checks and null pointer checks, which is giving efficiency ๐Ÿ”ฅ.
    • It's enabled by default at -O2 and higher.
    • Null pointer check elimination only happens if -fdelete-null-pointer-checks is enabled ๐Ÿ™ˆ.
  • -fsplit-paths ๐Ÿฆ‹ โ€” splits up paths that lead to loop backedges โ†ฉ๏ธ. This can seriously help 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 makes the scheduling passes more efficient ๐Ÿ’œ.
    • A combo of -fweb and CSE is often enough to get the same effect, ngl ๐Ÿคทโ€โ™€๏ธ. It isn't reliable though when the loop body is more complicated than a single basic block ๐Ÿ™ƒ.
    • 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 ๐Ÿ‘‘.
    • It's enabled by default for PowerPC targets, but disabled by default otherwise ๐Ÿ™ˆ.
  • -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 ๐Ÿ’– โ€” does 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, GCC generates instructions to prefetch memory, which speeds up loops that access large arrays ๐Ÿ“ฆ.
    • This might give better or worse code ๐ŸŽฒ. The results are highly dependent on how the loops are structured in the source โœจ.
    • Disabled at level -Os.

  • -fno-printf-return-value ๐Ÿ”ฎ โ€” tells GCC not to swap in constants for the known return value of formatted output functions like "sprintf", "snprintf", "vsprintf", and "vsnprintf" (but not "printf" or "fprintf"). The transformation itself lets GCC optimize or even eliminate branches based on that known return value, as long as the arguments are constant or known to be in a range where the exact return value can be figured out ๐Ÿง .

For example, with -fprintf-return-value in effect, both the branch and the body of the "if" statement (but not the call to "snprint") can be optimized away when "i" is a 32-bit or smaller integer, because the return value is guaranteed to be at most 8 ๐Ÿคฏ:

char buf[9];
if (snprintf (buf, "%08x", i) >= sizeof buf)
  ...

The -fprintf-return-value option relies on other optimizations and gives the best results with -O2 and above ๐Ÿ‘‘. It works in tandem with -Wformat-overflow and -Wformat-truncation ๐Ÿซถ. The -fprintf-return-value option is enabled by default โœ….


  • -fno-peephole, -fno-peephole2 ๐Ÿงผ โ€” disables any machine-specific peephole optimizations. The difference between them is in how they're implemented inside the compiler: some targets use one, some use the other, and a few use both ๐Ÿค“.
    • -fpeephole is enabled by default. -fpeephole2 is enabled at levels -O2, -O3, -Os.
  • -fno-guess-branch-probability ๐ŸŽฏ โ€” stops GCC from guessing branch probabilities using heuristics ๐Ÿ™…โ€โ™€๏ธ.
    • GCC uses heuristics to guess branch probabilities when they aren't provided by profiling feedback (-fprofile-arcs) ๐Ÿ“Š. These heuristics are based on the control flow graph ๐Ÿ—บ๏ธ.
    • If some branch probabilities are specified by "__builtin_expect", the heuristics guess the probabilities for the rest of the control flow graph, taking the "__builtin_expect" info into account ๐Ÿงฉ. The interactions between the two can get complicated, so sometimes it's useful to disable the heuristics so the effects of "__builtin_expect" are easier to understand ๐Ÿซถ.
    • You can also specify the expected probability of an expression with the "__builtin_expect_with_probability" built-in function โœจ.
    • The default is -fguess-branch-probability at levels -O, -O2, -O3, -Os.
  • -freorder-blocks ๐Ÿ›ค๏ธ โ€” reorders basic blocks in the compiled function to reduce the number of taken branches and improve code locality ๐Ÿ’….
    • Enabled at levels -O, -O2, -O3, -Os.
  • -freorder-blocks-algorithm=algorithm ๐Ÿงญ โ€” picks the algorithm used for basic block reordering. The algorithm argument can be:
    • simple, which doesn't increase code size (except sometimes through secondary effects like alignment) ๐Ÿชถ
    • stc, the "software trace cache" algorithm, which tries to put all the often-executed code together, minimizing the number of branches executed by making extra copies of code ๐Ÿงƒ
    • The default is simple at levels -O, -Os, and stc at levels -O2, -O3.
  • -freorder-blocks-and-partition ๐Ÿงฉ โ€” on top of reordering basic blocks to cut down on taken branches, this partitions hot and cold basic blocks into separate sections of the assembly and .o files ๐Ÿ—‚๏ธ. That improves paging and cache locality performance ๐Ÿš€.
    • 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 does not support named sections ๐Ÿ™…โ€โ™€๏ธ.
    • When -fsplit-stack is used, this option is not 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 ๐Ÿ“š. It does this with special subsections: ".text.hot" for the most frequently executed functions and ".text.unlikely" for the unlikely-executed ones ๐Ÿ”ฅ. The reordering is done by the linker, so the object file format must support named sections and the linker must place them in a reasonable way ๐Ÿ”—.
    • This option isn't effective unless you either provide profile feedback (see -fprofile-arcs for details) or manually annotate functions with "hot" or "cold" attributes ๐Ÿ’ญ.
    • Enabled at levels -O2, -O3, -Os.

  • -fstrict-aliasing ๐Ÿ•ต๏ธโ€โ™€๏ธ โ€” lets the compiler assume the strictest aliasing rules that apply to the language being compiled. For C (and C++), this activates optimizations based on the type of expressions ๐Ÿง. An object of one type is assumed to never reside at the same address as an object of a different type, unless the types are almost the same. For example, an "unsigned int" can alias an "int", but not a "void*" or a "double" ๐Ÿ™…. A character type may alias any other type ๐ŸŒŸ.

Pay special attention to code like this ๐Ÿ‘€:

union a_union {
  int i;
  double d;
};

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

Type-punning (reading from a different union member than the one most recently written to) is super common ๐Ÿฅด. Even with -fstrict-aliasing, type-punning is allowed, provided the memory is accessed through the union type. So the code above works as expected โœ…. However, this code might not ๐Ÿ˜ฌ:

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

Similarly, accessing by taking the address, casting the resulting pointer, and dereferencing the result has undefined behavior, even if the cast uses a union type ๐Ÿšจ:

int f() {
  double d = 3.0;
  return ((union a_union *) &d)->i;
}
Undefined behavior alert ๐Ÿšจ๐Ÿ’€: the address-casting trick above is undefined behavior, so please don't build your code on it, bestie.

The -fstrict-aliasing option is enabled at levels -O2, -O3, -Os ๐Ÿซถ.


  • -falign-functions, -falign-functions=n, -falign-functions=n:m, -falign-functions=n:m:n2, -falign-functions=n:m:n2:m2 ๐Ÿ“ โ€” aligns the start of functions to the next power-of-two that's greater than or equal to n, skipping up to m-1 bytes. This makes sure at least the first m bytes of the function can be fetched by the CPU without crossing an n-byte alignment boundary ๐Ÿงฒ.
    • If m isn't specified, it defaults to n ๐Ÿ™‚.
    • Examples ๐Ÿ‘€:
      • -falign-functions=32 aligns functions to the next 32-byte boundary.
      • -falign-functions=24 aligns to the next 32-byte boundary only if this can be done by skipping 23 bytes or less.
      • -falign-functions=32:7 aligns to the next 32-byte boundary only if this can be done by skipping 6 bytes or less.
    • The second pair of n2:m2 values lets you specify a secondary alignment ๐ŸŽฏ. For example, -falign-functions=64:7:32:3 aligns to the next 64-byte boundary if this can be done by skipping 6 bytes or less, otherwise it aligns to the next 32-byte boundary if this can be done by skipping 2 bytes or less. If m2 isn't specified, it defaults to n2.
    • Some assemblers only support this flag when n is a power of two. In that case, it gets rounded up ๐Ÿงฎ.
    • -fno-align-functions and -falign-functions=1 are equivalent and mean that functions are not aligned ๐Ÿ™….
    • If n is not specified or is zero, a machine-dependent default is used. The maximum allowed n value is 65536 ๐Ÿ“.
    • Enabled at levels -O2, -O3 ๐Ÿ”ฅ.
  • -flimit-function-alignment ๐ŸŒท โ€” when this is enabled, the compiler tries to avoid unnecessarily overaligning functions ๐Ÿ™…โ€โ™€๏ธ. It attempts to instruct the assembler to align by the amount specified by -falign-functions, but not to skip more bytes than the size of the function ๐Ÿ“.
  • -falign-labels, -falign-labels=n, -falign-labels=n:m, -falign-labels=n:m:n2, -falign-labels=n:m:n2:m2 ๐ŸŽฏ โ€” aligns all branch targets to a power-of-two boundary ๐Ÿ’œ.

Okay so these parameters work just like the ones for -falign-functions ๐Ÿ’…. And bestie, -fno-align-labels and -falign-labels=1 are literally the same thing: labels get no alignment at all ๐Ÿ™ˆ

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

If you don't give an n or it's zero, GCC picks a machine-dependent default, which is very likely 1 (aka no alignment, lol) ๐Ÿ’€. The max n you can use is 65536 ๐Ÿ”ฅ

Enabled at levels -O2, -O3 ๐ŸŒธ

-falign-loops

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

Okay this one is giving alignment for loops to a power-of-two boundary ๐Ÿฆ‹. If the loops run a lot of times, the padding instructions are totally worth it, since they only run once per loop entry and the speedup makes up for it ๐Ÿ”ฅ

If -falign-labels is bigger than this value, its value gets used instead ๐Ÿ’–

The parameters work the same way as -falign-functions. -fno-align-loops and -falign-loops=1 are equivalent and mean loops are not aligned ๐Ÿซถ. The max n is 65536 โœจ

If n isn't specified or is zero, you get a machine-dependent default ๐Ÿงš

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

-falign-jumps

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

This one aligns branch targets to a power-of-two boundary, but only for the targets you can only reach by jumping ๐Ÿฆ‹. Since you're jumping there anyway, no dummy operations need to run, so it's extra iconic ๐Ÿ’…

If -falign-labels is bigger than this value, its value gets used instead ๐ŸŒˆ

Parameters work like -falign-functions again ๐ŸŽ€. -fno-align-jumps and -falign-jumps=1 are equivalent and mean that loops are not aligned ๐Ÿ™ƒ

If n isn't specified or is zero, you get the machine-dependent default. The max n is 65536 ๐ŸŒธ

Enabled at levels -O2, -O3 โœจ

-fno-allocation-dce

Do not remove unused C++ allocations during dead code elimination. The compiler keeps them around, no cap ๐Ÿซถ

-fallow-store-data-races

Okay this one is kinda spicy ๐ŸŒถ๏ธ. 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 affect optimization of local data, though ๐Ÿ’œ

Examples of the optimizations this enables include hoisting or if-conversions that might cause a value already in memory to get re-written with that same value. That re-writing is safe in a single-threaded context but may be unsafe in a multi-threaded one ๐Ÿ’€. Also, on some processors, if-conversions may be required to enable vectorization ๐Ÿ”ฅ

Bestie, it's only safe to use this if you know global data won't be accessed by multiple threads. Otherwise, it's a whole mess ๐Ÿšจ

Enabled at level -Ofast ๐Ÿ‘‘

-funit-at-a-time

This one is only still here for compatibility reasons, so it has no effect ๐Ÿฅน. -fno-unit-at-a-time does have effects though: it implies -fno-toplevel-reorder and -fno-section-anchors ๐Ÿฆ‹

Enabled by default โœจ

-fno-toplevel-reorder

Do not reorder top-level functions, variables, and "asm" statements. They get output in the same order they appear in the input file ๐ŸŽ€. When you use this option, unreferenced static variables are not removed ๐Ÿ˜ฌ

This option exists 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 ๐Ÿงš. Also, -fno-toplevel-reorder implies -fno-section-anchors ๐Ÿ’œ

-fweb

This one constructs webs, which are commonly used for register allocation purposes, and assigns each web its own individual pseudo register ๐Ÿ•ธ๏ธ. The register allocation pass can then operate on pseudos directly, and it also strengthens several other optimization passes, like CSE, the loop optimizer, and the trivial dead code remover ๐Ÿ”ฅ

Heads up though: it can make debugging impossible, since variables no longer stay in a "home register" ๐Ÿ’€

Enabled by default with -funroll-loops ๐ŸŒธ

-fwhole-program

Okay so this tells the compiler to assume the current compilation unit is the whole program being compiled ๐ŸŒ. All public functions and variables become static functions, except for "main" and anything merged by the attribute "externally_visible". Because of that, the interprocedural optimizers can go way harder on them โœจ

Don't use this with -flto. Relying on a linker plugin should give you safer and more precise info instead ๐Ÿซถ

-flto[=n]

Main character of the whole page, fr fr ๐Ÿ‘‘. This runs the standard link-time optimizer. When you invoke it with source code, it generates GIMPLE (one of GCC's internal representations) and writes it into special ELF sections in the object file ๐Ÿงš. When the object files get linked together, all the function bodies are read from those ELF sections and instantiated as if they were part of the same translation unit ๐Ÿฆ‹

To use the link-time optimizer, -flto and optimization options should be specified at compile time and during the final link ๐Ÿ’–. It's recommended that you compile all the files in the same link with the same options, and also specify those options at link time. For example:

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

The first two invocations save a bytecode representation of GIMPLE into special ELF sections inside foo.o and bar.o ๐ŸŽ€. The final invocation reads 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 files are merged, all the interprocedural analyses and optimizations work across the two files like they're one single file ๐Ÿซถ. So 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 -flto. You can always override that automatic decision by passing -fno-lto to the link command ๐Ÿ™ƒ

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

When a file is compiled with -flto without -fuse-linker-plugin, the object file is bigger than a regular one ๐Ÿ“ฆ. That's because it contains GIMPLE bytecodes and the usual final code (see -ffat-lto-objects). Objects with LTO info can still be linked as normal object files. If you pass -fno-lto to the linker, no interprocedural optimizations are applied ๐Ÿ’€. Also, if you enable -fno-fat-lto-objects, 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 picks which files to optimize in LTO mode and which to link without further processing ๐Ÿ’œ

Generally, options specified at link time override the ones specified at compile time ๐Ÿ‘‘, although in some cases GCC tries to infer link-time options from the settings used to compile the input files ๐Ÿงš

If you don't specify an optimization level option -O at link time, GCC uses the highest optimization level used when compiling the object files ๐ŸŒˆ. Specifying an optimization level only at link time and not at compile time is generally ineffective, and there are two reasons why ๐Ÿ’€. First, compiling without optimization suppresses the compiler passes that gather info needed for effective optimization at link time. Second, some early optimization passes can only be performed at compile time, not at link time ๐Ÿ™ˆ

There are some code generation flags that GCC preserves when generating bytecodes, since they need to be used during the final link โœจ. Right now, the following options and their settings are taken from the first object file that explicitly specifies them: -fcommon, -fexceptions, -fnon-call-exceptions, -fgnu-tm, and all the -m target flags ๐ŸŽ€

The options -fPIC, -fpic, -fpie and -fPIE are combined based on 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 all compilation units. 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, are passed through to the link stage and merged conservatively for conflicting translation units ๐Ÿฆ‹. Specifically, -fno-strict-overflow, -fwrapv and -fno-trapv take precedence, and for example -ffp-contract=off takes precedence over -ffp-contract=fast ๐Ÿ’…. You can override them at link time โœจ

Okay bestie, so diagnostic options like -Wstringop-overflow get passed right through to the link stage ๐Ÿ’… and their setting lines up with the compile step at function granularity ๐Ÿงš. ngl this only matters for diagnostics that pop up during optimization โœจ. Also, code transforms like inlining can make warnings switch on or off for regions of code that don't match the setting from compile time ๐Ÿ™ˆ lowkey chaotic ๐Ÿ’€.

When you need to pass stuff to the assembler through -Wa or -Xassembler ๐ŸŽ€, either compile those translation units with -fno-lto, or use the exact same assembler options on every translation unit ๐Ÿซถ. You can also specify assembler options at LTO link time instead ๐Ÿฆ‹.

To get debug info you need -g at compile time ๐ŸŒธ. If any input files at link time were built with debug info, the link turns debug info on too ๐Ÿ’–. Fancy debug settings like the dwarf level -gdwarf-5 have to be repeated explicitly on the linker command line ๐Ÿ˜ญ, and mixing different settings across translation units is discouraged ๐Ÿ’€.

If LTO runs into objects with C linkage declared with incompatible types across separate translation units being linked together (undefined behavior according to ISO C99 6.2.7) ๐Ÿ˜ฌ, it may issue a non-fatal diagnostic ๐Ÿšจ. The behavior is still undefined at run time, so that's still a whole mess ๐Ÿ’€. Similar diagnostics may be raised for other languages too.

Another LTO feature is that you can apply interprocedural optimizations to files written in different languages ๐ŸŒˆ

gcc -c -flto foo.c
g++ -c -flto bar.cc
gfortran -c -flto baz.f90
g++ -o myprog -flto -O3 foo.o bar.o baz.o -lgfortran

Notice the final link is done with g++ to get the C++ runtime libraries, and -lgfortran gets added for the Fortran runtime libraries ๐Ÿ‘‘. In general, when mixing languages in LTO mode, use the same link command options you'd use when mixing languages in a regular (non-LTO) compilation ๐Ÿ’….

If object files containing GIMPLE bytecode are stored in a library archive, say libfoo.a, you can extract and use them in an LTO link as long as you're using a linker with plugin support ๐Ÿฆ‹. To 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 -fuse-linker-plugin so the library joins the LTO optimization process ๐Ÿ‘‘

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

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

If you aren't 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 need the whole program to be present ๐ŸŒธ. If the program doesn't require any symbols to be exported, you can combine -flto and -fwhole-program so the interprocedural optimizers can use more aggressive assumptions, which may lead to better optimization opportunities โญ. You don't need -fwhole-program 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 won't work with an older or newer version of GCC ๐Ÿ™ˆ.

Link-time optimization doesn't work well with debug info generation on systems other than those using a combination of ELF and DWARF ๐Ÿ˜ญ.

If you specify the optional n, the optimization and code generation done at link time runs in parallel using n parallel jobs by utilizing an installed make program ๐Ÿ”ฅ. The environment variable MAKE can be used to override which program gets used ๐Ÿ’….

You can also specify -flto=jobserver to use GNU make's job server mode to determine the number of parallel jobs ๐Ÿงš. This is super useful when the Makefile calling GCC is already running 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 it's available, or otherwise fall back to autodetecting the number of CPU threads in your system ๐ŸŒˆ.


  • -flto-partition=alg โ€” Picks the partitioning algorithm the link-time optimizer uses ๐Ÿงฉ. Your choices are:
    • 1to1 โ€” partitions mirror the original source files ๐Ÿ“‚ this can be used as a workaround for various code ordering issues ๐Ÿฉน
    • balanced โ€” partitions into equally sized chunks (whenever possible) โš–๏ธ this is the default ๐Ÿ‘‘
    • max โ€” creates a new partition for every symbol where possible ๐Ÿงช this one is intended for internal testing only ๐Ÿ™ˆ
    • none โ€” disables partitioning and streaming completely ๐Ÿšซ
    • one โ€” uses exactly one partition 1๏ธโƒฃ
Heads up: none bypasses partitioning and runs the link-time optimization step directly from the WPA phase, which is different from one ๐Ÿ’€
  • -flto-compression-level=n โ€” Sets the compression level for the intermediate language written to LTO object files ๐Ÿ—œ๏ธ this only means something when you're in 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 the range get clamped to the minimum or maximum of the supported values. If you don't give the option, a default balanced compression setting is used โœจ.
  • -fuse-linker-plugin โ€” Turns on the linker plugin during link-time optimization ๐Ÿ”Œ. This relies on plugin support in the linker, which is available in gold or in GNU ld 2.21 or newer ๐Ÿฆ‹. It lets GCC pull object files with GIMPLE bytecode out of library archives, which improves optimization by exposing more code to the link-time optimizer ๐Ÿ”ฅ. The plugin info also says which symbols can be accessed externally (by a non-LTO object or during dynamic linking) ๐ŸŒธ. The code quality gains on binaries (and shared libraries that use hidden visibility) are similar to -fwhole-program ๐Ÿ’–. See -flto for a description of what this flag does and how to use it.

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

  • -ffat-lto-objects โ€” Fat LTO objects are object files that contain both the intermediate language and the object code ๐Ÿฐ. That makes them usable for both LTO linking and normal linking ๐Ÿ’…. This option only takes effect when you're compiling with -flto, and it's ignored at link time ๐Ÿ™ˆ.
  • -fno-fat-lto-objects โ€” This one improves compilation time over plain LTO, but it requires the complete toolchain to be aware of LTO ๐Ÿงฐ. It needs a linker with linker plugin support for basic functionality ๐Ÿ”Œ. Also, nm, ar and ranlib need to support linker plugins to allow a full-featured build environment (capable of building static libraries and so on) ๐Ÿ“š. GCC provides the gcc-ar, gcc-nm and gcc-ranlib wrappers to pass the right options to these tools ๐ŸŽ€. 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 โ€” After register allocation and post-register-allocation instruction splitting, this finds arithmetic instructions that compute processor flags similar to a comparison operation based on that arithmetic ๐Ÿ”. If possible, it eliminates the explicit comparison operation ๐Ÿ—‘๏ธ. This pass only applies to certain targets that can't explicitly represent the comparison operation before register allocation is complete ๐ŸŽฏ. Turned on at -O, -O2, -O3, and -Os ๐Ÿ’….
  • -fcprop-registers โ€” After register allocation and post-register-allocation instruction splitting, this runs a copy-propagation pass to try to reduce scheduling dependencies and occasionally eliminate the copy ๐Ÿ“‹. Turned on at -O, -O2, -O3, and -Os ๐ŸŒˆ.
  • -fprofile-correction โ€” Profiles collected from an instrumented binary for multi-threaded programs can be inconsistent because of missed counter updates ๐Ÿงต. With this option, GCC uses heuristics to correct or smooth out those inconsistencies ๐Ÿฉน. By default, GCC emits an error message when an inconsistent profile is detected ๐Ÿšจ. This option is enabled by -fauto-profile โœจ.
  • -fprofile-partial-training โ€” With -fprofile-use, all the portions of your program that weren't executed during the train run get optimized aggressively for size rather than speed ๐Ÿ“. Sometimes it isn't practical to train every possible hot path in the program. For example, a program might contain functions specific to a given hardware setup, and training might not cover every hardware configuration the program runs on ๐Ÿ–ฅ๏ธ. With -fprofile-partial-training, profile feedback gets ignored for all functions not executed during the train run, so they're optimized as if they were compiled without profile feedback ๐Ÿง . This leads to better performance when the train run isn't representative, but it also leads to significantly bigger code ๐Ÿ“ฆ.
  • -fprofile-use, -fprofile-use=path โ€” Enables profile feedback-directed optimizations, and the following optimizations, many of which are generally only profitable with profile feedback available ๐Ÿ”ฎ

Bestie, here's the rest of the -fprofile-use squad ๐Ÿ’…โœจ

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

Okay so, the big catch ๐Ÿ™ˆ: before you can use this option, you must generate profiling information first. No shortcuts, no cap.

By default, GCC throws an error if the feedback profiles don't match your source code ๐Ÿ˜ญ. If you want that error to be a warning instead, use -Wno-error=coverage-mismatch. Just know this might give you poorly optimized code, so be careful ๐Ÿฅบ. Also by default, GCC gives you a warning if the feedback profiles don't exist at all (see -Wmissing-profile) ๐ŸŒธ.

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

  • -fauto-profile, -fauto-profile=path โ€” Okay this one is giving sampling-based feedback-directed optimizations ๐Ÿฆ‹. It turns on these optimizations too, and a lot 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-correction

path is the name of a file holding your AutoFDO profile info ๐Ÿ“. If you skip it, it defaults to fbdata.afdo in the current directory, no stress ๐ŸŽ€.

Making an AutoFDO profile file means you have to run your program with the perf utility on a supported GNU/Linux target system ๐Ÿง. For more deets, check out https://perf.wiki.kernel.org/ ๐Ÿ’œ.

Here's an example, E.g.:

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

Then you use the create_gcov tool to convert that raw profile data into a format GCC can actually read โœจ. You also have to hand it the unstripped binary for your program, so don't forget that part ๐Ÿซถ. See https://github.com/google/autofdo ๐ŸŒˆ.

Here's the example, E.g.:

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

Okay, next up is the floating-point crew ๐Ÿงš. These options control how the compiler handles floating-point math, and they're basically a speed-versus-correctness trade-off ๐Ÿ’…. You have to turn every single one of them on yourself, nothing happens automatically, periodt ๐Ÿ™ˆ.

  • -ffloat-store โ€” This one tells the compiler to not keep floating-point variables in registers, and to block any other options that might change whether a floating-point value comes from a register or from memory ๐ŸงŠ. It stops the "excess precision" drama on machines like the 68000, where the floating registers (of the 68881) hold more precision than a "double" is supposed to have ๐Ÿ˜ค. The x86 architecture has the same issue. For most programs, that extra precision is only a good thing ๐Ÿ’–, but a few programs depend on the exact definition of IEEE floating point. For those programs, use -ffloat-store after you've changed them to store all the important intermediate computations into variables ๐Ÿซถ.
  • -fexcess-precision=style โ€” This option gives you more control over excess precision on machines where floating-point operations happen in a format with more precision or range than IEEE standard and interchange floating-point types ๐Ÿฆ‹. By default, -fexcess-precision=fast is in effect, which means operations can happen in a wider precision than the types in your source code if that makes the code faster, and it's unpredictable when the rounding to your source types actually happens ๐ŸŒช๏ธ. When you're compiling C and you specify -fexcess-precision=standard, excess precision follows the rules in ISO C99. In particular, both casts and assignments get rounded to their semantic types, whereas -ffloat-store only touches assignments ๐Ÿ’…. This option is turned on by default for C if a strict conformance option like -std=c99 is used. -ffast-math turns on -fexcess-precision=fast by default no matter whether a strict conformance option is used ๐ŸŽ๏ธ.

-fexcess-precision=standard isn't implemented for languages other than C ๐Ÿ™…โ€โ™€๏ธ. On x86, it does nothing if you've specified -mfpmath=sse or -mfpmath=sse+387. With the former, IEEE semantics apply with no excess precision, and with the latter, rounding is unpredictable ๐Ÿฅด.

  • -ffast-math โ€” This sets -fno-math-errno, -funsafe-math-optimizations, -ffinite-math-only, -fno-rounding-math, -fno-signaling-nans, -fcx-limited-range and -fexcess-precision=fast all at once ๐ŸŽ๏ธ๐Ÿ’จ. It also causes the preprocessor macro "__FAST_MATH__" to get defined ๐ŸŽ€. This option is not turned on by any -O option besides -Ofast, because it can give incorrect output for programs that depend on an exact implementation of IEEE or ISO rules and specifications for math functions ๐Ÿ’€. It might, however, give you faster code for programs that don't need the guarantees of those specs โœจ.
  • -fno-math-errno โ€” Basically, don't set "errno" after calling math functions that run with a single instruction, like "sqrt" ๐Ÿง . A program that relies on IEEE exceptions for math error handling might want this flag for speed while still keeping IEEE arithmetic compatibility ๐Ÿฆ‹. This option is not turned on by any -O option, since it can give incorrect output for programs that depend on an exact implementation of IEEE or ISO rules and specifications for math functions. It might, however, give faster code for programs that don't need those guarantees ๐Ÿ’…. The default is -fmath-errno.

Fun Darwin detail ๐Ÿ: on Darwin systems, the math library never sets "errno". So there's no reason for the compiler to consider that it might, and -fno-math-errno is the default there ๐ŸŒˆ.

  • -funsafe-math-optimizations โ€” This allows optimizations for floating-point arithmetic that (a) assume arguments and results are valid and (b) may violate IEEE or ANSI standards ๐Ÿ˜ฌ. When it's used at link time, it may include libraries or startup files that change the default FPU control word or do other similar optimizations ๐Ÿ”ง. This option is not turned on by any -O option, since it can give incorrect output for programs that depend on an exact implementation of IEEE or ISO rules and specifications for math functions. It might, however, give faster code for programs that don't need those guarantees ๐Ÿ’œ. It enables -fno-signed-zeros, -fno-trapping-math, -fassociative-math and -freciprocal-math ๐Ÿซถ. The default is -fno-unsafe-math-optimizations.
  • -fassociative-math โ€” This allows re-association of operands in series of floating-point operations ๐Ÿ”€. Heads up, it violates the ISO C and C++ language standards by possibly changing the computation result ๐Ÿ˜ญ. NOTE: re-ordering may change the sign of zero, ignore NaNs, and inhibit or create underflow or overflow. That means it can't be used on code that relies on rounding behavior like "(x + 2**52) - 2**52". It may also reorder floating-point comparisons, so don't use it when ordered comparisons are required ๐Ÿ™…โ€โ™€๏ธ. This option requires that both -fno-signed-zeros and -fno-trapping-math be in effect. Also, it doesn't make much sense with -frounding-math. For Fortran, the option is automatically enabled when both -fno-signed-zeros and -fno-trapping-math are in effect ๐Ÿ‘‘. The default is -fno-associative-math.
  • -freciprocal-math โ€” This lets the reciprocal of a value get used instead of dividing by the value, if that enables optimizations โž—. For example, "x / y" can be replaced with "x * (1/y)", which is handy if "(1/y)" is subject to common subexpression elimination ๐Ÿงฎ. Just know that 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 arguments and results are not NaNs or +-Infs ๐Ÿ™ˆ. This option is not turned on by any -O option, since it can give incorrect output for programs that depend on an exact implementation of IEEE or ISO rules and specifications for math functions. It might, however, give faster code for programs that don't need those guarantees โœจ. The default is -fno-finite-math-only.
  • -fno-signed-zeros โ€” This allows optimizations for floating-point arithmetic that ignore the signedness of zero ๐ŸงŠ. IEEE arithmetic specifies how distinct +0.0 and -0.0 values behave, which then stops you from simplifying expressions like x+0.0 or 0.0*x (even with -ffinite-math-only) ๐Ÿšซ. This option means the sign of a zero result isn't significant ๐Ÿ’…. The default is -fsigned-zeros.
  • -fno-trapping-math โ€” This tells the compiler to assume floating-point operations can't generate user-visible traps ๐Ÿชค. Those traps include division by zero, overflow, underflow, inexact result and invalid operation โš ๏ธ. This option requires that -fno-signaling-nans be in effect. Turning it on might allow faster code if you rely on "non-stop" IEEE arithmetic, for example ๐Ÿƒโ€โ™€๏ธ.
This option should never be turned on by any -O option, since it can give incorrect output for programs that depend on an exact implementation of IEEE or ISO rules and specifications for math functions. Don't let it sneak in on you ๐Ÿ’€.

The default is -ftrapping-math.

  • -frounding-math โ€” This disables transformations and optimizations that assume the default floating-point rounding behavior ๐ŸŽฒ. That default is round-to-zero for all floating-point-to-integer conversions, and round-to-nearest for all other arithmetic truncations. You should specify this for programs that change the FP rounding mode dynamically, or that may get executed with a non-default rounding mode ๐Ÿ”„. It also disables constant folding of floating-point expressions at compile time (since that can be affected by rounding mode), along with arithmetic transformations that are unsafe with sign-dependent rounding modes ๐Ÿง . The default is -fno-rounding-math.
This option is experimental, and it doesn't currently guarantee to disable all GCC optimizations that are affected by rounding mode ๐Ÿงช. Future versions of GCC may give finer control over this setting using C99's "FENV_ACCESS" pragma. This command-line option will be used to specify the default state for "FENV_ACCESS" ๐ŸŒธ.
  • -fsignaling-nans: okay so this one tells GCC to assume IEEE signaling NaNs can cause user-visible traps during floating-point ops ๐Ÿ’ซ. Turning it on disables optimizations that could change how many exceptions show up with signaling NaNs. It implies -ftrapping-math.
    • Enabling it also defines the preprocessor macro "__SUPPORT_SNAN__" ๐ŸŽ€.
    • The default is -fno-signaling-nans ๐ŸŒธ.
    • > This one is experimental, and 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 versions) from generating code that raises the inexact floating-point exception for noninteger arguments ๐Ÿฆ‹. ISO C99 and C11 let these functions raise inexact, but ISO/IEC TS 18661-1:2014 (the C bindings to IEEE 754-2008, as folded into ISO C2X) doesn't, so this flag keeps you on the TS 18661 side ๐Ÿ‘‘.
    • The default is -ffp-int-builtin-inexact, which allows the exception to be raised, unless C2X or a later C standard is selected โœจ.
    • This option does nothing unless -ftrapping-math is in effect ๐Ÿ’….
    • Even with -fno-fp-int-builtin-inexact, if the functions end up calling a library function, inexact may still be raised if that library doesn't follow TS 18661 ๐Ÿ˜ญ.
  • -fsingle-precision-constant: floating-point constants get treated as single precision instead of being quietly converted to double-precision constants ๐Ÿ’–.
  • -fcx-limited-range: when this is on, GCC assumes no range reduction step is needed for complex division ๐Ÿงš. It also skips checking whether a complex multiplication or division result is NaN + I*NaN and trying to rescue that situation ๐Ÿ’€. The default is -fno-cx-limited-range, but -ffast-math turns it on ๐Ÿ”ฅ.
    • This option controls the default setting of the ISO C99 CX_LIMITED_RANGE pragma ๐ŸŒˆ.
    • It applies to all languages, not just C ๐Ÿซถ.
  • -fcx-fortran-rules: complex multiplication and division follow Fortran rules ๐Ÿ“. Range reduction happens as part of complex division, but there's still no checking for a NaN + I*NaN result or any rescue attempt ๐Ÿ’œ.
    • The default is -fno-cx-fortran-rules โญ.

The next group is all about optimizations that can boost performance but aren't switched on by any -O level ๐Ÿฆ‹. Heads up, bestie: this section also has experimental options that might produce broken code ๐Ÿ’€.

  • -fbranch-probabilities: this is the second act of profiling ๐Ÿ”ฎ. After you run a program built with -fprofile-arcs, you compile it again with -fbranch-probabilities so the optimizer can use how often each branch was actually taken ๐Ÿ“ˆ. When a -fprofile-arcs program exits, it saves arc execution counts to a file called sourcename.gcda for each source file ๐Ÿ’พ. That data is super dependent on the generated code's structure, so you need the same source code and the same optimization options for both compiles ๐Ÿซถ.
    • With -fbranch-probabilities, GCC attaches a REG_BR_PROB note to each JUMP_INSN and CALL_INSN ๐Ÿงฉ. Right now those notes are only used in one place: in reorg.c, where instead of guessing which path a branch is most likely to take, the REG_BR_PROB values are used to figure out exactly which path gets taken more often ๐ŸŽฏ.
    • Enabled by -fprofile-use and -fauto-profile โœจ.
  • -fprofile-values: combined with -fprofile-arcs, this adds code that gathers data about the values of expressions in your program ๐Ÿ“Š.
    • With -fbranch-probabilities, it reads that gathered data back in and uses it for optimizations ๐Ÿง .
    • Enabled by -fprofile-generate, -fprofile-use, and -fauto-profile ๐Ÿ’œ.
  • -fprofile-reorder-functions: function reordering based on profile instrumentation records the first time each function runs, then sorts the functions in ascending order by that time ๐Ÿƒโ€โ™€๏ธ.
    • Enabled with -fprofile-use ๐ŸŒธ.
  • -fvpt: combined with -fprofile-arcs, this tells the compiler to add code that collects information about expression values ๐Ÿ•ต๏ธโ€โ™€๏ธ.
    • With -fbranch-probabilities, it reads the data back and actually performs optimizations based on it. Right now those include specializing division operations using what it knows about the denominator's value ๐Ÿฐ.
    • Enabled with -fprofile-use and -fauto-profile ๐Ÿ‘‘.
  • -frename-registers: this tries to avoid false dependencies in scheduled code by using registers left over after register allocation ๐ŸŒˆ. It mostly helps processors with lots of registers ๐Ÿ’ช.
    • Heads up: depending on the debug information format the target uses, it can make debugging impossible, because variables no longer stay in a "home register" ๐Ÿ˜ญ.
    • Enabled by default with -funroll-loops ๐ŸŽ€.
  • -fschedule-fusion: a target-dependent pass over the instruction stream that schedules instructions of the same type together, since the target machine can run them more efficiently when they sit next to each other ๐Ÿš€.
    • Enabled at levels -O2, -O3, -Os ๐Ÿ’–.
  • -ftracer: performs tail duplication to enlarge superblock size ๐Ÿงต. This simplifies the function's control flow so other optimizations can do a better job ๐Ÿซถ.
    • Enabled by -fprofile-use and -fauto-profile โœจ.
  • -funroll-loops: unrolls loops whose iteration count can be figured out at compile time or when the loop is entered ๐Ÿ”.
    • -funroll-loops implies -frerun-cse-after-loop, -fweb and -frename-registers ๐Ÿงฉ.
    • It also turns on complete loop peeling, meaning loops with a small constant number of iterations get fully removed ๐Ÿ“.
    • > This makes code bigger, and it may or may not make it run faster ๐Ÿคทโ€โ™€๏ธ.
    • Enabled by -fprofile-use and -fauto-profile ๐Ÿ’….
  • -funroll-all-loops: unrolls all loops, even when their iteration count is uncertain on entry ๐Ÿ™ˆ.
    • > 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, either from profile feedback or static analysis ๐ŸŒ. It also turns on complete loop peeling, the same way as before, for loops with a small constant number of iterations โœจ.
    • Enabled by -O3, -fprofile-use, and -fauto-profile ๐Ÿฆ‹.
  • -fmove-loop-invariants: turns on the loop invariant motion pass in the RTL loop optimizer ๐ŸŒ€.
    • Enabled at level -O1 and higher, except for -Og ๐Ÿซถ.
  • -fsplit-loops: splits a loop into two if it contains a condition that's always true for one side of the iteration space and false for the other ๐Ÿช“.
    • Enabled by -fprofile-use and -fauto-profile ๐ŸŒธ.
  • -funswitch-loops: moves branches with loop invariant conditions outside the loop, with duplicates of the loop on both branches (each one adjusted to the result of the condition) ๐Ÿ”€.
    • Enabled by -fprofile-use and -fauto-profile ๐Ÿ‘‘.
  • -fversion-loops-for-strides: if a loop walks an array with a variable stride, GCC makes another version of the loop that assumes the stride is always one ๐Ÿ›ฃ๏ธ. Here's the vibe:
        for (int i = 0; i < n; ++i)
          x[i * stride] = ...;

becomes:

        if (stride == 1)
          for (int i = 0; i < n; ++i)
            x[i] = ...;
        else
          for (int i = 0; i < n; ++i)
            x[i * stride] = ...;
  • This is especially helpful for assumed-shape arrays in Fortran, where it can allow better vectorization by assuming contiguous accesses ๐Ÿง.
  • This flag is enabled by default at -O3 ๐Ÿ”ฅ. It's also enabled by -fprofile-use and -fauto-profile ๐Ÿ’–.
  • -ffunction-sections, -fdata-sections: each function or data item gets its own section in the output file, if the target supports arbitrary sections ๐Ÿ—‚๏ธ. The function's name or the data item's name decides the section name in the output file ๐Ÿท๏ธ.
    • Use these on systems where the linker can optimize for locality of reference in the instruction space. Most systems using the ELF object format have linkers like that. On AIX, the linker rearranges sections (CSECTs) based on the call graph, and the performance impact varies ๐ŸŽข.
    • Together with linker garbage collection (the linker --gc-sections option), these can lead to smaller statically-linked executables (after stripping) ๐Ÿงน.
    • On ELF/DWARF systems, these options don't degrade the quality of the debug information. There could be issues with other object file or debug info formats ๐Ÿค”.
    • > Only use these when there are significant benefits ๐Ÿ™. They make the assembler and linker produce larger object and executable files, and they're also slower ๐Ÿข. They also affect code generation: they prevent the compiler and assembler from using relative locations inside a translation unit, since those locations are unknown until link time ๐Ÿ”—. An example of an optimization that gets blocked is relaxing calls to short call instructions ๐Ÿ“ž.
  • -fstdarg-opt: optimizes the prologue of variadic argument functions based on how those arguments are used ๐ŸŽ.
    • NOTE: In Ubuntu 14.10 and later versions, -fstack-protector-strong is enabled by default for C, C++, ObjC, and ObjC++, as long as none of -fno-stack-protector, -nostdlib, or -ffreestanding are found ๐Ÿ›ก๏ธ.
  • -fsection-anchors: tries to reduce the number of symbolic address calculations by using shared "anchor" symbols to reach nearby objects โš“. On some targets, this can help cut down on GOT entries and GOT accesses ๐ŸŒˆ.
    • For example, take this function foo:
        static int a, b, c;
        int foo (void) { return a + b + c; }

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

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

Not all targets support this option. ๐Ÿ™ˆ

  • -fzero-call-used-regs=choice โ€” okay so this one zeroes out the call-used registers when a function returns ๐Ÿงน, which is lowkey iconic for security because it can either mitigate Return-Oriented Programming (ROP) attacks ๐Ÿ›ก๏ธ or prevent information leaking out through registers ๐Ÿ”. The possible values of choice are the same as for the zero_call_used_regs attribute, and the default is skip ๐Ÿ’…. You can control this for one specific function with the function attribute zero_call_used_regs โœจ.

โœจ --param name=value โœจ

bestie, GCC is constantly using secret little numbers to decide how much optimizing to do ๐Ÿค“. For example, it won't inline a function that has more than a certain number of instructions ๐Ÿ™…โ€โ™€๏ธ. You can tweak some of these numbers on the command line with the --param option ๐ŸŽ€.

Heads up, babe: the names of specific parameters, and what their values mean, are tied to the compiler's internals and can change without notice in future releases ๐Ÿšจ.

To get the minimal, maximal, and default value of a parameter, you can use --help=param -Q options ๐Ÿ”. In each case the value is 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 remove conditional branches around a block and swap them for conditionally executed instructions ๐Ÿช„. This is the max number of instructions in a block that should be considered for if-conversion. The compiler also uses other heuristics to decide whether if-conversion is likely to be profitable ๐Ÿง .
  • max-rtl-if-conversion-predictable-cost โ€” RTL if-conversion will try to remove conditional branches around a block and replace them with conditionally executed instructions ๐Ÿช„. These parameters give the max permissible cost for the sequence that would be generated, depending on whether the branch is statically determined to be predictable or not ๐Ÿ“. The units are the same as for the GCC internal seq_cost metric ๐Ÿงฎ. The compiler will try to provide a reasonable default using the BRANCH_COST target macro ๐ŸŽฏ.
  • max-crossjump-edges โ€” the max number of incoming edges to consider for cross-jumping ๐Ÿ”€. The algorithm used by -fcrossjumping is O(N^2) in the number of edges incoming to each block ๐Ÿข. Bigger values mean more aggressive optimization, making compile time go up for probably a small improvement 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 is ignored when all instructions in the block being cross-jumped from are matched ๐Ÿ™ˆ.
  • max-grow-copy-bb-insns โ€” the max code size expansion factor when copying basic blocks instead of jumping ๐Ÿ“ˆ. The expansion is relative to a jump instruction ๐Ÿฆ˜.
  • max-goto-duplication-insns โ€” the max number of instructions to duplicate into a block that jumps to a computed goto ๐Ÿช„. To avoid O(N^2) behavior in a number of passes, GCC factors computed gotos early in compilation and unfactors them as late as possible โฐ. Only computed jumps at the end of a basic block with no more than max-goto-duplication-insns get unfactored ๐Ÿ’….
  • max-delay-slot-insn-search โ€” the max number of instructions to consider when looking for an instruction to fill a delay slot ๐Ÿ”Ž. If more than this arbitrary number is searched, the time saved by filling the delay slot is minimal, so GCC stops searching ๐Ÿ›‘. Bigger values mean more aggressive optimization, making compile time go up for probably a small improvement in execution time ๐ŸŒ.
  • max-delay-slot-live-search โ€” when trying to fill delay slots, the max number of instructions to consider when searching for a block with valid live register information ๐Ÿ”. Increasing this arbitrarily chosen value means more aggressive optimization, which increases compile time ๐Ÿข. This parameter should be removed when the delay slot code is rewritten to maintain the control-flow graph ๐Ÿ—‘๏ธ.
  • max-gcse-memory โ€” the approximate max amount of memory in "kB" that can be allocated to do global common subexpression elimination ๐Ÿง . If more memory than specified is required, the optimization is not done ๐Ÿšซ.
  • max-gcse-insertion-ratio โ€” if the ratio of expression insertions to deletions is larger than this value for any expression, then RTL PRE inserts or removes the expression, leaving partially redundant computations in the instruction stream ๐ŸŒ€.
  • max-pending-list-length โ€” the max number of pending dependencies scheduling allows before flushing the current state and starting over ๐Ÿ”„. Large functions with few branches or calls can create excessively large lists that needlessly eat up memory and resources ๐Ÿ”.
  • max-modulo-backtrack-attempts โ€” the max number of backtrack attempts the scheduler should make when modulo scheduling a loop ๐Ÿ”. Larger values can exponentially increase compile time ๐Ÿ“ˆ๐Ÿ’€.
  • max-inline-insns-single โ€” several parameters control the tree inliner used in GCC ๐ŸŒณ. This number sets the max number of instructions (counted in GCC's internal representation) in a single function that the tree inliner considers for inlining ๐Ÿ“. It only affects functions declared inline and methods implemented in a class declaration (C++) ๐Ÿ’œ.
  • max-inline-insns-auto โ€” when you use -finline-functions (included in -O3), a lot of functions that would otherwise not be considered for inlining get investigated ๐Ÿ‘€. For those functions, a different and more restrictive limit than the one for functions declared inline can be applied (--param max-inline-insns-auto) ๐Ÿ”’.
  • max-inline-insns-small โ€” the bound applied to calls considered relevant with -finline-small-functions ๐Ÿญ.
  • max-inline-insns-size โ€” the bound applied to calls optimized for size ๐Ÿ“. Small growth may be desirable to anticipate optimization opportunities exposed by inlining โœจ.
  • uninlined-function-insns โ€” the number of instructions the inliner counts for function overhead, like the function prologue and epilogue ๐Ÿงพ.
  • uninlined-function-time โ€” the extra time the inliner counts for function overhead, like the time needed to execute the function prologue and epilogue โฑ๏ธ.
  • inline-heuristics-hint-percent โ€” the scale (in percent) applied to inline-insns-single, inline-insns-single-O2, and inline-insns-auto when inline heuristics hint that inlining is very profitable (it will enable later optimizations) ๐ŸŽ‰.
  • uninlined-thunk-insns, uninlined-thunk-time โ€” same as --param uninlined-function-insns and --param uninlined-function-time, but applied to function thunks ๐Ÿงต.
  • inline-min-speedup โ€” when the estimated performance improvement of caller + callee runtime exceeds this threshold (in percent), the function can be inlined regardless of the limit on --param max-inline-insns-single and --param max-inline-insns-auto ๐Ÿš€.
  • large-function-insns โ€” the limit that defines really large functions ๐Ÿ˜. For functions larger than this limit after inlining, inlining is constrained by --param large-function-growth ๐Ÿ”’. This parameter is mainly useful to avoid extreme compilation time caused by non-linear algorithms used by the back end ๐Ÿฅต.
  • large-function-growth โ€” the max growth of large functions caused by inlining, in percent ๐Ÿ“. For example, the value 100 limits large function growth to 2.0 times the original size ๐Ÿ’ฏ.
  • large-unit-insns โ€” the limit that defines a large translation unit ๐Ÿ“š. Growth caused by inlining units larger than this limit is constrained by --param inline-unit-growth. For small units that might be too tight ๐Ÿค. For example, consider a unit consisting of function A, which is inline, and B, which just calls A three times. If B is small relative to A, the growth of the unit is 300% and yet such inlining is very sane ๐Ÿ™Œ. For very large units made of small inlineable functions, though, the overall unit growth limit is needed to avoid exponential explosion of code size ๐Ÿ’ฅ. So for smaller units, the size gets bumped up to --param large-unit-insns before --param inline-unit-growth is applied ๐Ÿ“ˆ.
  • lazy-modules โ€” the max number of concurrently open C++ module files when lazy loading ๐Ÿ“‚.
  • inline-unit-growth โ€” the max overall growth of the compilation unit caused by inlining ๐ŸŒฑ. For example, the value 20 limits unit growth to 1.2 times the original size. Cold functions (either marked cold via an attribute or by profile feedback) are not counted in the unit size โ„๏ธ.
  • ipa-cp-unit-growth โ€” the max overall growth of the compilation unit caused by interprocedural constant propagation ๐ŸงŠ. For example, the value 10 limits unit growth to 1.1 times the original size.
  • ipa-cp-large-unit-insns โ€” the size of a translation unit that the IPA-CP pass considers large ๐Ÿ“.
  • large-stack-frame โ€” the limit specifying 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, the value 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 performing recursive inlining ๐Ÿ”โœจ.

okay so this is the tail end of the last bit ๐Ÿซถ --param max-inline-insns-recursive is the one for functions you actually declared inline ๐ŸŽ€. For functions that aren't declared inline, recursive inlining only happens when -finline-functions (included in -O3) is enabled, and then you want --param max-inline-insns-recursive-auto instead โœจ

  • max-inline-recursive-depth, max-inline-recursive-depth-auto โ€” ๐ŸŒˆ sets the max recursion depth for recursive inlining. --param max-inline-recursive-depth is for functions declared inline, and for non-inline functions (which only get recursive inlining when -finline-functions is on, so it's -O3 territory) you use --param max-inline-recursive-depth-auto instead.
  • min-inline-recursive-probability โ€” ๐Ÿฆ‹ recursive inlining is only worth it for functions that recurse deeply on average. For functions with barely any recursion, it can backfire by bulking up the prologue or making the function body more complicated for other optimizers ๐Ÿ’€. When profile feedback is available (see -fprofile-generate), the compiler can guess the real recursion depth from how likely a function is to recurse through a given call expression. This param only lets inlining happen for call expressions whose probability is above the threshold, given in percent.
  • early-inlining-insns โ€” ๐Ÿงš how much growth the early inliner is allowed to make. Basically, it bumps up the amount of inlining for code with a big abstraction penalty.
  • max-early-inliner-iterations โ€” ๐Ÿ”ฅ the limit on how many iterations the early inliner runs. This bounds how many nested indirect calls it can resolve. Deeper chains still get handled by late inlining.
  • comdat-sharing-probability โ€” ๐Ÿ’œ the probability (in percent) that C++ inline functions with comdat visibility get shared across multiple compilation units.
  • modref-max-bases, modref-max-refs, modref-max-accesses โ€” ๐Ÿ“ the max number of base pointers, references, and accesses stored for a single function by mod/ref analysis.
  • modref-max-tests โ€” ๐Ÿ’… the max number of tests the alias oracle can run to tell memory locations apart using mod/ref info. This one 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. Set it to 0 and the analysis is disabled completely ๐Ÿ™ˆ.
  • modref-max-escape-points โ€” โœจ the max number of escape points modref tracks per SSA-name.
  • profile-func-internal-id โ€” ๐ŸŽ€ controls whether the function's internal id gets used in the profile database lookup. If the value is 0, the compiler uses an id based on the function's assembler name and filename, which makes old profile data more forgiving of source changes like function reordering ๐Ÿฆ‹.
  • min-vect-loop-bound โ€” ๐Ÿซถ the minimum number of iterations below which loops don't get 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 in working out the max distance an expression can be moved by GCSE optimizations. It's only supported in the code hoisting pass ๐Ÿง . The bigger the ratio, the more aggressive the hoisting for simple expressions (ones costing less than gcse-unrestricted-cost). Setting it to 0 disables hoisting of simple expressions.
  • gcse-unrestricted-cost โ€” โญ roughly, the cost (measured as about one typical machine instruction) at which GCSE optimizations stop limiting how far an expression can travel. Also only supported in the code hoisting pass. The lower the cost, the more aggressive the hoisting. Setting it to 0 lets every expression travel unrestricted distances.
  • max-hoist-depth โ€” ๐Ÿ“ how deep the search goes up the dominator tree looking for expressions to hoist. This keeps the hoisting algorithm from going quadratic. A value of 0 doesn't limit the search, but it may slow down compilation of huge functions ๐Ÿข.
  • max-tail-merge-comparisons โ€” ๐Ÿ’– the max number of similar basic blocks a block gets compared against. This stops tree tail merging from going quadratic.
  • max-tail-merge-iterations โ€” ๐Ÿ”ฅ the max number of iterations of the pass over the function. It's there to cap compile time in tree tail merging.
  • store-merging-allow-unaligned โ€” ๐ŸŒธ lets the store merging pass introduce unaligned stores, but only if that's legal to do.
  • max-stores-to-merge โ€” ๐Ÿ’… the max number of stores the store merging pass will try to fold 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 in the store merging pass.
  • max-stores-to-track โ€” ๐Ÿฆ‹ the max number of stores tracked at the same time while trying to merge them into wider stores in the store merging pass.
  • max-unrolled-insns โ€” ๐ŸŽ€ the max number of instructions a loop can have and still get unrolled. If a loop does get unrolled, this param also decides how many times the loop code is unrolled ๐Ÿ”.
  • max-average-unrolled-insns โ€” โœจ same idea as above, but counts instructions biased by how likely they are to execute. If a loop gets unrolled, this param also decides how many times the loop code is unrolled.
  • max-unroll-times โ€” ๐Ÿ‘‘ the max number of unrollings for a single loop.
  • max-peeled-insns โ€” ๐ŸŒˆ the max number of instructions a loop can have and still get peeled. If a loop gets peeled, this param also decides how many times the loop code is peeled.
  • max-peel-times โ€” ๐Ÿ“ the max number of peelings for a single loop.
  • max-peel-branches โ€” ๐Ÿ’œ the max number of branches on the hot path through the peeled sequence.
  • max-completely-peeled-insns โ€” ๐Ÿซถ the max number of insns in a completely peeled loop.
  • max-completely-peel-times โ€” โญ the max number of iterations a loop can have and still be suitable for complete peeling.
  • max-completely-peel-loop-nest-depth โ€” ๐Ÿง  the max depth of a loop nest that's suitable for complete peeling.
  • max-unswitch-insns โ€” ๐Ÿ”ฅ the max number of insns in an unswitched loop.
  • max-unswitch-level โ€” ๐Ÿ’– the max number of branches unswitched in a single loop.
  • lim-expensive โ€” ๐Ÿ’… the minimum cost for an expression to count as expensive in loop invariant motion.
  • min-loop-cond-split-prob โ€” ๐Ÿฆ‹ when FDO profile information is available, this sets the minimum threshold for the probability of a semi-invariant condition statement triggering a loop split ๐ŸŒธ.
  • iv-consider-all-candidates-bound โ€” ๐Ÿงš the bound on the number of candidates for induction variables. Below this number, every candidate gets considered for each use in induction variable optimizations. Above it, only the most relevant ones get considered, to avoid quadratic time complexity.
  • iv-max-considered-uses โ€” ๐Ÿ™ˆ induction variable optimizations give up on loops that contain more induction variable uses than this.
  • iv-always-prune-cand-set-bound โ€” ๐ŸŽ€ if the candidate set is smaller than this value, the compiler always tries to remove unnecessary ivs from the set when adding a new one.
  • avg-loop-niter โ€” โœจ the average number of iterations of a loop.
  • dse-max-object-size โ€” ๐ŸŒˆ the max size (in bytes) of objects tracked bytewise by dead store elimination. Bigger values may mean longer compilation times ๐Ÿข.
  • dse-max-alias-queries-per-store โ€” ๐Ÿ’œ the max number of queries into the alias oracle per store. Bigger values mean longer compilation times and may remove more dead stores โœจ.
  • scev-max-expr-size โ€” ๐Ÿ“ the bound on the size of expressions used in the scalar evolutions analyzer. Large expressions slow the analyzer down.
  • scev-max-expr-complexity โ€” ๐Ÿ‘‘ the bound on the complexity of expressions in the scalar evolutions analyzer. Complex expressions slow the analyzer down 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 that can be done when loop versioning for alignment in the vectorizer.
  • vect-max-version-for-alias-checks โ€” ๐Ÿ’… the max number of run-time checks that can be done when loop versioning for alias in the vectorizer.
  • vect-max-peeling-for-alignment โ€” ๐Ÿงš the max number of loop peels to improve access alignment for the vectorizer. A value of -1 means no limit ๐ŸŒธ.
  • max-iterations-to-track โ€” ๐Ÿฆ‹ the max number of loop iterations the brute-force algorithm tries to evaluate when analyzing how many iterations a loop does.
  • hot-bb-count-fraction โ€” ๐ŸŽ€ the denominator n in the fraction 1/n of the maximal execution count of a basic block in the entire program. A basic block has to reach at least that much to count as hot. The default is 10000, which means a basic block counts as hot if its execution count is greater than 1/10000 of the maximal execution count. A value of 0 means it's never considered hot. This is used in non-LTO mode ๐Ÿ’–.
  • hot-bb-count-ws-permille โ€” okay so this is the number of the biggest-hitting permilles (anywhere from 0 to 1000) of the profiled execution of the whole program that a basic block's execution count has to be part of to count as hot ๐Ÿ”ฅ. The default is 990, so a block is hot if its count lands in the upper 990 permilles, or 99.0%, of the profiled run. 0 means it's never hot. This one is only used in LTO mode ๐ŸŽ€
  • hot-bb-frequency-fraction โ€” this is the denominator n in the fraction 1/n of the entry block's execution frequency of a function โœจ A basic block in that function needs to hit at least that much to be hot. The default is 1000, so a block is hot in a function if it runs more often than 1/1000 of the entry block's frequency. 0 means it's never hot ๐Ÿ’…
  • unlikely-bb-count-fraction โ€” the denominator n in 1/n of the number of profiled runs of the whole program ๐Ÿฆ‹ If a basic block's execution count is below that, it's considered unlikely executed. The default is 20, which means a block is unlikely if it runs in fewer than 1/20, or 5%, of the program's runs. 0 means it's always considered unlikely executed ๐Ÿ™ˆ
  • max-predicted-iterations โ€” the max number of loop iterations GCC will predict statically ๐Ÿงš This is clutch when a function has one loop with a known bound and another with an unknown bound. The known count gets predicted correctly, but the unknown one averages out to roughly 10, so the unbounded loop looks artificially cold next to the other one. It's giving unfair ๐Ÿ˜ญ
  • builtin-expect-probability โ€” controls the probability of an expression having the specified value ๐Ÿ’œ This takes a percentage, so 0 ... 100 ๐Ÿ“
  • builtin-string-cmp-inline-length โ€” the max length of a constant string for a builtin string cmp call that's allowed to get inlined ๐ŸŒธ
  • align-threshold โ€” picks a fraction of the maximal execution frequency of a basic block in a function, and that's what decides whether the block gets aligned ๐Ÿซถ
  • align-loop-iterations โ€” any loop that's expected to iterate at least this many times gets aligned โœจ
  • tracer-dynamic-coverage and tracer-dynamic-coverage-feedback โ€” these cap superblock formation once the given percentage of executed instructions is covered, so the code doesn't balloon for no reason ๐ŸŽ€

Heads up: tracer-dynamic-coverage-feedback only gets used when profile feedback is available ๐Ÿ”ฅ Real profiles are way less balanced than the statically estimated ones, so the threshold can be a bigger value.

  • tracer-max-code-growth โ€” stops tail duplication once code growth hits the given percentage ๐Ÿฆ‹ Ngl this one is kind of an artificial limit, since most of the duplicates get wiped out later in cross jumping. So it can be set way higher than the growth you actually want ๐ŸŒˆ
  • tracer-min-branch-ratio โ€” stops reverse growth when the reverse probability of the best edge drops below this threshold, in percent ๐Ÿ’…
  • tracer-min-branch-probability and tracer-min-branch-probability-feedback โ€” stop 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 for compiling with profile feedback, and tracer-min-branch-probability is for compiling without it. The feedback value needs to be more conservative (higher) to make the tracer actually effective ๐Ÿงš

  • stack-clash-protection-guard-size โ€” specifies the size of the operating system provided stack guard, as 2 raised to num bytes ๐Ÿ›ก๏ธ Higher values can mean fewer explicit probes, but if the value is larger than the OS guard, your code is vulnerable to stack clash style attacks ๐Ÿ’€
  • stack-clash-protection-probe-interval โ€” stack clash protection involves probing stack space as it gets allocated ๐ŸŒธ This controls the max distance between probes into the stack, as 2 raised to num bytes. Higher values can reduce the number of explicit probes, but a value bigger than the OS provided guard leaves your 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 sets the minimum percentage the GC heap is allowed to expand between collections. Tuning it might speed up compilation, but it has zero effect on code generation ๐Ÿ’–

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

  • ggc-min-heapsize โ€” the minimum size of the GC heap before it starts bothering to collect garbage ๐ŸŒˆ The first collection happens after the heap expands by ggc-min-expand% beyond ggc-min-heapsize. Again, tuning this may 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 don't get exceeded. It has a lower bound of 4096 (four megabytes) and an upper bound of 131072 (128 megabytes). If GCC can't calculate RAM on a platform, the lower bound is used. Setting this parameter very large effectively disables garbage collection ๐Ÿฆ‹ Setting this and ggc-min-expand to zero causes a full collection at every opportunity.

  • max-reload-search-insns โ€” the max number of instructions reload looks backward through for an equivalent register ๐Ÿ’… Bigger values mean more aggressive optimization, so compile time goes up for probably slightly better performance ๐Ÿ”ฅ
  • max-cselib-memory-locations โ€” the max number of memory locations cselib takes into account ๐Ÿ‘‘ Same deal: bigger values mean more aggressive optimization, longer compile times, and probably slightly better performance ๐ŸŒธ
  • max-sched-ready-insns โ€” the max number of instructions that are ready to be issued the scheduler should consider at any given time during the first scheduling pass ๐Ÿซถ Bigger values mean more thorough searches, so compile time goes up for probably little benefit ๐Ÿ’€
  • max-sched-region-blocks โ€” the max number of blocks in a region considered for interblock scheduling ๐Ÿงš
  • max-pipeline-region-blocks โ€” the max number of blocks in a region considered for pipelining in the selective scheduler ๐Ÿ“
  • max-sched-region-insns โ€” the max number of insns in a region considered for interblock scheduling ๐Ÿ’œ
  • max-pipeline-region-insns โ€” the max number of insns in a region considered for pipelining in the selective scheduler ๐ŸŒˆ
  • min-spec-prob โ€” the minimum probability, in percents, of reaching a source block for interblock speculative scheduling ๐ŸŽ€
  • max-sched-extend-regions-iters โ€” the max number of iterations through the CFG to extend regions โœจ A value of 0 disables region extensions ๐Ÿ™…
  • max-sched-insn-conflict-delay โ€” the max conflict delay an insn can have and still be considered for speculative motion ๐Ÿฆ‹
  • sched-spec-prob-cutoff โ€” the minimal probability of speculation success, in percents, needed before speculative insns get scheduled ๐Ÿ’…
  • sched-state-edge-prob-cutoff โ€” the minimum probability an edge must have before the scheduler saves its state across it ๐Ÿ‘‘
  • sched-mem-true-dep-cost โ€” the minimal distance, in CPU cycles, between a store and a load that target the same memory locations ๐Ÿ˜ญ
  • selsched-max-lookahead โ€” the max size of the lookahead window of selective scheduling ๐Ÿงš It's basically the depth of search for available instructions ๐Ÿ”ฅ
  • selsched-max-sched-times โ€” the max number of times an instruction gets scheduled during selective scheduling ๐ŸŒธ This is the limit on how many iterations the instruction can be pipelined through ๐Ÿ’–
  • selsched-insns-to-rename โ€” the max number of best instructions in the ready list that get considered for renaming in the selective scheduler ๐Ÿซถ
  • sms-min-sc โ€” the minimum value of stage count that the swing modulo scheduler generates ๐Ÿ“
  • max-last-value-rtl โ€” the max size, measured as the number of RTLs, that can be recorded in an expression in the combiner for a pseudo register as its last known value ๐ŸŒˆ
  • max-combine-insns โ€” the max number of instructions the RTL combiner tries to combine ๐Ÿ’…
  • integer-share-limit โ€” small integer constants can use a shared data structure, which cuts down on the compiler's memory usage and speeds it up โœจ This sets the max value of a shared integer constant ๐ŸŽ€
  • ssp-buffer-size โ€” the minimum size of buffers (aka arrays) that get stack smashing protection when -fstack-protection is used ๐Ÿ›ก๏ธ

Okay so, picking up where we left off, bestie. Before Ubuntu 10.10 the default was "8" ๐Ÿ™ˆ Now it's "4" โœจ, which means more functions get covered by the stack protector ๐Ÿ›ก๏ธ

  • min-size-for-stack-sharing โ€” the smallest size a variable can be to join in on stack slot sharing when you're not optimizing ๐Ÿงš
  • max-jump-thread-duplication-stmts โ€” the most statements a block can have and still get duplicated when jumps are threaded ๐Ÿงต
  • max-fields-for-field-sensitive โ€” how many fields a struct can have and still get the field-sensitive treatment during pointer analysis ๐Ÿ’œ
  • prefetch-latency โ€” a guess at how many instructions run on average before a prefetch finishes โฑ๏ธ The prefetch distance scales with this number, and cranking it up can mean fewer streams get prefetched (see simultaneous-prefetches) ๐ŸŒธ
  • simultaneous-prefetches โ€” the max number of prefetches allowed to 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 โ€” decides whether the loop array prefetch pass should slip in software prefetch hints for non-constant strides ๐Ÿ‘‘ Sometimes that helps, but a non-constant stride makes it super hard to tell when the hints are actually worth it ๐Ÿค”
    • Set it to 1 if you want hints issued 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 smallest constant stride, in bytes, where prefetch hints start kicking in ๐ŸŒˆ If the stride is below this threshold, no hints get issued ๐Ÿซถ
    • This one is useful on processors with hardware prefetchers, since the hardware and software prefetchers can clash. If the hardware prefetchers have a maximum stride they can handle, put that number here so the software prefetchers get used better ๐Ÿ’…
    • A value of -1 means there's no threshold, so hints can be issued for any constant stride โœจ
    • It only matters for strides that are known and constant ๐Ÿซง
  • loop-interchange-max-num-stmts โ€” the max number of statements in a loop that can get interchanged ๐Ÿ”
  • loop-interchange-stride-ratio โ€” the minimum ratio between the strides of two loops for an interchange to be worth it ๐Ÿ’ซ
  • min-insn-to-prefetch-ratio โ€” the minimum ratio of instructions to prefetches needed before a loop gets prefetching turned on ๐ŸŽ€
  • prefetch-min-insn-to-mem-ratio โ€” the minimum ratio of instructions to memory references needed to turn on prefetching in a loop ๐Ÿง
  • use-canonical-types โ€” whether the compiler uses the "canonical" type system ๐Ÿง  It should always be 1, since that's a more efficient internal way to compare types in C++ and Objective-C++ ๐Ÿ˜Œ But if bugs in the canonical type system are breaking your compiles, set it to 0 to turn canonical types off ๐Ÿ™…โ€โ™€๏ธ
  • switch-conversion-max-branch-ratio โ€” switch initialization conversion won't build arrays bigger than switch-conversion-max-branch-ratio times the number of branches in the switch ๐Ÿšซ
  • max-partial-antic-length โ€” the max length of the partial antic set computed during tree partial redundancy elimination (-ftree-pre) when you're optimizing at -O3 and up ๐ŸŒŸ Some code can make this optimization run away and eat all the memory on the host machine ๐Ÿ’€ This cap stops that runaway behavior by limiting how long the sets can get. Setting it to 0 means the set length is unlimited ๐Ÿ˜ค
  • rpo-vn-max-loop-depth โ€” the max loop depth that gets value-numbered optimistically ๐ŸŒ€ When the limit is hit, the innermost rpo-vn-max-loop-depth loops and the outermost loop in the loop nest are value-numbered optimistically, and the rest aren't ๐Ÿซถ
  • sccvn-max-alias-queries-per-access โ€” the max number of alias-oracle queries we run while hunting for redundant loads and stores ๐Ÿ•ต๏ธโ€โ™€๏ธ If the limit gets hit, the search is aborted and that load or store doesn't count as redundant. The number of queries is algorithmically capped at the number of stores on all paths from the load to the function entry ๐Ÿงฎ
  • ira-max-loops-num โ€” IRA uses regional register allocation by default ๐Ÿงฉ If a function has more loops than this number, only that many of the most frequently executed loops form regions for regional register allocation ๐ŸŽฏ
  • ira-max-conflict-table-size โ€” IRA is very smart about compressing the conflict table, but huge functions can still need an excessive amount of memory ๐Ÿ˜ญ If a function's conflict table could go over this many MB, the register allocator switches to a faster, simpler, lower-quality algorithm that doesn't build a pseudo-register conflict table ๐Ÿฅฒ
  • ira-loop-reserved-regs โ€” IRA can estimate register pressure more accurately in loops when deciding whether to move loop invariants (see -O3) ๐Ÿง˜ This sets how many available registers get reserved for other purposes. The default is the best value found from loads of experiments ๐Ÿ†
  • lra-inheritance-ebb-probability-cutoff โ€” LRA tries to reuse values reloaded into registers by later insns, and that's called inheritance ๐Ÿ”„ EBB is the region used for this, and this parameter sets the minimal fall-through edge probability (as a percentage) for adding a BB to the inheritance EBB in LRA ๐Ÿ“Š The default was picked from lots of SPEC2000 runs on x86-64 ๐Ÿ
  • loop-invariant-max-bbs-in-loop โ€” loop invariant motion can be super expensive in compile time and memory with really big loops ๐Ÿฅต Loops with more basic blocks than this won't get loop invariant motion done on them ๐Ÿ™…โ€โ™€๏ธ
  • loop-max-datarefs-for-datadeps โ€” building data dependencies is expensive for massive loops ๐Ÿ“š This caps how many data references in a loop get considered for data dependence analysis. Loops that are too big don't get handled by the optimizations that use loop data dependencies ๐Ÿ™ƒ
  • max-vartrack-size โ€” the max number of hash table slots used during variable tracking dataflow analysis of any function ๐Ÿ—‚๏ธ If that limit is blown with variable tracking at assignments enabled, the analysis gets retried without it after all debug insns are removed from the function ๐Ÿ” If it's still over the limit without debug insns, var tracking analysis is totally disabled for that function ๐Ÿ˜ต Setting it to zero makes it unlimited โ™พ๏ธ
  • max-vartrack-expr-depth โ€” the max recursion levels when mapping variable names or debug temporaries to value expressions ๐ŸŒฟ This trades compile time for more complete debug info. If it's set too low, value expressions that could've been in the debug info might not get used. Setting it higher lets the compiler find fancier debug expressions, but compile time and memory use can grow ๐Ÿ“ˆ
  • max-debug-marker-count โ€” the threshold for debug markers (like begin stmt markers) so you don't get a complexity explosion when inlining or expanding to RTL ๐Ÿ’ฅ If a function has more of these gimple stmts than the limit, they get dropped from the inlined copy of the function and from its RTL expansion ๐Ÿซ 
  • min-nondebug-insn-uid โ€” nondebug insns start their uids at this number ๐Ÿ”ข The range below it is reserved for debug insns created by -fvar-tracking-assignments, but debug insns can still get non-overlapping uids above it if that reserved range runs out ๐ŸŒ™
  • ipa-sra-ptr-growth-factor โ€” IPA-SRA only swaps a pointer to an aggregate for one or more new parameters if their cumulative size is less than or equal to ipa-sra-ptr-growth-factor times the size of the original pointer parameter ๐Ÿช„
  • ipa-sra-max-replacements โ€” the max number of pieces of an aggregate that IPA-SRA tracks ๐Ÿงฉ That also makes it the max number of replacements for a formal parameter ๐Ÿ™Œ
  • sra-max-scalarization-size-Ospeed, sra-max-scalarization-size-Osize โ€” both Scalar Reduction of Aggregates passes (SRA and IPA-SRA) try to swap scalar parts of aggregates for uses of independent scalar variables ๐Ÿงƒ These two params set the max size, in storage units, of an aggregate that's considered for that swap when compiling for speed (sra-max-scalarization-size-Ospeed) or for size (sra-max-scalarization-size-Osize) ๐ŸŽ๏ธ๐Ÿ“ฆ
  • sra-max-propagations โ€” the max number of artificial accesses that Scalar Replacement of Aggregates (SRA) tracks per local variable so it can do copy propagation ๐Ÿ”
  • tm-max-aggregate-size โ€” when copying thread-local variables inside a transaction, this sets the size in bytes after which variables get saved with the logging functions instead of save/restore code sequence pairs ๐Ÿ“ This only applies when you're using -fgnu-tm ๐ŸŽ€
  • graphite-max-nb-scop-params โ€” okay so the Graphite loop transforms can go exponential if you let them run wild ๐Ÿ’€, which is why the number of parameters in a Static Control Part (SCoP) gets capped ๐Ÿงข. Set it to 0 to lift the cap entirely โœจ. And a variable whose value isn't known at compile time and is defined outside a SCoP counts as one of that SCoP's parameters ๐Ÿฆ‹.
  • loop-block-tile-size โ€” loop blocking and strip mining (switched on with -floop-block or -floop-strip-mine) chop every loop in the nest into strips of a set number of iterations ๐ŸŽ€. You can change how long those strips are with this parameter ๐Ÿ’….
  • ipa-jump-function-lookups โ€” sets how many statements get visited while IPA hunts down jump function offsets ๐Ÿ”.
  • ipa-cp-value-list-size โ€” IPA-CP tries to track every value and type that gets passed into a function's parameter so it can propagate them and do devirtualization ๐Ÿง . This is the max number of values and types it'll store for each formal parameter ๐Ÿ’œ.
  • ipa-cp-eval-threshold โ€” IPA-CP scores its own cloning profitability ๐Ÿ“Š. Any cloning opportunity whose score beats ipa-cp-eval-threshold gets done ๐Ÿ”ฅ.
  • ipa-cp-max-recursive-depth โ€” the deepest level of recursive cloning allowed for a self-recursive function ๐ŸŒ€.
  • ipa-cp-min-recursive-probability โ€” recursive cloning only happens when the chance of the call actually running is higher than this parameter ๐ŸŽฒ.
  • ipa-cp-recursion-penalty โ€” a percentage penalty that recursive functions take when they're being evaluated for cloning ๐Ÿ“‰.
  • ipa-cp-single-call-penalty โ€” a percentage penalty for functions whose only job is making a single call to another function, applied when they're up for cloning ๐Ÿ“‰.
  • ipa-max-agg-items โ€” IPA-CP can also propagate scalar values that get passed inside an aggregate ๐Ÿ“ฆ. This caps how many of those values it'll handle for one parameter ๐Ÿ’–.
  • ipa-cp-loop-hint-bonus โ€” if IPA-CP figures out that a cloning candidate would make a loop's iteration count known, the candidate gets a bonus of ipa-cp-loop-hint-bonus added to its profitability score ๐ŸŽ.
  • ipa-max-loop-predicates โ€” the maximum number of different predicates IPA uses to describe when a function's loops have known properties ๐Ÿงฉ.
  • ipa-max-aa-steps โ€” IPA-CP uses alias analysis to keep track of what function parameters point to ๐Ÿ‘€. To avoid spending forever on huge functions, it gives up after examining ipa-max-aa-steps memory-modifying statements and just assumes all memory got clobbered ๐Ÿ™ˆ.
  • ipa-max-switch-predicate-bounds โ€” the maximum number of boundary endpoints for case ranges in a switch statement ๐Ÿ”€. If a switch goes over this limit, IPA-CP won't build the cloning cost predicate for its default case, which is what's used to estimate cloning benefit ๐Ÿšซ.
  • ipa-max-param-expr-ops โ€” IPA-CP will look at conditional statements that reference a function parameter to estimate the benefit of cloning for a certain constant value ๐Ÿค“. But if a parameter expression has more operations than ipa-max-param-expr-ops, it's considered too complicated and IPA analysis skips it ๐Ÿ’€.
  • lto-partitions โ€” the desired number of partitions made during WHOPR compilation ๐Ÿงฉ. You want this to be more than the number of CPUs being used for compilation ๐Ÿ–ฅ๏ธ.
  • lto-min-partition โ€” the minimum partition size for WHOPR, measured in estimated instructions ๐Ÿ“. This stops tiny programs from getting split into way too many partitions ๐Ÿ™…โ€โ™€๏ธ.
  • lto-max-partition โ€” the max partition size for WHOPR, also in estimated instructions ๐Ÿ“. It sets an upper bound on how big any single partition can get ๐Ÿซถ. It's only meant to be used with balanced partitioning โš–๏ธ.
  • lto-max-streaming-parallelism โ€” the maximum number of parallel processes used for LTO streaming ๐ŸŒŠ.
  • cxx-max-namespaces-for-diagnostic-help โ€” when C++ name lookup fails for an identifier, this is the max number of namespaces the compiler checks for suggestions ๐Ÿ”Ž.
  • sink-frequency-threshold โ€” the highest relative execution frequency (as a percent) that the target block can have, compared to the statement's original block, and still allow that statement to get sunk ๐Ÿ“‰. Bigger numbers mean more aggressive sinking ๐Ÿ”ฅ. Statements with memory operands get a small positive adjustment, since sinking them is even more profitable โœจ.
  • max-stores-to-sink โ€” the max number of conditional store pairs that can be sunk ๐Ÿ•ณ๏ธ. It gets set to 0 if either vectorization (-ftree-vectorize) or if-conversion (-ftree-loop-if-convert) is turned off ๐Ÿšซ.
  • case-values-threshold โ€” the smallest number of different values where a jump table is a better pick than a tree of conditional branches ๐ŸŒณ. If it's 0, the machine's default gets used ๐Ÿค–.
  • jump-table-max-growth-ratio-for-size โ€” the max code size growth ratio (in percent) when expanding into a jump table ๐Ÿ“. This one's used when you're optimizing for size ๐Ÿ—œ๏ธ.
  • jump-table-max-growth-ratio-for-speed โ€” same max code size growth ratio (in percent) for expanding into a jump table ๐Ÿ“. This one's used when you're optimizing for speed ๐ŸŽ๏ธ.
  • tree-reassoc-width โ€” sets the max number of instructions executed in parallel in a reassociated tree ๐ŸŒฒ. If it's set to a non-zero value, it overrides the target-dependent heuristics that would be used by default ๐Ÿ’ช.
  • sched-pressure-algorithm โ€” picks between the two implementations of -fsched-pressure ๐Ÿงช. Algorithm 1 is the original, and it's the one more likely to stop instructions from getting reordered ๐Ÿ™…โ€โ™€๏ธ. Algorithm 2 was built as a compromise between the pretty conservative algorithm 1 and the rather aggressive default scheduler โš–๏ธ. It leans harder on having a regular register file and accurate register pressure classes ๐Ÿงฒ. Check haifa-sched.c in the GCC sources for more details ๐Ÿ“š.

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

  • max-slsr-cand-scan โ€” the max number of existing candidates that get looked at when hunting for a basis for a new straight-line strength reduction candidate ๐Ÿ”.
  • asan-globals โ€” turns on buffer overflow detection for global objects ๐ŸŒ. This protection is on by default if you're using -fsanitize=address ๐Ÿ›ก๏ธ. To turn off global objects protection, use --param asan-globals=0 ๐Ÿ™…โ€โ™€๏ธ.
  • asan-stack โ€” turns on buffer overflow detection for stack objects ๐Ÿฅž. It's on by default when you use -fsanitize=address โœจ. To disable stack protection, use --param asan-stack=0 ๐Ÿšซ.
  • asan-instrument-reads โ€” turns on buffer overflow detection for memory reads ๐Ÿ‘“. It's on by default when using -fsanitize=address ๐Ÿ›ก๏ธ. To disable memory reads protection, use --param asan-instrument-reads=0 ๐Ÿ™…โ€โ™€๏ธ.
  • asan-instrument-writes โ€” turns on buffer overflow detection for memory writes โœ๏ธ. It's on by default when using -fsanitize=address ๐Ÿ›ก๏ธ. To disable memory writes protection, use --param asan-instrument-writes=0 ๐Ÿšซ.
  • asan-memintrin โ€” turns on detection for built-in functions ๐Ÿงฐ. It's on by default when using -fsanitize=address ๐Ÿ›ก๏ธ. To disable built-in functions protection, use --param asan-memintrin=0 ๐Ÿ™…โ€โ™€๏ธ.
  • asan-use-after-return โ€” turns on detection of use-after-return ๐Ÿ”™. It's on by default when using the -fsanitize=address option ๐Ÿ›ก๏ธ. To turn it off, use --param asan-use-after-return=0 ๐Ÿšซ.
Note: by default this check is disabled at run time ๐Ÿ˜ญ. To enable it, add "detect_stack_use_after_return=1" to the environment variable ASAN_OPTIONS ๐Ÿ”‘.
  • asan-instrumentation-with-call-threshold โ€” if a function being instrumented has at least this many memory accesses, the compiler uses callbacks instead of inline checks ๐Ÿ“ž. For example, to turn off inline code, use --param asan-instrumentation-with-call-threshold=0 ๐Ÿงš.
  • hwasan-instrument-stack โ€” turns on hwasan instrumentation of statically sized stack-allocated variables ๐Ÿงฑ. This is on by default with -fsanitize=hwaddress and off by default with -fsanitize=kernel-hwaddress ๐ŸŒ—. To turn stack instrumentation off, use --param hwasan-instrument-stack=0, and to turn it on, use --param hwasan-instrument-stack=1 ๐Ÿ”.
  • hwasan-random-frame-tag โ€” when stack instrumentation is on, tags for stack variables come from a deterministic sequence that starts at a random tag for each frame ๐ŸŽฒ. If this parameter isn't set, the tags use the same sequence but start from 1 ๐Ÿ”ข. It's on by default for -fsanitize=hwaddress and not available for -fsanitize=kernel-hwaddress ๐Ÿšซ. To turn it off, use --param hwasan-random-frame-tag=0 ๐Ÿ™…โ€โ™€๏ธ.
  • hwasan-instrument-allocas โ€” turns on 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 it off, use --param hwasan-instrument-allocas=0, and to turn it on, use --param hwasan-instrument-allocas=1 ๐Ÿ”.
  • hwasan-instrument-reads โ€” turns on hwasan checks on memory reads ๐Ÿ‘€. Read instrumentation is on by default for both -fsanitize=hwaddress and -fsanitize=kernel-hwaddress โœจ. To stop checking memory reads, use --param hwasan-instrument-reads=0 ๐Ÿ™…โ€โ™€๏ธ.
  • hwasan-instrument-writes โ€” Turns on hwasan checks for memory writes ๐Ÿ”ฅ. Write instrumentation is already on by default for both -fsanitize=hwaddress and -fsanitize=kernel-hwaddress, but if you want to skip checking writes, use --param hwasan-instrument-writes=0.
  • hwasan-instrument-mem-intrinsics โ€” Adds hwasan instrumentation to builtin functions ๐Ÿ’–. This is also on by default for both -fsanitize=hwaddress and -fsanitize=kernel-hwaddress, and you can turn it off with --param hwasan-instrument-mem-intrinsics=0.
  • use-after-scope-direct-emission-threshold โ€” If a local variable is <pink> this many bytes or smaller </pink>, the shadow memory gets poisoned (or unpoisoned) directly โœจ. Bigger variables fall back to run-time callbacks instead.
  • tsan-distinguish-volatile โ€” Gives accesses to volatiles their own special instrumentation ๐Ÿฆ‹.
  • tsan-instrument-func-entry-exit โ€” Emits instrumentation calls to __tsan_func_entry() and __tsan_func_exit() ๐Ÿงš.
  • max-fsm-thread-path-insns โ€” The most instructions that can get copied when duplicating blocks along a finite state automaton jump thread path ๐ŸŒธ.
  • max-fsm-thread-length โ€” The most basic blocks allowed on a finite state automaton jump thread path ๐ŸŽ€.
  • max-fsm-thread-paths โ€” The most new jump thread paths GCC will create for a finite state automaton ๐Ÿ’….
  • parloops-chunk-size โ€” The chunk size of the omp schedule for loops that parloops parallelizes ๐Ÿซถ.
  • parloops-schedule โ€” The omp schedule type for loops parallelized by parloops. You can pick from static, dynamic, guided, auto, or runtime ๐Ÿ‘‘.
  • parloops-min-per-thread โ€” The minimum number of iterations each thread needs in an innermost parallelized loop before the parallel version is preferred over the single-threaded one ๐Ÿงต. Heads up: for a parallelized loop nest, the minimum number of iterations of the outermost loop per thread is two, so that part's already set. ๐Ÿ’€
  • max-ssa-name-query-depth โ€” How deep the recursion can go when you query properties of SSA names in things like fold routines ๐Ÿ”. Each level of recursion means following one use-def chain.
  • max-speculative-devirt-maydefs โ€” The max number of may-defs analyzed while hunting for a must-def that tells you the dynamic type of an object making a virtual call ๐Ÿ•ต๏ธโ€โ™€๏ธ. Those are the ones that might get devirtualized speculatively.
  • max-vrp-switch-assertions โ€” The max number of assertions added along a switch statement's default edge during VRP ๐ŸŒˆ.
  • evrp-mode โ€” Picks the mode that Early VRP operates in โญ.
  • unroll-jam-min-percent โ€” The minimum percentage of memory references that have to get optimized away before the unroll-and-jam transformation counts as profitable ๐Ÿ’œ.
  • unroll-jam-max-unroll โ€” The max number of times the outer loop can be unrolled by unroll-and-jam ๐Ÿฆ‹.
  • max-rtl-if-conversion-unpredictable-cost โ€” The most expensive sequence the RTL if-conversion pass can generate for a branch that's considered unpredictable ๐Ÿ™ˆ.
  • max-variable-expansions-in-unroller โ€” When -fvariable-expansion-in-unroller is on, this is how many times one variable can get expanded during loop unrolling ๐Ÿ“.
  • tracer-min-branch-probability-feedback โ€” Stops forward growth once the probability of the best edge drops below this threshold (a percentage). It only kicks in when profile feedback is available ๐ŸŒธ.
  • partial-inlining-entry-probability โ€” The max probability of the entry BB of a split region (a percentage relative to the function's entry BB) that still lets partial inlining happen ๐ŸŽ€.
  • max-tracked-strlens โ€” The max number of strings the strlen optimization pass will track lengths for ๐Ÿ’….
  • gcse-after-reload-partial-fraction โ€” The threshold ratio for doing partial redundancy elimination after reload โœจ.
  • gcse-after-reload-critical-fraction โ€” The threshold ratio of critical-edge execution counts that allows redundancy elimination after reload ๐Ÿซถ.
  • max-loop-header-insns โ€” The max number of insns in a loop header that the copy loop headers pass is allowed to duplicate ๐Ÿ”ฅ.
  • vect-epilogues-nomask โ€” Turns on loop epilogue vectorization using a smaller vector size ๐Ÿ‘‘.
  • vect-partial-vector-usage โ€” Decides when the loop vectorizer is allowed to use partial vector loads and stores instead of falling back to scalar code ๐ŸŒˆ. The options are:
    • 0 โ€” the vectorizer never uses partial vector loads and stores.
    • 1 โ€” partial vector loads and stores are allowed, but only if vectorization gets rid of the need for the code to iterate.
    • 2 โ€” partial vector loads and stores are allowed in all loops.

This only does anything on targets that support partial vector loads and stores ๐Ÿ’–.

  • avoid-fma-max-bits โ€” The max number of bits for which GCC avoids creating FMAs ๐Ÿงš.
  • sms-loop-average-count-threshold โ€” A threshold on the average loop count that the swing modulo scheduler takes into account ๐Ÿฆ‹.
  • sms-dfa-history โ€” How many cycles the swing modulo scheduler looks at when checking for conflicts using DFA ๐ŸŒธ.
  • max-inline-insns-recursive-auto โ€” The max number of instructions a non-inline function can grow to through recursive inlining ๐ŸŽ€.
  • graphite-allow-codegen-errors โ€” Decides whether codegen errors should be ICEs when -fchecking is on ๐Ÿ™ˆ.
  • sms-max-ii-factor โ€” A factor for tuning the upper bound the swing modulo scheduler uses when it schedules a loop ๐Ÿ’….
  • lra-max-considered-reload-pseudos โ€” The max number of reload pseudos considered while spilling a non-reload pseudo โœจ.
  • max-pow-sqrt-depth โ€” The max depth of sqrt chains used when synthesizing exponentiation by a real constant ๐ŸŒˆ.
  • max-dse-active-local-stores โ€” The max number of active local stores in RTL dead store elimination ๐Ÿ“.
  • asan-instrument-allocas โ€” Turns on asan protection for allocas and VLAs ๐Ÿ›ก๏ธ.
  • max-iterations-computation-cost โ€” The bound on the cost of an expression used to compute the number of iterations ๐Ÿ’œ.
  • max-isl-operations โ€” The max number of isl operations. 0 means unlimited ๐Ÿ‘‘.
  • graphite-max-arrays-per-scop โ€” The max number of arrays per scop ๐ŸŒธ.
  • max-vartrack-reverse-op-size โ€” The max size of a loc list that's allowed to get reverse ops added ๐Ÿฆ‹.
  • tracer-dynamic-coverage-feedback โ€” The percentage of a function, weighted by execution frequency, that trace formation has to cover. This one's used when profile feedback is available ๐Ÿ”ฅ.
  • max-inline-recursive-depth-auto โ€” The max depth of recursive inlining for non-inline functions ๐ŸŽ€.
  • fsm-scale-path-stmts โ€” A scale factor applied to the number of statements in a threading path when it gets compared to the number of (scaled) blocks ๐Ÿ’….
  • fsm-maximum-phi-arguments โ€” The max number of arguments a PHI can have before the FSM threader stops trying to thread through its block โœจ.
  • uninit-control-dep-attempts โ€” The max number of nested calls used to search for control dependencies during uninitialized variable analysis ๐Ÿซถ.
  • sra-max-scalarization-size-Osize โ€” The max size, in storage units, of an aggregate that should be considered for scalarization when compiling for size ๐Ÿ‘‘.
  • fsm-scale-path-blocks โ€” A scale factor applied to the number of blocks in a threading path when it gets compared to the number of (scaled) statements ๐ŸŒˆ.
  • sched-autopref-queue-depth โ€” A control flag for the hardware autoprefetcher scheduler model ๐Ÿ’–. It sets how many lookahead cycles the model looks into. At ' ', only the instruction sorting heuristic gets enabled ๐Ÿงš.
  • loop-versioning-max-inner-insns โ€” The max number of instructions an inner loop can have before the loop versioning pass decides it's too big to copy ๐Ÿฆ‹.
  • loop-versioning-max-outer-insns โ€” The max number of instructions an outer loop can have before the loop versioning pass decides it's too big to copy ๐ŸŒธ. Any instructions in inner loops that directly benefit from versioning don't count toward that total ๐ŸŽ€.
  • ssa-name-def-chain-limit โ€” The max number of SSA_NAME assignments to follow when figuring out a property of a variable, like its value ๐Ÿ’…. This caps how many iterations or recursive calls GCC makes while optimizing certain statements or checking whether they're valid before it issues diagnostics โœจ.
  • store-merging-max-size โ€” The max size of a single store merging region, in bytes ๐Ÿซถ.
  • hash-table-verification-limit โ€” How many elements get hash table verification done for each searched element ๐Ÿ‘‘.
  • max-find-base-term-values โ€” The max number of VALUEs handled in a single find_base_term call ๐ŸŒˆ.
  • analyzer-max-enodes-per-program-point โ€” The max number of exploded nodes per program point within the analyzer. Once you hit it, 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 will think about summarizing its effects at call sites ๐Ÿฆ‹.
  • analyzer-max-enodes-for-full-dump โ€” The max depth of exploded nodes that can appear 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 within the analyzer. Once that's hit, analysis of a call that would recurse deeper stops ๐ŸŽ€.
  • analyzer-max-svalue-depth โ€” The max depth of a symbolic value. Past this, the value gets approximated 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 it takes for a basic block to count as hot ๐Ÿ”ฅ. This param is only used in the GIMPLE FE ๐Ÿซถ.
  • analyzer-bb-explosion-factor โ€” ๐Ÿ’– The most "after supernode" exploded nodes the analyzer can make per supernode. Once it hits this number, it stops the analysis โœจ.
  • ranger-logical-depth โ€” ๐Ÿง  How deep ranger is allowed to dig into logical expression evaluation when it checks the ranges on outgoing edges. This is the max depth, bestie ๐Ÿซถ.
  • openacc-kernels โ€” ๐ŸŒธ Picks how OpenACC kernels constructs get handled. There are two choices:
    • --param=openacc-kernels=decompose โ€” chops each kernels construct into parts, a sequence of compute constructs, and handles each one individually. It's still work in progress ๐Ÿšง.
    • --param=openacc-kernels=parloops โ€” handles kernels constructs with the parloops pass, all at once (en bloc). This is the current default, and it's giving stable ๐Ÿ‘‘.

The following are available on AArch64 targets ๐Ÿฆ‹:

  • aarch64-sve-compare-costs โ€” ๐Ÿ’… When vectorizing for SVE, GCC can consider "unpacked" vectors for smaller elements, then let the cost model 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 float types. When division approximation is enabled, the precision of division scales with this param. The default value is 1.
  • aarch64-double-recp-precision โ€” ๐Ÿ”ข The number of Newton iterations used to calculate the reciprocal for double types. When division approximation is enabled, the precision of division scales with this param. The default value is 2.
  • aarch64-autovec-preference โ€” ๐ŸŽฏ Forces an ISA selection strategy for auto-vectorization. It accepts values from 0 to 4, inclusive:
    • 0 โ€” Uses the default heuristics.
    • 1 โ€” Uses only Advanced SIMD for auto-vectorization.
    • 2 โ€” Uses only SVE for auto-vectorization.
    • 3 โ€” Uses both Advanced SIMD and SVE, and prefers Advanced SIMD when the costs are deemed equal.
    • 4 โ€” Uses both Advanced SIMD and SVE, and prefers SVE when the costs are deemed equal.

The default value is 0.

  • aarch64-loop-vect-issue-rate-niters โ€” ๐Ÿงš Some AArch64 CPUs tune by considering 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 that are known to execute in fewer than n Advanced SIMD iterations.

๐ŸŽ€ Program Instrumentation Options ๐ŸŽ€

GCC has a bunch of command-line options that add run-time instrumentation to the code it normally generates ๐Ÿ”. Instrumentation can collect profiling statistics so you can find your program's hot spots, do code coverage analysis, or feed profile-guided optimizations. Another kind of instrumentation adds run-time checking to 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 for 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 must use this option when compiling the source files you want data about, and you must also use it when linking.

You can use the function attribute "no_instrument_function" to stop profiling individual functions when compiling with these options.

  • -fprofile-arcs โ€” ๐Ÿน Adds code so that program flow arcs are instrumented. While the program runs, it records how many times each branch and call is executed, and how many times each is taken or returns. On targets that support constructors with priority, profiling properly handles constructors, destructors, and C++ constructors (and destructors) of classes that are used as the type of a global variable.

When the compiled program exits, it saves this data to a file called auxname.gcda for each source file. The data can be used for profile-directed optimizations (-fbranch-probabilities) or for test coverage analysis (-ftest-coverage). Each object file's auxname is generated from the name of the output file if it's explicitly specified and isn't the final executable. Otherwise, it's the basename of the source file. In both cases, any suffix is removed. For example, you get foo.gcda for input file dir/foo.c, or dir/foo.gcda for output file specified as -o dir/foo.o.

  • --coverage โ€” ๐Ÿงช Compiles and links code instrumented for coverage analysis. It's a synonym for -fprofile-arcs -ftest-coverage (when compiling) and -lgcov (when linking). Check the docs for those options for more details. Here's the full workflow:
    1. Compile the source files with -fprofile-arcs, plus optimization and code generation options. For test coverage analysis, add the -ftest-coverage option too. You don't need to profile every source file in a program.
    2. Compile the source files additionally with -fprofile-abs-path to create absolute path names in the .gcno files. This lets gcov find the correct sources in projects where compilations happen with different working directories.
    3. Link your object files with -lgcov or -fprofile-arcs. The latter implies the former.
    4. Run the program on a representative workload to generate the arc profile information. You can repeat this any number of times. You can run concurrent instances of your program, and as long as the file system supports locking, the data files will be updated correctly. Unless a strict ISO C dialect option is in effect, fork calls are detected and handled correctly without double counting ๐Ÿด.
    5. For profile-directed optimizations, compile the source files again with the same optimization and code generation options, plus -fbranch-probabilities.
    6. For test coverage analysis, use gcov to produce human-readable information from the .gcno and .gcda files. Check the gcov documentation for more info.

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

  • -ftest-coverage โ€” ๐Ÿ“ Produces a notes file that the gcov code-coverage utility can use to show program coverage. Each source file's notes file is called auxname.gcno. See the -fprofile-arcs option above for a description of auxname and instructions on generating test coverage data. Coverage data matches the source files more closely if you don't optimize.
  • -fprofile-abs-path โ€” ๐Ÿ—บ๏ธ Automatically converts relative source file names into absolute path names in the .gcno files. This lets gcov find the correct sources in projects where compilations happen with different working directories.
  • -fprofile-dir=path โ€” ๐Ÿ“‚ Sets the directory where profile data files are searched for to path. This option only affects profile data generated by -fprofile-generate, -ftest-coverage, and -fprofile-arcs, and used by -fprofile-use and -fbranch-probabilities and its related options. Both absolute and relative paths work. By default, GCC uses the current directory, so the profile data file sits in the same directory as the object file. To prevent file name clashes, if the object file name isn't an absolute path, GCC mangles the absolute path of the sourcename.gcda file and uses that as the .gcda file name. See the similar option -fprofile-note.

When an executable runs in a massively parallel environment, it's recommended to save profiles to different folders ๐Ÿ. You can do that with variables in path that get exported at run-time:

  • %p โ€” process ID.
  • %q{VAR} โ€” value of environment variable VAR.
  • -fprofile-generate, -fprofile-generate=path โ€” ๐Ÿญ Enables options that are usually used to instrument an application so it produces a profile useful for later recompilation with profile feedback-based optimization. You must use -fprofile-generate both when compiling and when linking your program.

The following options get enabled: -fprofile-arcs, -fprofile-values, -finline-functions, and -fipa-bit-cp.

If path is specified, GCC looks there for the profile feedback data files. See -fprofile-dir. To optimize the program based on the collected profile info, use -fprofile-use ๐Ÿš€.

  • -fprofile-info-section, -fprofile-info-section=name โ€” ๐Ÿ“ฆ Registers the profile information in the specified section instead of using a constructor/destructor. The section name is name if you specify it, otherwise it defaults to ".gcov_info". A pointer to the profile information generated by -fprofile-arcs or -ftest-coverage is placed in the specified section for each translation unit. This option disables profile information registration through a constructor, and it disables profile information processing through a destructor. It isn't meant for hosted environments like GNU/Linux. It targets systems with limited resources that don't support constructors and destructors. The linker could collect the input sections into a continuous memory block and define start and end symbols. The runtime support could dump the profiling information registered in this linker set to a serial line during program termination, for example. A GNU linker script example that defines a linker output section follows:
                     .gcov_info      :
                     {
                       PROVIDE (__gcov_info_start = .);
                       KEEP (*(.gcov_info))
                       PROVIDE (__gcov_info_end = .);
                     }
  • -fprofile-note=path โ€” okay so if you give it a path, GCC saves the .gcno file right into that location ๐Ÿ“โœจ Heads up, bestie: if you combine this with multiple source files, that .gcno file gets overwritten ๐Ÿ’€
  • -fprofile-prefix-path=path โ€” this one is giving teamwork with profile-generate=profile_dir and profile-use=profile_dir ๐Ÿค It tells GCC where the base directory of your built source tree lives ๐ŸŒณ By default, profile_dir gets files with mangled absolute paths of every object file in the built project, and ngl that's messy ๐Ÿ˜ญ It's a problem when the directory you used for the instrumented binary is different from the one you used for the optimized build, because then the profile data can't be found during the optimized build ๐Ÿ™ƒ So in those setups, -fprofile-prefix-path=path (with path pointing to the base build directory) strips the irrelevant bits and keeps all file names relative to the main build directory ๐Ÿงนโœจ
  • -fprofile-update=method โ€” this changes how an app instrumented for profile feedback based optimization updates its counters ๐Ÿ”„ The method should be one of single, atomic or prefer-atomic ๐Ÿ’– single is perfect for single-threaded apps, and atomic prevents profile corruption by emitting thread-safe code ๐Ÿงต
Warning: if an application doesn't properly join all of its threads (or it creates a detached thread), the profile file can still get corrupted ๐Ÿ˜ฑ

Using prefer-atomic gets transformed into atomic if the target supports it, or into single if it doesn't ๐ŸŽฏ The GCC driver automatically picks prefer-atomic whenever -pthread shows up in the command line ๐Ÿซถ

  • -fprofile-filter-files=regex โ€” only instruments functions from files whose names match any of the regular expressions (separated by semi-colons) ๐ŸŽ€

For example, -fprofile-filter-files=main\.c;module.*\.c will instrument only main.c and all C files starting with 'module' ๐ŸŒธ

  • -fprofile-exclude-files=regex โ€” the opposite energy ๐Ÿ™…โ€โ™€๏ธ It only instruments functions from files whose names do not match any of the regular expressions (separated by semi-colons) ๐Ÿšซ

For example, -fprofile-exclude-files=/usr/.* will prevent instrumentation of all files located in the /usr/ folder ๐Ÿงฑ

  • -fprofile-reproducible=[multithreaded|parallel-runs|serial] โ€” controls how reproducible the profile gathered by "-fprofile-generate" is ๐Ÿ” This lets you rebuild a program with the same outcome, which is super useful for things like distribution packages ๐Ÿ“ฆ๐Ÿ’…

With -fprofile-reproducible=serial, the profile gathered by -fprofile-generate is reproducible, provided that the trained program behaves the same at each invocation of the train run, it is not multi-threaded, and profile data streaming is always done in the same order ๐Ÿง  Also, profile streaming happens at the end of the program run, but also before the "fork" function is invoked ๐Ÿด

Literally, it's pretty common for execution counts in some parts of a program to depend on things like the length of temporary file names or memory space randomization (which may affect hash-table collision rate) ๐ŸŽฒ Those non-reproducible parts can be annotated with the "no_instrument_function" function attribute ๐Ÿท๏ธ You can use gcov-dump with -l to dump the gathered data and verify that it's actually reproducible ๐Ÿ”

With -fprofile-reproducible=parallel-runs, the collected profile stays reproducible no matter what order the data gets streamed into gcda files ๐ŸŒˆ This setting lets you run multiple instances of the instrumented program in parallel (like with make -j) ๐Ÿƒโ€โ™€๏ธ๐Ÿ’จ The catch is that it reduces the quality of the gathered data, especially for indirect call profiling ๐Ÿ˜ฌ

  • -fsanitize=address โ€” enables AddressSanitizer, a fast memory error detector ๐Ÿ”Ž Memory access instructions get instrumented to catch out-of-bounds and use-after-free bugs ๐Ÿ•ต๏ธโ€โ™€๏ธ This option also enables -fsanitize-address-use-after-scope ๐Ÿ’œ More details live at <https://github.com/google/sanitizers/wiki/AddressSanitizer> ๐Ÿ“š You can influence the run-time behavior with the ASAN_OPTIONS environment variable ๐ŸŽ›๏ธ When it's set to "help=1", the available options get shown at startup of the instrumented program ๐Ÿ‘€ For a list of supported options, check <https://github.com/google/sanitizers/wiki/AddressSanitizerFlags#run-time-flags> ๐Ÿ“ This option can't be combined with -fsanitize=thread or -fsanitize=hwaddress ๐Ÿ™…โ€โ™€๏ธ And FYI, the only target -fsanitize=hwaddress is currently supported on is AArch64 ๐Ÿฆพ
  • -fsanitize=kernel-address โ€” enables AddressSanitizer for the Linux kernel ๐Ÿง More details at <https://github.com/google/kasan> ๐Ÿงš
  • -fsanitize=hwaddress โ€” enables Hardware-assisted AddressSanitizer, which uses a hardware ability to ignore the top byte of a pointer so it can detect memory errors with low memory overhead โœจ Memory access instructions get instrumented to catch out-of-bounds and use-after-free bugs ๐Ÿซง This option enables -fsanitize-address-use-after-scope too ๐Ÿ’– See <https://clang.llvm.org/docs/HardwareAssistedAddressSanitizerDesign.html> for more details ๐Ÿ“– The run-time behavior can be influenced with the HWASAN_OPTIONS environment variable, and when it's set to "help=1", the available options are shown at startup of the instrumented program ๐ŸŽ€ This option can't be combined with -fsanitize=thread or -fsanitize=address, and it's currently only available on AArch64 ๐Ÿฆพ
  • -fsanitize=kernel-hwaddress โ€” enables Hardware-assisted AddressSanitizer for compiling the Linux kernel ๐Ÿงโšก It's similar to -fsanitize=kernel-address but uses an alternate instrumentation method, and it's similar to -fsanitize=hwaddress but with instrumentation differences needed for compiling the kernel ๐Ÿงฉ Those differences exist to avoid hwasan library initialization calls and to account for the stack pointer having a different value in its top byte ๐Ÿ™ˆ
Note: this option has different defaults from -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 can't be combined with -fsanitize=thread ๐Ÿ™…โ€โ™€๏ธ
Note: the check is disabled at run time by default ๐Ÿ˜Œ 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=pointer-subtract โ€” instruments subtraction with pointer operands ๐Ÿงฎ It must be combined with either -fsanitize=kernel-address or -fsanitize=address, and it can't be combined with -fsanitize=thread ๐Ÿšซ
Note: the check is disabled at run time by default ๐Ÿฅฒ 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 ๐Ÿ’…

Also, sanitized atomic builtins can't throw exceptions when operating on invalid memory addresses with non-call exceptions (-fnon-call-exceptions) ๐Ÿ˜ญ

  • -fsanitize=leak โ€” enables LeakSanitizer, a memory leak detector ๐Ÿ’ง This option only matters when linking executables, and the executable is linked against a library that overrides "malloc" and other allocator functions ๐Ÿง  See <https://github.com/google/sanitizers/wiki/AddressSanitizerLeakSanitizer> for more details ๐Ÿ“– The run-time behavior can be influenced with the LSAN_OPTIONS environment variable ๐ŸŽ›๏ธ This option can't be combined with -fsanitize=thread ๐Ÿšซ
  • -fsanitize=undefined โ€” enables UndefinedBehaviorSanitizer, a fast undefined behavior detector ๐Ÿ”โœจ Various computations get instrumented to catch undefined behavior at runtime ๐Ÿซง See <https://clang.llvm.org/docs/UndefinedBehaviorSanitizer.html> for more details ๐Ÿ“š The run-time behavior can be influenced with the UBSAN_OPTIONS environment variable ๐ŸŽ›๏ธ The current suboptions are:
    • -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, it checks that the result of the shift operation is not undefined ๐Ÿง Again, what exactly counts as undefined differs slightly between C and C++, as well as between ISO C90 and C99, etc. ๐Ÿ’…
    • -fsanitize=integer-divide-by-zero โ€” detects integer division by zero, as well as "INT_MIN / -1" division ๐Ÿ™ˆ
    • -fsanitize=unreachable โ€” the compiler turns the "__builtin_unreachable" call into a diagnostics message call instead ๐Ÿ“ฃ When execution reaches the "__builtin_unreachable" call, the behavior is undefined ๐Ÿ’€
    • -fsanitize=vla-bound โ€” the compiler checks that the size of a variable length array is positive ๐Ÿ“โœจ
  • -fsanitize=null โ€” pointer checking ๐Ÿ’– Your program will throw an error message when it tries to dereference a NULL pointer, when a reference (rvalue references included) gets bound to a NULL pointer, or when a method gets invoked on an object pointed at by a NULL pointer. ๐Ÿ˜ญ
  • -fsanitize=return โ€” return statement checking ๐Ÿ”ฅ If the end of a non-void function is reached without actually returning a value, you get an error message. This one only works in C++ ๐Ÿงš.
  • -fsanitize=signed-integer-overflow โ€” signed integer overflow checking โœจ It checks that the result of +, *, and both unary and binary - doesn't overflow in signed arithmetic. Integer promotion rules absolutely have to be taken into account here, so this one is NOT an overflow, bestie ๐Ÿ™ˆ:
signed char a = SCHAR_MAX;
a++;
  • -fsanitize=bounds โ€” array bounds instrumentation ๐Ÿ“ Various out-of-bounds accesses get detected. Flexible array members, flexible array member-like arrays, and initializers of variables with static storage are NOT instrumented ๐Ÿ™….
  • -fsanitize=bounds-strict โ€” the stricter, no-nonsense version ๐Ÿฆ‹ Most out-of-bounds accesses get detected, including flexible array members and flexible array member-like arrays. Initializers of variables with static storage still aren't instrumented.
  • -fsanitize=alignment โ€” checks pointer alignment ๐ŸŽ€ when pointers get 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 โ€” detects floating-point division by zero ๐Ÿ“ Unlike other similar options, this one is NOT turned on by -fsanitize=undefined, because dividing floats by zero can be a totally legit way to get infinities and NaNs ๐ŸŒธ.
  • -fsanitize=float-cast-overflow โ€” checks floating-point to integer conversions โœจ and that the result of the conversion doesn't overflow. Unlike other similar options, this one is NOT enabled by -fsanitize=undefined ๐Ÿ˜ฌ. It also doesn't play nicely with FE_INVALID exceptions enabled.
  • -fsanitize=nonnull-attribute โ€” instruments calls ๐Ÿ“ž and checks that NULL values aren't passed to arguments marked as requiring a non-null value by the nonnull function attribute.
  • -fsanitize=returns-nonnull-attribute โ€” instruments return statements in functions marked with the returns_nonnull function attribute ๐Ÿซถ so it can catch NULL values being returned from them.
  • -fsanitize=bool โ€” instruments loads from bool ๐Ÿ‘‘ If a value other than 0/1 gets loaded, you get a run-time error.
  • -fsanitize=enum โ€” instruments loads from an enum type ๐Ÿ’œ If a value outside the range of values for that enum type gets loaded, you get a run-time error.
  • -fsanitize=vptr โ€” instruments C++ member function calls, member accesses, and some conversions between pointers to base and derived classes ๐Ÿฆ‹ to verify the referenced object has the correct dynamic type.
  • -fsanitize=pointer-overflow โ€” instruments pointer arithmetic ๐ŸŒˆ If the pointer arithmetic overflows, you get a run-time error.
  • -fsanitize=builtin โ€” instruments arguments to selected builtin functions ๐Ÿ› ๏ธ If an invalid value gets passed to those arguments, you get a run-time error. For example, passing 0 as the argument to __builtin_ctz or __builtin_clz invokes undefined behavior, and this option diagnoses it ๐Ÿ’€.

While -ftrapv causes traps for signed overflows to be emitted, -fsanitize=undefined gives a diagnostic message ๐Ÿ’… This currently works only for the C family of languages.

  • -fno-sanitize=all โ€” disables all previously enabled sanitizers ๐Ÿงน
๐Ÿšจ -fsanitize=all is not allowed, as some sanitizers cannot be used together.
  • -fasan-shadow-offset=number โ€” forces GCC to use a custom shadow offset in AddressSanitizer checks ๐Ÿงช It's useful for experimenting with different shadow memory layouts in Kernel AddressSanitizer.
  • -fsanitize-sections=s1,s2,... โ€” sanitizes global variables in selected user-defined sections ๐Ÿ“ฆ si may contain wildcards.
  • -fsanitize-recover[=opts] โ€” ๐Ÿช„ controls the error recovery mode for the sanitizers in the comma-separated list opts. Turn it on for a sanitizer and it'll try to keep running the program like no error happened ๐Ÿ™ƒ. That means multiple runtime errors can get reported in one single run, and the exit code might say success even when errors were reported ๐Ÿ˜ฌ. The -fno-sanitize-recover= option can flip this: only the first detected error gets reported, and then the program exits with a non-zero exit code.

Right now this only works for -fsanitize=undefined (and its suboptions, except for -fsanitize=unreachable and -fsanitize=return), -fsanitize=float-cast-overflow, -fsanitize=float-divide-by-zero, -fsanitize=bounds-strict, -fsanitize=kernel-address and -fsanitize=address. For these sanitizers, error recovery is turned on by default, except for -fsanitize=address, where this feature is still experimental. -fsanitize-recover=all and -fno-sanitize-recover=all are also accepted: the former enables recovery for all sanitizers that support it, and the latter disables recovery for all sanitizers that support it.

Even if a recovery mode is turned on compiler-side, it also needs to be enabled on the runtime library side, otherwise the failures are still fatal ๐Ÿ’€. The runtime library defaults to halt_on_error=0 for ThreadSanitizer and UndefinedBehaviorSanitizer, while the default value for AddressSanitizer is halt_on_error=1. This can be overridden by setting the halt_on_error flag in the corresponding environment variable ๐ŸŒท.

๐Ÿšจ Syntax without an explicit opts parameter is deprecated. It's the same as specifying an opts list of:
undefined,float-cast-overflow,float-divide-by-zero,bounds-strict
  • -fsanitize-address-use-after-scope โ€” enables sanitization of local variables to catch use-after-scope bugs ๐Ÿ” This option sets -fstack-reuse to none.
  • -fsanitize-undefined-trap-on-error โ€” reports undefined behavior using __builtin_trap instead of a libubsan library routine ๐Ÿชค The advantage is that the libubsan library isn't needed and isn't linked in, so this is usable even in freestanding environments.
  • -fsanitize-coverage=trace-pc โ€” enables coverage-guided fuzzing code instrumentation ๐Ÿ› Inserts a call to __sanitizer_cov_trace_pc into every basic block.
  • -fsanitize-coverage=trace-cmp โ€” enables dataflow-guided fuzzing code instrumentation ๐Ÿง  Inserts calls to:
    • __sanitizer_cov_trace_cmp1, __sanitizer_cov_trace_cmp2, __sanitizer_cov_trace_cmp4 or __sanitizer_cov_trace_cmp8 for integral comparisons with both operands variable.
    • __sanitizer_cov_trace_const_cmp1, __sanitizer_cov_trace_const_cmp2, __sanitizer_cov_trace_const_cmp4 or __sanitizer_cov_trace_const_cmp8 for integral comparisons with one operand constant.
    • __sanitizer_cov_trace_cmpf or __sanitizer_cov_trace_cmpd for float or double comparisons.
    • __sanitizer_cov_trace_switch for switch statements.

  • -fcf-protection=[full|branch|return|none|check] โ€” ๐Ÿ›ก๏ธ enables code instrumentation of control-flow transfers to boost program security by checking that target addresses of control-flow transfer instructions (such as indirect function calls, function returns, and indirect jumps) are valid. This stops the flow of control from being diverted to an unexpected target. It's meant to protect against threats like Return-oriented Programming (ROP), and similarly call/jmp-oriented programming (COP/JOP).
    • branch: checks validity at the point of indirect branch instructions, i.e. call/jmp instructions.
    • return: checks validity at the point of returning from a function.
    • full: an alias for specifying both branch and return.
    • none: turns off instrumentation.
    • check: used for the final link with link-time optimization (LTO). An error is issued if LTO object files are compiled with different -fcf-protection values. This value is ignored at compile time.

The macro __CET__ is defined when -fcf-protection is used. The first bit of __CET__ is set to 1 for the value branch, and the second bit of __CET__ is set to 1 for return ๐Ÿฆ‹.

You can also use the nocf_check attribute to identify which functions and calls should be skipped from instrumentation.

Currently the x86 GNU/Linux target provides an implementation based on Intel Control-flow Enforcement Technology (CET), which works for i686 processors or newer โœจ.

๐Ÿ“ NOTE: In Ubuntu 19.10 and later versions, -fcf-protection is enabled by default for C, C++, ObjC, ObjC++, if none of -fno-cf-protection nor -fcf-protection=* are found. ๐ŸŒˆ
  • -fstack-protector โ€” ๐Ÿ›ก๏ธ okay bestie, this one is a total bodyguard for your stack ๐Ÿ’– It makes the compiler sneak in extra code that checks for buffer overflows, like those sneaky stack smashing attacks ๐Ÿซฃ It drops a guard variable into functions with vulnerable objects. That means functions that call alloca, plus functions with buffers that are 8 bytes or bigger (so larger than or equal to 8 bytes ๐Ÿ’…). The guards get set up when a function is entered and get checked again when it exits. If a guard check fails, an error message gets printed and the program exits ๐Ÿ’€ Only variables that are actually allocated on the stack count ๐Ÿฅน Optimized-away variables or variables living in registers don't count, sorry ๐Ÿ’…
  • -fstack-protector-all โ€” same energy as -fstack-protector, but now literally every function gets protected ๐Ÿ‘‘
  • -fstack-protector-strong โ€” the upgraded version of -fstack-protector ๐Ÿ”ฅ It protects even more functions, including the ones with local array definitions and the ones with references to local frame addresses. Same rule applies though: only variables actually allocated on the stack count, and optimized-away or register variables don't ๐Ÿซถ
  • -fstack-protector-explicit โ€” the VIP-list option ๐ŸŽ€ It only protects the functions that have the stack_protect attribute, so nobody else gets past the velvet rope ๐Ÿ“
  • -fstack-check โ€” generates code to check that you don't go past the boundary of the stack ๐Ÿงš You'd want this if you're in an environment with multiple threads ๐Ÿงต In a single-threaded environment you rarely need it, because stack overflow is automatically detected on nearly all systems when there's only one stack ๐Ÿ’…

That said, this switch doesn't actually do the checking itself ๐Ÿ™ƒ The operating system or the language runtime has to do that. The switch just makes sure the generated code lets them see the stack being extended.

You can also add a string parameter to -fstack-check=:

  • no โ€” no checking at all, zero, nada ๐Ÿ™…
  • generic โ€” forces the old-style checking ๐Ÿข
  • specific โ€” uses the best checking method, and it's equivalent to bare -fstack-check โœจ

Old-style checking is a generic mechanism that doesn't need any specific target support in the compiler, but it comes with these drawbacks ๐Ÿ˜ฌ

  1. Modified allocation strategy for large objects: they're always allocated dynamically if their size goes over a fixed threshold. Heads up, this may change the semantics of some code โš ๏ธ
  2. Fixed limit on the size of the static frame of functions: when it's topped by a particular function, stack checking isn't reliable and the compiler issues a warning โš ๏ธ
  3. Inefficiency: because of both the modified allocation strategy and the generic implementation, code performance gets hampered ๐ŸŒ

Old-style stack checking is also the fallback method for specific if no target support has been added to the compiler ๐Ÿ”„

-fstack-check= is designed for Ada's needs to detect infinite recursion and stack overflows ๐Ÿ‘ธ specific is an excellent choice when compiling Ada code. It's not generally sufficient to protect against stack-clash attacks though. To protect against those, you want -fstack-clash-protection ๐Ÿซถ

  • -fstack-clash-protection โ€” generates code to prevent stack clash style attacks ๐Ÿงฑ With this enabled, the compiler only allocates one page of stack space at a time, and each page gets accessed immediately after allocation. So allocations can't jump over any stack guard page the operating system provides ๐Ÿ™…โ€โ™€๏ธ

Most targets don't fully support stack clash protection. On those targets, though, -fstack-clash-protection will protect dynamic stack allocations ๐Ÿ’ซ It may also give limited protection for static stack allocations if the target supports -fstack-check=specific โœจ

โš ๏ธ NOTE: In Ubuntu 19.10 and later versions, -fstack-clash-protection is enabled by default for C, C++, ObjC, ObjC++, unless -fno-stack-clash-protection is found.
  • -fstack-limit-register=reg, -fstack-limit-symbol=sym, -fno-stack-limit โ€” these make sure the stack never grows beyond a certain value ๐Ÿšง That value is either the value of a register or the address of a symbol. If a larger stack is needed, a signal gets raised at run time ๐Ÿ“ฃ On most targets the signal is raised before the stack overruns the boundary, so you can catch it without taking any special precautions ๐Ÿง

For instance, if the stack starts at absolute address 0x80000000 and grows downwards, you can use the flags -fstack-limit-symbol=__stack_limit and -Wl,--defsym,__stack_limit=0x7ffe0000 to enforce a stack limit of 128KB. Note that this may only work with the GNU linker ๐Ÿง

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 can't allocate any more memory. This is most useful when running threaded programs, because you no longer need to calculate a good stack size to use for each thread ๐Ÿงตโœจ It's 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 left for the latter code to run in ๐Ÿ˜ต If compiling all code, including library code, with -fsplit-stack isn't an option, the linker can fix up these calls so the code compiled without -fsplit-stack always has a large stack. Support for this is in the gold linker in GNU binutils release 2.21 and later ๐Ÿ”ง

  • -fvtable-verify=[std|preinit|none] โ€” C++ only, bestie ๐Ÿ’œ This turns on (or off, if you use -fvtable-verify=none) the security feature that checks at run time, for every virtual call, that the vtable pointer used for the call 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 the program's execution is immediately halted ๐Ÿ›‘

This option makes run-time data structures get built at program startup, and those are what verify the vtable pointers ๐Ÿ—๏ธ The std and preinit values control when those data structures get built. In both cases they're built before execution reaches main. 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 shows up multiple times on the command line with different values, none takes the highest priority over both std and preinit, and preinit takes priority over std ๐Ÿ‘‘

  • -fvtv-debug โ€” use this with -fvtable-verify=std or -fvtable-verify=preinit ๐Ÿ” It makes debug versions of the runtime functions for the vtable verification feature get called. It also makes the compiler log which vtable pointers it finds for each class ๐Ÿ“’ That info is 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 in the current working directory otherwise ๐Ÿ“
๐Ÿ—‘๏ธ Heads up: this feature appends data to the log file. If you want a fresh log file, delete any existing one first.
  • -fvtv-counts โ€” a debugging flag ๐Ÿ› Used with -fvtable-verify=std or -fvtable-verify=preinit, it makes the compiler keep 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 it inserts, and logs that info for each compilation unit ๐Ÿ“Š The compiler writes this to a file named vtv_count_data.log in the directory named by VTV_LOGS_DIR if that's defined, or the current working directory otherwise. It also counts the size of the vtable pointer sets for each class and writes that to vtv_class_set_sizes.log in the same directory ๐Ÿงพ
๐Ÿ—‘๏ธ Heads up again: this feature appends data to the log files. For fresh log files, delete any existing ones first.
  • -finstrument-functions โ€” generates instrumentation calls for function entry and exit ๐Ÿ”ฌ Just after function entry and just before function exit, the following profiling functions get called with the address of the current function and its call site. (On some platforms, __builtin_return_address doesn't work beyond the current function, so the call site info might not be available to the profiling functions otherwise ๐Ÿ™ˆ)
void __cyg_profile_func_enter (void *this_fn,
                               void *call_site);
void __cyg_profile_func_exit  (void *this_fn,
                               void *call_site);

The first argument is the address of the start of the current function, which can be looked up exactly in the symbol table ๐Ÿ”Ž

This instrumentation is also done for functions expanded inline in other functions. The profiling calls show where, conceptually, the inline function is entered and exited ๐Ÿงฉ That means 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 isn't done. This can be used for things like the profiling functions listed above, high-priority interrupt routines, and any functions from which the profiling functions can't safely be called (perhaps signal handlers, if the profiling routines generate output or allocate memory) ๐Ÿšซ๐Ÿ’…

-finstrument-functions-exclude-file-list=file,file,... ๐ŸŽ€ okay so this one is the file version of skipping instrumentation (same deal as -finstrument-functions, so peek at that one first ๐Ÿ‘€). Any function defined in a file that matches one of your file entries just doesn't get instrumented. The matching is lowkey loose too: if your string shows up anywhere inside the file name, it counts as a match ๐Ÿซถ.

Here's a vibe 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 ๐Ÿ’…

Now, if you literally need a comma inside one of your entries (chaotic, but valid ๐Ÿ’€), type two commas, ,,, instead. So -finstrument-functions-exclude-file-list=',,tmp' works, and yes, the single quotes around the whole option are doing important shell-protecting work here ๐Ÿ˜ญ

  • -finstrument-functions-exclude-function-list=sym,sym,... โ€” ๐Ÿฆ‹ this is the function name sibling of the file list above. Same instrumentation skip, but you're matching function names instead of file names.

The name it matches is the user-visible one, like vector<int> blah(const vector<int> &), NOT the internal mangled gibberish like _Z4blahRSt6vectorIiSaIiEE ๐Ÿ™ˆ Matching is substring-based again: if your sym shows up inside the function name, it's a match. And for C99 and C++ extended identifiers, you have to write the function name in UTF-8, not with universal character names.

  • -fpatchable-function-entry=N[,M] โ€” โœจ generates N NOPs right at the start of each function, with the function entry point sitting before the Mth NOP. If you leave M out, it defaults to 0, so the entry point is the address right at the first NOP. Those NOPs reserve extra room you can patch instrumentation into at run time, as long as the code segment is writable. How much room you get is controlled indirectly, through the number of NOPs. The NOP instruction used matches what the internal GCC back-end interface gen_nop emits. This is target-specific and may also depend on the architecture variant and/or other compilation options ๐Ÿ”ฅ

For run-time identification, the starting addresses of these areas (which are their function entries minus M) also get collected in the "__patchable_function_entries" section of the resulting binary ๐Ÿงš

Note that __attribute__ ((patchable_function_entry (N,M))) takes precedence over the command-line option -fpatchable-function-entry=N,M ๐Ÿ‘‘ That means you can increase the area size, or remove it completely, on a single function. If N=0, no pad location is recorded.

The NOP instructions get inserted at---and maybe before, depending on M---the function entry address, even before the prologue. The maximum value of N and M is 65535 ๐Ÿ’œ

Heads up: that patching trick only works if the code segment is writable, so don't skip that part ๐Ÿ’€

โœจ Options Controlling the Preprocessor โœจ

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

If you use the -E option, nothing gets done except preprocessing. Some of these options only make sense together with -E, because they make the preprocessor output unsuitable for actual compilation.

Besides the options listed here, there are a bunch of options that control search paths for include files, documented in Directory Options. 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. Important bit: the definition gets truncated by embedded newline characters ๐Ÿ™ˆ

If you're invoking the preprocessor from a shell or shell-like program, you might need the shell's quoting syntax to protect characters like spaces that have a meaning in shell syntax ๐Ÿซถ

Want a function-like macro on the command line? Write its argument list with surrounding parentheses before the equals sign (if there is one). Parentheses are meaningful to most shells, so you should quote the option. With sh and csh, -D'name(args...)=definition' works โœจ

-D and -U options are processed in the order they're given on the command line. All -imacros file and -include file options get processed after all -D and -U options ๐Ÿ’…

  • -U name โ€” cancel any previous definition of name, whether it was built in or provided with a -D option ๐Ÿ’€
  • -include file โ€” process file as if #include "file" appeared as the first line of the primary source file. The twist: the first directory searched for file is the preprocessor's working directory, not the directory containing the main source file. If it's not found there, it gets searched for in the remainder of the #include "..." search chain as normal ๐Ÿฆ‹

If multiple -include options are given, the files are included in the order they appear on the command line.

  • -imacros file โ€” exactly like -include, except any output produced by 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 specified by -imacros are processed before all files specified by -include.

  • -undef โ€” do not predefine any system-specific or GCC-specific macros. The standard predefined macros stay defined ๐ŸŒˆ
  • -pthread โ€” defines additional macros required for using the POSIX threads library. You should use this option consistently for both compilation and linking. It's supported on GNU/Linux targets, most other Unix derivatives, and also on x86 Cygwin and MinGW targets ๐Ÿ”ฅ
  • -M โ€” instead of outputting the result of preprocessing, you get a rule suitable for make describing the dependencies of the main source file. The preprocessor outputs one make rule containing the object file name for that source file, a colon, and the names of all the included files, including those coming from -include or -imacros command-line options ๐Ÿ‘‘

Unless you specify it explicitly (with -MT or -MQ), the object file name is the name of the source file with any suffix replaced by the object file suffix, and with any leading directory parts removed. If there are many included files, the rule gets split into several lines using \-newline. The rule has no commands ๐Ÿ“

This option does not suppress the preprocessor's debug output, such as -dM. To avoid mixing that debug output with the dependency rules, explicitly specify the dependency output file with -MF, or use an environment variable like DEPENDENCIES_OUTPUT. Debug output is still sent to the regular output stream as normal ๐Ÿ’œ

Passing -M to the driver implies -E, and suppresses warnings with an implicit -w. Plan accordingly, bestie ๐Ÿ’€
  • -MM โ€” like -M, but don't mention header files that are found in system header directories, nor header files that are included, directly or indirectly, from such a header ๐ŸŒธ

This implies that the choice of angle brackets or double quotes in an #include directive does not, by itself, determine whether that header appears in -MM dependency output.

  • -MF file โ€” when used with -M or -MM, this specifies a file to write the dependencies to. If no -MF switch is given, 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 -, then the dependencies are written to stdout ๐ŸŽ€
  • -MG โ€” in conjunction with an option such as -M requesting dependency generation, -MG assumes missing header files are generated files and adds them to the dependency list without raising an error. The dependency filename is taken directly from the #include directive without prepending any path. -MG also suppresses preprocessed output, since a missing header file makes that useless ๐Ÿ™ˆ

This feature is used in automatic updating of makefiles ๐Ÿ› ๏ธ

  • -Mno-modules โ€” disables dependency generation for compiled module interfaces ๐Ÿฆ‹
  • -MP โ€” this instructs CPP to add a phony target for each dependency other than the main file, causing each to depend on nothing. These dummy rules work around errors make gives if you remove header files without updating the Makefile to match ๐Ÿ’…

This is typical output:

test.o: test.c test.h

test.h:
  • -MT target โ€” changes the target of the rule emitted by dependency generation. By default, CPP takes the name of the main input file, deletes any directory components and any file suffix such as .c, and appends the platform's usual object suffix. 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 which are special to Make. -MQ '$(objpfx)foo.o' gives:
$$(objpfx)foo.o: foo.c

The default target is automatically quoted, as if it were given with -MQ ๐Ÿ’–

  • -MD โ€” -MD is equivalent to -M -MF file, except that -E is not implied. The driver determines file based on whether an -o option is given. If it is, the driver uses its argument but with a suffix of .d. Otherwise, it takes the name of the input file, removes any directory components and suffix, and applies a .d suffix ๐ŸŒˆ

If -MD is used in conjunction with -E, any -o switch is understood to specify the dependency output file. But if it's used without -E, each -o is understood to specify a target object file.

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

  • -MMD โ€” like -MD except it mentions only user header files, not system header files ๐Ÿซถ
  • -fpreprocessed: ๐ŸŽ€ Okay so this one tells the preprocessor "hey, this file is ALREADY preprocessed, don't redo it!" ๐Ÿ’… It skips macro expansion, trigraph conversion, escaped newline splicing, and processing of most directives. Comments still get recognized and removed though, so you can totally pass it a file made with -C and it'll be fine ๐Ÿซถ. In this mode the integrated preprocessor is basically just a tokenizer for the front ends ๐Ÿงš.
    • -fpreprocessed is implicit if the input file has one of the extensions .i, .ii or .mi โœจ. Those are the extensions GCC uses for preprocessed files created by -save-temps.
  • -fdirectives-only: ๐Ÿฆ‹ When preprocessing, this handles directives but does NOT expand macros. How it acts depends on -E and -fpreprocessed, so let's break it down bestie ๐Ÿ‘‘.
    • With -E, preprocessing is limited to directives like #define, #ifdef, and #error. Macro expansion and trigraph conversion are not performed. The -dD option is also implicitly enabled.
    • With -fpreprocessed, predefinition of command line and most builtin macros is disabled. Contextually dependent macros like __LINE__ are handled normally. This lets you compile files that were previously preprocessed with -E -fdirectives-only ๐ŸŒธ.
    • With both -E and -fpreprocessed, the -fpreprocessed rules take precedence. This gives you full preprocessing of files that were previously preprocessed with -E -fdirectives-only ๐Ÿ’œ.
  • -fdollars-in-identifiers: ๐Ÿ’– Accepts $ in identifiers. Literally that's it, iconic.
  • -fextended-identifiers: โœจ Accepts universal character names and extended characters in identifiers. This one is on by default for C99 (and later C standard versions) and C++ ๐ŸŒˆ.
  • -fno-canonical-system-headers: ๐Ÿ“ When preprocessing, this stops system header paths from being shortened with canonicalization. No shortening, no cap ๐Ÿ™….
  • -fmax-include-depth=depth: ๐ŸŒธ Sets the maximum depth of nested #include. The default is 200 ๐Ÿ”ฅ.
  • -ftabstop=width: ๐Ÿฆ‹ Sets the distance between tab stops. This helps the preprocessor report correct column numbers in warnings or errors, even when tabs show up 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]: ๐Ÿ”ฅ Tracks token locations across macro expansions, so when a compile error happens inside a macro expansion, the compiler can show you the current macro expansion stack. Heads up though, using this makes the preprocessor and the compiler eat more memory ๐Ÿ’€. The level parameter lets you pick how precise the token location tracking is, so you can drop memory usage if you need to.
    • 0 deactivates this option.
    • 1 tracks token locations in a degraded mode for minimal memory overhead. In this mode, all tokens resulting from expanding an argument of a function-like macro share the same location.
    • 2 tracks token locations completely. This is the most memory hungry value ๐Ÿ™ˆ.
    • If you give this option no argument, the default parameter value is 2.
    • Note that -ftrack-macro-expansion=2 is activated by default ๐Ÿ‘‘.
  • -fmacro-prefix-map=old=new: ๐Ÿงš When preprocessing files living in directory old, the __FILE__ and __BASE_FILE__ macros expand as if the files lived in directory new instead. This is how you turn an absolute path into a relative one: use . for new. It can give you more reproducible, location-independent builds ๐Ÿซถ. This option 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. The charset can be any encoding your system's iconv library routine supports ๐ŸŒˆ.
  • -fwide-exec-charset=charset: ๐ŸŽ€ Sets the wide execution character set, used for wide string and character constants. The default is one of UTF-32BE, UTF-32LE, UTF-16BE, or UTF-16LE, whichever matches the width of wchar_t and the big-endian or little-endian byte order being used for code generation โœจ. Just like -fexec-charset, charset can be any encoding your system's iconv supports. Heads up though: 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 from the input file's character set to the source character set GCC uses. If the locale doesn't specify one, or GCC can't get that info from the locale, the default is UTF-8. This can be overridden by either the locale or this command-line option. Currently the command-line option wins if there's a conflict ๐Ÿ‘‘. The charset can be any encoding your system's iconv supports.
  • -fpch-deps: ๐Ÿ”ฅ When you're using precompiled headers, this flag 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 that were used to create it, since those aren't consulted when a precompiled header is used ๐Ÿ’….
  • -fpch-preprocess: ๐ŸŒธ This lets you use a precompiled header together with -E. It inserts a special #pragma, #pragma GCC pch_preprocess "filename", into the output to mark where the precompiled header was found, plus its filename โœจ. When -fpreprocessed is in use, GCC recognizes this #pragma and loads the PCH ๐Ÿงš.
    • This option is off by default, because the resulting preprocessed output is really only suitable as input to GCC ๐Ÿ™ˆ. It gets switched on by -save-temps.
    • You should not write this #pragma in your own code. But it's safe to edit the filename if the PCH file is available in a different location ๐Ÿซถ. The filename can be absolute, or relative to GCC's current directory.
  • -fworking-directory: ๐Ÿ’– Enables generation of linemarkers in the preprocessor output that let the compiler know the working directory at the time of preprocessing. When this is enabled, the preprocessor emits a second linemarker after the initial one, containing the current working directory followed by two slashes ๐ŸŒˆ. GCC uses that directory, if it's in the preprocessed input, as the directory it emits as the current working directory in some debugging information formats.
    • This option is implicitly enabled if debugging information is enabled. You can turn it off with the negated form -fno-working-directory ๐Ÿ™….
    • If the -P flag is in the command line, this option does nothing, since no #line directives get emitted whatsoever ๐Ÿ’€.
  • -A predicate=answer: โญ Makes an assertion with the predicate predicate and the answer answer. This form is 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: ๐ŸŽ€ Do not discard comments! All comments get passed through to the output file, except for comments in processed directives, which get deleted along with the directive ๐Ÿ’œ.
    • > Be prepared for side effects when you use -C. It makes the preprocessor 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: โœจ Do not discard comments, INCLUDING during macro expansion. This is like -C, except comments inside macros also get passed through to the output file wherever the macro is expanded ๐ŸŒธ.
    • On top of the side effects of -C, the -CC option 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 the linemarkers ๐Ÿ‘‘.
  • -traditional and -traditional-cpp: ๐Ÿฆ‹ These try to imitate pre-standard C preprocessors, as opposed to ISO C preprocessors. See the GNU CPP manual for details ๐Ÿ“–.
    • Note that GCC does NOT 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, such as MS-DOS ๐Ÿ’พ.
  • -H: ๐Ÿ”ฅ Prints the name of each header file used, in addition to the other normal activities. Each name is indented to show how deep it is in the #include stack ๐ŸŒธ. Precompiled header files get printed too, even if they turn out to be invalid. An invalid precompiled header is printed with ...x, and a valid one with ...! โœจ.
  • -dletters: ๐Ÿ’– 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, this generates a list of #define directives for all the macros defined during the execution of the preprocessor, including predefined macros. It's a way of finding 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

Run that and boom, it shows all the predefined macros ๐Ÿ’…โœจ

Heads up, bestie ๐Ÿ™ˆ if you use -dM without the -E option, it gets treated as a synonym for -fdump-rtl-mach. Not what you want, so don't sleep on it.

  • -dD โ€” Okay, so this is basically -dM with two twists ๐Ÿฆ‹. It skips the predefined macros, and it outputs both the #define directives and the result of preprocessing. Both kinds of output go to the standard output file.
  • -dN โ€” Same energy as -dD, but only the macro names get printed, not their expansions ๐ŸŒธ
  • -dI โ€” Adds #include directives to the preprocessing result ๐Ÿงš
  • -dU โ€” Like -dD, but way more selective ๐Ÿ‘‘. Only macros that get expanded, or whose definedness gets tested in preprocessor directives, are output. The output is held back until that macro is used or tested, and #undef directives also show up for macros that got tested but were undefined at the time.
  • -fdebug-cpp โ€” This one is only lowkey useful if you're debugging GCC itself ๐Ÿ”ฅ. When it's used from CPP or with -E, it dumps debugging information about location maps, and every token in the output gets preceded by the dump of the map its location belongs to. When it's used from GCC without -E, it does absolutely nothing ๐Ÿ’€
  • -Wp,option โ€” This lets you bypass the compiler driver and pass option straight through to the preprocessor. If option has commas, it gets split into multiple options at the commas. Here's the tea โ˜•: a lot of options get modified, translated, or interpreted by the compiler driver before they reach the preprocessor, and -Wp forcibly skips that step.
The preprocessor's direct interface is undocumented and subject to change, so whenever possible you should avoid -Wp and let the driver handle the options instead. Trust the driver, bestie ๐Ÿซถ
  • -Xpreprocessor option โ€” Passes option along to the preprocessor. This is your go-to for system-specific preprocessor options that GCC doesn't recognize ๐ŸŒˆ

If you want to pass an option that takes an argument, you have to use -Xpreprocessor twice, once for the option and once for the argument.

  • -no-integrated-cpp โ€” By default, GCC does preprocessing as part of input tokenization and parsing (so smooth ๐Ÿ˜Œ). With this option, preprocessing becomes its own separate pass before compilation. The appropriate language front end (cc1 for C, cc1plus for C++, and cc1obj for Objective-C) gets invoked twice instead, once for preprocessing only and once for actual compilation of the preprocessed input. This can come in clutch with the -B or -wrapper options if you want an alternate preprocessor or extra processing of the source between normal preprocessing and compilation โœจ
  • -flarge-source-files โ€” Tells GCC to expect large source files, at the expense of slower compilation and higher memory usage ๐Ÿข

Here's the deal: GCC normally tracks both column numbers and line numbers within 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. That means diagnostics for later lines won't include column numbers. It also means options like -Wmisleading-indentation stop working at that point, although the compiler prints a note if this happens ๐Ÿ˜ญ Passing -flarge-source-files significantly increases the number of source lines GCC can process before it stops tracking columns.


๐ŸŽ€ Passing Options to the Assembler ๐ŸŽ€

You can pass options to the assembler, so go off ๐Ÿ’–

  • -Wa,option โ€” Passes option to the assembler. If option has commas, it gets split into multiple options at the commas.
  • -Xassembler option โ€” Passes option to the assembler too. Use this for system-specific assembler options that GCC doesn't recognize ๐Ÿง

If you want to pass an option that takes an argument, you have to use -Xassembler twice, once for the option and once for the argument.


๐Ÿฆ‹ Options for Linking ๐Ÿฆ‹

These options come into play when the compiler links object files into an executable output file. They're meaningless if the compiler isn't doing a link step, so don't waste your energy on them ๐Ÿ™…โ€โ™€๏ธ

  • object-file-name โ€” A file name that doesn't end in a special recognized suffix is considered to name an object file or library. (The linker tells objects and libraries apart by looking at the file contents.) If linking happens, these object files are used as input to the linker.
  • -c, -S, -E โ€” If any of these options is used, the linker doesn't run, so object file names shouldn't 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 useful to set the type manually ๐Ÿ”ง Here's what each type does:
    • exec โ€” Code generation produces a static binary. In this case -fpic and -fpie are both disabled.
    • dyn โ€” Code generation produces a shared library. In this case -fpic or -fPIC is preserved, but not enabled automatically. This lets you build shared libraries without position-independent code on architectures where that's possible, i.e. on x86.
    • pie โ€” Code generation produces an -fpie executable. This gets similar optimizations as exec, except -fpie isn't disabled if it was specified at compilation time.
    • rel โ€” The compiler assumes incremental linking is happening. The sections containing intermediate code for link-time optimization are merged, pre-optimized, and output to the resulting object file. If -ffat-lto-objects is specified, binary code is also produced for future non-LTO linking. The object file from incremental linking is smaller than a static library made from the same object files, and at link time it also loads faster than a static library, assuming most objects in the library get used.
    • nolto-rel โ€” Configures the compiler for incremental linking where code generation is forced, a final binary is produced, and the intermediate code for later link-time optimization is stripped. When multiple object files get linked together, the resulting code is better optimized than with link-time optimizations disabled (cross-module inlining happens, for example), but most of the benefits of whole program optimizations are lost.

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

  • -fuse-ld=bfd โ€” Uses the bfd linker instead of the default linker ๐Ÿ”—
  • -fuse-ld=gold โ€” Uses the gold linker instead of the default linker โญ
  • -fuse-ld=lld โ€” Uses the LLVM lld linker instead of the default linker ๐ŸŒˆ
  • -fuse-ld=mold โ€” Uses the Modern Linker (mold) instead of the default linker ๐Ÿงš
  • -llibrary, -l library โ€” Searches the library named library when linking. (The second version, with the library as a separate argument, is only there for POSIX compliance and isn't recommended ๐Ÿ™ˆ)

The -l option gets passed directly to the linker by GCC, so check 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 the shared library unless the -static option is used.

Where you write this option in the command actually matters ๐Ÿ‘€ The linker searches and processes libraries and object files in the order they're specified. So foo.o -lz bar.o searches library z after file foo.o but before bar.o. If bar.o refers to functions in z, those functions may not be loaded.

  • -lobjc โ€” You need this special case of the -l option to link an Objective-C or Objective-C++ program ๐Ÿ’œ
  • -nostartfiles โ€” Doesn't use the standard system startup files when linking. The standard system libraries are still used normally, unless -nostdlib, -nolibc, or -nodefaultlibs is used.
  • -nodefaultlibs โ€” Doesn'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, such as -static-libgcc or -shared-libgcc, are ignored. The standard startup files are still used normally, unless -nostartfiles is used.
The compiler may generate calls to "memcmp", "memset", "memcpy" and "memmove". These entries are usually resolved by entries in libc. When this option is specified, these entry points should be supplied through some other mechanism, so keep that in mind ๐Ÿ˜ฌ
  • -nolibc โ€” Doesn't use the C library or the system libraries tightly coupled with it when linking. It still links with the startup files, libgcc, or toolchain-provided language support libraries 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. It's meant for bare-board targets where there really is no C library available ๐Ÿค–
  • -nostdlib โ€” Doesn't use the standard system startup files or libraries when linking. No startup files get used, only the libraries you specify are passed to the linker, and options specifying linkage of the system libraries, such as -static-libgcc or -shared-libgcc, are ignored ๐Ÿซถ

Okay bestie, so the compiler can sneakily call memcmp, memset, memcpy, and memmove all on its own ๐Ÿ™ˆ. Those are usually handled by libc, but when this option is on, you have to supply those entry points some other way ๐Ÿ’….

One of the standard libraries that -nostdlib and -nodefaultlibs skip is libgcc.a ๐Ÿ“š. It's a library of internal helper subroutines GCC uses to work around quirks of certain machines, or to meet special needs for some languages โœจ.

Lowkey, you almost always still need libgcc.a even when you're trying to dodge the other standard libraries ๐Ÿซถ. So when you use -nostdlib or -nodefaultlibs, you should usually add -lgcc too. That way you won't have any unresolved references to GCC's internal library subroutines ๐Ÿ’–. (An example of one of those is __main, which makes sure C++ constructors get called ๐ŸŒˆ.)

  • -e entry, --entry=entry โ€” sets the program entry point to entry ๐Ÿšช. The linker reads this argument, and the GNU linker accepts either a symbol name or an address ๐Ÿงš.
  • -pie โ€” makes a dynamically linked position independent executable on targets that support it ๐Ÿฆ‹. For predictable results, you also need to use the same set of options you used for compilation (-fpie, -fPIE, or model suboptions) when you pass this linker option ๐Ÿ’œ.
  • -no-pie โ€” no PIE for you ๐Ÿ™…. It won't make a dynamically linked position independent executable.
  • -static-pie โ€” makes a static position independent executable on targets that support it ๐ŸŒธ. It's kinda like a static executable, but it can be loaded at any address without needing a dynamic linker โœจ. Same deal as -pie: match the compilation options (-fpie, -fPIE, or model suboptions) for predictable results ๐ŸŽ€.
  • -pthread โ€” links with the POSIX threads library ๐Ÿงต. This works on GNU/Linux targets, most other Unix derivatives, and also x86 Cygwin and MinGW targets ๐ŸŒˆ. 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 -export-dynamic to the ELF linker on targets that support it ๐Ÿ”ฅ. This tells the linker to add all symbols to the dynamic symbol table, not just the used ones โœจ. You need it for some uses of dlopen, or to get backtraces from inside a program ๐Ÿ”.
  • -s โ€” removes all symbol table and relocation information from the executable ๐Ÿงน.
  • -static โ€” on systems that support dynamic linking, this overrides -pie and stops linking with the shared libraries ๐Ÿšซ. On other systems, it does nothing ๐Ÿคท.
  • -shared โ€” produces a shared object that you can later link with other objects to form an executable ๐Ÿง. Not every system supports this one. For predictable results, match the compilation options (-fpic, -fPIC, or model suboptions) when you use this linker option.[1]
  • -shared-libgcc, -static-libgcc โ€” on systems that provide libgcc as a shared library, these force the use of the shared or static version, respectively ๐ŸŽญ. If no shared version of libgcc was built when the compiler was configured, these have no effect.

There are a few situations where an app 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 those libraries, plus the app itself, should use the shared libgcc ๐Ÿซถ.

So the G++ driver automatically adds -shared-libgcc whenever you build a shared library or a main executable ๐Ÿ’. C++ programs typically use exceptions, so that's the right move โœ….

But if 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 of libgcc, so it links with the static version by default ๐Ÿง . This lets exceptions propagate through those shared libraries without incurring relocation costs at library load time โšก.

However, if a library or main executable is supposed to throw or catch exceptions, you must link it using the G++ driver, or using -shared-libgcc, so that it's linked with the shared libgcc ๐Ÿšจ.

  • -static-libasan โ€” when -fsanitize=address is used to link a program, the GCC driver automatically links against libasan ๐Ÿ•ต๏ธ. If libasan is available as a shared library and -static isn't used, it links against the shared version. -static-libasan tells the GCC driver to link libasan statically, without necessarily linking other libraries statically ๐ŸงŠ.
  • -static-libtsan โ€” when -fsanitize=thread is used to link a program, the GCC driver automatically links against libtsan ๐Ÿงต. If libtsan is available as a shared library and -static isn't used, it links against the shared version. -static-libtsan tells the GCC driver to link libtsan statically, without necessarily linking other libraries statically ๐ŸงŠ.
  • -static-liblsan โ€” when -fsanitize=leak is used to link a program, the GCC driver automatically links against liblsan ๐Ÿซง. If liblsan is available as a shared library and -static isn't used, it links against the shared version. -static-liblsan tells the GCC driver to link liblsan statically, without necessarily linking other libraries statically ๐ŸงŠ.
  • -static-libubsan โ€” when -fsanitize=undefined is used to link a program, the GCC driver automatically links against libubsan ๐Ÿซ . If libubsan is available as a shared library and -static isn't used, it links against the shared version. -static-libubsan tells the GCC driver to link libubsan statically, without necessarily linking other libraries statically ๐ŸงŠ.
  • -static-libstdc++ โ€” when the g++ program links a C++ program, it normally links against libstdc++ automatically ๐Ÿ’ป. If libstdc++ is available as a shared library and -static isn't used, it links against the shared version, which is normally fine ๐Ÿ‘Œ. Sometimes, though, you want to freeze the libstdc++ version your program uses without going all the way to a fully static link ๐ŸงŠ. -static-libstdc++ tells the g++ driver to link libstdc++ statically, without necessarily linking other libraries statically ๐Ÿ’œ.
  • -symbolic โ€” binds references to global symbols when building a shared object ๐Ÿ”—. It warns about any unresolved references (unless overridden by the link editor option -Xlinker -z -Xlinker defs) โš ๏ธ. Only a few systems support this one ๐Ÿฅฒ.
  • -T script โ€” uses script as the linker script ๐Ÿ“œ. This 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 to the linker ๐Ÿ› ๏ธ. Use this to supply system-specific linker options that GCC doesn't recognize ๐Ÿ’….

If you want to pass an option that takes a separate argument, you must use -Xlinker twice, once for the option and once for the argument ๐Ÿ‘ฏ. For example, to pass -assert definitions, you write -Xlinker -assert -Xlinker definitions. Writing -Xlinker "-assert definitions" does NOT work, because it passes the entire string as a single argument, and that's not what the linker expects ๐Ÿ™…โ€โ™€๏ธ.

When using the GNU linker, it's usually more convenient to pass arguments to linker options with the option=value syntax instead of as separate arguments ๐Ÿง . For example, you can write -Xlinker -Map=output.map 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 ๐Ÿš‚. 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 ๐Ÿ—บ๏ธ. With the GNU linker, you can get the same effect with -Wl,-Map=output.map โœจ.
NOTE: In Ubuntu 8.10 and later versions, for LDFLAGS, the option -Wl,-z,relro is used. To disable it, use -Wl,-z,norelro ๐Ÿšจ.
  • -u symbol โ€” pretends the symbol symbol is undefined, to force linking of the library modules that define it ๐ŸŽญ. You can use -u multiple times with different symbols to force loading of additional library modules ๐Ÿ’ซ.
  • -z keyword โ€” -z is passed straight on to the linker along with the keyword. Check the documentation for your linker to see the permitted values and what they mean ๐Ÿ“–.

These options specify the directories to search for header files, for libraries, and for parts of the compiler ๐Ÿ“‚.

  • -I dir, -iquote dir, -isystem dir, -idirafter dir โ€” adds the directory dir to the list of directories searched for header files during preprocessing ๐Ÿ“. If dir begins with = or $SYSROOT, then the = or $SYSROOT is replaced by the sysroot prefix; see --sysroot and -isysroot ๐Ÿ—บ๏ธ.

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

You can specify any number or combination of these options on the command line to search for header files in several directories ๐Ÿงบ. The lookup order goes like this:

  1. For the quote form of the include directive, the directory of the current file is searched first.
  2. okay so for the quote form of the include directive (#include "file"), the -iquote directories get searched left-to-right, in the order they show up on the command line โœจ
  3. next up, the -I directories get scanned left-to-right ๐Ÿฆ‹
  4. then the -isystem directories get scanned left-to-right too ๐Ÿ’…
  5. then the standard system directories get scanned ๐ŸŒธ
  6. last but not least, the -idirafter directories get scanned left-to-right ๐Ÿซถ

bestie, you can use -I to override a system header file and swap in your own version, bc these directories get searched before the standard system header file directories ๐ŸŽ€ but (and this is a big one) don't use this option to add directories with vendor-supplied system header files. use -isystem for that ๐Ÿ™ˆ

The -isystem and -idirafter options also mark the directory as a system directory, so it gets the same special treatment as the standard system directories โœจ

If a standard system include directory, or a directory given with -isystem, is also given with -I, the -I option gets ignored ๐Ÿ’€ The directory still gets searched, but as a system directory at its normal spot in the system include chain. This is so GCC's procedure to fix buggy system headers and the ordering for the #include_next directive don't get accidentally messed with ๐Ÿงš 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 one is deprecated, so yeah, we're not really using it anymore
Heads up: -I- is deprecated. Please use -iquote instead for -I directories that come before the -I-, and remove the -I- option.

Any directories given with -I before -I- only get searched for headers requested with #include "file". They are not searched for #include <file>. If extra directories are given with -I after the -I-, those get searched for all #include directives.

In addition, -I- stops the directory of the current file from being used as the first search directory for #include "file". There is no way to override this effect of -I-.

  • -iprefix prefix โ€” sets prefix as the prefix for later -iwithprefix options ๐ŸŒˆ if the prefix stands for a directory, 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 where -I would go, and -iwithprefix puts it where -idirafter would go
  • -isysroot dir โ€” this is like --sysroot, but it only applies to header files (except on Darwin targets, where it applies to both header files and libraries) ๐Ÿฆ‹ check the --sysroot option for more info
  • -imultilib dir โ€” uses dir as a subdirectory of the directory containing target-specific C++ headers ๐Ÿ’œ
  • -nostdinc โ€” don't search the standard system directories for header files ๐Ÿ™… only the directories you explicitly give with -I, -iquote, -isystem, and/or -idirafter (plus the directory of the current file, if appropriate) get searched
  • -nostdinc++ โ€” skip the C++-specific standard directories when searching for header files, but still search the other standard directories ๐Ÿ’… (this one is used when building the C++ library)
  • -iplugindir=dir โ€” sets the directory to search for plugins passed by -fplugin=name instead of -fplugin=path/name.so ๐Ÿงš this isn't meant for regular users; only the driver passes it
  • -Ldir โ€” adds directory dir to the list of directories to be searched for -l ๐ŸŒธ
  • -Bprefix โ€” this is where you tell the compiler where to find its own executables, libraries, include files, and data files ๐Ÿ‘‘

The compiler driver program runs one or more of the subprograms cpp, cc1, as and ld. It tries prefix as a prefix for each program it tries to run, both with and without machine/version/ for the corresponding target machine and compiler version.

For each subprogram to be run, the compiler driver first tries the -B prefix, if any. If that name isn't found, or if -B isn't specified, the driver tries two standard prefixes, /usr/lib/gcc/ and /usr/local/lib/gcc/. If neither of those results in a file name that is found, the unmodified program name is searched for using the directories specified in your PATH environment variable.

The compiler checks to see if the path provided by -B refers to a directory, and if necessary it adds a directory separator character at the end of the path.

-B prefixes that effectively specify directory names also apply to libraries in the linker, because the compiler translates these options into -L options for the linker. They also apply to include files in the preprocessor, because the compiler translates these options into -isystem options for the preprocessor. In this case, the compiler appends include to the prefix.

The runtime support file libgcc.a can also be searched for using the -B prefix, if needed. If it isn't found there, the two standard prefixes above are tried, and that is all. The file is 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, if the path provided by -B is [dir/]stageN/, where N is a number in the range 0 to 9, then it is replaced by [dir/]include. This is to help with boot-strapping the compiler ๐Ÿ“

  • -no-canonical-prefixes โ€” don't expand any symbolic links, resolve references to /../ or /./, or make the path absolute when generating a relative prefix ๐Ÿฆ‹
  • --sysroot=dir โ€” uses dir as the logical root directory for headers and libraries ๐ŸŒˆ for example, if the compiler normally searches for headers in /usr/include and libraries in /usr/lib, it instead searches dir/usr/include and dir/usr/lib

If you use both this option and the -isysroot option, then the --sysroot option applies to libraries, but the -isysroot option applies to header files.

The GNU linker (beginning with version 2.16) has the necessary support for this option. If your linker does not support this option, the header file aspect of --sysroot still works, but the library aspect does not.

  • --no-sysroot-suffix โ€” for some targets, a suffix gets added to the root directory specified with --sysroot, depending on the other options used, so headers may be found in dir/suffix/usr/include instead of dir/usr/include ๐Ÿ’€ this option turns off adding that suffix

โœจ Options for Code Generation Conventions โœจ

These machine-independent options control the interface conventions used in code generation ๐Ÿ’–

Most of them have both positive and negative forms; the negative form of -ffoo is -fno-foo. Only one of the forms is listed below, 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 reuse only for user defined local variables with names, and none disables stack reuse completely. The default value is all. You need this option 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 extending local lifetime is likely to break with the stack reuse optimization ๐Ÿ˜ญ

For example,

int *p;
{
  int local1;

  p = &local1;
  local1 = 10;
  ....
}
{
   int local2;
   local2 = 20;
   ...
}

if (*p == 10)  // out of scope use of local1
  {

  }

Another example:

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

A *ap;

void foo(const A& ar)
{
   ap = &ar;
}

void bar()
{
   foo(A(10)); // temp object's lifetime ends when foo returns

   {
     A a(20);
     ....
   }
   ap->i+= 10;  // ap references out of scope temp whose space
                // is reused with a. What is the value of ap->i?
}

The lifetime of a compiler generated temporary is well defined by the C++ standard. When the lifetime of a temporary ends, and if the temporary lives in memory, the optimizing compiler has the freedom to reuse its stack space with other temporaries or scoped local variables whose live range 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 the aggressive stack reuse can lead to runtime errors ๐Ÿ’€ This option is used to control the temporary stack reuse optimization โœจ

  • -ftrapv โ€” generates traps for signed overflow on addition, subtraction, and multiplication operations ๐Ÿ‘‘ -ftrapv and -fwrapv override each other, so 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: okay bestie, this one tells the compiler to assume that signed addition, subtraction and multiplication overflow wraps around using twos-complement representation ๐Ÿงš It turns some optimizations on and others off โœจ

-ftrapv and -fwrapv are lowkey rivals, so -ftrapv -fwrapv on the command line means -fwrapv wins ๐Ÿ‘‘ But only the active options count, so -ftrapv -fwrapv -fno-wrapv leaves -ftrapv in charge ๐Ÿ’…

  • -fwrapv-pointer: the pointer version ๐Ÿฆ‹ It assumes pointer arithmetic overflow on addition and subtraction wraps around using twos-complement representation. It also disables some optimizations that would otherwise assume pointer overflow is invalid ๐Ÿ™ˆ
  • -fstrict-overflow: this one is giving opposite energy ๐Ÿ”„ It implies -fno-wrapv -fno-wrapv-pointer, and when you negate it, it implies -fwrapv -fwrapv-pointer ๐Ÿ’€
  • -fexceptions: enables exception handling ๐Ÿ”ฅ It generates the extra code needed to propagate exceptions. On some targets this also means GCC generates frame unwind information for all functions, which can add a lot of data size overhead, though it doesn't change execution speed ๐Ÿ˜ญ

If you don't specify this option, GCC turns it on by default for languages like C++ that normally need exception handling, and turns it off for languages like C that don't ๐ŸŒธ You might still need to enable it when compiling C code that has to play nicely with exception handlers written in C++ ๐Ÿซถ You might also want to disable it if you're compiling older C++ programs that don't use exception handling.

  • -fnon-call-exceptions: generates code that lets trapping instructions throw exceptions โšก Heads up, this needs platform-specific runtime support that doesn't exist everywhere. It also only lets trapping instructions (memory references or floating-point instructions) throw exceptions. It can't throw exceptions from arbitrary signal handlers like "SIGALRM" ๐Ÿ™…โ€โ™€๏ธ
  • -fdelete-dead-exceptions: instructions that might throw exceptions but don't otherwise contribute to the program's execution can be optimized away ๐Ÿ—‘๏ธ This is enabled by default for the Ada compiler, which the Ada language specification allows. Optimization passes that remove dead exceptions are turned on independently at different optimization levels.
  • -funwind-tables: similar to -fexceptions, except it only generates any needed static data and doesn't touch the generated code in any other way ๐Ÿ“ฆ You usually don't need to turn this on yourself. A language processor that needs this handling will enable 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 garbage collector showing up mid-run ๐Ÿ”
  • -fno-gnu-unique: this one is a whole plot ๐Ÿ“– 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 with "RTLD_LOCAL" in the mix. That's needed so a library used by two different "RTLD_LOCAL" plugins doesn't disagree about the binding of a symbol. The tradeoff? It makes dlclose get ignored for affected DSOs ๐Ÿ˜ฌ So if your program relies on reinitializing a DSO through dlclose and dlopen, you can use -fno-gnu-unique.
  • -fpcc-struct-return: returns "short" "struct" and "union" values in memory, like longer ones, instead of in registers ๐Ÿงบ It's less efficient, but the perk is that files compiled by GCC can be intercallable with files built by other compilers, especially the Portable C Compiler (pcc) ๐Ÿค

The exact convention for returning structures in memory depends on the target configuration macros.

Short structures and unions are the ones whose size and alignment match some integer type.

Warning: code compiled with -fpcc-struct-return is not binary compatible with code compiled with -freg-struct-return. Only use it if you need 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 goes with whichever convention is standard for the target. If there isn't a standard convention, GCC defaults to -fpcc-struct-return, except on targets where GCC is the principal compiler. In those cases GCC gets to choose the standard, and it picked the more efficient register return option ๐Ÿ‘‘

Warning: code compiled with -freg-struct-return is not binary compatible with code compiled with -fpcc-struct-return. Only use it if you need to conform to a non-default application binary interface ๐Ÿšจ
  • -fshort-enums: gives an "enum" type only as many bytes as it needs for its declared range of possible values ๐Ÿ“ Specifically, the "enum" type becomes equivalent to the smallest integer type with enough room.
Warning: -fshort-enums makes GCC generate code that isn't binary compatible with code generated without that switch. Only use it to conform to a non-default application binary interface ๐Ÿšจ
  • -fshort-wchar: overrides the underlying type for "wchar_t" to be "short unsigned int" instead of the target's default ๐ŸŽ€ This one is useful for building programs that run under WINE.
Warning: -fshort-wchar makes GCC generate code that isn't binary compatible with code generated without that switch. Only use it to conform to a non-default application binary interface ๐Ÿšจ
  • -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 of a variable with the "extern" keyword, which don't allocate storage.

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

-fcommon puts uninitialized global variables in a common block instead. That lets the linker resolve all tentative definitions of the same variable across different compilation units to the same object, or to a non-tentative definition. It's inconsistent with C++, and on many targets it costs some speed and code size on global variable references ๐Ÿ˜ฌ It's mainly useful for getting legacy code to link without errors.

  • -fno-ident: ignores the "#ident" directive ๐Ÿ™ˆ
  • -finhibit-size-directive: doesn't output a ".size" assembler directive, or anything else that would cause trouble if the function gets split in the middle with the two halves placed far apart in memory ๐Ÿงฉ This is used when compiling crtstuff.c. Unless you're doing that, you shouldn't need it ๐Ÿ’…
  • -fverbose-asm: puts extra commentary into the generated assembly 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 out the extra info. 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.

Check out this C source file:

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

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

  return total;
}

Compiling it to (x86_64) assembly with -S, and sending the result straight to stdout with -o -:

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

gives output similar to this:

        .file   "test.c"
# GNU C11 (GCC) version 7.0.0 20160809 (experimental) (x86_64-pc-linux-gnu)
  [...snip...]
# options passed:
  [...snip...]

        .text
        .globl  test
        .type   test, @function
test:
.LFB0:
        .cfi_startproc
# test.c:4:   int total = 0;
        xorl    %eax, %eax      # <retval>
# test.c:6:   for (i = 0; i < n; i++)
        xorl    %edx, %edx      # i
.L2:
# test.c:6:   for (i = 0; i < n; i++)
        cmpl    %edi, %edx      # n, i
        jge     .L5     #,
# test.c:7:     total += i * i;
        movl    %edx, %ecx      # i, tmp92
        imull   %edx, %ecx      # i, tmp92
# test.c:6:   for (i = 0; i < n; i++)
        incl    %edx    # i
# test.c:7:     total += i * i;
        addl    %ecx, %eax      # tmp92, <retval>
        jmp     .L2     #
.L5:
# test.c:10: }
        ret
        .cfi_endproc
.LFE0:
        .size   test, .-test
        .ident  "GCC: (GNU) 7.0.0 20160809 (experimental)"
        .section        .note.GNU-stack,"",@progbits

The comments are meant for humans rather than machines, so the exact format of them is subject to change ๐Ÿ’–

  • -frecord-gcc-switches โ€” okay so this one makes the compiler stash the exact command line you used to invoke it inside the object file it's making ๐Ÿงพโœจ It's only implemented on some targets, and the exact format depends on the target and binary file format, but it usually shows up as a section full of ASCII text ๐ŸŽ€ Don't mix it up with -fverbose-asm, though. That one only drops info into the assembler output as comments, so it never reaches the object file ๐Ÿ™ˆ And see also -grecord-gcc-switches for another way to store compiler options in the object file ๐Ÿ’œ
  • -fpic โ€” main character energy for shared libraries ๐ŸŒˆ This generates position-independent code (PIC) that's suitable for a shared library, as long as the target machine supports it. The code reaches every constant address through a global offset table (GOT). The dynamic loader fills in the GOT entries when the program starts (the dynamic loader isn't part of GCC, it's part of the operating system, bestie ๐Ÿ’…). If the GOT size for the linked executable goes over a machine-specific maximum, the linker throws an error saying -fpic doesn't work, and in that case you just recompile with -fPIC instead ๐Ÿ˜ญ (The 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 โ€” the upgraded version ๐Ÿ‘‘ If it's supported for the target machine, this 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 โ€” these two are giving similar vibes to -fpic and -fPIC ๐Ÿงš The difference is that the generated position-independent code can only be linked into executables, not shared libraries ๐Ÿ™ˆ Usually these are used to compile code that will get linked using the -pie GCC option ๐Ÿ’œ

Both -fpie and -fPIE define the macros "__pie__" and "__PIE__". The macros have the value 1 for -fpie and 2 for -fPIE โœจ

  • -fno-plt โ€” no PLT for external function calls in position-independent code, bestie ๐Ÿ™…โ€โ™€๏ธ Instead, the callee address gets loaded at call sites from the GOT, and then the code branches to it ๐Ÿซถ This leads to more efficient code because it gets rid of PLT stubs and exposes GOT loads to optimizations ๐Ÿ”ฅ On architectures like 32-bit x86, where PLT stubs expect the GOT pointer in a specific register, this gives the compiler more register allocation freedom ๐Ÿ‘‘ Heads up, though: lazy binding requires use of the PLT, so with -fno-plt all external symbols are resolved at load time ๐Ÿ’€

Alternatively, the function attribute "noplt" can be used to avoid calls through the PLT for specific external functions ๐Ÿฆ‹

In position-dependent code, a few targets also convert calls to functions that are marked to not use the PLT so they use the GOT instead ๐ŸŒˆ

  • -fno-jump-tables โ€” don't use jump tables for switch statements, even where they'd be more efficient than other code generation strategies ๐Ÿ™ˆ This one is handy alongside -fpic or -fPIC when you're building code that forms part of a dynamic linker and can't reference the address of a jump table ๐Ÿ’… On some targets, jump tables don't require a GOT, so this option isn't needed there โœจ
  • -fno-bit-tests โ€” same energy as above, but for bit tests. Don't use them for switch statements, even where they'd be more efficient than other code generation strategies ๐Ÿ“
  • -ffixed-reg โ€” this one is the boss move ๐Ÿ‘‘ Treat the register named reg as a fixed register, so the generated code should never refer to it (except maybe as a stack pointer, frame pointer, or in some other fixed role) ๐ŸŽ€

reg has to be the name of a register. The accepted register names are machine-specific and are defined in the REGISTER_NAMES macro in the machine description macro file ๐Ÿงš

This flag doesn't have a negative form, because it specifies a three-way choice ๐Ÿ’…

  • -fcall-used-reg โ€” treat the register named reg as an allocable register that gets clobbered by function calls ๐Ÿฆ‹ It may be allocated for temporaries or variables that don't live across a call. Functions compiled this way do not save and restore the register reg ๐Ÿซถ

It is an error to use this flag with the frame pointer or stack pointer ๐Ÿ’€ Using this flag for other registers that have fixed pervasive roles in the machine's execution model produces disastrous results.

โš ๏ธ Don't do it, babe. Using this flag on registers with fixed pervasive roles in the machine's execution model produces disastrous results.

This flag doesn't have a negative form, because it specifies a three-way choice ๐Ÿ’…

  • -fcall-saved-reg โ€” treat the register named reg as an allocable register that gets saved by functions ๐ŸŒธ It may be allocated even for temporaries or variables that live across a call. Functions compiled this way save and restore the register reg if they use it โœจ

It is an error to use this flag with the frame pointer or stack pointer ๐Ÿ’€ Using this flag for other registers that have fixed pervasive roles in the machine's execution model produces disastrous results.

๐Ÿ’€ A different sort of disaster happens if you use this flag on a register that function values may be returned in.

This flag doesn't have a negative form, because it specifies a three-way choice ๐Ÿ’…

  • -fpack-struct[=n] โ€” without a value, this packs all structure members together with no holes ๐Ÿ“ฆ When you give a value (which must be a small power of two), structure members get packed according to that value, which is the maximum alignment (so objects with default alignment requirements larger than this are output potentially unaligned at the next fitting location ๐Ÿ™ƒ
โš ๏ธ Heads up, bestie: -fpack-struct makes GCC generate code that isn't binary compatible with code generated without that switch ๐Ÿ˜ญ It also makes the code suboptimal, so only use it to conform to a non-default application binary interface ๐Ÿซถ
  • -fleading-underscore โ€” this and its counterpart, -fno-leading-underscore, forcibly change the way C symbols are represented in the object file ๐Ÿงธ One use is to help link with legacy assembly code ๐Ÿ“
โš ๏ธ -fleading-underscore makes GCC generate code that isn't binary compatible with code generated without that switch. Only use it to conform to a non-default application binary interface, and know that not all targets provide complete support for this switch ๐Ÿ’€
  • -ftls-model=model โ€” alter the thread-local storage model that gets used ๐Ÿงต The model argument should be one of global-dynamic, local-dynamic, initial-exec or local-exec ๐Ÿ’– The choice is subject to optimization, though: the compiler may use a more efficient model for symbols that aren't visible outside of the translation unit, or if -fpic isn't given on the command line ๐Ÿซถ

Without -fpic, the default is initial-exec. With -fpic, the default is global-dynamic โœจ

  • -ftrampolines โ€” for targets that normally need trampolines for nested functions, this always generates them instead of using descriptors ๐Ÿฆ‹ For targets that don't need them, like HP-PA or IA-64, it does nothing ๐Ÿ™ˆ

A trampoline is a small piece of code that gets created at run time on the stack when the address of a nested function is taken. It's used to call the nested function indirectly. Because of that, it requires the stack to be made executable for the program to work properly ๐Ÿ˜ญ

-fno-trampolines is enabled by default on a language-by-language basis, so the compiler can avoid generating trampolines when it works out that's safe, and replace them with descriptors ๐Ÿงš Descriptors are made up of data only, but the generated code has to be prepared to deal with them. As of this writing, -fno-trampolines is enabled by default only for Ada ๐Ÿ‘‘

โš ๏ธ Code compiled with -ftrampolines and code compiled with -fno-trampolines are not binary compatible if nested functions are present. This option must therefore be used on a program-wide basis and be manipulated with extreme care ๐Ÿ’€
  • -fvisibility=[default|internal|hidden|protected] โ€” okay, this one is a whole vibe ๐ŸŒˆ It sets the default ELF image symbol visibility to the option you pick. All symbols get marked with this unless they're overridden within the code. Using this feature 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., every symbol is made public ๐ŸŒธ

A good explanation of the benefits of ensuring ELF symbols have the correct visibility is given by "How To Write Shared Libraries" by Ulrich Drepper (which can be found at <https://www.akkadia.org/drepper/>) ๐Ÿ“š A superior solution, made possible by this option, to marking things hidden when the default is public is to make the default hidden and mark things public instead ๐Ÿซถ This is the norm with DLLs on Windows. With -fvisibility=hidden and __attribute__ ((visibility("default"))) instead of __declspec(dllexport), you get almost identical semantics with identical syntax ๐Ÿฆ‹ This is a great boon to those working with cross-platform projects ๐ŸŒˆ

Okay so bestie, visibility is a whole vibe ๐Ÿ’… If you're adding it to code that already exists, #pragma GCC visibility is your best friend ๐ŸŽ€ You wrap the declarations you want to control with #pragma GCC visibility push(hidden) and close it with #pragma GCC visibility pop ๐Ÿฆ‹ Visibility is part of the API contract, so new code should always say what its visibility is whenever it isn't the default. Anything only used inside the local DSO should be marked hidden explicitly, which avoids PLT indirection overheads ๐Ÿ˜ญ It also makes the code super readable and self-documenting, so the whole team can see what's going on at a glance โœจ Also, thanks to the ISO C++ rules, operator new and operator delete have to be default visibility, no exceptions ๐Ÿ™ˆ

Heads up though: headers from outside your project, especially system headers and headers from other libraries you use, might not be expecting anything other than default visibility ๐Ÿ’€ If that happens, you may need to put #pragma GCC visibility push(default) right before including them.

extern declarations aren't affected by -fvisibility, which means a ton of your code can be recompiled with -fvisibility=hidden and you won't have to change a thing ๐ŸŒธ Lowkey though, calls to extern functions with no explicit visibility go through the PLT, so it's way more effective to use __attribute ((visibility)) and/or #pragma GCC visibility to tell the compiler which extern declarations should be treated as hidden ๐Ÿ”ฅ

Also, -fvisibility does affect C++ vague linkage entities. So if an exception class is getting thrown between DSOs, you have to mark it with default visibility explicitly so the type_info nodes get unified between the DSOs ๐Ÿ‘‘

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

  • -fstrict-volatile-bitfields โ€” forces volatile bit-field accesses to be a single access at the width of the field's type ๐Ÿ’–

This is the option you want when accesses to volatile bit-fields (or other structure fields, though the compiler usually respects those types anyway) need to be one single access at the width of the field's type, aligned to a natural alignment if that's possible. For example, targets with memory-mapped peripheral registers might need every access to be 16 bits wide. With this flag, you can declare all the peripheral bit-fields as unsigned short (assuming short is 16 bits on those targets) to force GCC into 16-bit accesses, instead of a maybe-more-efficient 32-bit access ๐Ÿ“

If this option is disabled, the compiler goes for the most efficient instruction it can find ๐Ÿง  In the example above, that might be a 32-bit load, even though it touches bytes that don't contain any part of the bit-field, or memory-mapped registers that have nothing to do with the one being updated. Yikes ๐Ÿ˜ฌ

When something like the packed attribute is applied to a structure field, it might not be possible to access that field with a single read or write that's correctly aligned for the target machine. In that case, GCC falls back to generating multiple accesses, rather than code that will 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 the bits of the field's type as bit-field members ๐Ÿ’œ

The default value of this option is determined by the application binary interface (ABI) for the target processor ๐ŸŒˆ

  • -fsync-libcalls โ€” controls whether any out-of-line instance of the __sync family can be used to implement the C++11 __atomic family ๐Ÿฆ‹

The default is enabled, so the only useful form of this option is -fno-sync-libcalls ๐Ÿ’… This option is used in the implementation of the libatomic runtime library โœจ


โœจ GCC Developer Options โœจ

This section is all about command-line options that are mainly interesting to GCC developers, like options that help with compiler testing and investigating compiler bugs and compile-time performance problems ๐Ÿ” That includes options that produce debug dumps at various points in the compilation, options that print statistics like memory use and execution time, and options that print info about GCC's configuration, like where it searches for libraries ๐Ÿ“š Honestly, you should rarely need any of these for ordinary compilation and linking tasks, 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 omitted, GCC builds a default dump file name by concatenating the base dump file name, a pass number, a phase letter, and the pass name โœจ The base dump file name is the name of the output file the compiler 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 are registered with the compiler's pass manager. That's usually the same as the order of execution, but passes registered by plugins, target-specific passes, or passes that 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 are created in the directory of the output file ๐Ÿซถ

  • -fcallgraph-info, -fcallgraph-info=MARKERS โ€” makes the compiler output callgraph information for your program, one per object file ๐Ÿ“Š

The info is generated in the common VCG format. You can decorate it with extra per-node and/or per-edge information by adding a comma-separated list of markers. When the su marker is specified, the callgraph is decorated with stack usage information, which is equivalent to -fstack-usage ๐Ÿ’œ When the da marker is specified, the callgraph is decorated with information about dynamically allocated objects ๐ŸŒˆ

When you're compiling with -flto, no callgraph information gets output along with the object file ๐Ÿ™ˆ At LTO link time, -fcallgraph-info may generate multiple callgraph information files right 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 letters ๐Ÿ”ฅ

This is for debugging the RTL-based passes of the compiler, so it's very much a deep dive ๐Ÿง  Some -dletters switches have a different meaning when -E is used for preprocessing โš ๏ธ

Debug dumps can be enabled with a -fdump-rtl switch or with some -d option letters. Here are the possible letters you can use in 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 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 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 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 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 enable dumping after the two forward propagation passes โžก๏ธ
  • -fdump-rtl-gcse1, -fdump-rtl-gcse2 โ€” these enable dumping after global common subexpression elimination ๐ŸŒ
  • -fdump-rtl-init-regs โ€” 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 enable dumping after the basic block scheduling passes ๐Ÿ—“๏ธ
  • -fdump-rtl-ree โ€” ๐Ÿงน Dumps right after sign/zero extension elimination, so you can see the cleanup happen.
  • -fdump-rtl-seqabstr โ€” ๐Ÿ” Dumps after common sequence discovery, once the repeated code gets spotted.
  • -fdump-rtl-shorten โ€” โœ‚๏ธ Dumps after branches get shortened.
  • -fdump-rtl-sibling โ€” ๐Ÿ‘ฏ Dumps after sibling call optimizations.
  • -fdump-rtl-split1, -fdump-rtl-split2, -fdump-rtl-split3, -fdump-rtl-split4, -fdump-rtl-split5 โ€” ๐Ÿฐ These five switches each give you a dump after one of five rounds of instruction splitting. Bestie, that's five slices of the same cake ๐Ÿ˜ญ
  • -fdump-rtl-sms โ€” ๐ŸŽถ Dumps after modulo scheduling. This pass only runs on some architectures, so don't panic if it's missing ๐Ÿ’…
  • -fdump-rtl-stack โ€” ๐Ÿฅž Dumps after GCC's "flat register file" registers get converted into the x87's stack-like registers. This pass only runs on x86 variants ๐Ÿ’ป
  • -fdump-rtl-subreg1, -fdump-rtl-subreg2 โ€” ๐Ÿงฉ These two dump after the two subreg expansion passes, one each.
  • -fdump-rtl-unshare โ€” ๐Ÿ”“ Dumps after all RTL has been unshared.
  • -fdump-rtl-vartrack โ€” ๐Ÿ“ Dumps after variable tracking.
  • -fdump-rtl-vregs โ€” ๐Ÿ” Dumps after virtual registers have been turned into 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 they always produce empty files, so no cap, don't waste your time on them.
โš ๏ธ Heads up: all five of those empty-file dumps are a total vibe check fail. They exist, but they will always give you nothing ๐Ÿ˜ญ
  • -da, -fdump-rtl-all โ€” ๐ŸŒˆ Produces every dump listed above. Maximum chaos, maximum files.
  • -dA โ€” ๐Ÿ–Š๏ธ Annotates the assembler output with miscellaneous debugging information.
  • -dD โ€” ๐Ÿ“œ Dumps all macro definitions at the end of preprocessing, on top of the normal output.
  • -dH โ€” ๐Ÿ’€ Produces a core dump whenever an error occurs. Iconic energy, but it's giving a lot of files.
  • -dp โ€” ๐Ÿท๏ธ Annotates the assembler output with a comment saying which pattern and alternative got used. The length and cost of each instruction get printed too.
  • -dP โ€” ๐ŸŽ€ Dumps the RTL in the assembler output as a comment before each instruction. This also turns on the -dp annotation, so it's two-for-one bestie ๐Ÿซถ
  • -dx โ€” ๐Ÿงš Just generates RTL for a function instead of compiling it. This is usually used with -fdump-rtl-expand.
  • -fdump-debug โ€” ๐Ÿ› Dumps the debugging information generated during the debug generation phase.
  • -fdump-earlydebug โ€” ๐ŸŒฑ Dumps the debugging information generated during the early debug generation phase.
  • -fdump-noaddr โ€” ๐Ÿ™ˆ When you're doing debugging dumps, this suppresses address output. It makes running diff on dumps way more doable when the compiler binaries differ, or when the text / bss / data / heap / stack / dso start locations differ.
  • -freport-bug โ€” ๐Ÿšจ If an internal compiler error (ICE) happens, this collects and dumps debug information into a temporary file for you.
  • -fdump-unnumbered โ€” ๐Ÿ”ข When you're doing debugging dumps, this suppresses instruction numbers and address output. It makes diff way easier for compiler invocations with different options, especially with and without -g.
  • -fdump-unnumbered-links โ€” ๐Ÿ”— When doing debugging dumps (see the -d option above), this suppresses instruction numbers for the links to the previous and next instructions in a sequence.
  • -fdump-ipa-switch, -fdump-ipa-switch-options โ€” ๐Ÿง  These control the dumping at various stages of inter-procedural analysis language tree to a file. The file name is made by appending a switch-specific suffix to the source file name, and it gets created in the same directory as the output file. Here are the possible dumps:
    • all โ€” enables all inter-procedural analysis dumps ๐ŸŒŸ
    • cgraph โ€” dumps info about call-graph optimization, unused function removal, and inlining decisions ๐Ÿ•ธ๏ธ
    • inline โ€” dumps after function inlining ๐Ÿ“ฆ

You can also add -optimized, -missed, -note, or -all, which mean the same thing as they do for -fopt-info. They default to -optimized if you skip them.

For example, -fdump-ipa-inline-optimized-missed will emit info on callsites that got inlined, and callsites that didn't ๐Ÿ‘€

By default, the dump has messages about successful optimizations (the same as -optimized), plus low-level details about the analysis ๐Ÿ”

  • -fdump-lang โ€” ๐Ÿ—ฃ๏ธ Dumps language-specific information. The file name is made by appending .lang to the source file name.
  • -fdump-lang-all, -fdump-lang-switch, -fdump-lang-switch-options, -fdump-lang-switch-options=filename โ€” ๐Ÿ—‚๏ธ These control the dumping of language-specific information. The options and filename parts work the same way as they do in the -fdump-tree option. Here are the switch values you can use:
    • all โ€” enables all language-specific dumps ๐ŸŒˆ
    • class โ€” dumps class hierarchy information. Virtual table information gets emitted unless you specify slim. This is C++ only ๐Ÿ‘‘
    • module โ€” dumps module information. The options lineno (locations), graph (reachability), blocks (clusters), uid (serialization), alias (mergeable), asmname (Elrond), eh (mapper) & vops (macros) may give you extra info. This is C++ only ๐Ÿ’œ
    • raw โ€” dumps the raw internal tree data. This is C++ only ๐Ÿงฑ
  • -fdump-passes โ€” ๐Ÿ“‹ Prints the list of optimization passes that the current command-line options turn on and off, straight to stderr.
  • -fdump-statistics-option โ€” ๐Ÿ“Š Enables and controls dumping of pass statistics into a separate file. The file name is made by appending a suffix that ends in .statistics to the source file name, and it's created in the same directory as the output file. With the -option form, -stats sums the counters over the whole compilation unit, while -details dumps every event as the passes generate it. With no option, the default is to sum counters for each function compiled.
  • -fdump-tree-all, -fdump-tree-switch, -fdump-tree-switch-options, -fdump-tree-switch-options=filename โ€” ๐ŸŒณ These control the dumping at various stages of processing the intermediate language tree to a file. If you use the -options form, options is a list of - separated options that control the details of the dump. Not every option works with every dump, and the ones that don't make sense get ignored. These options are available:
    • address โ€” prints the address of each node. This is usually not meaningful, since it changes depending on the environment and source file. Its main use is tying a dump file to a debug environment ๐Ÿ 
    • asmname โ€” if DECL_ASSEMBLER_NAME has been set for a given decl, uses that in the dump instead of DECL_NAME. Its main use is working backward from mangled names in the assembly file ๐Ÿ”™
    • slim โ€” when dumping front-end intermediate representations, stops members of a scope or body of a function from being dumped just because that scope was reached. Those items only get dumped when some other path reaches them directly. When dumping pretty-printed trees, this skips the bodies of control structures. When dumping RTL, it prints the RTL in slim (condensed) form instead of the default LISP-like representation ๐Ÿงƒ
    • raw โ€” prints a raw representation of the tree. By default, trees 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) ๐Ÿ“ˆ
    • blocks โ€” enables showing basic block boundaries (disabled in raw dumps) ๐Ÿงฑ
    • graph โ€” for each of the other indicated dump files (-fdump-rtl-pass), dumps a representation of the control flow graph to file.passid.pass.dot, which is suitable for viewing with GraphViz. Each function in the file gets pretty-printed as a subgraph, so GraphViz can render them all in a single plot ๐Ÿ•ธ๏ธ This option only works for RTL dumps right now, and the RTL is always dumped in slim form.
    • vops โ€” enables showing virtual operands for every statement ๐Ÿงฎ
    • lineno โ€” enables showing line numbers for statements ๐Ÿ“
    • uid โ€” enables showing the unique ID (DECL_UID) for each variable ๐Ÿ†”
    • verbose โ€” enables showing the tree dump for each statement ๐Ÿ“
    • eh โ€” enables showing the EH region number holding each statement ๐Ÿ›Ÿ
    • scev โ€” enables showing scalar evolution analysis details ๐Ÿ“
    • optimized โ€” enables showing optimization information (only available in certain passes) โœ…
    • missed โ€” enables showing missed optimization information (only available in certain passes) โŒ
    • note โ€” enables other detailed optimization information (only available in certain passes) ๐Ÿ—’๏ธ
    • all โ€” turns on all options, except raw, slim, verbose and lineno ๐ŸŒˆ
    • optall โ€” turns on all optimization options, i.e., optimized, missed, and note ๐Ÿ†

Okay, so, 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 distinct invocations of the same pass ๐Ÿ”Ž
  2. To turn on 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 too. If you don't specify one, GCC creates it as described below ๐Ÿ‘€
  3. Okay so step three is hunting down the pass dump ๐Ÿ” It lives in a file whose name has three parts glued together with periods ๐Ÿงš: first the name of the source file you asked GCC to compile, then a numeric suffix for the pass number with a t for tree passes (or an r for RTL passes ๐ŸŒˆ), and finally the pass code. For example, the Early VRP pass dump might be sitting in myfile.c.038t.evrp in your current working directory ๐ŸŽ€. Bestie, real talk: those numeric codes are NOT stable ๐Ÿ˜ญ they can change from one version of GCC to another.
  • -fopt-info, -fopt-info-options, -fopt-info-options=filename โ€” this is the optimization dump flag and it's giving main character energy ๐Ÿ‘‘ It controls the optimization dumps coming from the various optimization passes. If you use the -options form, options is a list of --separated option keywords that pick the dump details and the optimizations you care about.

The keywords sort into three groups, and you can mix and match them ๐Ÿ’…

  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.

Within each group you can freely mix keywords, since they don't overlap ๐Ÿซถ Just know that if things conflict, the later option on the command line wins ๐Ÿ‘€

The following options control which kinds of messages get emitted:

  • optimized โ€” prints info when an optimization is successfully applied ๐Ÿ”ฅ Each pass gets to decide what info is relevant. For example, the vectorizer passes print the source location of loops that got successfully vectorized.
  • missed โ€” prints info about missed optimizations ๐Ÿ™ˆ Individual passes control what goes into the output.
  • note โ€” prints verbose info about optimizations, like certain transformations and more detailed messages about decisions ๐Ÿง 
  • all โ€” prints detailed optimization info, which includes optimized, missed, and note ๐Ÿ’–

The following option controls the dump verbosity:

  • internals โ€” by default only "high-level" messages get emitted ๐Ÿ’… This one unlocks the extra, more detailed messages, which are mostly of interest to GCC developers ๐Ÿค“

One or more of these keywords can be used to describe a group of optimizations:

  • ipa โ€” enables dumps from all interprocedural optimizations ๐Ÿฆ‹
  • loop โ€” enables dumps from all loop optimizations ๐ŸŒ€
  • inline โ€” enables dumps from all inlining optimizations โœจ
  • omp โ€” enables dumps from all OMP (Offloading and Multi Processing) optimizations ๐Ÿš€
  • vec โ€” enables dumps from all vectorization optimizations ๐ŸŒธ
  • optall โ€” enables dumps from all optimizations ๐Ÿ‘‘ This is a superset of the optimization groups listed above.

If options is omitted, it defaults to optimized-optall, which means dumping messages about successful optimizations from all the passes, while skipping the messages treated as "internals" ๐Ÿงš

If you provide a filename, the dumps from all the applicable optimizations get concatenated into that file. Otherwise the dump goes to stderr. You can pass several -fopt-info options, but only one of them can include a filename. If other filenames are provided, all but the first such option get ignored ๐Ÿ™ƒ

Heads up! The output filename gets overwritten when there are multiple translation units ๐Ÿ˜ญ If you want combined output from multiple translation units, use stderr instead.

Here's the example where the optimization info goes to stderr ๐ŸŽ€

gcc -O3 -fopt-info

This one outputs the missed optimization report from all the passes into missed.all ๐Ÿ“

gcc -O3 -fopt-info-missed=missed.all

And this one prints info about missed optimization opportunities from the vectorization passes on stderr ๐Ÿ’… 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 slay however you like ๐Ÿ’–

gcc -O2 -ftree-vectorize -fopt-info-vec-missed

As another example, this one outputs info about missed optimizations as well as optimized locations from all the inlining passes into inline.txt ๐Ÿฆ‹

gcc -O3 -fopt-info-inline-optimized-missed=inline.txt

Finally, consider this one ๐Ÿ‘€

gcc -fopt-info-vec-missed=vec.miss -fopt-info-loop-optimized=loop.opt

Here the two output filenames vec.miss and loop.opt are in conflict, since only one output file is allowed ๐Ÿ˜ฉ In this case only the first option takes effect and the subsequent options get ignored. So only vec.miss is produced, containing dumps from the vectorizer about missed opportunities.

  • -fsave-optimization-record โ€” writes a SRCFILE.opt-record.json.gz file detailing what optimizations were performed, for the optimizations that support -fopt-info ๐ŸŒˆ
Experimental alert! โš ๏ธ This option is experimental, and the format of the data inside the compressed JSON file is subject to change ๐Ÿ’€

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. Each message also gets these extra goodies ๐ŸŽ

  • the execution count of the code being optimized, plus metadata about whether that 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 gets inlined into several different places (which might themselves be inlined), you can tell the copies apart ๐Ÿชž
  • objects identifying the parts of the message that refer to expressions, statements, or symbol-table nodes, which of these categories they are, and, when available, their source code location ๐Ÿ“
  • the GCC pass that emitted the message, and
  • the location in GCC's own code from which the message was emitted ๐Ÿคฏ

Some messages are logically nested within other messages too, reflecting implementation details of the optimization passes ๐Ÿซถ

  • -fsched-verbose=n โ€” on targets that use instruction scheduling, this controls how much debugging output the scheduler prints to the dump files ๐Ÿ“š
    • For n greater than zero, it outputs the same info as -fdump-rtl-sched1 and -fdump-rtl-sched2 ๐ŸŒธ
    • For n greater than one, it also outputs basic block probabilities, detailed ready list info, and unit/insn info โœจ
    • For n greater than two, it includes RTL at the abort point, plus control-flow and regions info ๐ŸŒ€
    • And for n over four, -fsched-verbose also includes dependence info ๐Ÿคฏ
  • -fenable-kind-pass, -fdisable-kind-pass=range-list โ€” a set of options for explicitly disabling and enabling optimization passes ๐Ÿ”ง They're meant for debugging GCC itself.
Compiler users should stick to the regular options for enabling and disabling passes instead, bestie ๐Ÿ’–
  • -fdisable-ipa-pass โ€” disables the IPA pass called pass. If the same pass gets statically invoked in the compiler multiple times, append a sequential number starting from 1 to the pass name ๐Ÿ”ข
  • -fdisable-rtl-pass, -fdisable-rtl-pass=range-list โ€” disables the RTL pass called pass. Same numbering rule as above. range-list is a comma-separated list of function ranges or assembler names ๐Ÿ“‹ Each range is a number pair separated by a colon, and it's inclusive at both ends. If the range is trivial, the number pair can be simplified to a single number. If a function's call graph node uid falls within one of the specified ranges, the pass is disabled for that function ๐Ÿฆ‹ The uid shows up in the function header of a dump file, and you can dump the pass names by using -fdump-passes ๐Ÿ‘€
  • -fdisable-tree-pass, -fdisable-tree-pass=range-list โ€” disables the tree pass called pass. Check -fdisable-rtl-pass for how the option arguments work ๐ŸŒณ
  • -fenable-ipa-pass โ€” enables the IPA pass called pass. Same numbering rule applies for repeated invocations ๐Ÿ™Œ
  • -fenable-rtl-pass, -fenable-rtl-pass=range-list โ€” enables the RTL pass called pass. See -fdisable-rtl for the option argument description and examples ๐Ÿ’ซ
  • -fenable-tree-pass, -fenable-tree-pass=range-list โ€” enables the tree pass called pass. See -fdisable-rtl for the description of option arguments ๐ŸŒฒ

Here are some examples showing how to use these options ๐ŸŽ€

# disable ccp1 for all functions
   -fdisable-tree-ccp1
# disable complete unroll for function whose cgraph node uid is 1
   -fenable-tree-cunroll=1
# disable gcse2 for functions at the following ranges [1,1],
# [300,400], and [400,1000]
# disable gcse2 for functions foo and foo2
   -fdisable-rtl-gcse2=foo,foo2
# disable early inlining
   -fdisable-tree-einline
# disable ipa inlining
   -fdisable-ipa-inline
# enable tree full unroll
   -fenable-tree-unroll
  • -fchecking, -fchecking=n โ€” enables internal consistency checking ๐Ÿง The default depends on the compiler configuration. -fchecking=2 enables further internal consistency checking that might affect code generation ๐Ÿ’…
  • -frandom-seed=string โ€” this gives GCC a seed to use instead 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. Use -frandom-seed to produce reproducibly identical object files ๐Ÿซถ The string can be a number (decimal, octal, or hex) or an arbitrary string, which gets converted to a number by computing CRC32 โœจ

Make sure the string is different for every file you compile, bestie ๐ŸŽ€โœจ

  • -save-temps โ€” okay so this one is keep-the-receipts energy ๐Ÿงพ๐Ÿ’… It stores the usual "temporary" intermediate files permanently instead of tossing them, and names them as auxiliary output files, as described under -dumpbase and -dumpdir ๐Ÿฆ‹ When you combine it with the -x option, -save-temps is sensible enough to avoid overwriting an input source file that has the same extension as an intermediate file ๐Ÿ™Œ If you need that intermediate file, rename the source file before using -save-temps ๐Ÿซถ
  • -save-temps=cwd โ€” literally just -save-temps with a twist, it's equivalent to:
-save-temps -dumpdir ./.
  • -save-temps=obj โ€” this one is equivalent to -save-temps -dumpdir outdir/ ๐Ÿ“ Here, outdir/ is the directory of the output file you named after -o, including any directory separators. If you don't use -o, then -save-temps=obj acts exactly like -save-temps=cwd ๐Ÿ’œ
  • -time[=file] โ€” main character energy โฑ๏ธ This reports the CPU time taken by each subprocess in the compilation sequence. For C source files, that's the compiler proper and the assembler (plus the linker, if linking is happening) ๐ŸŒธ

Without an output file, the output looks like this:

# cc1 0.12 0.01
# as 0.00 0.01

The first number on each line is the "user time," which is the time spent running the program itself. The second number is the "system time," which is the time spent in operating system routines on the program's behalf. Both numbers are in seconds โญ

With an output file, the output gets 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 "system time" get moved before the program name, and the options passed to the program are shown too, so you can later tell which file was being compiled and with which options ๐Ÿงš

  • -fdump-final-insns[=file] โ€” dumps the final internal representation (RTL) to file ๐Ÿ”ฅ If you leave out the optional argument (or file is .), the dump file gets named by appending .gkd to the dump base name, see -dumpbase ๐Ÿฆ‹
  • -fcompare-debug[=opts] โ€” bestie, this one is a whole vibe ๐Ÿ” If no error happens during compilation, the compiler runs a second time with opts and -fcompare-debug-second added to the arguments for that second compilation. It dumps the final internal representation in both compilations and prints an error if they differ ๐Ÿ’€ If you omit the equal sign, the default -gtoggle gets used โœจ

The environment variable GCC_COMPARE_DEBUG, if it's defined, non-empty, and nonzero, implicitly enables -fcompare-debug ๐ŸŒˆ If GCC_COMPARE_DEBUG is set to a string starting with a dash, that string is used for opts. Otherwise, the default -gtoggle is used ๐Ÿ’–

-fcompare-debug=, with the equal sign but without opts, is equivalent to -fno-compare-debug. That one disables the dumping of the final representation and the second compilation, and it even stops GCC_COMPARE_DEBUG from taking effect ๐Ÿ™…โ€โ™€๏ธ

To verify full coverage during -fcompare-debug testing, set GCC_COMPARE_DEBUG to something like -fcompare-debug-not-overridden. GCC rejects that as an invalid option in any real compilation (rather than preprocessing, assembly, or linking) ๐Ÿงช If you just want a warning, setting GCC_COMPARE_DEBUG to -w%n-fcompare-debug not overridden will do the trick ๐ŸŽ€

  • -fcompare-debug-second โ€” this one 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 other options that would make the compiler produce output to files or to standard output as a side effect. Dump files and preserved temporary files get renamed to include the extra .gk extension during the second compilation, so they don't overwrite the ones from the first run ๐Ÿฆ‹

When this option is passed to the compiler driver, the first compilation gets skipped. That makes it useful for pretty much nothing except debugging the compiler proper ๐Ÿ™ˆ

  • -gtoggle โ€” this flips debug info like a light switch ๐Ÿ’ก It turns generation of debug info off if leaving out this option would generate it, or turns it on at level 2 otherwise. Where you put it on the command line doesn't matter. It takes effect after all the other options are processed, and it only does so once, no matter how many times you give it ๐Ÿซถ It's mainly meant to be used with -fcompare-debug ๐Ÿ’œ
  • -fvar-tracking-assignments-toggle โ€” toggles -fvar-tracking-assignments the same way -gtoggle toggles -g ๐Ÿ”„
  • -Q โ€” makes the compiler print out each function name as it gets compiled, and print some statistics about each pass when it finishes ๐Ÿ“Š
  • -ftime-report โ€” makes the compiler print some statistics about the time consumed by each pass when it finishes โณ
  • -ftime-report-details โ€” records the time consumed by infrastructure parts separately for each pass ๐Ÿ”
  • -fira-verbose=n โ€” controls how verbose the dump file for the integrated register allocator is ๐Ÿ—‚๏ธ The default value is 5. If the value n is greater or equal to 10, the dump output gets sent to stderr, using the same format as n minus 10 ๐ŸŒธ
  • -flto-report โ€” prints a report with internal details on how the link-time optimizer is working ๐Ÿ”ง The contents of this report vary 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 โ€” like -flto-report, but only prints for the WPA phase of link-time optimization ๐ŸŽฏ
  • -fmem-report โ€” makes the compiler print some statistics about permanent memory allocation when it finishes ๐Ÿง 
  • -fmem-report-wpa โ€” makes the compiler print statistics about permanent memory allocation for the WPA phase only ๐Ÿง โœจ
  • -fpre-ipa-mem-report, -fpost-ipa-mem-report โ€” makes the compiler print some statistics about permanent memory allocation, either before or after interprocedural optimization ๐Ÿช„
  • -fprofile-report โ€” makes the compiler print some statistics about the consistency of the (estimated) profile and the effect of individual passes ๐Ÿ“ˆ
  • -fstack-usage โ€” okay this is so useful ๐Ÿฅน It makes the compiler output stack usage information for the program, on a per-function basis. The filename for the dump is made by appending .su to the auxname. The auxname is generated from the name of the output file, if it's explicitly specified 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 qualifier static 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 are made in the function. The second field is this fixed number of bytes.

The qualifier dynamic means the function manipulates the stack dynamically ๐ŸŒ€ On top of the static allocation described above, stack adjustments get made in the body of the function, for example to push and pop arguments around function calls. If the qualifier bounded is also present, the amount of these adjustments is bounded at compile time, and the second field is an upper bound on the total amount of stack the function uses. If bounded isn't present, the amount of these 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 tuples in the form name:lower_bound1-upper_bound1 [:lower_bound2-upper_bound2...]. These set the name of the counter and a list of closed intervals. The lower_bound is optional and is zero-initialized if it isn't set. For example, with -fdbg-cnt=dce:2-4:10-11,tail_call:10, dbg_cnt(dce) returns true only for the second, third, fourth, tenth, and eleventh invocation. For dbg_cnt(tail_call), true is returned for the first 10 invocations ๐Ÿชฉ
  • -print-file-name=library โ€” prints the full absolute name of the library file library that would be used when linking, and then stops ๐Ÿ—บ๏ธ With this option, GCC doesn't compile or link anything. It just prints the file name ๐Ÿ’…
  • -print-multi-directory โ€” prints the directory name that matches 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 @ instead of -, with no spaces between multiple switches. This is supposed to make shell processing easier ๐Ÿš
  • -print-multi-os-directory โ€” prints the path to the OS libraries for the selected multilib, relative to some lib subdirectory ๐Ÿชž If the OS libraries are in the lib subdirectory and no multilibs are used, this is usually just .. If the OS libraries are in libsuffix sibling directories, it prints something like ../lib64, ../lib, or ../lib32. If the OS libraries are in lib/subdir subdirectories, it prints something like amd64, sparcv9, or ev6 ๐ŸŒˆ
  • -print-multiarch โ€” prints the path to the OS libraries for the selected multiarch, relative to some lib subdirectory ๐Ÿฆ‹
  • -print-prog-name=program โ€” 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 this:
gcc -nostdlib <files>... `gcc -print-libgcc-file-name`
  • -print-search-dirs โ€” prints the name of the configured installation directory and a list of the program and library directories gcc searches, and then stops ๐Ÿ—‚๏ธ Nothing else happens after that โœจ

okay so this bit is lowkey the most important part bestie ๐Ÿ’… if gcc yells installation problem, cannot exec cpp0: No such file or directory at you, it means the compiler pieces (like cpp0) aren't where gcc is looking for them ๐Ÿ˜ญ you can either move cpp0 and friends to the spot gcc expects, OR set the GCC_EXEC_PREFIX environment variable to the folder where you installed everything. and periodt, don't forget the trailing / ๐Ÿซถ

  • -print-sysroot โ€” okay this one prints the target sysroot directory that gets used during compilation โœจ it's the one you set at configure time or with the --sysroot option, and it might come with an extra suffix that depends on your compilation options. if there's no target sysroot at all? it just prints nothing ๐Ÿ™ˆ
  • -print-sysroot-headers-suffix โ€” prints the suffix that gets tacked onto the target sysroot when gcc goes hunting for headers ๐ŸŽ€ and if your compiler wasn't configured with one, it throws an error instead. either way it doesn't do anything else, no cap ๐Ÿ’–
  • -dumpmachine โ€” prints the compiler's target machine (like i686-pc-linux-gnu) and then stops right there ๐Ÿฆ‹
  • -dumpversion โ€” prints the compiler version (think 3.0, 6.3.0 or 7) and then bounces, nothing else โœจ this is the version that shows up in filesystem paths and specs, and depending on how the compiler was configured, it can be:
    • just one number (the major version) ๐ŸŒธ
    • two numbers separated by a dot (major and minor) ๐Ÿ’œ
    • three numbers separated by dots (major, minor and patchlevel) ๐Ÿ‘‘
  • -dumpfullversion โ€” prints the full compiler version and then stops ๐Ÿ’… the output is always three numbers separated by dots: major, minor and patchlevel. no exceptions, it's giving consistency ๐ŸŒˆ
  • -dumpspecs โ€” prints the compiler's built-in specs and that's it ๐Ÿงš this one is used when GCC itself is being built, so it's kinda behind-the-scenes energy ๐Ÿ™ˆ

๐ŸŒธ Machine-Dependent Options ๐ŸŒธ

okay so every target machine that GCC supports can have its very own options ๐Ÿ’– these let you do stuff like compile for a specific processor variant or ABI, or control optimizations that only make sense for that machine โœจ by convention, the names of machine-specific options start with -m, so look out for those ๐Ÿ‘€

some configurations also support extra target-specific options too, usually so the compiler can play nice with other compilers on the same platform ๐Ÿซถ

๐Ÿฆ‹ AArch64 Options ๐Ÿฆ‹

these options are defined for AArch64 implementations, so if you're working on that architecture, this is your moment ๐Ÿ”ฅ

  • -mabi=name โ€” generates code for the specified data model ๐Ÿ’… the valid values are:
    • ilp32 for the SysV-like data model where int, long int and pointers are all 32 bits ๐ŸŒธ
    • lp64 for the SysV-like data model where int is 32 bits, but long int and pointers are 64 bits ๐Ÿ’œ

the default depends on your specific target configuration ๐Ÿ™ˆ and be careful, the LP64 and ILP32 ABIs are not link-compatible! you have to compile your entire program with the same ABI and link it with a compatible set of libraries, or it's gonna be a whole mess ๐Ÿ’€

  • -mbig-endian โ€” generates big-endian code ๐ŸŒˆ this is the default when GCC is configured for an aarch64_be-*-* target
  • -mgeneral-regs-only โ€” generates code that only uses the general-purpose registers โœจ this stops the compiler from touching floating-point and Advanced SIMD registers, but it doesn't put any restrictions on the assembler
  • -mlittle-endian โ€” generates little-endian code ๐ŸŽ€ this is the default when GCC is configured for an aarch64-*-* target but not an aarch64_be-*-* one
  • -mcmodel=tiny โ€” generates code for the tiny code model ๐Ÿฆ‹ the program and its statically defined symbols have to be within 1MB of each other. programs can be statically or dynamically linked
  • -mcmodel=small โ€” generates code for the small code model ๐Ÿ’– the program and its statically defined symbols have to be within 4GB of each other. programs can be statically or dynamically linked, and this is the default code model โœจ
  • -mcmodel=large โ€” generates code for the large code model ๐Ÿ‘‘ it makes no assumptions about addresses and sizes of sections, but programs can only be statically linked. also, -mcmodel=large is incompatible with -mabi=ilp32, -fpic and -fPIC, so don't mix them ๐Ÿšซ
  • -mstrict-align, -mno-strict-align โ€” these let you avoid (or allow) generating memory accesses that might not be aligned on a natural object boundary, as the architecture specification describes ๐Ÿงš
  • -momit-leaf-frame-pointer, -mno-omit-leaf-frame-pointer โ€” omit or keep the frame pointer in leaf functions ๐ŸŒธ the first one (omitting it) is the default behaviour
  • -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 sysreg for a canary in an appropriate system register
    • with the sysreg choice, -mstack-protector-guard-reg=reg and -mstack-protector-guard-offset=offset specify which system register to use as the base register for reading the canary, plus the offset from that base register ๐Ÿ’…
    • there is no default register or offset here, because this is entirely for use within the Linux kernel ๐Ÿง
  • -mtls-dialect=desc โ€” uses TLS descriptors as the thread-local storage mechanism for dynamic accesses of TLS variables ๐Ÿ’– this is the default
  • -mtls-dialect=traditional โ€” uses traditional TLS as the thread-local storage mechanism for dynamic accesses of TLS variables ๐ŸŒˆ
  • -mtls-size=size โ€” specifies the bit size of immediate TLS offsets ๐ŸŽ€ the valid values are 12, 24, 32 and 48. this option requires binutils 2.26 or newer โœจ
  • -mfix-cortex-a53-835769, -mno-fix-cortex-a53-835769 โ€” enables or disables the workaround for ARM Cortex-A53 erratum number 835769 ๐Ÿฆ‹ this involves inserting a NOP instruction between memory instructions and 64-bit integer multiply-accumulate instructions
  • -mfix-cortex-a53-843419, -mno-fix-cortex-a53-843419 โ€” enables or disables the workaround for ARM Cortex-A53 erratum number 843419 ๐Ÿ’œ this erratum workaround is made at link time, so this option only passes the corresponding flag to the linker
  • -mlow-precision-recip-sqrt, -mno-low-precision-recip-sqrt โ€” enables or disables the reciprocal square root approximation ๐Ÿงš this only has an effect if -ffast-math or -funsafe-math-optimizations is used as well. when enabled, it reduces the precision of reciprocal square root results to about 16 bits for single precision and to 32 bits for double precision โšก
  • -mlow-precision-sqrt, -mno-low-precision-sqrt โ€” enables or disables the square root approximation ๐ŸŒธ this only has an effect if -ffast-math or -funsafe-math-optimizations is used as well. when enabled, it reduces the precision of square root results to about 16 bits for single precision and to 32 bits for double precision. and if it's enabled, it implies -mlow-precision-recip-sqrt ๐Ÿ”ฅ
  • -mlow-precision-div, -mno-low-precision-div โ€” enables or disables the division approximation ๐Ÿ’… this only has an effect if -ffast-math or -funsafe-math-optimizations is used as well. when enabled, it reduces the precision of division results to about 16 bits for single precision and to 32 bits for double precision ๐ŸŽ€
  • -mtrack-speculation, -mno-track-speculation โ€” enables or disables generation of extra code that tracks speculative execution through conditional branches ๐Ÿฆ‹ the tracking state can then be used by the compiler when expanding calls to "__builtin_speculation_safe_copy", so it can generate a more efficient code sequence ๐Ÿง 
  • -moutline-atomics, -mno-outline-atomics โ€” enables or disables calls to out-of-line helpers that implement atomic operations ๐Ÿ’– these helpers figure out at runtime whether the LSE instructions from ARMv8.1-A can be used. if they can't, they fall back to the load/store-exclusive instructions that are present in the base ARMv8.0 ISA ๐ŸŒˆ
    • this option only applies when you're compiling for the base ARMv8.0 instruction set ๐Ÿ™ˆ if you're using a later revision, like -march=armv8.1-a or -march=armv8-a+lse, the ARMv8.1-Atomics instructions get used directly. the same goes for -mcpu= when the selected CPU supports the lse feature
    • this option is on by default โœจ
  • -march=name โ€” specifies the name of the target architecture and, optionally, one or more feature modifiers ๐Ÿ‘‘ this option has the form -march=arch{+[no]feature}*

the table below (well, a list now, lol) summarizes the permissible values for arch and the features they enable by default ๐Ÿ’…

  • armv8-a (Armv8-A) โ€” includes by default +fp, +simd ๐ŸŒธ
  • armv8.1-a (Armv8.1-A) โ€” includes by default armv8-a, +crc, +lse, +rdma ๐Ÿ’œ
  • armv8.2-a (Armv8.2-A) โ€” includes by default armv8.1-a ๐Ÿฆ‹
  • armv8.3-a (Armv8.3-A) โ€” includes by default armv8.2-a, +pauth โœจ
  • armv8.4-a (Armv8.4-A) โ€” includes by default armv8.3-a, +flagm, +fp16fml, +dotprod ๐Ÿ”ฅ
  • armv8.5-a (Armv8.5-A) โ€” includes by default armv8.4-a, +sb, +ssbs, +predres ๐ŸŒˆ
  • armv8.6-a (Armv8.6-A) โ€” includes by default armv8.5-a, +bf16, +i8mm ๐ŸŽ€
  • armv8-r (Armv8-R) โ€” includes by default armv8-r ๐Ÿงš

the value native is available on native AArch64 GNU/Linux and makes the compiler pick the architecture of the host system ๐Ÿซถ this option has no effect if the compiler is unable to recognize the architecture of the host system.

the permissible values for feature are listed in the sub-section on aarch64-feature-modifiers,,-march and -mcpu Feature Modifiers. if you specify conflicting feature modifiers, the right-most feature is used, so the last one wins ๐Ÿ‘‘

GCC uses name to figure out what kind of instructions it can emit when generating assembly code ๐Ÿ’– if -march is specified without -mtune or -mcpu also being specified, the code gets tuned to perform well across a range of target processors that implement the target architecture ๐ŸŒธ

  • -mtune=name โ€” specifies the name of the target processor that GCC should tune the performance of the code for โœจ the permissible values for this option are:
generic, cortex-a35, cortex-a53, cortex-a55, cortex-a57,
cortex-a72, cortex-a73, cortex-a75, cortex-a76, cortex-a76ae,
cortex-a77, cortex-a65, cortex-a65ae, cortex-a34, cortex-a78,
cortex-a78ae, cortex-a78c, ares, exynos-m1, emag, falkor,
neoverse-512tvb, neoverse-e1, neoverse-n1, neoverse-n2,
neoverse-v1,neoverse-v2, grace, qdf24xx, saphira, phecda, xgene1,
vulcan, octeontx, octeontx81,  octeontx83, octeontx2, octeontx2t98,
octeontx2t96 octeontx2t93, octeontx2f95, octeontx2f95n,
octeontx2f95mm, a64fx, thunderx, thunderxt88, thunderxt88p1,
thunderxt81, tsv110, thunderxt83, thunderx2t99, thunderx3t110, zeus,
cortex-a57.cortex-a53, cortex-a72.cortex-a53, cortex-a73.cortex-a35,
cortex-a73.cortex-a53, cortex-a75.cortex-a55, cortex-a76.cortex-a55,
cortex-r82, cortex-x1, ampere1, ampere1a, cobalt-100 and native.

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 are giving big.LITTLE realness ๐ŸŒˆ. They tell GCC to tune for a big.LITTLE system ๐Ÿ’œ.

the value neoverse-512tvb is the main character here ๐Ÿ‘‘. It tells GCC to tune for Neoverse cores that (a) implement SVE and (b) have a total vector bandwidth of 512 bits per cycle. ngl that's a lot of words, so here's the vibe: GCC is tuning for Neoverse cores that can run 4 128-bit Advanced SIMD arithmetic instructions a cycle, plus an equivalent number of SVE arithmetic instructions per cycle (2 for 256-bit SVE, 4 for 128-bit SVE) ๐Ÿ’…. It's more general than tuning for one specific core like Neoverse V1, but more specific than the default tuning described below โœจ.

additionally, on native AArch64 GNU/Linux systems, the value native tunes performance to the host system ๐Ÿซถ. This option has no effect if the compiler can't recognise the processor of the host system ๐Ÿ’€.

where none of -mtune=, -mcpu= or -march= are specified, the code is tuned to perform well across a range of target processors ๐ŸŽ€.

this option cannot be suffixed by feature modifiers ๐Ÿ™…

  • -mcpu=name โ€” Pick the target processor, optionally with one or more feature modifiers tacked on ๐ŸŽ€. The form is -mcpu=cpu{+[no]feature}*, where the values for cpu are the same ones you'd get with -mtune. The values for feature are documented in the sub-section on aarch64-feature-modifiers,,-march and -mcpu Feature Modifiers. If you give conflicting feature modifiers, the right-most one wins ๐Ÿ‘‘.
    • GCC uses name to figure out what kind of instructions it can emit when generating assembly (as if by -march), and which processor to tune performance for (as if by -mtune). If you use this with -march or -mtune, those take precedence over the matching part of this option ๐Ÿ’–.
    • -mcpu=neoverse-512tvb is special ๐Ÿฆ‹. It doesn't refer to one specific core. Instead it refers to all Neoverse cores that (a) implement SVE and (b) have a total vector bandwidth of 512 bits a cycle. Unless you override it with -march, -mcpu=neoverse-512tvb generates code that can run on a Neoverse V1 core, since Neoverse V1 is the first Neoverse core with these properties. Unless you override it with -mtune, -mcpu=neoverse-512tvb tunes code the same way as -mtune=neoverse-512tvb ๐ŸŒธ.
  • -moverride=string โ€” Overrides the tuning decisions the back-end makes in response to a -mtune= switch ๐Ÿ™ˆ. The syntax, semantics and accepted values for string aren't guaranteed to stay consistent across releases.
โš ๏ธ This option is only intended to be useful when developing GCC. Don't go poking at it in your everyday builds, bestie.
  • -mverbose-cost-dump โ€” Turns on verbose cost model dumping in the debug dump files ๐Ÿ”. This one's only here for debugging the compiler itself ๐Ÿงš.
  • -mpc-relative-literal-loads, -mno-pc-relative-literal-loads โ€” Enables or disables PC-relative literal loads ๐Ÿ’œ. With this option, literal pools are accessed using a single instruction and emitted after each function. That limits the maximum size of functions to 1MB ๐Ÿซ . It's enabled by default for -mcmodel=tiny.
  • -msign-return-address=scope โ€” Picks the function scope that return address signing gets applied to ๐Ÿ”. The permissible values are:
    • none โ€” disables return address signing.
    • non-leaf โ€” enables pointer signing for functions which are not leaf functions.
    • all โ€” enables pointer signing for all functions.

The default value 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 types of branch protection features. If a feature has additional tuning options, standard sets it to its standard level.
    • pac-ret[+leaf] turns on return address signing to its standard level. That means signing functions that save the return address to memory (non-leaf functions will practically always do this) using the a-key. The optional argument leaf can be used to extend the signing to include leaf functions. The optional argument b-key can be used to sign the functions with the B-key instead of the A-key.
    • bti turns on the branch target identification mechanism โœจ.
  • -mharden-sls=opts โ€” Enables compiler hardening against straight line speculation (SLS) ๐ŸŒˆ. opts is a comma-separated list of the following options:
    • retbr
    • blr

In addition, -mharden-sls=all enables all SLS hardening, while -mharden-sls=none disables all SLS hardening ๐Ÿ’….

  • -msve-vector-bits=bits โ€” Sets how many bits live in an SVE vector register ๐Ÿฆ‹. It only has an effect when SVE is enabled.
    • GCC supports two forms of SVE code generation. "Vector-length agnostic" output works with any size of vector register. "Vector-length specific" output lets GCC make assumptions about the vector length when that's useful for optimisation reasons ๐Ÿง .
    • The possible values of bits are scalable, 128, 256, 512, 1024 and 2048. Specifying scalable selects vector-length agnostic output. At present, -msve-vector-bits=128 also generates vector-length agnostic output for big-endian targets. All other values generate vector-length specific code ๐ŸŽ€.
    • The behaviour of these values may change in future releases, and no value except scalable should be relied on for producing code that's portable across different hardware SVE vector lengths. ๐Ÿšจ
    • The default is -msve-vector-bits=scalable, which produces vector-length agnostic code ๐Ÿซถ.

๐Ÿฆ‹ -march and -mcpu Feature Modifiers ๐Ÿฆ‹

feature modifiers used with -march and -mcpu can be any of the following, and each one also has an inverse, nofeature โœจ.

  • crc โ€” Enables the CRC extension. This is on by default for -march=armv8.1-a ๐Ÿ’–.
  • crypto โ€” Enables the Crypto extension. This also turns on Advanced SIMD and floating-point instructions ๐Ÿ”.
  • fp โ€” Enables floating-point instructions. This is on by default for all possible values for options -march and -mcpu ๐ŸŒธ.
  • simd โ€” Enables Advanced SIMD instructions. This also turns on floating-point instructions. It's on by default for all possible values for options -march and -mcpu ๐Ÿ”ฅ.
  • sve โ€” Enables Scalable Vector Extension instructions. This also turns on 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 turns on floating-point instructions ๐ŸŽ€.
  • fp16fml โ€” Enables the FP16 fmla extension. This also turns on FP16 extensions and floating-point instructions. It's enabled by default for -march=armv8.4-a. Using this option 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's passed on to the assembler, so inline asm statements can use instructions from the RcPc extension ๐Ÿงš.
  • dotprod โ€” Enables the Dot Product extension. This also turns on Advanced SIMD instructions ๐Ÿ’œ.
  • aes โ€” Enables the Armv8-a aes and pmull crypto extension. This also turns on Advanced SIMD instructions ๐Ÿ”.
  • sha2 โ€” Enables the Armv8-a sha2 crypto extension. This also turns on Advanced SIMD instructions ๐ŸŒˆ.
  • sha3 โ€” Enables the sha512 and sha3 crypto extension. This also turns on Advanced SIMD instructions. Using this option with architectures prior to Armv8.2-A is not supported ๐Ÿ™ˆ.
  • sm4 โ€” Enables the sm3 and sm4 crypto extension. This also turns on Advanced SIMD instructions. Using this option with architectures prior to Armv8.2-A is not supported ๐Ÿซ .
  • profile โ€” Enables the Statistical Profiling extension. This option only enables the extension at the assembler level and does not affect code generation ๐Ÿ”.
  • rng โ€” Enables the Armv8.5-a Random Number instructions. This option only enables the extension at the assembler level and does not affect code generation ๐ŸŽฒ.
  • memtag โ€” Enables the Armv8.5-a Memory Tagging Extensions. Using this option with architectures prior to Armv8.5-A is not supported ๐Ÿท๏ธ.
  • sb โ€” Enables the Armv8-a Speculation Barrier instruction. This option only enables the extension at the assembler level and does not affect code generation. It's enabled by default for -march=armv8.5-a ๐Ÿ›ก๏ธ.
  • ssbs โ€” Enables the Armv8-a Speculative Store Bypass Safe instruction. This option only enables the extension at the assembler level and does not affect code generation. It's enabled by default for -march=armv8.5-a โœจ.
  • predres โ€” Enables the Armv8-a Execution and Data Prediction Restriction instructions. This option only enables the extension at the assembler level and does not affect code generation. It's enabled by default for -march=armv8.5-a ๐Ÿ’….
  • sve2 โ€” Enables the Armv8-a Scalable Vector Extension 2. This also enables SVE instructions ๐Ÿฆ‹.
  • sve2-bitperm โ€” Enables SVE2 bitperm instructions. This also enables SVE2 instructions ๐ŸŒธ.
  • sve2-sm4 โ€” Enables SVE2 sm4 instructions. This also enables SVE2 instructions ๐Ÿ’œ.
  • sve2-aes โ€” Enables SVE2 aes instructions. This also enables SVE2 instructions ๐Ÿ”.
  • sve2-sha3 โ€” Enables SVE2 sha3 instructions. This also enables SVE2 instructions ๐ŸŒˆ.
  • tme โ€” Enables the Transactional Memory Extension ๐Ÿซถ.
  • i8mm โ€” Enables 8-bit Integer Matrix Multiply instructions. This also turns on Advanced SIMD and floating-point instructions. It's enabled by default for -march=armv8.6-a. Using this option 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 option 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 option with architectures prior to Armv8.2-A is not supported ๐Ÿ‘‘.
  • bf16 โ€” ๐Ÿ’– okay so this one turns on brain half-precision floating-point instructions! โœจ It also switches on Advanced SIMD and floating-point instructions too. It's on by default for -march=armv8.6-a, so you're already set if you're using that. ๐Ÿซถ
๐Ÿšจ Using this with architectures older than Armv8.2-A is not supported, so please don't do that bestie ๐Ÿ’€
  • flagm โ€” ๐Ÿฆ‹ Enables the Flag Manipulation instructions Extension.
  • pauth โ€” ๐Ÿ‘‘ Enables the Pointer Authentication Extension.

Okay so crypto implies aes, sha2, and simd, and simd implies fp. ๐Ÿ”ฅ The other way around, nofp implies nosimd, which implies nocrypto, noaes and nosha2. It's giving chain reaction ๐Ÿ’…

โœจ Adapteva Epiphany Options โœจ

These -m options are defined for Adapteva Epiphany ๐Ÿธ

  • -mhalf-reg-file โ€” ๐ŸŒธ Don't allocate any register in the range "r32"..."r63". That way your code can run on hardware variants that don't have these registers at all.
  • -mprefer-short-insn-regs โ€” ๐Ÿงš Prefers registers that let the compiler generate short instructions. Heads up though, this can bump up the instruction count, so overall code size might go down or up. ๐Ÿคทโ€โ™€๏ธ
  • -mbranch-cost=num โ€” ๐Ÿ“ Sets the cost of branches to roughly num "simple" instructions. This is only a heuristic, so it's not guaranteed to give consistent results across releases. Not a promise, just a vibe ๐Ÿ’œ
  • -mcmove โ€” โญ Turns on the generation of conditional moves.
  • -mnops=num โ€” ๐ŸŒˆ Emits num NOPs before every other generated instruction. Very spacious ๐Ÿ™ˆ
  • -mno-soft-cmpsf โ€” ๐Ÿ’€ For single-precision floating-point comparisons, this emits an "fsub" instruction and tests the flags. It's faster than a software comparison, BUT it can give incorrect results when NaNs are involved, or when two different small numbers are compared and their difference works out to zero. The default is -msoft-cmpsf, which uses slower software comparisons that are IEEE-compliant. Slower but correct is the move โœจ
โš ๏ธ Be careful with -mno-soft-cmpsf if you're dealing with NaNs or tiny numbers. Your results could be wrong, bestie.
  • -mstack-offset=num โ€” ๐ŸŽ€ Sets the offset between the top of the stack and the stack pointer. For example, a value of 8 means the eight bytes in the range "sp+0...sp+7" can be used by leaf functions without stack allocation. Values other than 8 or 16 are untested and unlikely to work. Also, this option changes the ABI, so compiling a program with a different stack offset than the libraries were built with generally does not work.
๐Ÿšจ This changes the ABI! Mixing stack offsets with your libraries usually breaks things, so be very careful here.

This option is handy if you want to test whether a different stack offset gives you better code. But if you want to actually build working programs with a different stack offset, the recommended move is to configure the toolchain with the appropriate --with-stack-offset=num option ๐Ÿ› ๏ธ

  • -mno-round-nearest โ€” ๐Ÿฆ‹ Makes the scheduler assume the rounding mode has been set to truncating. The default is -mround-nearest.
  • -mlong-calls โ€” ๐Ÿข If not otherwise specified by an attribute, this assumes all calls might be beyond the offset range of the "b" / "bl" instructions. So it loads the function address into a register before doing a call that would otherwise be direct. This is the default.
  • -mshort-calls โ€” โšก If not otherwise specified by an attribute, this assumes all direct calls are in range of the "b" / "bl" instructions, so those instructions get used for direct calls. The default is -mlong-calls.
  • -msmall16 โ€” ๐ŸŒท Assumes addresses can be loaded as 16-bit unsigned values. This doesn't apply to function addresses where -mlong-calls semantics are in effect.
  • -mfp-mode=mode โ€” ๐Ÿ‘‘ Sets the prevailing mode of the floating-point unit. This decides the floating-point mode that's provided and expected at function call and return time. Matching this to the mode you mostly need at function start can make your programs smaller and faster by avoiding unnecessary mode switches. ๐ŸŽ๏ธ

mode can be set to one of these values:

  • caller โ€” Any mode at function entry is valid, and it gets retained or restored when the function returns, and when it calls other functions. This is the move for libraries or other compilation units you want to drop into different programs with different prevailing FPU modes. A single object file is super convenient, even though you pay a bit in size and speed for the extra mode switching you might need compared to a more specific choice.
  • truncate โ€” The mode used for floating-point calculations with truncating (round towards zero) rounding mode. That includes conversion from floating point to integer.
  • round-nearest โ€” The mode used for floating-point calculations with round-to-nearest-or-even rounding mode.
  • int โ€” The mode used to do integer calculations in the FPU, like integer multiply or integer multiply-and-accumulate.

The default is -mfp-mode=caller ๐Ÿซถ

  • -mno-split-lohi, -mno-postinc, -mno-postmodify โ€” ๐Ÿงฉ Code generation tweaks that turn off, respectively, splitting of 32-bit loads, generation of post-increment addresses, and generation of post-modify addresses. The defaults are msplit-lohi, -mpost-inc, and -mpost-modify.
  • -mnovect-double โ€” ๐Ÿญ Changes the preferred SIMD mode to SImode. The default is -mvect-double, which uses DImode as the preferred SIMD mode.
  • -max-vect-align=num โ€” ๐Ÿ“ The maximum alignment for SIMD vector mode types. num can be 4 or 8, and the default is 8. This is an ABI change, even though lots of library function interfaces are unaffected if they don't use SIMD vector modes in places that affect the size and/or alignment of relevant types.
๐Ÿšจ Yep, this is an ABI change, so handle it with care ๐Ÿ’…
  • -msplit-vecmove-early โ€” ๐ŸŒŠ Splits vector moves into single word moves before reload. In theory this can give better register allocation, but so far the reverse seems to be generally the case. Theory vs. reality, bestie ๐Ÿ˜ญ
  • -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 fix that register for this purpose, and none, which means no register is used for this. The default is -m1reg-none.

โœจ AMD GCN Options โœจ

These options are defined specifically for the AMD GCN port ๐ŸŒˆ

  • -march=gpu, -mtune=gpu โ€” ๐Ÿ”ฅ Sets the architecture type or tuning for gpu. Supported values for gpu are:
    • fiji โ€” 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 suited to devices with the SRAM-ECC feature enabled, disabled, or either mode. Some devices let you enable this per-process. 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). Beware, there may be lots of threads and limited memory available ๐Ÿ’€ The size of the stack allocation may also affect run-time performance. The default is 32KB when using OpenACC or OpenMP, and 1MB otherwise.
  • -mxnack โ€” ๐Ÿฆ„ Compiles binaries suited to devices with the XNACK feature enabled. Some devices always require XNACK, and some let the user configure it. The compiled code must match the device mode. The default is -mno-xnack. Right now this option is a placeholder for support that isn't implemented yet, so it's a bit of a promise for later ๐Ÿ™ˆ

โœจ ARC Options โœจ

The following options control the architecture variant that code is compiled for ๐Ÿฆ‹

  • -mbarrel-shifter โ€” ๐ŸŒ€ Generates instructions supported by the barrel shifter. This is the default unless -mcpu=ARC601 or -mcpu=ARCEM is in effect.
  • -mjli-always โ€” ๐Ÿ“ž Forces a function call to use the jli_s instruction. This option is only valid for the ARCv2 architecture.
  • -mcpu=cpu โ€” ๐Ÿง Sets the architecture type, register usage, and instruction scheduling parameters for cpu. There are also shortcut alias options for backward compatibility and convenience. 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 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. Currently only "divaw", "adds", "subs", and "sat16" are supported. This is only valid for -mcpu=ARC700.
  • -mno-mpy โ€” ๐Ÿ™…โ€โ™€๏ธ Do NOT generate the mpy-family instructions for ARC700. ngl this one is deprecated, so it's basically retired ๐Ÿ’€
  • -mmul32x16 โ€” โœจ Generates 32x16-bit multiply and multiply-accumulate instructions. Main character multiply energy ๐Ÿ’…
  • -mmul64 โ€” ๐Ÿ”ฅ Generates mul64 and mulu64 instructions. Only valid for -mcpu=ARC600, so don't try it anywhere else ๐Ÿ™ˆ
  • -mnorm โ€” ๐Ÿงš Generates norm instructions. It's already on by default if -mcpu=ARC700 is in effect, so you're set ๐Ÿ‘‘
  • -mspfp, -mspfp-compact โ€” ๐ŸŒธ Generates single-precision FPX instructions, tuned for the compact implementation.
  • -mspfp-fast โ€” โšก Generates single-precision FPX instructions, tuned for the fast implementation.
  • -msimd โ€” ๐Ÿ’œ Turns on ARC SIMD instructions through target-specific builtins. Only valid for -mcpu=ARC700.
  • -msoft-float โ€” ๐Ÿซถ This one gets ignored. It's only here for compatibility, bestie. Software floating-point code is emitted by default, and that default can be overridden by FPX options: -mspfp, -mspfp-compact, or -mspfp-fast for single precision, and -mdpfp, -mdpfp-compact, or -mdpfp-fast for double precision.
  • -mswap โ€” ๐Ÿ”„ Generates swap instructions.
  • -matomic โ€” โš›๏ธ Unlocks the locked load/store conditional extension, which the compiler uses to build the atomic memory built-in functions. Not available for ARC 6xx or ARC EM cores ๐Ÿ’€
  • -mdiv-rem โ€” โž— Enables div and rem instructions for ARCv2 cores.
  • -mcode-density โ€” ๐Ÿ“ Enables code density instructions for ARC EM. It's on by default for ARC HS, so ARC HS users are already winning.
  • -mll64 โ€” ๐Ÿ’พ Enables double load/store operations for ARC HS cores.
  • -mtp-regno=regno โ€” ๐Ÿงต Sets the thread pointer register number.
  • -mmpy-option=multo โ€” ๐Ÿงฎ Compiles ARCv2 code with a multiplier design option. You can pass multo as either a string or a number. wlh1 is the default. The recognized values are:
    • 0 or none โ€” No multiplier at all. Rough, but valid ๐Ÿ’€
    • 1 or w โ€” 16x16 multiplier, fully pipelined. Enables mpyw and mpyuw.
    • 2 or wlh1 โ€” 32x32 multiplier, fully pipelined (1 stage). On top of that, it enables mpy, mpyu, mpym, mpymu, and mpy_s. This is the default ๐Ÿ‘‘
    • 3 or wlh2 โ€” 32x32 multiplier, fully pipelined (2 stages). Also enables mpy, mpyu, mpym, mpymu, and mpy_s.
    • 4 or wlh3 โ€” Two 16x16 multipliers, blocking, sequential. Also enables mpy, mpyu, mpym, mpymu, and mpy_s.
    • 5 or wlh4 โ€” One 16x16 multiplier, blocking, sequential. Also enables mpy, mpyu, mpym, mpymu, and mpy_s.
    • 6 or wlh5 โ€” One 32x4 multiplier, blocking, sequential. Also enables mpy, mpyu, mpym, mpymu, and mpy_s.
    • 7 or plus_dmpy โ€” ARC HS SIMD support ๐ŸŒˆ
    • 8 or plus_macd โ€” ARC HS SIMD support ๐ŸŒˆ
    • 9 or plus_qmacw โ€” ARC HS SIMD support ๐ŸŒˆ
โš ๏ธ This option is only available for ARCv2 cores.
  • -mfpu=fpu โ€” ๐Ÿฆ‹ Turns on specific floating-point hardware extensions for ARCv2 cores. The supported values for fpu are:
    • fpus โ€” Enables single-precision floating-point hardware extensions.
    • fpud โ€” Enables double-precision floating-point hardware extensions. The single-precision extension comes along for the ride too. Not available for ARC EM.
    • fpuda โ€” Enables double-precision floating-point hardware extensions using double-precision assist instructions. The single-precision extension is enabled as well. Only available for ARC EM.
    • fpuda_div โ€” Enables double-precision floating-point hardware extensions using double-precision assist instructions. The single-precision floating-point, square-root, and divide extensions are enabled too. Only available for ARC EM.
    • fpuda_fma โ€” Enables double-precision floating-point hardware extensions using double-precision assist instructions. The single-precision floating-point and fused multiply and add extensions are enabled too. Only available for ARC EM.
    • fpuda_all โ€” Enables double-precision floating-point hardware extensions using double-precision assist instructions. Every single-precision floating-point hardware extension is enabled too. Only available for ARC EM.
    • fpus_div โ€” Enables single-precision floating-point, square-root, and divide hardware extensions.
    • fpud_div โ€” Enables double-precision floating-point, square-root, and divide hardware extensions. This includes fpus_div. Not available for ARC EM.
    • fpus_fma โ€” Enables single-precision floating-point and fused multiply and add hardware extensions.
    • fpud_fma โ€” Enables double-precision floating-point and fused multiply and add hardware extensions. This includes fpus_fma. Not available for ARC EM.
    • fpus_all โ€” Enables all single-precision floating-point hardware extensions.
    • fpud_all โ€” Enables all single- and double-precision floating-point hardware extensions. Not available for ARC EM.
  • -mirq-ctrl-saved=register-range, blink, lp_count โ€” ๐Ÿ›ก๏ธ Picks the general-purpose registers that the processor automatically saves and restores on interrupt entry and exit. The register-range is written as two registers separated by a dash. The range always starts at r0, and the upper limit is the fp register. blink and lp_count are optional. This option is only valid for ARC EM and ARC HS cores.
  • -mrgf-banked-regs=number โ€” ๐Ÿฆ Sets how many registers get replicated into the second register bank when entering a fast interrupt. Fast interrupts are the ones at 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 permitted values are 4, 8, 16, and 32.
  • -mlpc-width=width โ€” ๐Ÿ”ข Sets the width of the lp_count register. Valid values for width are 8, 16, 20, 24, 28, and 32 bits, and the default is a fixed 32 bits. If the width is less than 32, the compiler won't try to turn loops in your program into the zero-delay loop mechanism unless it knows that 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 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.

  • -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 enabled by default in tool chains built for arc-linux-uclibc and arceb-linux-uclibc targets when profiling is not requested.
  • -marclinux_prof โ€” ๐Ÿ“Š Passed through to the linker to specify use of the arclinux_prof emulation. This is enabled by default in tool chains built for arc-linux-uclibc and arceb-linux-uclibc targets when profiling is requested.

The following options control the semantics of 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, which is the offset available for an unconditional branch-and-link instruction. Conditional execution of function calls is suppressed so the 25-bit range can be used, instead of the 21-bit range you'd get with conditional branch-and-link. This is the default for tool chains built for arc-linux-uclibc and arceb-linux-uclibc targets ๐Ÿ’–

โœจ OPTIONS โœจ

  • -G num ๐Ÿงš โ€” Okay, bestie, this one tells GCC to tuck externally-visible data into a small data section, but only if that data is no bigger than num bytes. The default num is 4 for any ARC config, or 8 when you've got double load/store operations ๐Ÿ’–
  • -mno-sdata ๐ŸŒธ โ€” No sdata references for you! This is the default for toolchains built for arc-linux-uclibc and arceb-linux-uclibc targets ๐Ÿซถ
  • -mvolatile-cache ๐Ÿ’œ โ€” Volatile references get ordinary cached memory accesses. This is the default, so you're already slaying โœจ
  • -mno-volatile-cache ๐Ÿฆ‹ โ€” Turns on cache bypass for volatile references instead ๐Ÿ™ˆ

The following options fine tune code generation ๐Ÿ’…

  • -malign-call โญ โ€” Does alignment optimizations for call instructions ๐ŸŒˆ
  • -mauto-modify-reg ๐Ÿ“ โ€” Lets you use pre/post modify with register displacement ๐Ÿ”ฅ
  • -mbbit-peephole โœจ โ€” Enables bbit peephole2 ๐Ÿ’œ
  • -mno-brcc ๐Ÿ™ˆ โ€” Disables a target-specific pass in arc_reorg that would generate compare-and-branch (brcc) instructions. It doesn't touch the ones the combiner pass makes, though, so those are still on the table ๐Ÿ’…
  • -mcase-vector-pcrel ๐Ÿฆ‹ โ€” Uses PC-relative switch case tables so case table shortening can happen. This is the default for -Os ๐Ÿ‘‘
  • -mcompact-casesi ๐ŸŒธ โ€” Enables the compact casesi pattern. It's the default for -Os, only works on ARCv1 cores, and is deprecated, so, not gonna lie, it's on its way out ๐Ÿ’€
  • -mno-cond-exec ๐ŸŽ€ โ€” Disables the ARCompact-specific pass that generates conditional execution instructions

Okay, the tea on -mno-cond-exec ๐Ÿซ–: the target-independent conditional execution pass is kinda lacking because of delay slot scheduling and the way operand numbers, literal sizes, instruction lengths, and conditional execution all interact. So the ARC port keeps a special pass around that digs for more conditional execution opportunities after register allocation, branch shortening, and delay slot scheduling are done. It usually (not always!) improves performance and code size, but it costs extra compilation time, which is exactly why there's an option to switch it off ๐Ÿ˜ญ If call instructions are blowing past their allowable offset range because they got conditionalized, try -mmedium-calls instead ๐Ÿงš

  • -mearly-cbranchsi ๐Ÿ’– โ€” Enables pre-reload use of the cbranchsi pattern โœจ
  • -mexpand-adddi ๐Ÿฅ€ โ€” Expands adddi3 and subdi3 at RTL generation time into add.f, adc etc. Deprecated, so use it at your own risk ๐Ÿ’€
  • -mindexed-loads โš ๏ธ โ€” Enables indexed loads. Be careful, because some optimizers then assume indexed stores exist, and they don't, so this can get messy ๐Ÿ™ƒ
  • -mlra ๐Ÿงช โ€” Enables Local Register Allocation. It's still experimental for ARC, so by default the compiler uses standard reload (that's -mno-lra) ๐Ÿ”ฌ
  • -mlra-priority-none ๐Ÿซฅ โ€” Doesn't indicate any priority for target registers
  • -mlra-priority-compact ๐ŸŒท โ€” Indicates target register priority for r0..r3 / r12..r15
  • -mlra-priority-noncompact ๐Ÿ‚ โ€” Reduces target register priority for r0..r3 / r12..r15
  • -mmillicode ๐ŸŒ™ โ€” When you're optimizing for size with -Os, prologues and epilogues that have to save or restore a ton of registers often get shortened by calling a special function in libgcc. That's called a millicode call. These calls can cause performance issues, 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 only work on CPUs with the code-density feature ๐Ÿ’…
  • -mmixed-code ๐ŸŒˆ โ€” Tweaks register allocation to help with 16-bit instruction generation. The upside is a smaller average instruction size, the downside is more instructions overall โญ
  • -mq-class ๐Ÿฅฑ โ€” Deprecated. Enables q instruction alternatives, and it's the default for -Os ๐Ÿซ 
  • -mRcq ๐Ÿ’œ โ€” Enables Rcq constraint handling. Most short code generation depends on this, and it's the default ๐Ÿ‘‘
  • -mRcw ๐Ÿฆ‹ โ€” Enables Rcw constraint handling. Most ccfsm condexec depends on this, and it's the default too ๐Ÿ”ฅ
  • -msize-level=level ๐Ÿ“ โ€” Fine-tunes size optimization around instruction lengths and alignment. Here are the recognized values for level:
    • 0 โ€” No size optimization. This level is deprecated and treated like 1 ๐Ÿ’€
    • 1 โ€” Short instructions get used opportunistically โœจ
    • 2 โ€” On top of level 1, alignment of loops and of code after barriers gets dropped ๐Ÿซถ
    • 3 โ€” On top of level 2, optional data alignment gets dropped, and the option Os is enabled ๐Ÿ”ฅ

It defaults to 3 when -Os is in effect. Otherwise, if 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 ๐Ÿงฎ โ€” The cost to assume for a multiply instruction, with 4 being equal to a normal instruction โœจ
  • -munalign-prob-threshold=probability ๐Ÿ“ โ€” Sets the probability threshold for unaligning branches. When you're tuning for ARC700 and optimizing for speed, branches without a filled delay slot are preferably emitted unaligned and long, unless profiling shows the branch is taken with a probability below probability. The default is (REG_BR_PROB_BASE/2), i.e. 5000 ๐Ÿ’–

The following options are maintained for backward compatibility, but are 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 deprecated now. Big-endian code is supported by configuring GCC to build the arceb-elf32 and arceb-linux-uclibc targets, where big endian is the default ๐Ÿ’œ
  • -mlittle-endian, -EL ๐ŸŒŠ โ€” Compiles code for little-endian targets. Using these is deprecated now. Little-endian code is supported by configuring GCC to build the arc-elf32 and arc-linux-uclibc targets, where little endian is the default ๐Ÿ’œ
  • -mbarrel_shifter โ€” Replaced by -mbarrel-shifter ๐Ÿ”
  • -mdpfp_compact โ€” Replaced by -mdpfp-compact ๐Ÿ”
  • -mdpfp_fast โ€” Replaced by -mdpfp-fast ๐Ÿ”
  • -mdsp_packa โ€” Replaced by -mdsp-packa ๐Ÿ”
  • -mEA โ€” Replaced by -mea ๐Ÿ”
  • -mmac_24 โ€” Replaced by -mmac-24 ๐Ÿ”
  • -mmac_d16 โ€” Replaced by -mmac-d16 ๐Ÿ”
  • -mspfp_compact โ€” Replaced by -mspfp-compact ๐Ÿ”
  • -mspfp_fast โ€” Replaced by -mspfp-fast ๐Ÿ”
  • -mtune=cpu โ€” The values arc600, arc601, arc700 and arc700-xmac for cpu are replaced by ARC600, ARC601, ARC700 and ARC700-xmac respectively ๐Ÿ”
  • -multcost=num โ€” Replaced by -mmultcost ๐Ÿ”

โœจ ARM Options โœจ

These -m options are defined for the ARM port ๐Ÿฆพ

  • -mabi=name ๐Ÿ‘‘ โ€” Generates code for the specified ABI. The permissible values are apcs-gnu, atpcs, aapcs, aapcs-linux and iwmmxt ๐Ÿ’…
  • -mapcs-frame ๐Ÿงฑ โ€” Generates a stack frame that complies with the ARM Procedure Call Standard for all functions, even when it isn't strictly needed for the code to run correctly. Pairing it with -fomit-frame-pointer means stack frames don't get generated for leaf functions. The default is -mno-apcs-frame, and this option is deprecated ๐Ÿฅ€
  • -mapcs ๐Ÿฅ€ โ€” A synonym for -mapcs-frame. It's deprecated too ๐Ÿ’€
  • -mthumb-interwork ๐Ÿ”€ โ€” Generates code that supports calling between the ARM and Thumb instruction sets. Without it, on pre-v5 architectures, the two instruction sets can't be reliably used inside one program. The default is -mno-thumb-interwork, since turning this on generates slightly larger code. In AAPCS configurations this option is meaningless ๐Ÿ™ƒ
  • -mno-sched-prolog ๐Ÿงญ โ€” Stops instructions in the function prologue from getting reordered, or merged with instructions in the function's body. That means every function starts with a recognizable set of instructions (or one of a small set of different function prologues), so you can use that info to find where functions start inside an executable piece of 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 โ€” GCC generates output with library calls for floating-point operations ๐Ÿ“š
    • softfp โ€” Lets you generate code with hardware floating-point instructions, but still uses the soft-float calling conventions ๐Ÿงฉ
    • hard โ€” Generates floating-point instructions and uses FPU-specific calling conventions โšก

The default depends on your specific target configuration.

Heads up, 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 with a compatible set of libraries, or things will get messy fr fr.
  • -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 compiling for a little-endian processor ๐Ÿ’™
  • -mbe8, -mbe32 ๐Ÿงฌ โ€” When you're linking a big-endian image, these pick between the BE8 and BE32 formats. They have no effect on little-endian images and get ignored there. The default depends on the selected target architecture: for ARMv6 and later it's BE8, and for older architectures it's BE32. ARM has deprecated the BE32 format ๐Ÿฅฒ
  • -march=name[+extension...] ๐Ÿ›๏ธ โ€” Specifies the name of the target ARM architecture. GCC uses this name to figure out what kinds of instructions it's allowed to emit when generating assembly code. You can use this option together with -mcpu= or instead of it โœจ

Okay so 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, armv7-r, armv8-r, armv6-m, armv6s-m, armv7-m, armv7e-m, armv8-m.base, armv8-m.main, armv8.1-m.main, iwmmxt and iwmmxt2. ๐ŸŽ€โœจ

Additionally, the following architectures, which lack support for the Thumb execution state, are recognized but support is deprecated: armv4.

๐Ÿ’€ Heads up, bestie: armv4 is still accepted, but it's deprecated, so don't build your whole life around it. ๐Ÿฅ€

Many of the architectures support extensions ๐Ÿ’– These can be added by appending +extension to the architecture name. Extension options are processed in order and capabilities accumulate, so they stack up like a good outfit ๐Ÿ‘— An extension will also enable any necessary base extensions upon which it depends. For example, the +crypto extension will always enable the +simd extension. The exception to the additive construction is for extensions that are prefixed with +no...: these extensions disable the specified option and any other extensions that may depend on the presence of that extension. Main character energy, but make it a kill switch ๐Ÿ’…

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. ๐Ÿ˜ญ The +nofp basically erases +simd before it even gets a chance to show up.

Most extension names are generically named, but their effect depends on the architecture they're applied to. For example, the +simd option can be applied to both armv7-a and armv8-a architectures, but it will enable the original ARMv7-A Advanced SIMD (Neon) extensions for armv7-a and the ARMv8-A variant for armv8-a. Same name, different glow-up โœจ

The list below shows the supported extensions for each architecture. Architectures not mentioned do not support any extensions. ๐ŸŒธ

armv5te, armv6, armv6j, armv6k, armv6kz, armv6t2, armv6z, armv6zk ๐Ÿฆ‹

  • +fp โ€” The VFPv2 floating-point instructions. The extension +vfpv2 can be used as an alias for this extension.
  • +nofp โ€” Disable the floating-point instructions. ๐Ÿ™…โ€โ™€๏ธ

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. The extension +vfpv3-d16 can be used as an alias for this extension. Note that floating-point is not supported by the base ARMv7-M architecture, but is compatible with both the ARMv7-A and ARMv7-R architectures. ๐Ÿ™ˆ
  • +nofp โ€” Disable the floating-point instructions.

armv7-a ๐Ÿ‘‘

  • +mp โ€” The multiprocessing extension. ๐Ÿงš
  • +sec โ€” The security extension. ๐Ÿ”’
  • +fp โ€” The VFPv3 floating-point instructions, with 16 double-precision registers. The extension +vfpv3-d16 can be used as an alias for this extension.
  • +simd โ€” The Advanced SIMD (Neon) v1 and the VFPv3 floating-point instructions. The extensions +neon and +neon-vfpv3 can be used as aliases for this extension.
  • +vfpv3 โ€” The VFPv3 floating-point instructions, with 32 double-precision registers.
  • +vfpv3-d16-fp16 โ€” The VFPv3 floating-point instructions, with 16 double-precision registers and the half-precision floating-point conversion operations.
  • +vfpv3-fp16 โ€” The VFPv3 floating-point instructions, with 32 double-precision registers and the half-precision floating-point conversion operations.
  • +vfpv4-d16 โ€” The VFPv4 floating-point instructions, with 16 double-precision registers.
  • +vfpv4 โ€” The VFPv4 floating-point instructions, with 32 double-precision registers.
  • +neon-fp16 โ€” The Advanced SIMD (Neon) v1 and the VFPv3 floating-point instructions, with the half-precision floating-point conversion operations.
  • +neon-vfpv4 โ€” The Advanced SIMD (Neon) v2 and the VFPv4 floating-point instructions.
  • +nosimd โ€” Disable the Advanced SIMD instructions (does not disable floating point).
  • +nofp โ€” Disable the floating-point and Advanced SIMD instructions. ๐Ÿ’”

armv7ve ๐Ÿ’œ

The extended version of the ARMv7-A architecture with support for virtualization. Very sus-in-a-good-way energy ๐Ÿ˜Œ

  • +fp โ€” The VFPv4 floating-point instructions, with 16 double-precision registers. The extension +vfpv4-d16 can be used as an alias for this extension.
  • +simd โ€” The Advanced SIMD (Neon) v2 and the VFPv4 floating-point instructions. The extension +neon-vfpv4 can be used as an alias for this extension.
  • +vfpv3-d16 โ€” The VFPv3 floating-point instructions, with 16 double-precision registers.
  • +vfpv3 โ€” The VFPv3 floating-point instructions, with 32 double-precision registers.
  • +vfpv3-d16-fp16 โ€” The VFPv3 floating-point instructions, with 16 double-precision registers and the half-precision floating-point conversion operations.
  • +vfpv3-fp16 โ€” The VFPv3 floating-point instructions, with 32 double-precision registers and the half-precision floating-point conversion operations.
  • +vfpv4-d16 โ€” The VFPv4 floating-point instructions, with 16 double-precision registers.
  • +vfpv4 โ€” The VFPv4 floating-point instructions, with 32 double-precision registers.
  • +neon โ€” The Advanced SIMD (Neon) v1 and the VFPv3 floating-point instructions. The extension +neon-vfpv3 can be used as an alias for this extension.
  • +neon-fp16 โ€” The Advanced SIMD (Neon) v1 and the VFPv3 floating-point instructions, with the half-precision floating-point conversion operations.
  • +nosimd โ€” Disable the Advanced SIMD instructions (does not disable floating point).
  • +nofp โ€” Disable the floating-point and Advanced SIMD instructions.

armv8-a โœจ

  • +crc โ€” The Cyclic Redundancy Check (CRC) instructions. ๐Ÿงผ
  • +simd โ€” The ARMv8-A Advanced SIMD and floating-point instructions.
  • +crypto โ€” The cryptographic instructions. ๐Ÿ”
  • +nocrypto โ€” Disable the cryptographic instructions.
  • +nofp โ€” Disable the floating-point, Advanced SIMD and cryptographic instructions.
  • +sb โ€” Speculation Barrier Instruction.
  • +predres โ€” Execution and Data Prediction Restriction Instructions.

armv8.1-a ๐Ÿ“

  • +simd โ€” The ARMv8.1-A Advanced SIMD and floating-point instructions.
  • +crypto โ€” The cryptographic instructions. This also enables the Advanced SIMD and floating-point instructions.
  • +nocrypto โ€” Disable the cryptographic instructions.
  • +nofp โ€” Disable the floating-point, Advanced SIMD and cryptographic instructions.
  • +sb โ€” Speculation Barrier Instruction.
  • +predres โ€” Execution and Data Prediction Restriction Instructions.

armv8.2-a, armv8.3-a ๐Ÿš€

  • +fp16 โ€” The half-precision floating-point data processing instructions. This also enables the Advanced SIMD and floating-point instructions.
  • +fp16fml โ€” The half-precision floating-point fmla extension. This also enables the half-precision floating-point extension and Advanced SIMD and floating-point instructions.
  • +simd โ€” The ARMv8.1-A Advanced SIMD and floating-point instructions.
  • +crypto โ€” The cryptographic instructions. This also enables the Advanced SIMD and floating-point instructions.
  • +dotprod โ€” Enable the Dot Product extension. This also enables Advanced SIMD instructions.
  • +nocrypto โ€” Disable the cryptographic extension.
  • +nofp โ€” Disable the floating-point, Advanced SIMD and cryptographic instructions.
  • +sb โ€” Speculation Barrier Instruction.
  • +predres โ€” Execution and Data Prediction Restriction Instructions.
  • +i8mm โ€” 8-bit Integer Matrix Multiply instructions. This also enables Advanced SIMD and floating-point instructions.
  • +bf16 โ€” Brain half-precision floating-point instructions. This also enables Advanced SIMD and floating-point instructions.

armv8.4-a ๐Ÿฆ„

  • +fp16 โ€” The half-precision floating-point data processing instructions. This also enables the Advanced SIMD and floating-point instructions as well as the Dot Product extension and the half-precision floating-point fmla extension.
  • +simd โ€” The ARMv8.3-A Advanced SIMD and floating-point instructions as well as the Dot Product extension.
  • +crypto โ€” The cryptographic instructions. This also enables the Advanced SIMD and floating-point instructions as well as the Dot Product extension.
  • +nocrypto โ€” Disable the cryptographic extension.
  • +nofp โ€” Disable the floating-point, Advanced SIMD and cryptographic instructions.
  • +sb โ€” Speculation Barrier Instruction.
  • +predres โ€” Execution and Data Prediction Restriction Instructions.
  • +i8mm โ€” 8-bit Integer Matrix Multiply instructions. This also enables Advanced SIMD and floating-point instructions.
  • +bf16 โ€” Brain half-precision floating-point instructions. This also enables Advanced SIMD and floating-point instructions.

armv8.5-a ๐ŸŒŸ

  • +fp16 โ€” The half-precision floating-point data processing instructions. This also enables the Advanced SIMD and floating-point instructions as well as the Dot Product extension and the half-precision floating-point fmla extension.
  • +simd โ€” okay so this one switches on the ARMv8.3-A Advanced SIMD and floating-point instructions, plus the Dot Product extension. ๐ŸŽ€โœจ
  • +crypto โ€” the cryptographic instructions ๐Ÿ”. This also turns on the Advanced SIMD and floating-point instructions, and the Dot Product extension. Iconic multitasking ๐Ÿ’…
  • +nocrypto โ€” disables the cryptographic extension. Bye bye, crypto ๐Ÿ‘‹
  • +nofp โ€” disables the floating-point, Advanced SIMD and cryptographic instructions all at once. Major drama, use with care ๐Ÿ’€
  • +i8mm โ€” 8-bit Integer Matrix Multiply instructions ๐Ÿงฎ. It also enables Advanced SIMD and floating-point instructions, so you get the whole squad ๐Ÿซถ
  • +bf16 โ€” 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, the Dot Product extension, and the half-precision floating-point fmla extension. Main character energy, no cap โญ
  • +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 as well as the Dot Product extension ๐Ÿ’œ
  • +nocrypto โ€” disables the cryptographic extension ๐Ÿ™ˆ
  • +nofp โ€” disables the floating-point, Advanced SIMD and cryptographic instructions. It's giving a full reset ๐Ÿงน
  • +i8mm โ€” 8-bit Integer Matrix Multiply instructions ๐Ÿงฎ. Also enables Advanced SIMD and floating-point instructions ๐Ÿ“
  • +bf16 โ€” Brain half-precision floating-point instructions ๐Ÿง . Also enables Advanced SIMD and floating-point instructions ๐Ÿฆ‹

๐ŸŒˆ armv7-r

  • +fp.sp โ€” the single-precision VFPv3 floating-point instructions ๐ŸŽ€. You can also use +vfpv3xd as an alias for this extension, so pick your fave ๐Ÿ’–
  • +fp โ€” the VFPv3 floating-point instructions with 16 double-precision registers โœจ. You can use +vfpv3-d16 as an alias for this one too ๐Ÿงš
  • +vfpv3xd-d16-fp16 โ€” the single-precision VFPv3 floating-point instructions with 16 double-precision registers, plus the half-precision floating-point conversion operations ๐ŸŒธ
  • +vfpv3-d16-fp16 โ€” the VFPv3 floating-point instructions with 16 double-precision registers, plus the half-precision floating-point conversion operations ๐Ÿ”ฅ
  • +nofp โ€” disables the floating-point extension ๐Ÿ™…โ€โ™€๏ธ
  • +idiv โ€” the ARM-state integer division instructions โž—
  • +noidiv โ€” disables the ARM-state integer division extension ๐Ÿ’…

๐Ÿ“ armv7e-m

  • +fp โ€” the single-precision VFPv4 floating-point instructions โญ
  • +fpv5 โ€” the single-precision FPv5 floating-point instructions ๐Ÿ”ฅ
  • +fp.dp โ€” the single- and double-precision FPv5 floating-point instructions ๐Ÿ‘‘
  • +nofp โ€” disables the floating-point extensions ๐Ÿซถ

๐Ÿ’œ armv8.1-m.main

  • +dsp โ€” the DSP instructions ๐ŸŽถ
  • +mve โ€” the M-Profile Vector Extension (MVE) integer instructions ๐Ÿฆ‹
  • +mve.fp โ€” the M-Profile Vector Extension (MVE) integer instructions and the 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 โ€” these turn on the Custom Datapath Extension (CDE) on selected coprocessors ๐Ÿงฉ. Which coprocessors you get depends on the numbers you give in the options, and those numbers have to be 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 ๐Ÿงฉ. The numbers in the options, from 0 to 7, decide which coprocessors get it ๐Ÿ”ข

๐Ÿงš armv8-r

  • +crc โ€” the Cyclic Redundancy Check (CRC) instructions ๐Ÿ”
  • +fp.sp โ€” the single-precision FPv5 floating-point instructions ๐ŸŒท
  • +simd โ€” the ARMv8-A Advanced SIMD and floating-point instructions ๐Ÿ’–
  • +crypto โ€” the cryptographic instructions ๐Ÿ”
  • +nocrypto โ€” disables the cryptographic instructions ๐Ÿ™ˆ
  • +nofp โ€” disables the floating-point, Advanced SIMD and cryptographic instructions ๐Ÿงน

-march=native tells the compiler to auto-detect the architecture of the build computer ๐Ÿ•ต๏ธโ€โ™€๏ธ. Lowkey this only works on GNU/Linux right now, and not every architecture gets recognized ๐Ÿ˜ญ. If the auto-detect doesn't work out, the option just has no effect ๐Ÿซ .

๐ŸŽ€ -mtune=name

This option picks the name of the target ARM processor that GCC should tune the performance of your code for ๐ŸŽฏ. Some ARM implementations can run better when you use this option, so it's worth a look ๐Ÿ’…. These are the permissible names:

arm7tdmi, arm7tdmi-s, arm710t, arm720t, arm740t, strongarm, strongarm110,
strongarm1100, 0strongarm1110, arm8, arm810, arm9, arm9e, arm920, arm920t,
arm922t, arm946e-s, arm966e-s, arm968e-s, arm926ej-s, arm940t, arm9tdmi,
arm10tdmi, arm1020t, arm1026ej-s, arm10e, arm1020e, arm1022e, arm1136j-s,
arm1136jf-s, mpcore, mpcorenovfp, arm1156t2-s, arm1156t2f-s, arm1176jz-s,
arm1176jzf-s, generic-armv7-a, cortex-a5, cortex-a7, cortex-a8, cortex-a9,
cortex-a12, cortex-a15, cortex-a17, cortex-a32, cortex-a35, cortex-a53,
cortex-a55, cortex-a57, cortex-a72, cortex-a73, cortex-a75, cortex-a76,
cortex-a76ae, cortex-a77, cortex-a78, cortex-a78ae, cortex-a78c, ares,
cortex-r4, cortex-r4f, cortex-r5, cortex-r7, cortex-r8, cortex-r52, cortex-m0,
cortex-m0plus, cortex-m1, cortex-m3, cortex-m4, cortex-m7, cortex-m23,
cortex-m33, cortex-m35p, cortex-m55, cortex-x1, cortex-m1.small-multiply,
cortex-m0.small-multiply, cortex-m0plus.small-multiply, exynos-m1, marvell-pj4,
neoverse-n1, neoverse-n2, neoverse-v1, xscale, iwmmxt, iwmmxt2, ep9312, fa526,
fa626, fa606te, fa626te, fmp626, fa726te, xgene1

Also, this option can tell GCC to tune your code for a big.LITTLE system ๐Ÿง ๐Ÿ’ž. These are the permissible names for that:

cortex-a15.cortex-a7, cortex-a17.cortex-a7, cortex-a57.cortex-a53,
cortex-a72.cortex-a53, cortex-a72.cortex-a35, cortex-a73.cortex-a53,
cortex-a75.cortex-a55, cortex-a76.cortex-a55

-mtune=generic-arch tells GCC to tune the performance for a blend of processors within the architecture arch ๐ŸŒˆ. The goal is code that runs well on the most popular processors right now, balancing the optimizations that help some CPUs in the range while avoiding the performance pitfalls of others ๐Ÿซถ. The effects of this option may change in future GCC versions, since CPU models come and go ๐Ÿฆ‹.

-mtune accepts the same extension options as -mcpu, but the extension options don't change how the generated code gets tuned ๐Ÿ™ƒ.

-mtune=native tells the compiler to auto-detect the CPU of the build computer ๐Ÿ”. Same deal as before: this is only supported on GNU/Linux for now, and not all architectures are recognized ๐Ÿ˜ฌ. If the auto-detect doesn't work, the option has no effect ๐Ÿ’ค.

๐Ÿ‘‘ -mcpu=name[+extension...]

This picks the name of the target ARM processor ๐Ÿ‘ธ. GCC uses that name to figure out the target ARM architecture (as if you'd set it with -march) and the ARM processor type to tune for performance (as if you'd set it with -mtune) ๐Ÿ’…. If you use -march or -mtune together with this option, those two win for their own part of the job ๐Ÿฅ‡.

Lots of the supported CPUs have optional architectural extensions ๐Ÿงฉ. When they do, those extensions are usually turned on by default. But if there are implementations that lack an extension, you can use the extension syntax to turn off the ones that are missing ๐Ÿ™…โ€โ™€๏ธ.

For floating-point and Advanced SIMD (Neon) instructions, you also have to think about -mfloat-abi and -mfpu ๐Ÿง. Floating-point and Advanced SIMD instructions only get used if -mfloat-abi isn't set to soft. And any -mfpu setting other than auto overrides the floating-point and SIMD extension instructions that would otherwise be available ๐Ÿšจ.

For example, cortex-a9 shows up in three major 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 the 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 and cortex-m7 ๐ŸŒท
  • +nosimd โ€” disables the SIMD instructions (but keeps the floating-point ones) on generic-armv7-a, cortex-a5, cortex-a7 and cortex-a9 ๐Ÿง
  • +crypto โ€” okay bestie, this one switches on the cryptographic instructions ๐Ÿ”โœจ for 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. Iconic ๐Ÿ’…

Okay so the generic-armv7-a pseudo target is giving main character energy ๐Ÿ‘‘ by defaulting to VFPv3 with 16 double-precision registers. It accepts these extension options: mp, sec, vfpv3-d16, vfpv3, vfpv3-d16-fp16, vfpv3-fp16, vfpv4-d16, vfpv4, neon, neon-vfpv3, neon-fp16 and neon-vfpv4. Their meanings are the same as the extensions for -march=armv7-a, no cap ๐Ÿซถ

-mcpu=generic-arch is also allowed, and it's the same as -march=arch -mtune=generic-arch. Check -mtune for the full tea ๐Ÿ“

-mcpu=native tells the compiler to auto-detect the CPU of the build computer ๐Ÿงš Lowkey this only works on GNU/Linux right now, and not every architecture gets recognized. If the auto-detect doesn't work out, the option just does nothing ๐Ÿฅฒ

  • -mfpu=name โ€” this one describes what floating-point hardware (or hardware emulation) the target has ๐ŸŒˆ 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. Also, neon is just an alias for neon-vfpv3, and vfp is an alias for vfpv2 โœจ

auto is the default and it's kinda special ๐Ÿฆ‹ It makes the compiler pick the floating-point and Advanced SIMD instructions based on the settings of -mcpu and -march.

If the hardware you picked includes the NEON extension (like -mfpu=neon), heads up: floating-point operations won't be generated by GCC's auto-vectorization pass unless -funsafe-math-optimizations is also specified ๐Ÿ™ˆ This is because NEON hardware doesn't fully implement the IEEE 754 standard for floating-point arithmetic (denormal values get treated as zero, specifically), so using NEON instructions might lead to a loss of precision ๐Ÿ’€

You can also set the fpu name at function level with the target("fpu=") function attributes or pragmas ๐ŸŽ€

  • -mfp16-format=name โ€” pick the format of the "__fp16" half-precision floating-point type ๐Ÿ’– The permissible names are none, ieee and alternative. The default is none, and in that case the "__fp16" type isn't defined at all ๐Ÿ˜ญ
  • -mstructure-size-boundary=n โ€” this rounds up the sizes of all structures and unions to a multiple of the number of bits you set here ๐Ÿ“ The permissible values are 8, 32 and 64. The default varies between toolchains, but for the COFF targeted toolchain it's 8. A value of 64 is only allowed if the underlying ABI supports it.

Going bigger can make faster, more efficient code, but it can also make your program bigger ๐Ÿง Different values are potentially incompatible. Code compiled with one value can't necessarily work with code or libraries compiled with another value, if they swap info using structures or unions.

โš ๏ธ This option is deprecated. Bestie, don't build your whole life around it ๐Ÿ’€
  • -mabort-on-noreturn โ€” generates a call to the function "abort" at the end of a "noreturn" function ๐ŸŒธ It runs if the function tries to return.
  • -mlong-calls, -mno-long-calls โ€” this tells the compiler to do function calls by loading the function's address into a register first, and then making a subroutine call on that register ๐Ÿฆ‹ You need this switch if the target function lives outside the 64-megabyte addressing range of the offset-based version of the subroutine call instruction.

Even with this switch on, not every function call becomes a long call ๐Ÿ˜Œ The heuristic is that static functions, functions with the "short_call" attribute, functions inside the scope of a #pragma no_long_calls directive, and functions whose definitions were already compiled within the current compilation unit don't get turned into long calls. The exceptions are that weak function definitions, functions with the "long_call" attribute or the "section" attribute, and functions inside the scope of a #pragma long_calls directive always get turned into long calls.

This feature isn't enabled by default ๐Ÿ™…โ€โ™€๏ธ Specifying -mno-long-calls restores the default behavior, and so does putting the function calls inside the scope of a #pragma long_calls_off directive. Also, these switches have no effect on how the compiler generates code for function calls made via function pointers ๐Ÿ’…

  • -msingle-pic-base โ€” treats the register used for PIC addressing as read-only, instead of loading it in the prologue for each function ๐Ÿงš The runtime system is responsible for setting this register to an appropriate value before execution begins.
  • -mpic-register=reg โ€” specifies the register to use for PIC addressing โœจ For the standard PIC base case, the default is any suitable register the compiler decides on. For the single PIC base case, the default is R9 if the target is EABI based or stack-checking is enabled. Otherwise the default is R10.
  • -mpic-data-is-text-relative โ€” assumes the displacement between the text and data segments is fixed at static link time ๐ŸŒˆ This permits using PC-relative addressing operations to access data known to be in the data segment. For non-VxWorks RTP targets this option is enabled by default. When it's disabled on those targets, it'll enable -msingle-pic-base by default.
  • -mpoke-function-name โ€” writes the name of each function into the text section, right before the function prologue ๐Ÿ”ฅ The generated code is kinda like this:
                        t0
                            .ascii "arm_poke_function_name", 0
                            .align
                        t1
                            .word 0xff000000 + (t1 - t0)
                        arm_poke_function_name
                            mov     ip, sp
                            stmfd   sp!, {fp, ip, lr, pc}
                            sub     fp, ip, #4

When you do a stack backtrace, code can inspect the value of "pc" stored at fp + 0. If the trace function then looks at location pc - 12 and the top 8 bits are set, then we know there's a function name embedded right before this location, with a length of ((pc[-3]) & 0xff000000) ๐Ÿ”โœจ

  • -mthumb, -marm โ€” picks between generating code that runs in ARM state and code that runs in Thumb state ๐Ÿ’œ Most configurations default to ARM state, but that default can be changed by configuring GCC with the --with-mode=state configure option.

You can also override ARM and Thumb mode for each function with the target("thumb") and target("arm") function attributes or pragmas ๐Ÿฆ‹

  • -mflip-thumb โ€” switches ARM/Thumb modes on alternating functions ๐Ÿ™ˆ This one is only here for regression testing of mixed Thumb/ARM code generation, so it's not meant for ordinary code compiling. Please don't use it for your everyday stuff, bestie ๐Ÿ˜ญ
  • -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 header switches to Thumb mode before the rest of the function runs. This lets these functions get called from non-interworking code. This option isn't valid in AAPCS configurations, because interworking is already enabled by default there ๐Ÿ’€
  • -mcaller-super-interworking โ€” lets calls via function pointers (including virtual functions) run correctly, no matter whether the target code was compiled for interworking or not ๐Ÿ’– There's a small overhead in the cost of executing a function pointer if you turn this on. Also not valid in AAPCS configurations, since interworking is enabled by default there too ๐Ÿซถ
  • -mtp=name โ€” specifies the access model for the thread local storage pointer ๐ŸŒˆ The valid models are soft, which generates calls to "__aeabi_read_tp"; cp15, which fetches the thread pointer from "cp15" directly (supported in the arm6k architecture); and auto, which uses the best available method for the selected processor. The default setting is auto โœจ
  • -mtls-dialect=dialect โ€” specifies the dialect to use for accessing thread local storage ๐Ÿ‘‘ Two dialects are supported, gnu and gnu2. The gnu dialect selects the original GNU scheme for supporting local and global dynamic TLS models. The gnu2 dialect selects the GNU descriptor scheme, which gives better performance for shared libraries ๐Ÿ”ฅ The GNU descriptor scheme is compatible with the original scheme, but it does require new assembler, linker and library support. Initial and local exec TLS models 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.
  • -munaligned-access, -mno-unaligned-access โ€” enables (or disables) reading and writing of 16- and 32-bit values from addresses that aren't 16- or 32-bit aligned ๐Ÿง By default, unaligned access is disabled for all pre-ARMv6, all ARMv6-M and for ARMv8-M Baseline architectures, and enabled for all other architectures. If unaligned access isn't enabled, then words in packed data structures get accessed one byte at a time ๐Ÿฅน

The ARM attribute Tag_CPU_unaligned_access ๐Ÿฆ‹ gets set in the generated object file to either true or false, depending on how this option is set. If unaligned access is turned on, the preprocessor symbol __ARM_FEATURE_UNALIGNED gets defined too โœจ. It's giving "tell the other tools what I'm up to" energy ๐Ÿ’….

  • -mneon-for-64bits โ€” ๐Ÿ™ˆ This one is deprecated and literally does nothing, bestie. Zero effect. ๐Ÿ’€
  • -mslow-flash-data โ€” ๐Ÿงš Assumes that loading data from flash is slower than fetching instructions, so it keeps literal loads to a minimum for better performance. This is only supported when compiling for ARMv7 M-profile, it's off by default, and it conflicts with -mword-relocations ๐Ÿ’”.
  • -masm-syntax-unified โ€” ๐ŸŒธ Assumes that inline assembler uses unified asm syntax. The default is currently off, which means divided syntax. This option has no impact on Thumb2, but it may change in future releases of GCC ๐Ÿ‘€. > Divided syntax should be considered deprecated, so maybe start thinking about moving on ๐Ÿ’….
  • -mrestrict-it โ€” ๐Ÿ’– Restricts IT block generation so it follows the rules of ARMv8-A. IT blocks can only contain a single 16-bit instruction from a select set of instructions. This is on by default for ARMv8-A Thumb mode โœจ.
  • -mprint-tune-info โ€” ๐Ÿ” Prints CPU tuning information as a comment in the assembler file. This is only used for regression testing of the compiler and is not meant for ordinary code compiling ๐Ÿ™…โ€โ™€๏ธ. It's disabled by default.
  • -mverbose-cost-dump โ€” ๐Ÿ“ Enables verbose cost model dumping in the debug dump files. This is provided for debugging the compiler ๐Ÿ› ๏ธ.
  • -mpure-code โ€” ๐Ÿ”’ Doesn't allow constant data to be placed in code sections. Also, when compiling for ELF object format, it gives all text sections the ELF processor-specific section attribute SHF_ARM_PURECODE. This is only available when generating non-pic code for M-profile targets ๐Ÿ’œ.
  • -mcmse โ€” ๐Ÿ›ก๏ธ Generates secure code following the "ARMv8-M Security Extensions: Requirements on Development Tools Engineering Specification", which you can find at <https://developer.arm.com/documentation/ecm0359818/latest/> ๐ŸŒˆ.
  • -mfix-cmse-cve-2021-35465 โ€” ๐Ÿšจ Mitigates a potential security issue with the "VLLDM" instruction on some M-profile devices when using CMSE (CVE-2021-365465). This is enabled by default when -mcpu= is used with "cortex-m33", "cortex-m35p" or "cortex-m55". To turn the mitigation off, use -mno-fix-cmse-cve-2021-35465 ๐Ÿซถ.
  • -mfdpic, -mno-fdpic โ€” ๐Ÿฆ‹ Selects the FDPIC ABI, which uses 64-bit function descriptors to represent pointers to functions. When the compiler is configured for "arm-*-uclinuxfdpiceabi" targets, this is on by default and implies -fPIE if none of the PIC/PIE-related options are given. On other targets, it only turns on the FDPIC-specific code generation features, so you should explicitly provide the PIC/PIE-related options as needed ๐Ÿง .

Static linking is not supported, because it would still involve the dynamic linker when the program self-relocates. If that behavior is acceptable to you, use -static and -Wl,-dynamic-linker options ๐Ÿ™ˆ.

The opposite -mno-fdpic option is useful (and required) for building the Linux kernel with the same ("arm-*-uclinuxfdpiceabi") toolchain you used for your userland programs ๐Ÿ‘‘.


โœจ AVR Options โœจ

Here's the AVR squad ๐Ÿงš. These options are defined for AVR implementations:

  • -mmcu=mcu โ€” ๐Ÿ”ง Specifies the Atmel AVR instruction set architecture (ISA) or MCU type.
    • The default for this option is avr2 ๐Ÿ’–.
    • GCC supports the following AVR devices and ISAs ๐Ÿ‘‡:
      • "avr2" โ€” "Classic" devices with up to 8 KiB of program memory. mcu = "attiny22", "attiny26", "at90s2313", "at90s2323", "at90s2333", "at90s2343", "at90s4414", "at90s4433", "at90s4434", "at90c8534", "at90s8515", "at90s8535"
      • "avr25" โ€” "Classic" devices with up to 8 KiB of program memory and with the "MOVW" instruction. mcu = "attiny13", "attiny13a", "attiny24", "attiny24a", "attiny25", "attiny261", "attiny261a", "attiny2313", "attiny2313a", "attiny43u", "attiny44", "attiny44a", "attiny45", "attiny48", "attiny441", "attiny461", "attiny461a", "attiny4313", "attiny84", "attiny84a", "attiny85", "attiny87", "attiny88", "attiny828", "attiny841", "attiny861", "attiny861a", "ata5272", "ata6616c", "at86rf401"
      • "avr3" โ€” "Classic" devices with 16 KiB up to 64 KiB of program memory. mcu = "at76c711", "at43usb355"
      • "avr31" โ€” "Classic" devices with 128 KiB of program memory. mcu = "atmega103", "at43usb320"
      • "avr35" โ€” "Classic" devices with 16 KiB up to 64 KiB of program memory and with the "MOVW" instruction. mcu = "attiny167", "attiny1634", "atmega8u2", "atmega16u2", "atmega32u2", "ata5505", "ata6617c", "ata664251", "at90usb82", "at90usb162"
      • "avr4" โ€” "Enhanced" devices with up to 8 KiB of program memory. mcu = "atmega48", "atmega48a", "atmega48p", "atmega48pa", "atmega48pb", "atmega8", "atmega8a", "atmega8hva", "atmega88", "atmega88a", "atmega88p", "atmega88pa", "atmega88pb", "atmega8515", "atmega8535", "ata6285", "ata6286", "ata6289", "ata6612c", "at90pwm1", "at90pwm2", "at90pwm2b", "at90pwm3", "at90pwm3b", "at90pwm81"
      • "avr5" โ€” "Enhanced" devices with 16 KiB up to 64 KiB of program memory. mcu = "atmega16", "atmega16a", "atmega16hva", "atmega16hva2", "atmega16hvb", "atmega16hvbrevb", "atmega16m1", "atmega16u4", "atmega161", "atmega162", "atmega163", "atmega164a", "atmega164p", "atmega164pa", "atmega165", "atmega165a", "atmega165p", "atmega165pa", "atmega168", "atmega168a", "atmega168p", "atmega168pa", "atmega168pb", "atmega169", "atmega169a", "atmega169p", "atmega169pa", "atmega32", "atmega32a", "atmega32c1", "atmega32hvb", "atmega32hvbrevb", "atmega32m1", "atmega32u4", "atmega32u6", "atmega323", "atmega324a", "atmega324p", "atmega324pa", "atmega325", "atmega325a", "atmega325p", "atmega325pa", "atmega328", "atmega328p", "atmega328pb", "atmega329", "atmega329a", "atmega329p", "atmega329pa", "atmega3250", "atmega3250a", "atmega3250p", "atmega3250pa", "atmega3290", "atmega3290a", "atmega3290p", "atmega3290pa", "atmega406", "atmega64", "atmega64a", "atmega64c1", "atmega64hve", "atmega64hve2", "atmega64m1", "atmega64rfr2", "atmega640", "atmega644", "atmega644a", "atmega644p", "atmega644pa", "atmega644rfr2", "atmega645", "atmega645a", "atmega645p", "atmega649", "atmega649a", "atmega649p", "atmega6450", "atmega6450a", "atmega6450p", "atmega6490", "atmega6490a", "atmega6490p", "ata5795", "ata5790", "ata5790n", "ata5791", "ata6613c", "ata6614q", "ata5782", "ata5831", "ata8210", "ata8510", "ata5702m322", "at90pwm161", "at90pwm216", "at90pwm316", "at90can32", "at90can64", "at90scr100", "at90usb646", "at90usb647", "at94k", "m3000"
      • "avr51" โ€” "Enhanced" devices with 128 KiB of program memory. mcu = "atmega128", "atmega128a", "atmega128rfa1", "atmega128rfr2", "atmega1280", "atmega1281", "atmega1284", "atmega1284p", "atmega1284rfr2", "at90can128", "at90usb1286", "at90usb1287"
      • "avr6" โ€” "Enhanced" devices with 3-byte PC, i.e. with more than 128 KiB of program memory. mcu = "atmega256rfr2", "atmega2560", "atmega2561", "atmega2564rfr2"
      • "avrxmega2" โ€” "XMEGA" devices with more than 8 KiB and up to 64 KiB of program memory. mcu = "atxmega8e5", "atxmega16a4", "atxmega16a4u", "atxmega16c4", "atxmega16d4", "atxmega16e5", "atxmega32a4", "atxmega32a4u", "atxmega32c3", "atxmega32c4", "atxmega32d3", "atxmega32d4", "atxmega32e5"
      • "avrxmega3" โ€” "XMEGA" devices with up to 64 KiB of combined program memory and RAM, and with program memory visible in the RAM address space. mcu = "attiny202", "attiny204", "attiny212", "attiny214", "attiny402", "attiny404", "attiny406", "attiny412", "attiny414", "attiny416", "attiny417", "attiny804", "attiny806", "attiny807", "attiny814", "attiny816", "attiny817", "attiny1604", "attiny1606", "attiny1607", "attiny1614", "attiny1616", "attiny1617", "attiny3214", "attiny3216", "attiny3217", "atmega808", "atmega809", "atmega1608", "atmega1609", "atmega3208", "atmega3209", "atmega4808", "atmega4809"
      • "avrxmega4" โ€” "XMEGA" devices with more than 64 KiB and up to 128 KiB of program memory. mcu = "atxmega64a3", "atxmega64a3u", "atxmega64a4u", "atxmega64b1", "atxmega64b3", "atxmega64c3", "atxmega64d3", "atxmega64d4"
      • "avrxmega5" โ€” "XMEGA" devices with more than 64 KiB and up to 128 KiB of program memory and more than 64 KiB of RAM. mcu = "atxmega64a1", "atxmega64a1u"
      • "avrxmega6" โ€” "XMEGA" devices with more than 128 KiB of program memory. mcu = "atxmega128a3", "atxmega128a3u", "atxmega128b1", "atxmega128b3", "atxmega128c3", "atxmega128d3", "atxmega128d4", "atxmega192a3", "atxmega192a3u", "atxmega192c3", "atxmega192d3", "atxmega256a3", "atxmega256a3b", "atxmega256a3bu", "atxmega256a3u", "atxmega256c3", "atxmega256d3", "atxmega384c3", "atxmega384d3"
      • "avrxmega7" โ€” "XMEGA" devices with more than 128 KiB of program memory and more than 64 KiB of RAM. mcu = "atxmega128a1", "atxmega128a1u", "atxmega128a4u"
      • "avrtiny" โ€” "TINY" Tiny core devices with 512 B up to 4 KiB of program memory. mcu = "attiny4", "attiny5", "attiny9", "attiny10", "attiny20", "attiny40"
      • "avr1" โ€” This ISA is implemented by the minimal AVR core and is supported for the assembler only ๐Ÿฃ. mcu = "attiny11", "attiny12", "attiny15", "attiny28", "at90s1200"
  • -mabsdata โ€” ๐Ÿ“ฆ Assumes that all data in static storage can be accessed by LDS / STS instructions. This only has an effect on reduced Tiny devices like ATtiny40. See also the "absdata" AVR Variable Attributes,variable attribute ๐Ÿงพ.
  • -maccumulate-args โ€” ๐Ÿงบ Accumulates outgoing function arguments and acquires/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 ๐ŸŒˆ.

okay so popping the arguments off the stack after a function call can be super pricey on AVR ๐Ÿ’ธ, which means letting the stack space pile up can actually lead to smaller executables ๐Ÿฆ‹. The arguments don't have to get removed from the stack after each call, so no cap, it's giving galaxy brain ๐Ÿง โœจ

This option can lead to reduced code size for functions that make a bunch of calls to functions that take 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 and epilogues get expanded as calls to the appropriate subroutines, so the code size comes out smaller ๐Ÿงš
  • -mdouble=bits, -mlong-double=bits โ€” sets the size (in bits) of the "double" or "long double" type, respectively ๐ŸŽ€ Possible values for bits are 32 and 64. Whether or not a specific value for bits is allowed depends on the --with-double= and --with-long-double= configure options (https://gcc.gnu.org/install/configure.html#avr), and the same applies for the default values of the options.
  • -mgas-isr-prologues โ€” ISRs are allowed to 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). This feature is turned on by default if optimization is on (but not with -Og, see Optimize Options), and if GNU Binutils supports PR21683 (https://sourceware.org/PR21683).
  • -mint8 โ€” assume "int" is an 8-bit integer ๐Ÿ™ˆ This affects the sizes of all types: a "char" is 1 byte, an "int" is 1 byte, a "long" is 2 bytes, and a "long long" is 4 bytes.
โš ๏ธ Heads up, please note this option does not conform to the C standards, but it does result in smaller code size.
  • -mmain-is-OS_task โ€” don't save registers in "main" ๐Ÿ’œ This has the same effect as attaching the "OS_task" attribute (see AVR Function Attributes) to "main". It's activated per default if optimization is on.
  • -mn-flash=num โ€” assume the flash memory has a size of num times 64 KiB โœจ
  • -mno-interrupts โ€” the generated code is not compatible with hardware interrupts ๐Ÿ’€ The upside is that code size comes out smaller.
  • -mrelax โ€” tries to swap a CALL (resp. JMP) for the shorter RCALL (resp. RJMP) instruction, if applicable ๐Ÿฆ‹ Setting -mrelax just adds the --mlink-relax option to the assembler's command line and the --relax option to the linker's command line.

Jump relaxing is performed by the linker, because jump offsets aren't known until the code is located ๐Ÿ—บ๏ธ So the assembler code the compiler generates stays the same, but the instructions in the executable may differ from the instructions in the assembler code.

Relaxing must be turned on if linker stubs are needed, see the section on "EIND" and linker stubs below.

  • -mrmw โ€” assume the device supports the Read-Modify-Write instructions XCH, LAC, LAS and LAT ๐Ÿ”ฅ
  • -mshort-calls โ€” assume RJMP and RCALL can target the whole program memory ๐ŸŒธ This option is used internally for multilib selection. It is not an optimization option, and you don't need to set it by hand.
  • -msp8 โ€” treat the stack pointer register as an 8-bit register, i.e. assume the high byte of the stack pointer is zero ๐Ÿ’… In general, you don't need to set this option by hand.

This option is used internally by the compiler to select and build multilibs for architectures avr2 and avr25. These architectures mix devices with and without SPH. For any setting other than -mmcu=avr2 or -mmcu=avr25, the compiler driver adds or removes this option from the compiler proper's command line, because the compiler then knows if the device or architecture has an 8-bit stack pointer and thus no SPH register or not.

  • -mstrict-X โ€” use the address register X the way the hardware proposes ๐Ÿงš That means X is only used in indirect, post-increment or pre-decrement addressing.

Without this option, the X register may be used in the same way as Y or Z, which then gets emulated by additional instructions. For example, loading a value with X+const addressing, with a small non-negative const < 64 into a register Rn, is performed as:

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 ๐Ÿงš The user takes responsibility for supplying the subprocesses (compiler proper, assembler and linker) with appropriate command line options. This means the user has to supply her private device specs file by means of -specs=path-to-specs-file. There is no more need for the option -mmcu=mcu.

This option can also serve as a replacement for the older way of specifying custom device-specs files, which needed -B some-path to point to a directory containing a folder named "device-specs", which contains a specs file named "specs-mcu", where mcu was specified by -mmcu=mcu.

  • -Waddr-space-convert โ€” warn about conversions between address spaces in the case where the resulting address space is not contained in the incoming address space โš ๏ธ
  • -Wmisspelled-isr โ€” warn if the ISR is misspelled, i.e. without the __vector prefix. Enabled by default. ๐Ÿ‘‘

โœจ "EIND" and Devices with More Than 128 Ki Bytes of Flash โœจ

Pointers in the implementation are 16 bits wide. The address of a function or label is 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 space, there's a special function register called EIND ๐Ÿ”‘ It serves as the most significant part of the target address when EICALL or EIJMP instructions are used.

Indirect jumps and calls on these devices are handled as follows by the compiler, and they come with some limitations ๐Ÿ™ˆ

  • The compiler never sets EIND.
  • The compiler uses EIND implicitly in EICALL/EIJMP instructions, or might read EIND directly in order to emulate an indirect call/jump by means of a RET instruction.
  • The compiler assumes that EIND never changes during the startup code or during the application. In particular, EIND is not saved/restored in function or interrupt service routine prologue/epilogue.
  • For indirect calls to functions and computed goto, the linker generates stubs. Stubs are jump pads, sometimes also called trampolines. Thus, the indirect call/jump jumps to such a stub. 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, a custom linker script has to be used in order 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 is legitimate for user-specific startup code to set up EIND early, for example by means of initialization code located in section .init3. Such code runs prior to the general startup code that initializes RAM and calls constructors, but after the bit of startup code from AVR-LibC 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:
    • The final location of that label is in a code segment outside the segment where the stubs are located.

Like so, for the first condition:

LDI r24, lo8(gs(<func>))
LDI r25, hi8(gs(<func>))
  • 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 prologue-save function is used, see the -mcall-prologues command-line option.
    • Switch/case dispatch tables. If you do not want such dispatch tables, you can specify the -fno-jump-tables command-line option.
    • C and C++ constructors/destructors called during startup/shutdown.
    • If the tools hit a gs() modifier explained above.
  • Jumping to non-symbolic addresses like so is not supported:
int main (void)
{
    /* Call function at word address 0x2 */
    return ((int(*)(void)) 0x2)();
}

Instead, a stub has to be set up, i.e. the function has to be called through a symbol (func_4 in the example):

int main (void)
{
    extern int func_4 (void);

    /* Call function at byte address 0x4 */
    return func_4();
}

and the application be linked with -Wl,--defsym,func_4=0x4. Alternatively, func_4 can be defined in the linker script.

๐Ÿฆ‹ Handling of the "RAMPD", "RAMPX", "RAMPY" and "RAMPZ" Special Function Registers

Okay so bestie, some AVR chips have more memory than a 16-bit pointer can reach ๐Ÿ˜ญ To get past that 64 KiB wall, the chip uses a little "RAMP" register as the high part of the address ๐Ÿ’… The X, Y, Z address registers get glued to RAMPX, RAMPY, RAMPZ (respectively) to make one wide address โœจ And RAMPD teams up with direct addressing, same energy ๐Ÿฆ‹

  • The startup code sets all the RAMP special function registers to zero ๐ŸŒธ
  • If an AVR Named Address Spaces, named address space other than generic or __flash is used, RAMPZ gets set as needed before the operation ๐ŸŽ€
  • If the device supports RAM bigger than 64 KiB and the compiler has to change RAMPZ to pull off an operation, RAMPZ gets reset to zero afterwards ๐Ÿงน
  • If the device has 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 ๐Ÿซถ
๐Ÿ’€ RAM larger than 64 KiB is not supported by GCC for AVR targets. If you use inline assembler to read from locations outside the 16-bit address range and change one of the RAMP registers, you must reset it to zero after the access. Do not skip this, bestie!

โœจ AVR Built-in Macros โœจ

GCC defines several built-in macros so your code can test for the presence or absence of features ๐Ÿงš Almost any of the following built-in macros are deduced from device capabilities and thus triggered by the -mmcu= command-line option ๐Ÿ’–

For even more AVR-specific built-in macros see AVR Named Address Spaces and AVR Built-in Functions ๐ŸŒˆ

"__AVR_ARCH__"

Built-in macro that resolves to a decimal number that identifies the architecture and depends on the -mmcu=mcu option. Possible values are:

  • 2, 25, 3, 31, 35, 4, 5, 51, 6 for mcu="avr2", "avr25", "avr3", "avr31", "avr35", "avr4", "avr5", "avr51", "avr6", respectively
  • 100, 102, 103, 104, 105, 106, 107 for mcu="avrtiny", "avrxmega2", "avrxmega3", "avrxmega4", "avrxmega5", "avrxmega6", "avrxmega7", respectively

If mcu specifies a device, this built-in macro is set accordingly. For example, with -mmcu=atmega8 the macro is defined to 4 ๐Ÿ“

"__AVR_Device__"

Setting -mmcu=device defines this built-in macro, which reflects the device's name ๐Ÿฆ‹ For example, -mmcu=atmega8 defines the built-in macro "__AVR_ATmega8__", -mmcu=attiny261a defines "__AVR_ATtiny261A__", etc.

The built-in macros' names follow the scheme "__AVR_Device__" where Device is the device name as from the AVR user manual. The difference between Device in the built-in macro and device in -mmcu=device is that the latter is always lowercase ๐Ÿ™ˆ

If device is not a device but only a core architecture like avr51, this macro is not defined.

"__AVR_DEVICE_NAME__"

Setting -mmcu=device defines this built-in macro to the device's name. For example, with -mmcu=atmega8 the macro is defined to "atmega8" ๐ŸŒธ

If device is not a device but only a core architecture like avr51, this macro is not defined.

"__AVR_XMEGA__"

The device / architecture belongs to the XMEGA family of devices ๐Ÿ‘‘

"__AVR_HAVE_ELPM__"

The device has the ELPM instruction โœจ

"__AVR_HAVE_ELPMX__"

The device has the "ELPM Rn,Z" and "ELPM Rn,Z+" instructions ๐Ÿ’…

"__AVR_HAVE_MOVW__"

The device has the "MOVW" instruction to perform 16-bit register-register moves ๐ŸŽ€

"__AVR_HAVE_LPMX__"

The device has the "LPM Rn,Z" and "LPM Rn,Z+" instructions ๐Ÿซถ

"__AVR_HAVE_MUL__"

The device has a hardware multiplier ๐Ÿ”ฅ

"__AVR_HAVE_JMP_CALL__"

The device has the "JMP" and "CALL" instructions. This is the case for devices with more than 8 KiB of program memory ๐ŸŒˆ

"__AVR_HAVE_EIJMP_EICALL__" 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. This also means that 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 stack pointer (SP) register is treated as 8-bit respectively 16-bit register by the compiler. 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", "RAMPZ" special function register, respectively ๐Ÿซถ

"__NO_INTERRUPTS__"

This macro reflects the -mno-interrupts command-line option ๐Ÿ™ˆ

"__AVR_ERRATA_SKIP__" and "__AVR_ERRATA_SKIP_JMP_CALL__"

Some AVR devices (AT90S8515, ATmega103) must not skip 32-bit instructions because of a hardware erratum ๐Ÿ’€ Skip instructions are "SBRS", "SBRC", "SBIS", "SBIC" and "CPSE". The second macro is only defined if "__AVR_HAVE_JMP_CALL__" is also set.

"__AVR_ISA_RMW__"

The device has Read-Modify-Write instructions (XCH, LAC, LAS and LAT) ๐Ÿ”ฅ

"__AVR_SFR_OFFSET__=offset"

Instructions that can address I/O special function registers directly, like IN, OUT, SBI, etc., may use a different address than an instruction that accesses RAM, like LD or STS. This offset depends on the device architecture and has to be subtracted from the RAM address in order to get the respective I/O address ๐Ÿงš

"__AVR_SHORT_CALLS__"

The -mshort-calls command line option is set โœจ

"__AVR_PM_BASE_ADDRESS__=addr"

Some devices support reading from flash memory by means of LD* instructions. The flash memory is seen in the data address space at an offset of "__AVR_PM_BASE_ADDRESS__". If this macro is not defined, this feature is not available. If 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 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 resp. 64-bit double. The actual layout is specified by option -mdouble= ๐Ÿ’–

"__DEFAULT_DOUBLE__"

The size in bits of "double" if -mdouble= is not set. To test the layout of "double" in a program, use the built-in macro "__SIZEOF_DOUBLE__" ๐ŸŒธ

"__HAVE_LONG_DOUBLE32__", "__HAVE_LONG_DOUBLE64__", "__HAVE_LONG_DOUBLE_MULTILIB__" and "__DEFAULT_LONG_DOUBLE__"

Same as above, but for "long double" instead of "double" ๐Ÿซถ

"__WITH_DOUBLE_COMPARISON__"

Reflects the "--with-double-comparison={tristate|bool|libf7}" configure option ("https://gcc.gnu.org/install/configure.html#avr") and is defined to 2 or 3 ๐Ÿงš

"__WITH_LIBF7_LIBGCC__", "__WITH_LIBF7_MATH__" and "__WITH_LIBF7_MATH_SYMBOLS__"

Reflects the "--with-libf7={libgcc|math|math-symbols}" configure option ("https://gcc.gnu.org/install/configure.html#avr") โœจ


๐Ÿฆ‹ Blackfin Options ๐Ÿฆ‹

  • -mcpu=cpu[-sirevision] โ€” Okay, this one picks your 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, bf592. The optional sirevision is the silicon revision of the target chip, and any workarounds for that 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 that support for bf561 is incomplete. For bf561, only the preprocessor macro is defined ๐Ÿ™ˆ
  • -msim โ€” Specifies that the program will be run on the simulator ๐Ÿงš This causes the simulator BSP provided by libgloss to be linked in. This option has effect only for bfin-elf toolchain. Certain other options, such as -mid-shared-library and -mfdpic, imply -msim ๐Ÿ’–
  • -momit-leaf-frame-pointer โ€” Don't keep the frame pointer in a register for leaf functions ๐ŸŒธ This avoids the instructions to save, set up and restore frame pointers and makes an extra register available in leaf functions ๐Ÿซถ
  • -mspecld-anomaly โ€” When enabled, the compiler ensures that the generated code does not contain speculative loads after jump instructions ๐ŸŽ€ If this option is used, "__WORKAROUND_SPECULATIVE_LOADS" is defined ๐Ÿฆ‹
  • -mno-specld-anomaly โ€” Don't generate extra code to prevent speculative loads from occurring ๐Ÿ’…
  • -mcsync-anomaly โ€” When enabled, the compiler ensures that the generated code does not contain CSYNC or SSYNC instructions too soon after conditional branches โœจ If this option is used, "__WORKAROUND_SPECULATIVE_SYNCS" is defined ๐ŸŒˆ
  • -mno-csync-anomaly โ€” Don't generate extra code to prevent CSYNC or SSYNC instructions from occurring too soon after a conditional branch ๐Ÿงš
  • -mlow64k โ€” When enabled, the compiler is free to take advantage of the knowledge that the entire program fits into the low 64k of memory ๐Ÿ‘‘
  • -mno-low64k โ€” ๐ŸŒธ Okay so this one tells the compiler to assume the program can be arbitrarily large ๐Ÿ˜. It's the default, so you're already getting it.
  • -mstack-check-l1 โ€” ๐Ÿ›ก๏ธ Turns on stack checking using info the uClinux kernel stashes in L1 scratchpad memory. Lowkey clutch. โœจ
  • -mid-shared-library โ€” ๐Ÿฆ‹ Generates code that supports shared libraries through the library ID method. This is how you get execute in place and shared libraries in an environment with no virtual memory management ๐Ÿ™Œ. It implies -fPIC, and with a bfin-elf target it also implies -msim ๐Ÿ’….
  • -mno-id-shared-library โ€” ๐Ÿ™…โ€โ™€๏ธ Generates code that doesn't assume ID-based shared libraries are in use. This is the default, bestie.
  • -mleaf-id-shared-library โ€” ๐Ÿ“ Supports shared libraries through the library ID method, but assumes this library or executable won't link against any other ID shared libraries. Because of that promise, the compiler gets to use faster code for jumps and calls ๐ŸŽ๏ธ.
  • -mno-leaf-id-shared-library โ€” ๐Ÿข Doesn't assume the code won't link against any ID shared libraries. The result is slower code for jump and call instructions. Not the vibe, but it's the safe bet.
  • -mshared-library-id=n โ€” ๐Ÿ”ข Sets the identification number of the ID-based shared library being compiled. A value of 0 gives you more compact code ๐Ÿค. 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 โ€” ๐Ÿงฉ Generates code that lets the data segment live in a different area of memory from the text segment. This is giving execute in place in an environment without virtual memory management, because it gets rid of relocations against the text section ๐Ÿซถ.
  • -mno-sep-data โ€” ๐Ÿ“ฆ Generates code that assumes the data segment follows the text segment. This is the default.
  • -mlong-calls, -mno-long-calls โ€” ๐Ÿ“ž Tells the compiler to make function calls by first loading the function's address into a register, then doing a subroutine call on that register. You need this if the target function lives outside the 24-bit addressing range of the offset-based subroutine call instruction ๐ŸŒ. This feature is not enabled by default, and -mno-long-calls brings back the default behaviour. Heads up: these switches do nothing for function calls made through function pointers ๐Ÿ™ˆ.
  • -mfast-fp โ€” โšก Links with the fast floating-point library. It relaxes some of the IEEE floating-point standard's rules for checking inputs against Not-a-Number (NAN), all in the name of performance ๐Ÿš€.
  • -minline-plt โ€” ๐Ÿช„ Enables inlining of PLT entries in function calls to functions that aren't known to bind locally. Fair warning: it has no effect unless you also use -mfdpic ๐Ÿซ .
  • -mmulticore โ€” ๐Ÿง  Builds a standalone application for multicore Blackfin processors. This makes the compiler use start files and link scripts that support multicore, and it defines the macro "__BFIN_MULTICORE" ๐Ÿ’œ. It can only be used with -mcpu=bf561[-sirevision].
    • It can be paired with -mcorea or -mcoreb for the one-application-per-core model. Without either of those, you get the single-application/dual-core model ๐Ÿ‘ฏ. In that model, Core B's main function should be named "coreb_main".
    • Skip this option entirely and you get the single-core application model ๐ŸŒฑ.
  • -mcorea โ€” ๐Ÿ…ฐ๏ธ Builds a standalone application for Core A of BF561 when you're using the one-application-per-core model. It uses the right start files and link scripts for Core A and defines "__BFIN_COREA". This one can only be used alongside -mmulticore ๐Ÿ‘‘.
  • -mcoreb โ€” ๐Ÿ…ฑ๏ธ Same energy as -mcorea, but for Core B of BF561. It defines "__BFIN_COREB", and when you use it, "coreb_main" should be used instead of "main" ๐ŸŽ€. It also needs -mmulticore.
  • -msdram โ€” ๐Ÿ’พ Builds a standalone application for SDRAM. The start files and link scripts put your app into SDRAM and define "__BFIN_SDRAM". Make sure your loader initialises SDRAM before it loads the application ๐Ÿ™.
  • -micplb โ€” ๐Ÿงฑ Assumes ICPLBs are enabled at run time. This affects certain anomaly workarounds ๐Ÿ”ง. For Linux targets the default is to assume ICPLBs are enabled, but for standalone applications the default is off.

๐ŸŒˆ C6X Options ๐ŸŒˆ

  • -march=name โ€” ๐Ÿ—๏ธ Specifies the name of the target architecture. GCC uses this to decide which kinds of instructions it can 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 โ€” ๐Ÿ–ฅ๏ธ Chooses startup files and a linker script that suit the simulator.
  • -msdata=default โ€” ๐Ÿ—‚๏ธ Puts small global and static data into the .neardata section, which is pointed to by register B14 ๐Ÿ“. Small uninitialised global and static data goes into the .bss section, which sits right next to .neardata. Small read-only data goes into the .rodata section. The 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, and uses addressing relative to the B14 register to get to them.
  • -msdata=none โ€” ๐Ÿšซ Makes no use of the small-data sections and uses absolute addresses to access all data. All initialised global and static data goes in .fardata, all uninitialised data goes in .far, and all constant data goes in .const ๐Ÿ’….

๐Ÿฆ‹ CRIS Options ๐Ÿฆ‹

These options are defined specifically for the CRIS ports ๐ŸŽ€.

  • -march=architecture-type, -mcpu=architecture-type โ€” ๐Ÿ› ๏ธ Generates code for the specified architecture. The choices for architecture-type are v3, v8 and v10, which correspond to ETRAX 4, ETRAX 100, and ETRAX 100 LX respectively. The default is v0.
  • -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 active by default.
  • -mpdebug โ€” ๐Ÿ” Enables CRIS-specific verbose debug-related information in the assembly code. It also turns off the #NO_APP formatted-code indicator that goes to the assembler at the start of the assembly file ๐Ÿ™ƒ.
  • -mcc-init โ€” ๐Ÿšฆ Doesn't use condition-code results from previous instructions. It always emits compare and test instructions before any use of 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 options (the no- ones eliminate it) arrange for the stack frame, individual data and constants to be aligned to the maximum single data access size for the chosen CPU model. The default is 32-bit alignment. ABI details, like structure layout, are not affected by these ๐Ÿ™Œ.
  • -m32-bit, -m16-bit, -m8-bit โ€” ๐Ÿ”ข Similar to the stack, data and const align options above, these make the stack frame, writable data and constants all 32-bit, 16-bit or 8-bit aligned. The default is 32-bit alignment.
  • -mno-prologue-epilogue, -mprologue-epilogue โ€” ๐Ÿšจ With -mno-prologue-epilogue, the normal function prologue and epilogue that set up the stack frame are left out, and no return instructions or return sequences get generated.
โš ๏ธ Bestie, read this one twice. Only use -mno-prologue-epilogue alongside careful visual inspection of the compiled code. No warnings or errors are generated when call-saved registers need saving, or when storage for local variables needs allocating. Nothing will warn you, so you're on your own ๐Ÿ’€.
  • -melf โ€” ๐Ÿซฅ A legacy no-op option, so it does nothing.
  • -sim โ€” ๐ŸŽฎ Links with the input-output functions from a simulator library. Code, initialised data and zero-initialised data are allocated consecutively ๐Ÿงต.
  • -sim2 โ€” ๐Ÿงญ Works like -sim, but also passes linker options that locate initialised data at 0x40000000 and zero-initialised data at 0x80000000 โœจ.

๐ŸŒธ CR16 Options ๐ŸŒธ

These options are defined specifically for the CR16 ports ๐Ÿ’œ.

  • -mmac โ€” ๐Ÿงฎ Enables the use of multiply-accumulate instructions. It's disabled by default.
  • -mcr16cplus, -mcr16c โ€” ๐Ÿง  Generates code for the CR16C or CR16C+ architecture. The CR16C+ architecture is the default.
  • -msim โ€” ๐Ÿ–ฅ๏ธ Links the library libsim.a, which is compatible with the simulator. This only applies to the ELF compiler.
  • -mint32 โ€” ๐Ÿ”ข Chooses a 32-bit wide integer type.
  • -mbit-ops โ€” ๐ŸŽ›๏ธ Generates "sbit" and "cbit" instructions for bit manipulations.
  • -mdata-model=model โ€” ๐Ÿงณ Chooses a data model. The choices for model are near, far or medium, and medium is the default. Note that far is not valid with -mcr16c, since 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 ๐Ÿ’–.

Bestie, the -mcpu=cpu flag is how you tell GCC which C-SKY target processor you're building for ๐Ÿ’…. The valid values for cpu are ck801, ck801t, ck802, ck802t, ck802j, ck803, ck803h, ck803t, ck803ht, ck803f, ck803fh, ck803e, ck803eh, ck803et, ck803eht, ck803ef, ck803efh, ck803ft, ck803eft, ck803efht, ck803r1, ck803hr1, ck803tr1, ck803htr1, ck803fr1, ck803fhr1, ck803er1, ck803ehr1, ck803etr1, ck803ehtr1, ck803efr1, ck803efhr1, ck803ftr1, ck803eftr1, ck803efhtr1, ck803s, ck803st, ck803se, ck803sf, ck803sef, ck803seft, ck807e, ck807ef, ck807, ck807f, ck810e, ck810et, ck810ef, ck810eft, ck810, ck810v, ck810f, ck810t, ck810fv, ck810tv, ck810ft, and ck810ftv ๐ŸŒธ

  • -mbig-endian, -EB, -mlittle-endian, -EL โ€” Pick your byte order! Big-endian or little-endian, your call ๐Ÿงš. Little-endian is the default, so if you don't pick, you get that โœจ
  • -mfloat-abi=name โ€” This one chooses which floating-point ABI you're vibing with. Your options are soft, softfp, and hard ๐ŸŽ€
    • soft makes GCC spit out library calls for all the floating-point math. No hardware floating-point stuff, just library calls, fr fr.
    • softfp lets GCC use the hardware floating-point instructions, but it still follows the soft-float calling conventions ๐Ÿฆ‹
    • hard gives you floating-point instructions and FPU-specific calling conventions. Full hardware glow-up ๐Ÿ”ฅ

The default depends on your specific target configuration, so check what you're working with first ๐Ÿ’–

Heads up, 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 disaster ๐Ÿ’€
  • -mhard-float, -msoft-float โ€” Pick hardware or software floating-point implementations. The default is soft float ๐ŸŒˆ
  • -mdouble-float, -mno-double-float โ€” When -mhard-float is in effect, this turns on generation of double-precision float instructions. It's the default except when you're compiling for CK803 ๐Ÿ’œ
  • -mfdivdu, -mno-fdivdu โ€” When -mhard-float is in effect, this enables generation of "frecipd", "fsqrtd", and "fdivd" instructions. Also the default except when compiling for CK803 โœจ
  • -mfpu=fpu โ€” Choose your floating-point processor! This one only works with -mhard-float. The values for fpu are:
    • fpv2_sf, which is equivalent to -mno-double-float -mno-fdivdu
    • fpv2, which is -mdouble-float -mno-divdu
    • fpv2_divd, which is -mdouble-float -mdivdu
  • -melrw, -mno-elrw โ€” Turns the extended "lrw" instruction on or off. It defaults to on for CK801 and off for everything else ๐Ÿ“
  • -mistack, -mno-istack โ€” Enable interrupt stack instructions. The default is off. Also, -mistack is required if you want to handle the "interrupt" and "isr" function attributes ๐Ÿ™ˆ
  • -mmp โ€” Enable multiprocessor instructions. Default is off ๐Ÿ‘‘
  • -mcp โ€” Enable coprocessor instructions. Default is off ๐Ÿฆ‹
  • -mcache โ€” Enable coprocessor instructions. Default is off ๐ŸŒธ
  • -msecurity โ€” Enable C-SKY security instructions. Default is off ๐Ÿ”ฅ
  • -mtrust โ€” Enable C-SKY trust instructions. Default is off ๐Ÿ’…
  • -mdsp, -medsp, -mvdsp โ€” Enable C-SKY DSP, Enhanced DSP, or Vector DSP instructions, respectively. All of these default to off ๐Ÿงš
  • -mdiv, -mno-div โ€” Generate divide instructions. Default is off ๐ŸŽ€
  • -msmart, -mno-smart โ€” Generate code for Smart Mode, which only uses registers numbered 0-7 so you can use 16-bit instructions. This is ignored for CK801, where it's already the required behavior, and it defaults to on for CK802. For other targets, the default is off ๐Ÿซถ
  • -mhigh-registers, -mno-high-registers โ€” Generate code using the high registers numbered 16-31. This isn't supported on CK801, CK802, or CK803, but it's enabled by default for other processors โญ
  • -manchor, -mno-anchor โ€” Generate code using global anchor symbol addresses ๐ŸŒˆ
  • -mpushpop, -mno-pushpop โ€” Generate code using "push" and "pop" instructions. This one defaults to on ๐Ÿ’–
  • -mmultiple-stld, -mstm, -mno-multiple-stld, -mno-stm โ€” Generate code using "stm" and "ldm" instructions. This isn't supported on CK801, but it's enabled by default on other processors ๐Ÿ‘‘
  • -mconstpool, -mno-constpool โ€” Create constant pools in the compiler instead of handing that job off to the assembler. This is the default and it's required for correct code generation on CK801 and CK802. It's optional on other processors ๐Ÿงš
  • -mstack-size, -mno-stack-size โ€” Emit ".stack_size" directives for each function in the assembly output. This defaults to off ๐Ÿ“
  • -mccrt, -mno-ccrt โ€” Generate code for the C-SKY compiler runtime instead of libgcc. Defaults to off ๐Ÿฆ‹
  • -mbranch-cost=n โ€” Set the branch costs to roughly n instructions. The default is 1 โœจ
  • -msched-prolog, -mno-sched-prolog โ€” Permit scheduling of function prologue and epilogue sequences. Okay, real talk, this one is a little risky:
Using this option can result in code that isn't compliant with the C-SKY V2 ABI prologue requirements, and that code might not be debuggable or backtraceable. It's disabled by default, so leave it off unless you know exactly why you need it ๐Ÿ™ˆ
  • -msim โ€” Links the library libsemi.a, which is compatible with the simulator. This only applies to the ELF compiler ๐ŸŒธ

๐Ÿฆ‹ Darwin Options ๐Ÿฆ‹

These options are defined for all architectures running the Darwin operating system ๐ŸŽ

FSF GCC on Darwin doesn't make "fat" object files. Instead, it makes an object file for the single architecture that GCC was built to target. Apple's GCC on Darwin does make "fat" files if you use multiple -arch options. It does this by running the compiler or linker multiple times and then joining the results together with lipo ๐Ÿ’œ

The subtype of the file you create (like ppc7400, ppc970, or i686) gets decided by the flags that specify the ISA GCC is targeting, like -mcpu or -march. If you want to override that, the -force_cpusubtype_ALL option can do it โœจ

The Darwin tools act differently when they hit an ISA mismatch, so let's break it down ๐Ÿงš

  • The assembler, as, only lets you use instructions that are valid for the subtype of the file it's generating. So you can't put 64-bit instructions in a ppc750 object file, sorry not sorry ๐Ÿ™…
  • The linker for shared libraries, /usr/bin/libtool, fails and prints an error if you ask it to create a shared library with a less restrictive subtype than its input files. For example, trying to put a ppc970 object file in a ppc7400 library is a no-go ๐Ÿ”ฅ
  • The linker for executables, ld, quietly gives the executable the most restrictive subtype of any of its input files ๐Ÿคซ
  • -Fdir โ€” Adds the framework directory dir to the head of the list of directories searched for header files. These directories are interleaved with the ones from -I options, and they get scanned left-to-right ๐ŸŽ€

A framework directory is just a directory with frameworks in it. A framework is a directory with a Headers and/or PrivateHeaders directory sitting directly inside it, and its name ends in .framework. The name of a framework is that directory's 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 of the framework that contains the subframework, or in a sibling subframework header. Two subframeworks are siblings if they live in the same framework ๐Ÿ‘ฏ

A subframework shouldn't share a name with a framework, and if it does, you'll get a warning. Right now, a subframework can't have subframeworks of its own, but that might get extended in the future ๐ŸŒˆ

The standard frameworks live in /System/Library/Frameworks and /Library/Frameworks. An example include looks like this, where Framework is the framework's name and header.h lives in the PrivateHeaders or Headers directory:

#include <Framework/header.h>
  • -iframeworkdir โ€” This is 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 โ€” Emit debugging information for symbols that are used. If you're using the stabs debugging format, this enables -feliminate-unused-debug-symbols. It's ON by default ๐Ÿฆ‹
  • -gfull โ€” Emit debugging information for all symbols and types. Go big or go home ๐Ÿ”ฅ
  • -fconstant-cfstrings โ€” This is just an alias for -mconstant-cfstrings ๐ŸŒธ
  • -mconstant-cfstrings โ€” When the NeXT runtime is being used (which is the default on these systems), this overrides any -fconstant-string-class setting. It also makes "@"..."" literals get laid out as constant CoreFoundation strings ๐Ÿ’œ
  • -mmacosx-version-min=version โ€” The earliest version of MacOS X that this executable will run on is version. Typical values supported for version include 12, 10.12, and 10.5.8 ๐ŸŽ

If the compiler was built to use the system's headers by default, then the default for this option is the system version the compiler is running on. Otherwise, the default is to make choices that are compatible with as many systems and code bases as possible โœจ

  • -mkernel โ€” Turns on kernel development mode! This sets -static, -fno-common, -fno-use-cxa-atexit, -fno-exceptions, -fno-non-call-exceptions, -fapple-kext, -fno-weak, and -fno-rtti, where applicable. For PowerPC targets, it also sets -mno-altivec, -msoft-float, -fno-builtin, and -mlong-branch ๐Ÿ‘‘
  • -mone-byte-bool โ€” Overrides the defaults for "bool" so that sizeof(bool)==1. By default, sizeof(bool) is 4 when compiling for Darwin/PowerPC and 1 when compiling for Darwin/x86, so this option has no effect on x86 ๐Ÿ™ˆ
Warning, bestie! The -mone-byte-bool switch makes GCC generate code that isn't binary compatible with code generated without it. You may need to recompile all the other modules in your program, including the system libraries. Only use this switch to conform to a non-default data model ๐Ÿ’€
  • -mfix-and-continue, -ffix-and-continue, -findirect-data โ€” Generate code that's perfect 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. Check man ld(1) for more info ๐Ÿ“š
  • -arch_errors_fatal โ€” Makes errors about files with the wrong architecture fatal, so they stop the build instead of just being a vibe ๐Ÿ˜ญ
  • -bind_at_load โ€” marks the output file so the dynamic linker binds all undefined references when the file gets loaded or launched โœจ
  • -bundle โ€” makes a Mach-o bundle format file ๐Ÿ“ฆ See man ld(1) for the full tea.
  • -bundle_loader executable โ€” names the executable that will load the output file being linked ๐ŸŽ€ See man ld(1) for more info.
  • -dynamiclib โ€” when you pass this, GCC makes a dynamic library instead of an executable at link time, using the Darwin libtool command ๐Ÿฆ‹
  • -force_cpusubtype_ALL โ€” gives GCC's output file the ALL subtype, instead of one controlled by -mcpu or -march ๐Ÿ’…
  • -allowable_client client_name โ€” passed to the Darwin linker ๐ŸŽ
  • -client_name โ€” passed to the Darwin linker ๐ŸŽ
  • -compatibility_version โ€” passed to the Darwin linker ๐ŸŽ
  • -current_version โ€” passed to the Darwin linker ๐ŸŽ
  • -dead_strip โ€” passed to the Darwin linker ๐ŸŽ
  • -dependency-file โ€” passed to the Darwin linker ๐ŸŽ
  • -dylib_file โ€” passed to the Darwin linker ๐ŸŽ
  • -dylinker_install_name โ€” passed to the Darwin linker ๐ŸŽ
  • -dynamic โ€” passed to the Darwin linker ๐ŸŽ
  • -exported_symbols_list โ€” passed to the Darwin linker ๐ŸŽ
  • -filelist โ€” passed to the Darwin linker ๐ŸŽ
  • -flat_namespace โ€” passed to the Darwin linker ๐ŸŽ
  • -force_flat_namespace โ€” passed to the Darwin linker ๐ŸŽ
  • -headerpad_max_install_names โ€” passed to the Darwin linker ๐ŸŽ
  • -image_base โ€” passed to the Darwin linker ๐ŸŽ
  • -init โ€” passed to the Darwin linker ๐ŸŽ
  • -install_name โ€” passed to the Darwin linker ๐ŸŽ
  • -keep_private_externs โ€” passed to the Darwin linker ๐ŸŽ
  • -multi_module โ€” passed to the Darwin linker ๐ŸŽ
  • -multiply_defined โ€” passed to the Darwin linker ๐ŸŽ
  • -multiply_defined_unused โ€” passed to the Darwin linker ๐ŸŽ
  • -noall_load โ€” passed to the Darwin linker ๐ŸŽ
  • -no_dead_strip_inits_and_terms โ€” passed to the Darwin linker ๐ŸŽ
  • -nofixprebinding โ€” passed to the Darwin linker ๐ŸŽ
  • -nomultidefs โ€” passed to the Darwin linker ๐ŸŽ
  • -noprebind โ€” passed to the Darwin linker ๐ŸŽ
  • -noseglinkedit โ€” passed to the Darwin linker ๐ŸŽ
  • -pagezero_size โ€” passed to the Darwin linker ๐ŸŽ
  • -prebind โ€” passed to the Darwin linker ๐ŸŽ
  • -prebind_all_twolevel_modules โ€” passed to the Darwin linker ๐ŸŽ
  • -private_bundle โ€” passed to the Darwin linker ๐ŸŽ
  • -read_only_relocs โ€” passed to the Darwin linker ๐ŸŽ
  • -sectalign โ€” passed to the Darwin linker ๐ŸŽ
  • -sectobjectsymbols โ€” passed to the Darwin linker ๐ŸŽ
  • -whyload โ€” passed to the Darwin linker ๐ŸŽ
  • -seg1addr โ€” passed to the Darwin linker ๐ŸŽ
  • -sectcreate โ€” passed to the Darwin linker ๐ŸŽ
  • -sectobjectsymbols โ€” passed to the Darwin linker ๐ŸŽ
  • -sectorder โ€” passed to the Darwin linker ๐ŸŽ
  • -segaddr โ€” passed to the Darwin linker ๐ŸŽ
  • -segs_read_only_addr โ€” passed to the Darwin linker ๐ŸŽ
  • -segs_read_write_addr โ€” passed to the Darwin linker ๐ŸŽ
  • -seg_addr_table โ€” passed to the Darwin linker ๐ŸŽ
  • -seg_addr_table_filename โ€” passed to the Darwin linker ๐ŸŽ
  • -seglinkedit โ€” passed to the Darwin linker ๐ŸŽ
  • -segprot โ€” passed to the Darwin linker ๐ŸŽ
  • -segs_read_only_addr โ€” passed to the Darwin linker ๐ŸŽ
  • -segs_read_write_addr โ€” passed to the Darwin linker ๐ŸŽ
  • -single_module โ€” passed to the Darwin linker ๐ŸŽ
  • -static โ€” passed to the Darwin linker ๐ŸŽ
  • -sub_library โ€” passed to the Darwin linker ๐ŸŽ
  • -sub_umbrella โ€” passed to the Darwin linker ๐ŸŽ
  • -twolevel_namespace โ€” passed to the Darwin linker ๐ŸŽ
  • -umbrella โ€” passed to the Darwin linker ๐ŸŽ
  • -undefined โ€” passed to the Darwin linker ๐ŸŽ
  • -unexported_symbols_list โ€” passed to the Darwin linker ๐ŸŽ
  • -weak_reference_mismatches โ€” passed to the Darwin linker ๐ŸŽ
  • -whatsloaded โ€” passed to the Darwin linker ๐ŸŽ

These are all passed along to the Darwin linker, and the Darwin linker man page describes them in detail ๐ŸŽ๐Ÿ’…


๐Ÿ’œ DEC Alpha Options ๐Ÿ’œ

These -m options are defined for the DEC Alpha implementations, so if you're on an Alpha, these are your people ๐Ÿงš

  • -mno-soft-float, -msoft-float โ€” use (or skip) the hardware floating-point instructions for floating-point operations. When -msoft-float is specified, functions in libgcc.a do the floating-point work instead. Unless they get replaced by routines that emulate the floating-point operations, or compiled in a way that makes them call those emulation routines, these routines end up issuing floating-point operations. If you're compiling for an Alpha without floating-point operations, you must make sure the library is built so it doesn't call them ๐Ÿ’€ Heads up: Alpha implementations without floating-point operations are still required to have floating-point registers.
  • -mfp-reg, -mno-fp-regs โ€” generates code that uses (or doesn't use) the floating-point register set. -mno-fp-regs implies -msoft-float. If the floating-point register set isn't used, floating-point operands get passed in integer registers as if they were integers, and floating-point results get passed in $0 instead of $f0. This is a non-standard calling sequence, so any function with a floating-point argument or return value that's called by code compiled with -mno-fp-regs must also be compiled with that option. A typical use of this option is building a kernel that doesn't use, and hence doesn't need to save and restore, any floating-point registers ๐Ÿ”ฅ
โš ๏ธ Non-standard calling sequence alert: anything calling -mno-fp-regs code with a floating-point argument or return value has to be compiled with that option too.
  • -mieee โ€” the Alpha architecture has floating-point hardware built for maximum performance, and it's mostly compliant with the IEEE floating-point standard. Full compliance needs software help though ๐Ÿ’… This option generates fully IEEE-compliant code, except the inexact-flag isn't maintained (see below). When it's turned on, the preprocessor macro "_IEEE_FP" is defined during compilation. The resulting code is less efficient, but it can correctly support denormalized numbers and exceptional IEEE values such as not-a-number and plus/minus infinity. Other Alpha compilers call this option -ieee_with_no_inexact.
  • -mieee-with-inexact โ€” like -mieee, except the generated code also maintains the IEEE inexact-flag. Turning this on makes the code implement fully-compliant IEEE math. In addition to "_IEEE_FP", "_IEEE_FP_EXACT" is defined as a preprocessor macro. On some Alpha implementations the resulting code may run significantly slower than the code generated by default. 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 โ€” controls which floating-point related traps are enabled ๐Ÿฆ‹ Other Alpha compilers call this option -fptm trap-mode. The trap mode can be set to one of four values:
    • n โ€” this is the default (normal) setting. The only traps enabled are the ones that can't be disabled in software (e.g., division by zero trap).
    • u โ€” on top of the traps enabled by n, underflow traps are enabled as well.
    • su โ€” like u, but the instructions are marked as safe for software completion (see Alpha architecture manual for details).
    • sui โ€” like su, but inexact traps are enabled as well.
  • -mfp-rounding-mode=rounding-mode โ€” selects the IEEE rounding mode ๐ŸŒˆ Other Alpha compilers call this option -fprm rounding-mode. The rounding-mode can be one of:
    • n โ€” normal IEEE rounding mode. Floating-point numbers are rounded towards the nearest machine number, or towards the even machine number in case of a tie.
    • m โ€” round towards minus infinity.
    • c โ€” chopped rounding mode. Floating-point numbers are rounded towards zero.
    • d โ€” dynamic rounding mode. A field in the floating-point control register (fpcr, see Alpha architecture reference manual) controls the rounding mode in effect. The C library initializes this register for rounding towards plus infinity. Thus, unless your program modifies the fpcr, d corresponds to round towards plus infinity.
  • -mtrap-precision=trap-precision โ€” in the Alpha architecture, floating-point traps are imprecise ๐Ÿ˜ญ That means without software assistance it's impossible to recover from a floating trap, and program execution normally 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 your application's requirements, you can pick a different level of precision:
    • p โ€” program precision. This option is the default, and means a trap handler can only identify which program caused a floating-point exception.
    • f โ€” function precision. The trap handler can determine the function that caused a floating-point exception.
    • i โ€” instruction precision. The trap handler can determine the exact instruction that caused a floating-point exception.

Other Alpha compilers provide the equivalent options called -scope_safe and -resumption_safe.

  • -mieee-conformant โ€” marks the generated code as IEEE conformant ๐ŸŽ€
โš ๏ธ Don't 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 checks whether a 32- or 64-bit integer constant can be built from smaller constants in two or three instructions. If it can't, it outputs the constant as a literal and generates code to load it from the data segment at run time. Use this option to require GCC to build all integer constants using code, even if it takes more instructions (the maximum is six). You typically use this option to build a shared library dynamic loader. Since it's a shared library itself, it must relocate itself in memory before it can find the variables and constants in its own data segment โœจ
  • -mbwx, -mno-bwx, -mcix, -mno-cix, -mfix, -mno-fix, -mmax, -mno-max โ€” indicates 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 specified via -mcpu= option, or that of the CPU on which GCC was built if none is specified.
  • -mfloat-vax, -mfloat-ieee โ€” generates code that uses (or doesn't use) VAX F and G floating-point arithmetic instead of IEEE single and double precision ๐ŸŒธ
  • -mexplicit-relocs, -mno-explicit-relocs โ€” older Alpha assemblers provided no way to generate symbol relocations except via assembler macros, and 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 is built and sets the default accordingly ๐Ÿ™ˆ
  • -msmall-data, -mlarge-data โ€” when -mexplicit-relocs is in effect, static data is accessed via gp-relative relocations. When -msmall-data is used, objects 8 bytes long or smaller are placed in a small data area (the ".sdata" and ".sbss" sections) and accessed via 16-bit relocations off of the $gp register. This limits the size of the small data area to 64KB, but allows the variables to be accessed directly via a single instruction. The default is -mlarge-data. With this option, the data area is limited to just below 2GB. Programs that 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: okay so -msmall-text tells the compiler to assume the code of the whole program (or shared library) fits in 4MB, which means it's reachable with a branch instruction ๐Ÿงš. When -msmall-data is used, the compiler can assume all local symbols share the same $gp value, so a function call drops from 4 instructions to 1. Iconic efficiency ๐Ÿ’…โœจ

The default is -mlarge-text. ๐ŸŒธ

  • -mcpu=cpu_type: this sets the instruction set and instruction scheduling parameters for machine type cpu_type ๐Ÿ’–. You can name the EV style or use the chip number. GCC has scheduling parameters for the EV4, EV5, and EV6 families and picks its default instruction set from whatever processor you specify. If you don't name a processor, GCC defaults to the processor the compiler was built on ๐Ÿฆ‹.

Supported values for cpu_type are:

  • ev4, ev45, 21064: schedules as an EV4 and has no instruction set extensions ๐ŸŽ€
  • ev5, 21164: schedules as an EV5 and has no instruction set extensions ๐ŸŽ€
  • ev56, 21164a: schedules as an EV5 and supports the BWX extension ๐ŸŒˆ
  • pca56, 21164pc, 21164PC: schedules as an EV5 and supports the BWX and MAX extensions ๐ŸŒˆ
  • ev6, 21264: schedules as an EV6 and supports the BWX, FIX, and MAX extensions ๐Ÿ”ฅ
  • ev67, 21264a: schedules as an EV6 and supports the BWX, CIX, FIX, and MAX extensions ๐Ÿ‘‘

Native toolchains also support the value native, which picks the best architecture option for the host processor. -mcpu=native has no effect if GCC doesn't recognize the processor ๐Ÿซถ.

  • -mtune=cpu_type: this sets only the instruction scheduling parameters for machine type cpu_type. The instruction set stays exactly the same ๐Ÿ“.

Native toolchains also support the value native, which picks the best architecture option for the host processor. -mtune=native has no effect if GCC doesn't recognize the processor ๐Ÿ’œ.

  • -mmemory-latency=time: this sets the latency the scheduler should assume for typical memory references as the application sees them. It's super dependent on the app's memory access patterns and the size of the external cache on the machine ๐Ÿง .

Valid options for time are:

  • number: a decimal number representing clock cycles โฑ๏ธ
  • L1, L2, L3, main: the compiler has estimates of clock cycles for "typical" EV4 & EV5 hardware for the Level 1, 2, and 3 caches (also called Dcache, Scache, and Bcache), as well as main memory. Heads up, L3 is only valid for EV5 ๐Ÿ™ˆ.

โœจ eBPF Options โœจ

  • -mframe-limit=bytes: this sets the hard limit for frame sizes, in bytes ๐ŸŒธ. Right now the value you specify should be less than or equal to 32767. It defaults to whatever limit is imposed by the version of the Linux kernel being targeted ๐Ÿง.
  • -mkernel=version: this is the minimum kernel version that will run the compiled program ๐Ÿ‘‘. GCC uses it to figure out which instructions to use, which kernel helpers to allow, and so on. Right now version can be one of 4.0, 4.1, 4.2, 4.3, 4.4, 4.5, 4.6, 4.7, 4.8, 4.9, 4.10, 4.11, 4.12, 4.13, 4.14, 4.15, 4.16, 4.17, 4.18, 4.19, 4.20, 5.0, 5.1, 5.2, latest, or native ๐Ÿฆ‹.
  • -mbig-endian: generates code for a big-endian target ๐Ÿ’–.
  • -mlittle-endian: generates code for a little-endian target. This is the default ๐ŸŒˆ.
  • -mxbpf: generates code for an expanded version of BPF, which relaxes some of the restrictions imposed by the BPF architecture โœจ.
    • -<Save and restore callee-saved registers at function entry and> exit, respectively.

๐Ÿ’– FR30 Options ๐Ÿ’–

These options are defined specifically for the FR30 port ๐ŸŽ€.

  • -msmall-model: uses the small address space model. This can produce smaller code, but it does assume that all symbolic values and addresses fit into a 20-bit range ๐Ÿงš.
  • -mno-lsim: assumes runtime support has already been provided, so there's no need to include the simulator library (libsim.a) on the linker command line ๐Ÿ’….

๐Ÿฆ‹ FT32 Options ๐Ÿฆ‹

These options are defined specifically for the FT32 port ๐ŸŒธ.

  • -msim: specifies that the program will run on the simulator. This causes an alternate runtime startup and library to be linked. Bestie, you must not use this option when generating programs for real hardware ๐Ÿšซ. You have to provide your own runtime library for whatever I/O functions you need ๐Ÿ˜ญ.
  • -mlra: enables Local Register Allocation. It's still experimental for FT32, so by default the compiler uses standard reload ๐Ÿงช.
  • -mnodiv: do not use div and mod instructions ๐Ÿ™…โ€โ™€๏ธ.
  • -mft32b: enables use of the extended instructions of the FT32B processor ๐Ÿ”ฅ.
  • -mcompress: compresses all code using the Ft32B code compression scheme ๐Ÿ—œ๏ธ.
  • -mnopm: 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: do not try to dynamically allocate condition code registers. Only use "icc0" and "fcc0" ๐Ÿ™ˆ.
  • -mdword: changes the ABI to use double word instructions ๐Ÿ’œ.
  • -mno-dword: do not use double word instructions ๐Ÿšซ.
  • -mdouble: use floating-point double instructions ๐Ÿฆ‹.
  • -mno-double: do not use floating-point double instructions ๐Ÿซถ.
  • -mmedia: use media instructions ๐ŸŽถ.
  • -mno-media: do not use media instructions ๐Ÿ™…โ€โ™€๏ธ.
  • -mmuladd: use multiply and add/subtract instructions โž•.
  • -mno-muladd: do not use multiply and add/subtract instructions โž–.
  • -mfdpic: selects the FDPIC ABI, which uses function descriptors to represent pointers to functions ๐ŸŒŸ. Without any PIC/PIE-related options, it implies -fPIE. With -fpic or -fpie, it assumes GOT entries and small data are within a 12-bit range from the GOT base address. With -fPIC or -fPIE, GOT offsets are computed with 32 bits. With a bfin-elf target, this option implies -msim ๐Ÿง .
  • -minline-plt: enables inlining of PLT entries in function calls to functions that 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 on the command line ๐Ÿš€.
  • -mTLS: assumes a large TLS segment when generating thread-local code ๐Ÿงต.
  • -mtls: does not assume a large TLS segment when generating thread-local code ๐Ÿงต.
  • -mgprel-ro: enables the use of "GPREL" relocations in the FDPIC ABI for data that is known to be in read-only sections ๐Ÿ“–. It's enabled by default, except for -fpic or -fpie: even though it may help make the global offset table smaller, it trades 1 instruction for 4. With -fPIC or -fPIE, it trades 3 instructions for 4, one of which may be shared by multiple symbols, and it avoids the need for a GOT entry for the referenced symbol, so it's more likely to be a win. If it isn't, -mno-gprel-ro can be used to disable it ๐Ÿค”.
  • -multilib-library-pic: links with the (library, not FD) pic libraries ๐Ÿ“š. It's implied by -mlibrary-pic, as well as by -fPIC and -fpic without -mfdpic. You should never have to use it explicitly ๐Ÿ™ƒ.
  • -mlinked-fp: follows the EABI requirement of always creating a frame pointer whenever a stack frame is allocated ๐Ÿ–ผ๏ธ. This option is enabled by default and can be disabled with -mno-linked-fp ๐Ÿšซ.
  • -mlong-calls: uses indirect addressing to call functions outside the current compilation unit ๐Ÿ“ž. This allows the functions to be placed anywhere within the 32-bit address space ๐ŸŒ.
  • -malign-labels: tries to align labels to an 8-byte boundary by inserting NOPs into the previous packet ๐Ÿ“. This option only has an effect when VLIW packing is enabled. It doesn't create new packets; it just adds NOPs to existing ones ๐Ÿงฉ.
  • -mlibrary-pic: generates position-independent EABI code ๐ŸŒ.
  • -macc-4: use only the first four media accumulator registers ๐ŸŽฏ.
  • -macc-8: use all eight media accumulator registers ๐ŸŽฏ.
  • -mpack: packs VLIW instructions ๐Ÿ“ฆ.
  • -mno-pack: do not pack VLIW instructions ๐Ÿ™…โ€โ™€๏ธ.
  • -mno-eflags: do not mark ABI switches in e_flags ๐Ÿณ๏ธ.
  • -mcond-move: enables the use of conditional-move instructions (default) โœ….

Heads up: this switch is mainly for debugging the compiler and will likely be removed in a future version. ๐Ÿ›

  • -mno-cond-move: disables the use of conditional-move instructions โŒ.

Heads up: this switch is mainly for debugging the compiler and will likely be removed in a future version. ๐Ÿ›

  • -mscc: enables the use of conditional set instructions (default) โœ….

Heads up: this switch is mainly for debugging the compiler and will likely be removed in a future version. ๐Ÿ›

  • -mno-scc: disables the use of conditional set instructions โŒ.

Heads up: this switch is mainly for debugging the compiler and will likely be removed in a future version. ๐Ÿ›

  • -mcond-exec: enables the use of conditional execution (default) โœ….

Heads up: this switch is mainly for debugging the compiler and will likely be removed in a future version. ๐Ÿ›

  • -mno-cond-exec: disables the use of conditional execution โŒ.

Heads up: this switch is mainly for debugging the compiler and will likely be removed in a future version. ๐Ÿ›

  • -mvliw-branch: runs a pass to pack branches into VLIW instructions (default) ๐ŸŒ€.

Heads up: this switch is mainly for debugging the compiler and will likely be removed in a future version. ๐Ÿ›

  • -mno-vliw-branch: does not run a pass to pack branches into VLIW instructions ๐Ÿ™…โ€โ™€๏ธ.

Heads up: this switch is mainly for debugging the compiler and will likely be removed in a future version. ๐Ÿ›

  • -mmulti-cond-exec: enables optimization of "&&" and "||" in conditional execution (default) ๐Ÿง .

Heads up: this switch is mainly for debugging the compiler and will likely be removed in a future version. ๐Ÿ›

  • -mno-multi-cond-exec โ€” okay so this one switches OFF the optimization of && and || in conditional execution ๐Ÿ™ˆ It's mainly a debugging tool for the compiler and will likely be removed in a future version ๐Ÿ’€
  • -mnested-cond-exec โ€” turns ON nested conditional execution optimizations, and this is the default โœจ Also mostly for compiler debugging, so it'll likely be removed in a future version too ๐ŸŒธ
  • -mno-nested-cond-exec โ€” the opposite! It disables nested conditional execution optimizations ๐Ÿ™… Again, mainly debugging, and likely gone later ๐Ÿซถ
  • -moptimize-membar โ€” removes redundant membar instructions from the compiler-generated code. It's on by default, so you get it for free ๐Ÿ’–
  • -mno-optimize-membar โ€” disables that automatic removal of redundant membar instructions from the generated code ๐Ÿฅฒ
  • -mtomcat-stats โ€” makes gas print out tomcat statistics ๐Ÿ“Š
  • -mcpu=cpu โ€” picks the processor type you want code generated for ๐Ÿ‘‘ The possible values are frv, fr550, tomcat, fr500, fr450, fr405, fr400, fr300 and simple ๐Ÿงš

โœจ GNU/Linux Options โœจ

These -m options are defined for GNU/Linux targets ๐Ÿง

  • -mglibc โ€” uses the GNU C library. This is the default except on *-*-linux-*uclibc*, *-*-linux-*musl* and *-*-linux-*android* targets ๐Ÿ’…
  • -muclibc โ€” uses the uClibc C library. This is the default on *-*-linux-*uclibc* targets ๐ŸŒˆ
  • -mmusl โ€” uses the musl C library. This is the default on *-*-linux-*musl* targets โญ
  • -mbionic โ€” uses the Bionic C library. This is the default on *-*-linux-*android* targets ๐Ÿฆ‹
  • -mandroid โ€” compiles code that's compatible with the Android platform. This is the default on *-*-linux-*android* targets ๐Ÿค–
    • When compiling, it enables -mbionic, -fPIC, -fno-exceptions and -fno-rtti by default ๐ŸŽ€
    • When linking, it makes the GCC driver pass Android-specific options to the linker ๐Ÿ”—
    • It also causes the preprocessor macro __ANDROID__ to be defined โœจ
  • -tno-android-cc โ€” disables the compilation effects of -mandroid, i.e. it does not enable -mbionic, -fPIC, -fno-exceptions and -fno-rtti by default ๐Ÿ™…
  • -tno-android-ld โ€” disables the linking effects of -mandroid, i.e. it passes standard Linux linking options to the linker ๐Ÿงท

โœจ H8/300 Options โœจ

These -m options are defined for the H8/300 implementations ๐Ÿ”ง

  • -mrelax โ€” shortens some address references at link time, when possible. It uses the linker option -relax ๐Ÿƒ
  • -mh โ€” generates code for the H8/300H ๐Ÿ’œ
  • -ms โ€” generates code for the H8S ๐Ÿ’œ
  • -mn โ€” generates code for the H8S and H8/300H in the normal mode. This switch has to be used with either -mh or -ms ๐Ÿ“
  • -ms2600 โ€” generates code for the H8S/2600. This switch has to be used with -ms ๐ŸŒธ
  • -mexr โ€” extended registers get stored on the stack before a function with the monitor attribute runs. The default is -mexr. This option is only valid for H8S targets ๐Ÿ“š
  • -mno-exr โ€” extended registers do not get stored on the stack before a function with the monitor attribute runs. The default is -mno-exr. This option is only valid for H8S targets ๐Ÿ™ˆ
  • -mint32 โ€” makes int data 32 bits by default ๐Ÿ’–
  • -malign-300 โ€” on the H8/300H and H8S, uses the same alignment rules as the H8/300. The H8/300H and H8S normally align longs and floats on 4-byte boundaries, but -malign-300 moves them to 2-byte boundaries. This option has no effect on the H8/300 ๐Ÿง

โœจ HPPA Options โœจ

These -m options are defined for the HPPA family of computers ๐Ÿ–ฅ๏ธ

  • -march=architecture-type โ€” generates code for the specified architecture. The choices are 1.0 for PA 1.0, 1.1 for PA 1.1, and 2.0 for PA 2.0 processors ๐Ÿ—๏ธ
    • To figure out the right architecture option for your machine, check out /usr/lib/sched.models on an HP-UX system ๐Ÿ”
    • Code compiled for lower numbered architectures runs on higher numbered architectures, but not the other way around โš ๏ธ
  • -mpa-risc-1-0, -mpa-risc-1-1, -mpa-risc-2-0 โ€” synonyms for -march=1.0, -march=1.1, and -march=2.0 respectively ๐Ÿ‘ฏ
  • -mcaller-copies โ€” the caller copies function arguments that are passed by hidden reference ๐Ÿซฃ Use this with care, because it's not compatible with the default 32-bit runtime. Only aggregates larger than eight bytes get passed by hidden reference, though, and this option gives you better compatibility with OpenMP ๐Ÿงฉ
  • -mjump-in-delay โ€” this option is ignored and only provided for compatibility purposes ๐Ÿคท
  • -mdisable-fpregs โ€” stops floating-point registers from being used in any manner ๐Ÿšซ This is necessary for compiling kernels that do lazy context switching of floating-point registers. If you use this option and then try to do floating-point operations, the compiler aborts ๐Ÿ’€
  • -mdisable-indexing โ€” stops the compiler from using indexing address modes. This avoids 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 โšก
    • Such code is suitable for level 0 PA systems and kernels ๐Ÿง 
  • -mfast-indirect-calls โ€” generates code that assumes calls never cross space boundaries. This lets GCC emit code that performs faster indirect calls ๐ŸŽ๏ธ
    • This option does not work in the presence of shared libraries or nested functions ๐Ÿ™…โ€โ™€๏ธ
  • -mfixed-range=register-range โ€” generates code that treats the given register range as fixed registers. A fixed register is one the register allocator can't use, which is super handy for kernel code ๐Ÿ”’ A register range is written as two registers separated by a dash, and you can separate multiple ranges with a comma ๐ŸŽ€
  • -mlong-load-store โ€” generates 3-instruction load and store sequences, which are sometimes required by the HP-UX 10 linker. 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 for cpu-type are 700 7100, 7100LC, 7200, 7300 and 8000. Check /usr/lib/sched.models on an HP-UX system to find the right scheduling option for your machine. The default scheduling is 8000 ๐Ÿ“…
  • -mlinker-opt โ€” enables the optimization pass in the HP-UX linker ๐Ÿ› ๏ธ
โš ๏ธ Heads up bestie: this makes symbolic debugging impossible. It also triggers a bug in the HP-UX 8 and HP-UX 9 linkers, where they give bogus error messages when linking some programs ๐Ÿ˜ญ
  • -msoft-float โ€” generates output containing library calls for floating point ๐Ÿงฎ
โš ๏ธ Warning: the requisite libraries are not available for all HPPA targets. Normally the facilities of the machine's usual C compiler are used, but that can't be done directly in cross-compilation. You'll have to make your own arrangements to provide suitable library functions for cross-compilation ๐Ÿซ 

-msoft-float changes the calling convention in the output file, so it's only useful if you compile all of a program with this option. In particular, you need to compile libgcc.a, the library that comes with GCC, with -msoft-float for this to work ๐Ÿงฉ

  • -msio โ€” generates the predefine _SIO for server IO. The default is -mwsio, which generates the predefines __hp9000s700, __hp9000s700__ and _WSIO for workstation IO. These options are available under HP-UX and HI-UX ๐Ÿ–จ๏ธ
  • -mgnu-ld โ€” uses options specific to GNU ld. This passes -shared to ld when building a shared library. It's the default when GCC is configured (explicitly or implicitly) with the GNU linker ๐Ÿƒ This option doesn't affect which ld gets called. It only changes what parameters get passed to that ld. The ld that gets called is determined by the --with-ld configure option, GCC's program search path, and finally by the user's PATH. You can print the linker GCC uses with which gcc -print-prog-name=ld``. This option is only available on the 64-bit HP-UX GCC, i.e. configured with hppa*64*-*-hpux* ๐Ÿ’ซ
  • -mhp-ld โ€” uses options specific to HP ld. This passes -b to ld when building a shared library, and passes +Accept TypeMismatch to ld on all links. It's the default when GCC is configured (explicitly or implicitly) with the HP linker ๐Ÿท๏ธ Like -mgnu-ld, this option doesn't affect which ld is called. 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 over a predefined limit set by the branch type being used. The limits for normal calls are 7,600,000 and 240,000 bytes, respectively for the PA 2.0 and PA 1.X architectures. Sibcalls are always limited at 240,000 bytes ๐Ÿ“
    • Distances are measured from the beginning of functions when using the -ffunction-sections option, or when using the -mgas and -mno-portable-runtime options together under HP-UX with the SOM linker ๐Ÿงญ
    • It's normally not desirable to use this option, because it degrades performance ๐ŸŒ It may be useful in large applications, particularly when partial linking is used to build the application ๐Ÿฐ
    • The types of long calls used depend on the capabilities of the assembler and linker, and on the type of code being generated. The impact on systems that support long absolute calls, and long pic symbol-difference or pc-relative calls, should be relatively small. However, an indirect call is used on 32-bit ELF systems in pic code, and it is quite long ๐Ÿ˜

Okay so, the HP-UX stuff is next, bestie, and it's giving very specific vibes ๐Ÿงš๐Ÿ’œ

  • -munix=unix-std โ€” this one picks which UNIX standard you're vibing with ๐ŸŒธ It sets up the compiler predefines and chooses a startfile for that standard. The options are 93, 95, and 98. 93 works on every HP-UX version. 95 needs HP-UX 10.10 or later, and 98 needs HP-UX 11.11 or later. If you don't pick one, the default depends on your HP-UX version: 93 on HP-UX 10.00, 95 from HP-UX 10.10 through 11.00, and 98 on 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 ๐Ÿ‘‘
๐Ÿ˜ญ Be careful with this one, bestie! Changing the UNIX standard changes the interfaces for a bunch of library routines, and it also messes with how the C library behaves. Handle it with extreme care ๐Ÿ’€

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. Honestly, most GNU software doesn't do this yet ๐Ÿ™ˆ

  • -nolibdld โ€” stops the compiler from adding link options that search libdld.sl when you use -static on HP-UX 10 and later ๐Ÿ“
  • -static โ€” okay, the HP-UX version of setlocale in libc depends on libdld.sl, and there's no archive version of that library ๐Ÿ˜ญ So when you use -static, you need some special link options to deal with it. On HP-UX 10 and later, the GCC driver adds those options for you to link with libdld.sl. The catch is that this makes the binary dynamic. On the 64-bit port, the linkers make dynamic binaries by default anyway. If you don't want the driver adding those link options, use -nolibdld ๐Ÿฆ‹
  • -threads โ€” adds multithreading support using the DCE thread library under HP-UX. This one sets flags for both the preprocessor and the linker ๐Ÿงต

โœจ IA-64 Options โœจ

These are the -m options for the Intel IA-64 architecture ๐Ÿ’œ

  • -mbig-endian โ€” generates code for a big-endian target. This is the HP-UX default ๐ŸŒˆ
  • -mlittle-endian โ€” generates code for a little-endian target. This is the default for AIX5 and GNU/Linux ๐Ÿซถ
  • -mgnu-as, -mno-gnu-as โ€” generates (or doesn't) code for the GNU assembler. The default is -mgnu-as โœจ
  • -mgnu-ld, -mno-gnu-ld โ€” generates (or doesn't) code for the GNU linker. The default is -mgnu-ld ๐Ÿ”ฅ
  • -mno-pic โ€” generates code that doesn't use a global pointer register. Heads up: the result isn't position independent code, and it breaks the IA-64 ABI ๐Ÿ’€
  • -mvolatile-asm-stop, -mno-volatile-asm-stop โ€” generates (or doesn't) a stop bit right before and right after volatile asm statements ๐ŸŽ€
  • -mregister-names, -mno-register-names โ€” generates (or doesn't) in, loc, and out register names for the stacked registers. This can make assembler output easier to read ๐Ÿ‘€
  • -mno-sdata, -msdata โ€” disables (or enables) optimizations that use the small data section. This can be handy for working around optimizer bugs ๐Ÿ™ˆ
  • -mconstant-gp โ€” generates code that uses one constant global pointer value. This is useful when compiling kernel code ๐Ÿงš
  • -mauto-pic โ€” generates code that's self-relocatable. This one implies -mconstant-gp, and it's useful when compiling firmware code ๐Ÿ’–
  • -minline-float-divide-min-latency โ€” generates inline floating-point divides using the minimum latency algorithm ๐ŸŒธ
  • -minline-float-divide-max-throughput โ€” generates inline floating-point divides using the maximum throughput algorithm ๐ŸŒธ
  • -mno-inline-float-divide โ€” doesn't generate inline code for floating-point divides ๐Ÿšซ
  • -minline-int-divide-min-latency โ€” generates inline integer divides using the minimum latency algorithm ๐Ÿ’…
  • -minline-int-divide-max-throughput โ€” generates inline integer divides using the maximum throughput algorithm ๐Ÿ’…
  • -mno-inline-int-divide โ€” doesn't generate inline code for integer divides ๐Ÿšซ
  • -minline-sqrt-min-latency โ€” generates inline square roots using the minimum latency algorithm ๐Ÿฆ‹
  • -minline-sqrt-max-throughput โ€” generates inline square roots using the maximum throughput algorithm ๐Ÿฆ‹
  • -mno-inline-sqrt โ€” doesn't generate inline code for "sqrt" ๐Ÿšซ
  • -mfused-madd, -mno-fused-madd โ€” does (or doesn't) generate code that uses the fused multiply/add or multiply/subtract instructions. The default is to use them ๐Ÿ”ฅ
  • -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 go earlier than right before the instruction that triggered them. This can improve instruction scheduling, but it doesn't always ๐ŸŒˆ
  • -mfixed-range=register-range โ€” generates code that treats the given register range as fixed registers. A fixed register is one the register allocator can't use, which is useful for kernel code ๐Ÿ‘‘ You specify a range as two registers separated by a dash, and you can list several ranges separated by commas ๐Ÿ’œ
  • -mtls-size=tls-size โ€” sets the bit size of immediate TLS offsets. Valid values are 14, 22, and 64 โœจ
  • -mtune=cpu-type โ€” tunes the instruction scheduling for a specific CPU. Valid values are itanium, itanium1, merced, itanium2, and mckinley ๐Ÿ”ฅ
  • -milp32, -mlp64 โ€” generates code for a 32-bit or 64-bit environment. The 32-bit environment sets int, long, and pointer to 32 bits. The 64-bit environment sets int to 32 bits, and long and pointer to 64 bits. These are HP-UX specific flags ๐Ÿ“
  • -mno-sched-br-data-spec, -msched-br-data-spec โ€” (dis/en)ables data speculative scheduling before reload. This results in ld.a instructions and the matching check instructions ld.c / chk.a. It's disabled by default ๐Ÿฆ‹
  • -msched-ar-data-spec, -mno-sched-ar-data-spec โ€” (en/dis)ables data speculative scheduling after reload. This results in ld.a instructions and the matching check instructions ld.c / chk.a. It's enabled by default ๐ŸŒธ
  • -mno-sched-control-spec, -msched-control-spec โ€” (dis/en)ables control speculative scheduling. This is only available during region scheduling, which means before reload. It results in ld.s instructions and the matching check instructions chk.s. It's disabled by default ๐Ÿ’…
  • -msched-br-in-data-spec, -mno-sched-br-in-data-spec โ€” (en/dis)ables speculative scheduling of instructions that depend on data speculative loads before reload. This only works when -msched-br-data-spec is enabled. It's enabled by default ๐Ÿซถ
  • -msched-ar-in-data-spec, -mno-sched-ar-in-data-spec โ€” (en/dis)ables speculative scheduling of instructions that depend on data speculative loads after reload. This only works when -msched-ar-data-spec is enabled. It's enabled by default ๐Ÿซถ
  • -msched-in-control-spec, -mno-sched-in-control-spec โ€” (en/dis)ables speculative scheduling of instructions that depend on control speculative loads. This only works when -msched-control-spec is enabled. It's enabled by default ๐Ÿซถ
  • -mno-sched-prefer-non-data-spec-insns, -msched-prefer-non-data-spec-insns โ€” if enabled, data-speculative instructions only get scheduled when there are no other choices at the moment. This makes data speculation way more conservative. It's disabled by default ๐Ÿ™ˆ
  • -mno-sched-prefer-non-control-spec-insns, -msched-prefer-non-control-spec-insns โ€” if enabled, control-speculative instructions only get scheduled when there are no other choices at the moment. This makes control speculation way more conservative. It's disabled by default ๐Ÿ™ˆ
  • -mno-sched-count-spec-in-critical-path, -msched-count-spec-in-critical-path โ€” if enabled, speculative dependencies get counted when computing instruction priorities. This makes speculation a bit more conservative. It's disabled by default ๐ŸŒˆ
  • -msched-spec-ldc โ€” uses a simple data speculation check. This one's on by default โœจ
  • -msched-control-spec-ldc โ€” uses a simple check for control speculation. This one's on by default โœจ
  • -msched-stop-bits-after-every-cycle โ€” places a stop bit after every cycle when scheduling. This one's on by default โœจ
  • -msched-fp-mem-deps-zero-cost โ€” assumes floating-point stores and loads aren't likely to conflict when they're placed in the same instruction group. This one's disabled by default ๐Ÿ’œ
  • -msel-sched-dont-check-control-spec โ€” generates checks for control speculation in selective scheduling. This flag is disabled by default ๐Ÿ’œ
  • -msched-max-memory-insns=max-insns โ€” limits the number of memory insns per instruction group, and gives lower priority to later memory insns that try to schedule in the same group. This is often useful for preventing cache bank conflicts. The default value is 1 ๐Ÿงš
  • -msched-max-memory-insns-hard-limit โ€” turns the -msched-max-memory-insns limit into a hard limit, so no more than that number of memory insns can go in an instruction group. Otherwise the limit is "soft," which means non-memory operations get preferred once the limit is hit, but memory operations can still get scheduled ๐ŸŒธ

โœจ LM32 Options โœจ

These -m options are defined for the LatticeMico32 architecture ๐Ÿฆ‹

  • -mbarrel-shift-enabled โ€” enables barrel-shift instructions ๐Ÿ”ฅ
  • -mdivide-enabled โ€” enables divide and modulus instructions ๐Ÿ”ฅ
  • -mmultiply-enabled โ€” enables multiply instructions ๐Ÿ”ฅ
  • -msign-extend-enabled โ€” enables sign extend instructions ๐Ÿ”ฅ
  • -muser-enabled โ€” enables user-defined instructions ๐Ÿ”ฅ

โœจ M32C Options โœจ

  • -mcpu=name โ€” okay so this one picks which CPU your code gets generated for ๐ŸŽ€ name can be r8c for the R8C/Tiny series, m16c for the M16C (up to /60) series, m32cm for the M16C/80 series, or m32c for the M32C/80 series.
  • -msim โ€” this is the simulator option โœจ It links in an alternate runtime library that supports stuff like file I/O, so your program can actually do its thing while it's being tested.
โš ๏ธ bestie, do NOT use -msim when you're building for real hardware. You'll need to bring your own runtime library for whatever I/O functions you need.
  • -memregs=number โ€” this sets how many memory-based pseudo-registers GCC uses during code generation ๐Ÿ’… They act like real registers, so it's a tradeoff: GCC gets better odds of fitting your code into the registers it has, but you pay a performance penalty for leaning on memory instead.
๐Ÿ™ˆ every module in your program has to be compiled with the same number, and you should not use this option with GCC's default runtime libraries.

โœจ M32R/D Options โœจ

These -m options are defined for Renesas M32R/D architectures ๐Ÿฆ‹

  • -m32r2 โ€” generates code for the M32R/2.
  • -m32rx โ€” generates code for the M32R/X.
  • -m32r โ€” generates code for the M32R. This one's the default ๐Ÿ’–
  • -mmodel=small โ€” assumes all objects live in the lower 16MB of memory, so their addresses can be loaded with the ld24 instruction, and that all subroutines are reachable with the bl instruction. This is the default ๐Ÿ‘‘

You can set the addressability of one specific object with the model attribute.

  • -mmodel=medium โ€” assumes objects can be anywhere in the 32-bit address space (the compiler uses 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 (again with seth/add3 to load their addresses), but assumes subroutines may NOT be reachable with bl. The compiler falls back to the much slower seth/add3/jl instruction sequence ๐Ÿข
  • -msdata=none โ€” disables the small data area ๐Ÿšซ Variables get shoved into .data, .bss, or .rodata (unless you gave them a section attribute). This is the default.

The small data area is made up of the .sdata and .sbss sections. You can explicitly put objects in there by using the section attribute with one of these sections.

  • -msdata=sdata โ€” puts small global and static data in the small data area, but doesn't generate any special code to reference it.
  • -msdata=use โ€” puts small global and static data in the small data area AND generates special instructions to reference it ๐Ÿ”ฅ
  • -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 num is 8. This option only does something if -msdata is set to sdata or use.

Every module 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 throws an error message. Incorrect code is not generated, though---phew.

  • -mdebug โ€” makes the M32R-specific code in the compiler display some statistics that might help you debug your programs ๐Ÿ”
  • -malign-loops โ€” aligns all loops to a 32-byte boundary.
  • -mno-align-loops โ€” does NOT enforce a 32-byte alignment for loops. This is the default.
  • -missue-rate=number โ€” issues number instructions per cycle. number can only be 1 or 2.
  • -mbranch-cost=number โ€” number can only be 1 or 2. If it's 1, branches are preferred over conditional code. If it's 2, the opposite applies.
  • -mflush-trap=number โ€” specifies the trap number used to flush the cache. The default is 12, and valid numbers are between 0 and 15 inclusive.
  • -mno-flush-trap โ€” specifies that the cache cannot be flushed by using a trap.
  • -mflush-func=name โ€” specifies the name of the operating system function to call to flush the cache. The default is _flush_cache, but a function call is only used if a trap isn't available.
  • -mno-flush-func โ€” indicates there is no OS function for flushing the cache.

โœจ M680x0 Options โœจ

These are the -m options defined for M680x0 and ColdFire processors ๐Ÿ’œ The default settings depend on which architecture was selected when the compiler was configured. The defaults for the most common choices are given below.

  • -march=arch โ€” generates code for a specific M680x0 or ColdFire instruction set architecture. For M680x0 architectures, the permissible values of arch are: 68000, 68010, 68020, 68030, 68040, 68060 and cpu32. ColdFire architectures are selected according to Freescale's ISA classification, and the permissible values are: isaa, isaaplus, isab and isac.

GCC defines a macro __mcfarch__ whenever it's generating code for a ColdFire target. The arch in this macro is one of the -march arguments listed above ๐ŸŒธ

When you use -march and -mtune together, you get code that runs on a whole family of similar processors, but is optimized for one particular microarchitecture ๐Ÿงš

  • -mcpu=cpu โ€” generates code for a specific M680x0 or ColdFire processor. The M680x0 cpus are: 68000, 68010, 68020, 68030, 68040, 68060, 68302, 68332 and cpu32. The ColdFire cpus are given in the table below, which also sorts the CPUs into families ๐Ÿ“‹
Family : -mcpu arguments
51 : 51 51ac 51ag 51cn 51em 51je 51jf 51jg 51jm 51mm 51qe 51qm
5206 : 5202 5204 5206
5206e : 5206e
5208 : 5207 5208
5211a : 5210a 5211a
5213 : 5211 5212 5213
5216 : 5214 5216
52235 : 52230 52231 52232 52233 52234 52235
5225 : 5224 5225
52259 : 52252 52254 52255 52256 52258 52259
5235 : 5232 5233 5234 5235 523x
5249 : 5249
5250 : 5250
5271 : 5270 5271
5272 : 5272
5275 : 5274 5275
5282 : 5280 5281 5282 528x
53017 : 53011 53012 53013 53014 53015 53016 53017
5307 : 5307
5329 : 5327 5328 5329 532x
5373 : 5372 5373 537x
5407 : 5407
5475 : 5470 5471 5472 5473 5474 5475 547x 5480 5481 5482 5483 5484
5485

-mcpu=cpu overrides -march=arch if arch is compatible with cpu. Other combinations of -mcpu and -march get rejected ๐Ÿ™…โ€โ™€๏ธ

GCC defines the macro __mcf_cpu_cpu when a ColdFire target cpu is selected. It also defines __mcf_family_family, where the value of family comes from the table above.

  • -mtune=tune โ€” tunes the code for a particular microarchitecture, within the constraints set by -march and -mcpu ๐ŸŽฏ The M680x0 microarchitectures are: 68000, 68010, 68020, 68030, 68040, 68060 and cpu32. The ColdFire microarchitectures are: cfv1, cfv2, cfv3, cfv4 and cfv4e.

You can also use -mtune=68020-40 for code that needs to run relatively well on 68020, 68030 and 68040 targets. -mtune=68020-60 is similar, but it 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 the 680x0 architecture arch. It also defines mcarch unless either -ansi or a non-GNU -std option is used. If GCC is tuning for a range of architectures, as selected by -mtune=68020-40 or -mtune=68020-60, it defines the macros for every architecture in that range.

GCC also defines the macro __muarch__ when tuning for ColdFire microarchitecture uarch, where uarch is one of the arguments listed above.

  • -m68000, -mc68000 โ€” generates output for a 68000. This is the default when the compiler is configured for 68000-based systems, and it's equivalent to -march=68000.

Use this for microcontrollers with a 68000 or EC000 core, including the 68008, 68302, 68306, 68307, 68322, 68328 and 68356.

  • -m68010 โ€” generates output for a 68010. This is the default when the compiler is configured for 68010-based systems, and it's equivalent to -march=68010.
  • -m68020, -mc68020 โ€” generates output for a 68020. This is the default when the compiler is configured for 68020-based systems, and it's equivalent to -march=68020.
  • -m68030 โ€” generates output for a 68030. This is the default when the compiler is configured for 68030-based systems, and it's equivalent to -march=68030.
  • -m68040 โ€” generates output for a 68040. This is the default when the compiler is configured for 68040-based systems, and it's equivalent to -march=68040 ๐Ÿ’…

This option inhibits the use of 68881/68882 instructions that have to be emulated by software on the 68040. Use it if your 68040 doesn't have code to emulate those instructions.

  • -m68060 โ€” generates output for a 68060. This is the default when the compiler is configured for 68060-based systems, and it's equivalent to -march=68060.

This option inhibits the use of 68020 and 68881/68882 instructions that have to be emulated by software on the 68060. Use it if your 68060 doesn't have code to emulate those instructions.

  • -mcpu32 โ€” generates output for a CPU32. This is the default when the compiler is configured for CPU32-based systems, and it's equivalent to -march=cpu32.

Use this for microcontrollers with a CPU32 or CPU32+ core, including the 68330, 68331, 68332, 68333, 68334, 68336, 68340, 68341, 68349 and 68360.

  • -m5200 โ€” generates output for a 520X ColdFire CPU. This is the default when the compiler is configured for 520X-based systems. It's equivalent to -mcpu=5206, and it's now deprecated in favor of that option โš ๏ธ

Use this 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.
  • -m528x โ€” generates output for a member of the ColdFire 528X family. This option is now deprecated in favor of the equivalent -mcpu=528x.
  • -m5307 โ€” generates output for a ColdFire 5307 CPU. This option is now deprecated in favor of the equivalent -mcpu=5307.
  • -m5407 โ€” okay bestie, this one generates output for a ColdFire 5407 CPU ๐Ÿฆ‹. It's deprecated now, so just use -mcpu=5407 instead ๐Ÿซถ
  • -mcfv4e โ€” this is for the ColdFire V4e family (think 547x/548x) ๐Ÿ”ฅ. It includes hardware floating-point instructions โœจ. It's equivalent to -mcpu=547x, and it's deprecated in favor of that option ๐Ÿ’œ
  • -m68020-40 โ€” generate output for a 68040 without using 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 get emulated on the 68040. This is equivalent to -march=68020 -mtune=68020-40 ๐Ÿ’…
  • -m68020-60 โ€” same energy, but for a 68060 ๐Ÿฆ‹. The generated code runs pretty efficiently on a 68020/68881, a 68030, or a 68040, and it does use the 68881 instructions that get emulated on the 68060 ๐Ÿ’–. This is equivalent to -march=68020 -mtune=68020-60 ๐Ÿซถ
  • -mhard-float, -m68881 โ€” turns on floating-point instructions ๐Ÿ”ฅ. This is the default for 68020 and up, and for ColdFire devices that have an FPU. It defines the macro __HAVE_68881__ on M680x0 targets and __mcffpu__ on ColdFire targets ๐Ÿ‘‘
  • -msoft-float โ€” no floating-point instructions here, you get 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 โ€” generate (or don't generate) ColdFire hardware divide and remainder instructions ๐Ÿ’…. If -march is used without -mcpu, the default is "on" for ColdFire architectures and "off" for M680x0 architectures ๐Ÿ’€. Otherwise the default comes from the target CPU, either the default CPU or whichever one you picked with -mcpu. For example, the default is "off" for -mcpu=5206 and "on" for -mcpu=5206e โœจ

GCC defines the macro __mcfhwdiv__ when this option is enabled ๐Ÿ’–

  • -mshort โ€” makes int 16 bits wide, just like short int ๐Ÿ“. Parameters passed on the stack also get aligned to a 16-bit boundary, even on targets that normally promote to 32-bit โœจ
  • -mno-short โ€” int is not 16 bits wide. This is the default ๐ŸŒˆ
  • -mnobitfield, -mno-bitfield โ€” don't use the bit-field instructions ๐Ÿ™…. The -m68000, -mcpu32, and -m5200 options all imply -mnobitfield ๐Ÿ’€
  • -mbitfield โ€” do use the bit-field instructions ๐Ÿ’…. The -m68020 option implies -mbitfield. This is the default if you use a configuration designed for a 68020 ๐Ÿ‘‘
  • -mrtd โ€” a different function-calling convention ๐Ÿฆ‹. Functions that take a fixed number of arguments return with the rtd instruction, which pops their arguments while returning. This saves one instruction in the caller, since there's no need to pop the arguments there ๐Ÿงš

This calling convention is incompatible with the one normally used on Unix, so you can't use it if you need to call libraries compiled with the Unix compiler ๐Ÿ˜ญ

You must provide function prototypes for all functions that take variable numbers of arguments (including printf), otherwise incorrect code gets generated for calls to those functions ๐Ÿ’€

Seriously incorrect code results if you call a function with too many arguments. (Normally, extra arguments are harmlessly ignored.)

The rtd instruction is supported by the 68010, 68020, 68030, 68040, 68060, and CPU32 processors, but not by the 68000 or 5200 ๐ŸŒธ

The default is -mno-rtd โœจ

  • -malign-int, -mno-align-int โ€” controls whether GCC aligns int, long, long long, float, double, and long double variables on a 32-bit boundary (-malign-int) or a 16-bit boundary (-mno-align-int) ๐ŸŽ€. Aligning on 32-bit boundaries gives code that runs 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 ๐Ÿ˜ฌ
  • -mpcrel โ€” okay, this one tells GCC to use the pc-relative addressing mode of the 68000 directly, instead of a global offset table ๐Ÿฆ‹. Right now it implies -fpic, which allows at most a 16-bit offset for pc-relative addressing ๐Ÿ’œ. -fPIC isn't presently supported with -mpcrel, though it could be supported for 68020 and higher processors ๐Ÿฅบ
  • -mno-strict-align, -mstrict-align โ€” -mno-strict-align means don't assume unaligned memory references are handled by the system, and -mstrict-align means do assume that ๐Ÿซถ
  • -msep-data โ€” generates code that lets the data segment live in a different area of memory from the text segment ๐Ÿงš. This allows execute-in-place in an environment without virtual memory management โœจ. This option implies -fPIC ๐Ÿ’–
  • -mno-sep-data โ€” generates code that assumes the data segment follows the text segment. This is the default ๐ŸŒธ
  • -mid-shared-library โ€” generates code that supports shared libraries via the library ID method ๐Ÿ“š. This allows execute-in-place and shared libraries in an environment without virtual memory management ๐Ÿฆ‹. This option implies -fPIC ๐Ÿ’œ
  • -mno-id-shared-library โ€” 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 โ€” when generating position-independent code for ColdFire, this generates code that works if the GOT has more than 8192 entries ๐ŸŒˆ. That code is larger and slower than code generated without this option. On M680x0 processors this option isn't needed, since -fPIC is enough ๐Ÿ’…

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 makes the linker report an error like this:

relocation truncated to fit: R_68K_GOT16O foobar

If that happens, recompile your code with -mxgot. It should then work with very large GOTs ๐Ÿซถ. However, code generated with -mxgot is less efficient, since it takes 4 instructions to fetch the value of a global symbol ๐Ÿ˜ญ

Some linkers, including newer versions of the GNU linker, can create multiple GOTs and sort GOT entries ๐Ÿ”ฅ. If you have one of those, 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 โ€” generate code for the 210 processor ๐Ÿ’œ
  • -mno-lsim โ€” assumes runtime support has been provided, so the simulator library (libsim.a) gets omitted 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 gets placed in. name may be tiny, near, or far ๐Ÿฆ‹
  • -mclip โ€” enables the clip instruction ๐Ÿ’–. Heads up, -mclip isn't useful unless you also provide -mminmax ๐Ÿ˜ญ
  • -mconfig=name โ€” selects one of the built-in core configurations โœจ. Each MeP chip has one or more modules, and each module has a core CPU plus a variety of coprocessors, optional instructions, and peripherals ๐Ÿงฉ. The "MeP-Integrator" tool, which is not part of GCC, provides these configurations through this option. Using this option is the same as using all the corresponding command-line options ๐Ÿ’œ. The default configuration is default ๐ŸŒธ
  • -mcop โ€” enables the coprocessor instructions ๐Ÿ”ฅ. By default, this is a 32-bit coprocessor ๐Ÿ’…. Note that the coprocessor is normally enabled via the -mconfig= option ๐Ÿซถ
  • -mcop32 โ€” enables the 32-bit coprocessor's instructions ๐ŸŒˆ
  • -mcop64 โ€” enables the 64-bit coprocessor's instructions ๐ŸŒˆ
  • -mivc2 โ€” enables IVC2 scheduling ๐Ÿง . IVC2 is a 64-bit VLIW coprocessor ๐Ÿš€
  • -mdc โ€” causes constant variables to be placed in the .near section ๐ŸŽ€
  • -mdiv โ€” enables the div and divu instructions โœจ
  • -meb โ€” generates big-endian code ๐Ÿ’œ
  • -mel โ€” okay bestie, this one just says generate little-endian code ๐ŸŒธ
  • -mio-volatile โ€” tells the compiler that any variable with the "io" attribute is volatile no matter what ๐Ÿ’œ
  • -ml โ€” makes variables land in the ".far" section by default ๐Ÿฆ‹
  • -mleadz โ€” turns on the "leadz" (leading zero) instruction โœจ
  • -mm โ€” makes variables land in the ".near" section by default ๐ŸŒท
  • -mminmax โ€” unlocks the "min" and "max" instructions ๐Ÿ’…
  • -mmult โ€” unlocks the multiplication and multiply-accumulate instructions ๐Ÿ”ฅ
  • -mno-opts โ€” disables all the optional instructions that -mall-opts turned on ๐Ÿ™ˆ
  • -mrepeat โ€” unlocks the "repeat" and "erepeat" instructions, which are for low-overhead looping ๐Ÿ”
  • -ms โ€” makes all variables default to the ".tiny" section ๐Ÿงš. Heads up, this section has a 65536-byte limit, and accesses go through the %gp base register ๐Ÿ’€
  • -msatur โ€” enables the saturation instructions. Ngl, the compiler doesn't generate these on its own yet, but the option is here so it plays nice 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 leaves out the built-in support for reset and exception vectors and tables ๐ŸŽ€
  • -mtf โ€” makes all functions default to the ".far" section. Without this one, functions default to ".near" ๐Ÿฆ‹
  • -mtiny=n โ€” variables that are n bytes or smaller get put in the ".tiny" section, and they use the $gp base register. The default is 4, but remember the ".tiny" section has that 65536-byte limit too โœจ

โœจ MicroBlaze Options โœจ

  • -msoft-float โ€” uses software emulation for floating point. This is the default ๐Ÿ’–
  • -mhard-float โ€” uses hardware floating-point instructions ๐Ÿ”ฅ
  • -mmemcpy โ€” doesn't optimize block moves, and uses memcpy instead ๐Ÿงš
  • -mno-clearbss โ€” deprecated ๐Ÿ’€. Use -fno-zero-initialized-in-bss instead ๐Ÿซถ
  • -mcpu=cpu-type โ€” uses the features of, and schedules code for, the CPU you give it ๐Ÿ‘‘. Supported values look like vX.YY.Z, where X is the major version, YY is the minor version, and Z is compatibility code. Example values are v3.00.a, v4.00.b, v5.00.a, v5.00.b, and v6.00.a ๐ŸŒธ
  • -mxl-soft-mul โ€” uses software multiply emulation. This is the default ๐ŸŒท
  • -mxl-soft-div โ€” uses software emulation for divides. This is 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" and ".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 โ€” the normal executable, and the default. It uses the startup code crt0.o ๐ŸŽ€
    • -mpic-data-is-text-relative โ€” assumes the displacement between the text and data segments is fixed at static link time. This lets data be referenced by offset from the start of the text address instead of the GOT, since PC-relative addressing isn't supported ๐Ÿง 
    • xmdstub โ€” for use with the Xilinx Microprocessor Debugger (XMD) based software intrusive debug agent called xmdstub. This uses the startup file crt1.o and sets the start address of the program to 0x800 ๐Ÿž
    • bootstrap โ€” for applications loaded by a bootloader. This model uses the startup file crt2.o, which doesn't contain a processor reset vector handler. It's suitable for handing control to the bootloader on a processor reset instead of the application ๐Ÿฅพ
    • novectors โ€” for applications that don't need any of the MicroBlaze vectors. This can be handy for apps running inside a monitoring application. This model uses crt3.o as its startup file ๐Ÿ“

Option -xl-mode-app-model is a deprecated alias for -mxl-mode-app-model ๐Ÿ’€


โœจ MIPS Options โœจ

  • -EB โ€” generates big-endian code ๐ŸŒŠ
  • -EL โ€” generates little-endian code. This is the default for mips*el-*-* configurations ๐ŸŒŠ
  • -march=arch โ€” generates code that runs on arch, which can be the name of a generic MIPS ISA or the name of a particular processor ๐Ÿ‘‘. The ISA names are mips1, mips2, mips3, mips4, mips32, mips32r2, mips32r3, mips32r5, mips32r6, mips64, mips64r2, mips64r3, mips64r5, and mips64r6. The processor names are 4kc, 4km, 4kp, 4ksc, 4kec, 4kem, 4kep, 4ksd, 5kc, 5kf, 20kc, 24kc, 24kf2_1, 24kf1_1, 24kec, 24kef2_1, 24kef1_1, 34kc, 34kf2_1, 34kf1_1, 34kn, 74kc, 74kf2_1, 74kf1_1, 74kf3_2, 1004kc, 1004kf2_1, 1004kf1_1, i6400, i6500, interaptiv, loongson2e, loongson2f, loongson3a, gs464, gs464e, gs264e, m4k, m14k, m14kc, m14ke, m14kec, m5100, m5101, octeon, octeon+, octeon2, octeon3, orion, p5600, p6600, r2000, r3000, r3900, r4000, r4400, r4600, r4650, r4700, r5900, r6000, r8000, rm7000, rm9000, r10000, r12000, r14000, r16000, sb1, sr71000, vr4100, vr4111, vr4120, vr4130, vr4300, vr5000, vr5400, vr5500, xlr, and xlp. The special value from-abi picks the most compatible architecture for the selected ABI, which 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 family of processors but is optimized for one particular member of that family ๐Ÿ‘‘

-mtune defines the macros "_MIPS_TUNE" and "_MIPS_TUNE_foo", which work the same way as the -march ones described above ๐ŸŽ€

  • -mips1 โ€” equivalent to -march=mips1 ๐Ÿฆ‹
  • -mips2 โ€” equivalent to -march=mips2 ๐Ÿฆ‹
  • -mips3 โ€” equivalent to -march=mips3 ๐Ÿฆ‹
  • -mips4 โ€” equivalent to -march=mips4 ๐Ÿฆ‹
  • -mips32 โ€” equivalent to -march=mips32 ๐Ÿฆ‹
  • -mips32r3 โ€” equivalent to -march=mips32r3 ๐Ÿฆ‹
  • -mips32r5 โ€” equivalent to -march=mips32r5 ๐Ÿฆ‹
  • -mips32r6 โ€” equivalent to -march=mips32r6 ๐Ÿฆ‹
  • -mips64 โ€” equivalent to -march=mips64 ๐Ÿฆ‹
  • -mips64r2 โ€” equivalent to -march=mips64r2 ๐Ÿฆ‹
  • -mips64r3 โ€” equivalent to -march=mips64r3 ๐Ÿฆ‹
  • -mips64r5 โ€” equivalent to -march=mips64r5 ๐Ÿฆ‹
  • -mips64r6 โ€” equivalent to -march=mips64r6 ๐Ÿฆ‹
  • -mips16, -mno-mips16 โ€” generates (or doesn't generate) MIPS16 code. If GCC is targeting a MIPS32 or MIPS64 architecture, it uses the MIPS16e ASE ๐Ÿง 

MIPS16 code generation can also be controlled on a per-function basis with the "mips16" and "nomips16" attributes ๐Ÿ’œ

  • -mflip-mips16 โ€” generates MIPS16 code on alternating functions. This is provided for regression testing of mixed MIPS16/non-MIPS16 code generation, and it's not intended for ordinary use when compiling user code ๐Ÿ™ˆ
  • -minterlink-compressed, -mno-interlink-compressed โ€” requires (or doesn't require) that code using the standard (uncompressed) MIPS ISA be link-compatible with MIPS16 and microMIPS code, and vice versa ๐Ÿ”—

For example, code using the standard ISA encoding can't jump directly to MIPS16 or microMIPS code. It has to either use a call or an indirect jump. -minterlink-compressed therefore disables direct jumps unless GCC knows that the jump's target 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 select a 64-bit architecture, but you can use -mgp32 to get 32-bit code instead ๐ŸŒท

For information about the O64 ABI, see http://gcc.gnu.org/projects/mipso64-abi.html ๐Ÿ“š

GCC supports a variant of the o32 ABI in which floating-point registers are 64 rather than 32 bits wide ๐ŸŒˆ. You can select this combination with -mabi=32 -mfp64. This ABI relies on the "mthc1" and "mfhc1" instructions, so it's only supported for MIPS32R2, MIPS32R3, and MIPS32R5 processors ๐Ÿฅน

The register assignments for arguments and return values stay exactly the same ๐Ÿซถ, but each scalar value now gets packed into a single 64-bit register instead of a pair of 32-bit ones ๐Ÿ’…. Scalar floating-point values come back in $f0 only, NOT a $f0/$f1 pair โœจ. The set of call-saved registers is also unchanged, so the even-numbered double-precision registers still get saved ๐Ÿฆ‹.

Two extra flavours of the o32 ABI exist to help you hop from 32-bit to 64-bit registers ๐ŸŒˆ: FPXX (-mfpxx) and FP64A (-mfp64 -mno-odd-spreg). FPXX is the strict one ๐Ÿ˜ค. All code has to run correctly whether it's using 32-bit or 64-bit registers. FPXX code can be interlinked with FP32 or FP64, but not both ๐Ÿ’€. FP64A is basically FP64 but it forbids the odd-numbered single-precision registers ๐ŸŽ€. It pairs well with the "FRE" mode of FPUs in MIPS32R5 processors and lets FP32 and FP64A code interlink and run in the same process without changing FPU modes ๐Ÿงš.

  • -mabicalls, -mno-abicalls โ€” Okay so these tell GCC whether to generate code that fits SVR4-style dynamic objects ๐ŸŒธ. Yes or no, your call. -mabicalls is the default on SVR4-based systems โœจ.
  • -mshared, -mno-shared โ€” -mshared makes fully position-independent code that can be linked into shared libraries ๐Ÿ’œ. -mno-shared is the spicy one ๐ŸŒถ๏ธ. This option only affects -mabicalls. All -mabicalls code has traditionally been position-independent, no matter what -fPIC or -fpic say ๐Ÿ™ˆ. BUT as an extension, the GNU toolchain lets executables use absolute accesses for locally-binding symbols, use shorter GP initialization sequences, and generate direct calls to locally-defined functions. -mno-shared turns all that on ๐Ÿ”ฅ.
-mno-shared needs binutils 2.16 or higher, and the objects it makes can only be linked by the GNU linker ๐Ÿ’€. Heads up, though: the option doesn't change the ABI of the final executable. It only changes the ABI of relocatable objects ๐Ÿซถ. Using -mno-shared usually makes executables both smaller and quicker ๐Ÿƒโ€โ™€๏ธ๐Ÿ’จ.

-mshared is the default ๐Ÿ’–.

  • -mplt, -mno-plt โ€” Assume (or don't assume) that the static and dynamic linkers support PLTs and copy relocations ๐Ÿฆ‹. This only affects -mno-shared -mabicalls. For the n64 ABI, it does nothing unless you also use -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 size limits on the global offset table ๐Ÿ“.

GCC normally uses a single instruction to load values from the GOT. It's pretty efficient, but it only works if the GOT is smaller than about 64k ๐Ÿ˜ฌ. Anything bigger and the linker will 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 less efficient, since it takes three instructions to fetch the value of a global symbol ๐Ÿข.

Some linkers can create multiple GOTs. If yours is one of them, you should only need -mxgot when a single object file accesses more than 64k's worth of GOT entries. Very few linkers do ๐Ÿซฃ.

These options do nothing unless GCC is generating position-independent code ๐Ÿคทโ€โ™€๏ธ.

  • -mgp32 โ€” Assume general-purpose registers are 32 bits wide ๐Ÿ’œ.
  • -mgp64 โ€” Assume general-purpose registers are 64 bits wide ๐Ÿ‘‘.
  • -mfp32 โ€” Assume floating-point registers are 32 bits wide ๐ŸŒธ.
  • -mfp64 โ€” Assume floating-point registers are 64 bits wide ๐Ÿ”ฅ.
  • -mfpxx โ€” Don't assume any particular width for floating-point registers ๐Ÿฆ‹.
  • -mhard-float โ€” Use the floating-point coprocessor instructions ๐Ÿ’ช.
  • -msoft-float โ€” Don't use the floating-point coprocessor instructions. Instead, floating-point math gets done with library calls ๐Ÿ“š.
  • -mno-float โ€” Same as -msoft-float, but it also swears the program doesn't do any floating-point operations at all ๐Ÿคž. Right now this is only supported by some bare-metal MIPS configurations, which may pick a special set of libraries that have zero floating-point support, including things like the floating-point printf formats ๐Ÿ–จ๏ธ.
If code compiled with -mno-float accidentally has floating-point operations in it, it'll most likely crash at link time or at run time ๐Ÿ˜ญ. Don't lie to the compiler, bestie.
  • -msingle-float โ€” Assume the floating-point coprocessor only supports single-precision operations ๐ŸŽ€.
  • -mdouble-float โ€” Assume the floating-point coprocessor supports double-precision operations. This is the default ๐Ÿ’–.
  • -modd-spreg, -mno-odd-spreg โ€” Enable (or don't enable) the use of odd-numbered single-precision floating-point registers for the o32 ABI ๐Ÿฆ‹. This is the default for processors known to support these registers. When you're using the o32 FPXX ABI, -mno-odd-spreg is set by default ๐Ÿซถ.
  • -mabs=2008, -mabs=legacy โ€” These control how the special not-a-number (NaN) IEEE 754 floating-point data gets handled by the "abs.fmt" and "neg.fmt" machine instructions ๐Ÿง.

By default, or when you use -mabs=legacy, you get the legacy treatment ๐Ÿ•ฐ๏ธ. In this case those instructions count as arithmetic, so they get avoided wherever correct operation matters and the input might be a NaN. Instead, a longer sequence of instructions that manipulates the sign bit by hand is used, unless -ffinite-math-only has also been specified ๐Ÿ™ˆ.

-mabs=2008 selects the IEEE 754-2008 treatment โœจ. Here those instructions count as non-arithmetic, so they operate correctly in all cases, including when the input operand is a NaN. That's why they're always used for the respective operations ๐Ÿ‘‘.

  • -mnan=2008, -mnan=legacy โ€” These control the encoding of the special not-a-number (NaN) IEEE 754 floating-point data ๐ŸŒˆ.

-mnan=legacy selects the legacy encoding ๐Ÿ•ฐ๏ธ. Quiet NaNs (qNaNs) have the first bit of their trailing significand field set to 0, and signaling NaNs (sNaNs) have it set to 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 was configured with --with-nan=2008 ๐Ÿซถ.

  • -mllsc, -mno-llsc โ€” Use (or don't use) the ll, sc, and sync instructions to implement the atomic memory built-in functions โš›๏ธ. If you specify neither, GCC uses those instructions as long as the target architecture supports them โœจ.

-mllsc is handy if the runtime environment can emulate the instructions, and -mno-llsc can be useful when 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 details ๐Ÿ“–.

  • -mdsp, -mno-dsp โ€” Use (or don't use) revision 1 of the MIPS DSP ASE ๐ŸŽถ. This option defines the preprocessor macro "__mips_dsp". It also defines "__mips_dsp_rev" to 1 ๐Ÿ”ข.
  • -mdspr2, -mno-dspr2 โ€” Use (or don't use) revision 2 of the MIPS DSP ASE ๐ŸŽถ. This option defines the preprocessor macros "__mips_dsp" and "__mips_dspr2". It also defines "__mips_dsp_rev" to 2 ๐Ÿ”ข.
  • -msmartmips, -mno-smartmips โ€” Use (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 can only be used when generating 64-bit code, and it also requires hardware floating-point support to be enabled ๐Ÿ’ป.
  • -mips3d, -mno-mips3d โ€” Use (or don't use) the MIPS-3D ASE ๐ŸงŠ. The option -mips3d implies -mpaired-single โœจ.
  • -mmicromips, -mno-micromips โ€” Generate (or don't generate) microMIPS code ๐Ÿฃ.

You can also control microMIPS code generation on a per-function basis with the "micromips" and "nomicromips" attributes ๐ŸŽฏ.

  • -mmt, -mno-mt โ€” Use (or don't use) MT Multithreading instructions ๐Ÿงต.
  • -mmcu, -mno-mcu โ€” Use (or don't use) the MIPS MCU ASE instructions ๐Ÿ› ๏ธ.
  • -meva, -mno-eva โ€” Use (or don't use) the MIPS Enhanced Virtual Addressing instructions ๐Ÿ—บ๏ธ.
  • -mvirt, -mno-virt โ€” Use (or don't use) the MIPS Virtualization (VZ) instructions ๐Ÿ–ฅ๏ธ.
  • -mxpa, -mno-xpa โ€” Use (or don't use) the MIPS eXtended Physical Address (XPA) instructions ๐Ÿ .
  • -mcrc, -mno-crc โ€” Use (or don't use) the MIPS Cyclic Redundancy Check (CRC) instructions ๐Ÿ”.
  • -mginv, -mno-ginv โ€” Use (or don't use) the MIPS Global INValidate (GINV) instructions ๐Ÿงน.
  • -mloongson-mmi, -mno-loongson-mmi โ€” Use (or don't use) the MIPS Loongson MultiMedia extensions Instructions (MMI) ๐ŸŽž๏ธ.
  • -mloongson-ext, -mno-loongson-ext โ€” Use (or don't use) the MIPS Loongson EXTensions (EXT) instructions โž•.
  • -mloongson-ext2, -mno-loongson-ext2 โ€” Use (or don't use) the MIPS Loongson EXTensions r2 (EXT2) instructions โž•โœจ.
  • -mlong64 โ€” Force "long" types to be 64 bits wide ๐ŸŒŒ. See -mlong32 for an explanation of the default and how the pointer size gets determined ๐Ÿ‘€.
  • -mlong32 โ€” Force "long", "int", and pointer types to be 32 bits wide ๐ŸŽ€.

The default sizes of "int"s, "long"s, and pointers depend on the ABI ๐Ÿงพ. All the supported ABIs use 32-bit "int"s. The n64 ABI uses 64-bit "long"s, and so does the 64-bit EABI. The others use 32-bit "long"s ๐ŸŒท. Pointers are the same size as "long"s, or the same size as integer registers, whichever is smaller ๐Ÿ“.

  • -msym32, -mno-sym32 โ€” Assume (or don't assume) that all symbols have 32-bit values, no matter which ABI you picked ๐Ÿ”. This is useful together with -mabi=64 and -mno-abicalls, because it lets GCC generate shorter and faster references to symbolic addresses ๐ŸŽ๏ธ๐Ÿ’จ.
  • -G num โ€” Okay so this one shoves definitions of externally-visible data into a little small data section ๐Ÿงš, but only if that data is no bigger than num bytes. Bonus: GCC can then generate way more efficient accesses to the data, so check -mgpopt for the deets ๐Ÿ’–. The default -G value depends on your configuration, so it's not one-size-fits-all โœจ
  • -mlocal-sdata, -mno-local-sdata โ€” Extends (or doesn't extend) the -G behaviour to local data too, like static variables in C ๐ŸŽ€. -mlocal-sdata is the default for all configurations.
    • If the linker starts complaining that an app is using too much small data ๐Ÿ˜ญ, try rebuilding the less performance-critical parts with -mno-local-sdata.
    • You might also wanna build big libraries with -mno-local-sdata so they leave more room for the main program ๐ŸŒธ.
  • -mextern-sdata, -mno-extern-sdata โ€” Assumes (or doesn't assume) that externally-defined data lives in a small data section, as long as its size is within the -G limit ๐Ÿฆ‹. -mextern-sdata is the default for all configurations.
    • Okay this part is important ๐Ÿ’€. If you compile a module Mod with -mextern-sdata -G num -mgpopt, and Mod references a variable Var that's no bigger than num bytes, you must make sure Var gets placed in a small data section.
    • If Var is defined by another module, you either compile that module with a high-enough -G setting, or attach a "section" attribute to Var's definition.
    • If Var is common, you need to link the application with a high-enough -G setting.
    • The easiest way to keep everything happy is to compile and link every module with the same -G option ๐Ÿ‘‘. But if you're building a library that supports several different small data limits, compile it with the highest supported -G setting and also use -mno-extern-sdata. That stops the library from 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 ๐Ÿ™ˆ. Like, if the code is part of a library that might be used in a boot monitor, programs calling 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 the small data section if possible, and otherwise to data. It gives slightly slower code than the default, but it cuts down on the RAM needed while executing, so some embedded systems might prefer it ๐Ÿ“.
  • -muninit-const-in-rodata, -mno-uninit-const-in-rodata โ€” Puts uninitialized "const" variables in the read-only data section. This one is only meaningful alongside -membedded-data โœจ.
  • -mcode-readable=setting โ€” Specifies whether GCC may generate code that reads from executable sections. There are three possible settings, and they are giving options ๐ŸŒˆ:
    • -mcode-readable=yes โ€” Instructions may freely access executable sections. This is the default setting.
    • -mcode-readable=pcrel โ€” MIPS16 PC-relative load instructions can access executable sections, but other instructions must not ๐Ÿ‘€. This is useful on 4KSc and 4KSd processors when the code TLBs have the Read Inhibit bit set. It's also useful on processors that can be configured to have a dual instruction/data SRAM interface and that, like the M4K, automatically redirect PC-relative loads to the instruction RAM.
    • -mcode-readable=no โ€” Instructions must not access executable sections ๐Ÿšซ. This can be useful on targets configured 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 (or disables) use of the %hi() and %lo() assembler relocation operators. This one has been superseded by -mexplicit-relocs but is kept around for backwards compatibility ๐Ÿ•ฐ๏ธ.
  • -mexplicit-relocs, -mno-explicit-relocs โ€” Uses (or doesn't use) assembler relocation operators when dealing with symbolic addresses โœจ. The alternative, 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 you can override that at configure time using --with-divide=breaks. Divide-by-zero checks can be completely disabled with -mno-check-zero-division ๐Ÿ™…โ€โ™€๏ธ.
  • -mload-store-pairs, -mno-load-store-pairs โ€” Enables (or disables) an optimization that pairs consecutive load or store instructions to enable load/store bonding ๐Ÿ’œ. This is on by default, but it only takes effect when the selected architecture is known to support bonding.
  • -mmemcpy, -mno-memcpy โ€” Forces (or doesn't force) the use of "memcpy" for non-trivial block moves ๐Ÿ“ฆ. The default is -mno-memcpy, which lets GCC inline most constant-sized copies.
  • -mlong-calls, -mno-long-calls โ€” Disables (or doesn't disable) use of the "jal" instruction. Calling functions with "jal" is more efficient, but it requires the caller and callee to be in the same 256 megabyte segment ๐Ÿ—บ๏ธ. This option has no effect on abicalls code. The default is -mno-long-calls.
  • -mmad, -mno-mad โ€” Enables (or disables) use of the "mad", "madu" and "mul" instructions, as provided by the R4650 ISA ๐Ÿ”ฅ.
  • -mimadd, -mno-imadd โ€” Enables (or disables) use of the "madd" and "msub" integer instructions. The default is -mimadd on architectures that support "madd" and "msub", except for the 74k architecture, where it was found to generate slower code ๐Ÿข.
  • -mfused-madd, -mno-fused-madd โ€” Enables (or disables) use of the floating-point multiply-accumulate instructions, when they're available โœจ. The default is -mfused-madd.
    • Heads up ๐Ÿ˜ฌ: on the R8000 CPU, when multiply-accumulate instructions are used, the intermediate product is calculated to infinite precision and is not subject to the FCSR Flush to Zero bit. That might be undesirable in some circumstances. On other processors the result is numerically identical to the equivalent computation using separate multiply, add, subtract and negate instructions.
  • -nocpp โ€” 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 ๐ŸŒ€. Always schedule a "nop" instruction there instead. The short loop bug can, under certain conditions, make loops execute only once or twice, thanks to a hardware bug in the R5900 chip. The workaround is implemented by the assembler rather than by GCC.
  • -mfix-rm7000, -mno-fix-rm7000 โ€” 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, those functions are only provided by the mips64vr*-elf configurations. Other VR4120 errata require a NOP to be inserted between certain pairs of instructions. Those are handled by the assembler, not by GCC itself ๐Ÿ’….

  • -mfix-vr4130 โ€” Works around the VR4130 "mflo"/"mfhi" errata ๐Ÿฉน. The workarounds are implemented by the assembler rather than by GCC, although GCC avoids using "mflo" and "mfhi" if the VR4130 "macc", "macchi", "dmacc" and "dmacchi" instructions are available instead ๐Ÿฆ‹.
  • -mfix-sb1, -mno-fix-sb1 โ€” Works around certain SB-1 CPU core errata ๐Ÿ› ๏ธ. (This flag currently works around the SB-1 revision 2 "F1" and "F2" floating-point errata.)
  • -mr10k-cache-barrier=setting โ€” Specifies whether GCC should insert cache barriers to avoid the side effects of speculation on R10K processors ๐Ÿšง.

Okay so, the R10K is lowkey sneaky ๐Ÿ™ˆ Like many processors, it tries to guess which way a conditional branch will go and starts running instructions from the "taken" branch ahead of time. If the guess was wrong, it aborts those instructions. The tea is that on the R10K, even aborted instructions can leave side effects behind ๐Ÿ’€

This mostly matters for kernel stores and, depending on the system, kernel loads. Picture this: a speculatively-executed store pulls the target memory into cache and marks that cache line as dirty, even though the store gets aborted later ๐Ÿ˜ญ If a DMA operation writes to the same memory before that "dirty" line gets flushed, the cached data overwrites the DMA-ed data. Absolutely unhinged. The R10K processor manual has the full breakdown, including other potential problems, so go check it if you're curious ๐Ÿ“–

One workaround is to insert cache barrier instructions before every memory access that might get speculatively executed and that might have side effects even if it's aborted. -mr10k-cache-barrier=setting controls how GCC handles this workaround ๐Ÿ›ก๏ธ It assumes that aborted accesses to any byte in the following regions have no side effects:

  1. the memory occupied by the current function's stack frame;
  2. the memory occupied by an incoming stack argument;
  3. the memory occupied by an object with a link-time-constant address.

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 allow j foo and jal foo to be executed speculatively. GCC honors this restriction for functions it compiles itself ๐Ÿ’… It expects non-GCC functions, like hand-written assembly code, to do the same thing.

The option comes in three forms:

  • -mr10k-cache-barrier=load-store โ€” inserts a cache barrier before a load or store that might be speculatively executed and that might have side effects even if it gets aborted ๐Ÿงฑ
  • -mr10k-cache-barrier=store โ€” inserts a cache barrier before a store that might be speculatively executed and that might have side effects even if it gets aborted โœจ
  • -mr10k-cache-barrier=none โ€” disables cache barrier insertion. This is the default, so no barriers unless you ask for them ๐ŸŒธ

  • -mflush-func=func, -mno-flush-func โ€” picks the function to call for flushing the I and D caches, or tells GCC to never call one ๐Ÿงน 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 how GCC was configured, but it's commonly either _flush_func or __cpu_flush ๐Ÿฆ‹
  • mbranch-cost=num โ€” sets the cost of branches to roughly num "simple" instructions ๐Ÿ’œ This cost is only a heuristic, so it's not guaranteed to give consistent results across releases, so don't build your whole personality around it ๐Ÿ™ˆ A zero cost just redundantly selects the default, which is based on the -mtune setting.
  • -mbranch-likely, -mno-branch-likely โ€” enables or disables Branch Likely instructions, no matter what the selected architecture defaults to ๐Ÿ‘‘ By default, Branch Likely instructions may be generated if the selected architecture supports them. The exception is the MIPS32 and MIPS64 architectures, and processors that implement them. For those, Branch Likely instructions are not 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 a compact branch instruction isn't available, a delay slot form of the branch gets used instead.
    • This option is supported from MIPS Release 6 onwards ๐Ÿงš
    • -mcompact-branches=optimal uses a delay slot branch if one is available in the current ISA and the delay slot is successfully filled. If the delay slot doesn't get filled, a compact branch is chosen if one is available.
  • -mfp-exceptions, -mno-fp-exceptions โ€” specifies whether FP exceptions are enabled ๐Ÿ”ฅ This affects how FP instructions get scheduled 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, then we can use both FP pipes. Otherwise, we can only use one FP pipe ๐Ÿ’–

  • -mvr4130-align, -mno-vr4130-align โ€” the VR4130 pipeline is two-way superscalar, but it can only issue two instructions together if the first one is 8-byte aligned ๐Ÿ“ When this option is enabled, GCC aligns pairs of instructions that it thinks should execute in parallel.

This option only has an effect when you're optimizing for the VR4130. It normally makes code faster, but at the expense of making it bigger ๐Ÿ“ It's enabled by default at optimization level -O3.

  • -msynci, -mno-synci โ€” enables (or disables) generation of synci instructions on architectures that support them ๐ŸŒˆ The synci instructions, if enabled, are generated when __builtin___clear_cache gets compiled.

This option defaults to -mno-synci, but you can override the default by configuring GCC with --with-synci โš™๏ธ

When compiling code for single processor systems, it's generally safe to use synci. However, on many multi-core (SMP) systems, it does not invalidate the instruction caches on all cores and may lead to undefined behavior. Be careful, bestie ๐Ÿ˜ญ
  • -mrelax-pic-calls, -mno-relax-pic-calls โ€” tries to turn PIC calls that are normally dispatched via register $25 into direct calls โœจ This is only possible if the linker can resolve the destination at link time, and if the destination is within range for a direct call.

-mrelax-pic-calls is the default if GCC was configured to use an assembler and a linker that support the .reloc assembly directive, and -mexplicit-relocs is in effect. With -mno-explicit-relocs, this optimization can be performed by the assembler and the linker alone, without help from the compiler ๐Ÿฆ‹

  • -mmcount-ra-address, -mno-mcount-ra-address โ€” emits (or does not emit) code that lets _mcount modify the calling function's return address ๐Ÿ”ฎ When enabled, this option extends the usual _mcount interface with a new ra-address parameter. It has type intptr_t * and gets passed in register $12. _mcount can then modify the return address by doing both of the following:
    • Returning the new address in register $31.
    • Storing the new address in *ra-address, if ra-address is nonnull.

The default is -mno-mcount-ra-address ๐Ÿ’…

  • -mframe-header-opt, -mno-frame-header-opt โ€” enables (or disables) frame header optimization in the o32 ABI ๐Ÿงบ When you use the o32 ABI, calling functions allocate 16 bytes on the stack for the called function to write out register arguments. When this optimization is enabled, it suppresses the allocation of the frame header if it can be determined that the header is unused.

This optimization is off by default at all optimization levels ๐Ÿ™ƒ

  • -mlxc1-sxc1, -mno-lxc1-sxc1 โ€” when applicable, enables (or disables) generation of lwxc1, swxc1, ldxc1, and sdxc1 instructions. Enabled by default ๐ŸŒŸ
  • -mmadd4, -mno-madd4 โ€” when applicable, enables (or disables) generation of 4-operand madd.s, madd.d, and related instructions. Enabled by default ๐Ÿ’œ

โœจ MMIX Options โœจ

These options are defined for the MMIX ๐ŸŒŒ

  • -mlibfuncs, -mno-libfuncs โ€” specifies that intrinsic library functions are being compiled, passing all values in registers, no matter the size ๐Ÿ“š
  • -mepsilon, -mno-epsilon โ€” generates floating-point comparison instructions that compare with respect to the rE epsilon register ๐Ÿงฎ
  • -mabi=mmixware, -mabi=gnu โ€” -mabi=mmixware generates code that passes function parameters and return values which, in the called function, are seen as registers $0 and up. The GNU ABI, by contrast, uses global registers $231 and up ๐ŸŒ€
  • -mzero-extend, -mno-zero-extend โ€” when reading data from memory in sizes shorter than 64 bits, uses (or doesn't use) zero-extending load instructions by default, instead of sign-extending ones ๐Ÿซง
  • -mknuthdiv, -mno-knuthdiv โ€” makes the result of a division that yields a remainder have the same sign as the divisor. With the default, -mno-knuthdiv, the sign of the remainder follows the sign of the dividend. Both methods are arithmetically valid, though the latter is almost exclusively used ๐Ÿค“
  • -mtoplevel-symbols, -mno-toplevel-symbols โ€” prepends (or doesn't prepend) a : to all global symbols, so the assembly code can be used with the PREFIX assembly directive ๐ŸŽฏ
  • -melf โ€” generates an executable in the ELF format, instead of the default mmo format used by the mmix simulator ๐Ÿš
  • -mbranch-predict, -mno-branch-predict โ€” uses (or doesn't use) the probable-branch instructions when static branch prediction indicates a probable branch ๐Ÿ”€
  • -mbase-addresses, -mno-base-addresses โ€” generates (or doesn't generate) code that uses base addresses ๐Ÿ  Using a base address automatically generates a request, handled by the assembler and the linker, for a constant to be set up in a global register. That register is used for one or more base address requests within the range 0 to 255 from the value held in the register. This generally leads to short and fast code, but the number of different data items that can be addressed is limited. So a program that uses lots of static data may require -mno-base-addresses ๐Ÿฅน
  • -msingle-exit, -mno-single-exit โ€” forces (or doesn't force) generated code to have a single exit point in each function ๐Ÿšช

๐ŸŒธ MN10300 Options ๐ŸŒธ

These -m options are defined for Matsushita MN10300 architectures ๐Ÿ‡ฏ๐Ÿ‡ต

  • -mmult-bug โ€” generates code to avoid bugs in the multiply instructions for the MN10300 processors. This is the default ๐Ÿ› ๏ธ
  • -mno-mult-bug โ€” skip the workaround ๐Ÿ™… Don't generate code to dodge the bugs in the multiply instructions on the MN10300 processors.
  • -mam33 โ€” Generate code using features specific to the AM33 processor โœจ
  • -mno-am33 โ€” No AM33-only features, thanks ๐Ÿ’… This is the default.
  • -mam33-2 โ€” Generate code using features specific to the AM33/2.0 processor ๐Ÿฆ‹
  • -mam34 โ€” Generate code using features specific to the AM34 processor ๐ŸŒธ
  • -mtune=cpu-type โ€” Schedule instructions using the timing characteristics of the CPU type you name, but it doesn't change the targeted processor type, so it's more of a vibe-matching move than a glow-up ๐Ÿงš The CPU type must be one of mn10300, am33, am33-2 or am34.
  • -mreturn-pointer-on-d0 โ€” When a function returns a pointer, the pointer comes back in both "a0" and "d0" ๐Ÿ’– Otherwise it only comes back in "a0", and calling those functions without a prototype throws errors ๐Ÿ’€ This option is on by default. 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 only does something when you use it on the command line for the final link step.
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 also defines the preprocessor macro "__LIW__".
  • -mno-liw โ€” No Long Instruction Word instructions from the compiler ๐Ÿ™… 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 โ€” The compiler can't generate SETLB or Lcc instructions ๐Ÿ“ It defines the preprocessor macro "__NO_SETLB__".

๐Ÿฆ‹ Moxie Options ๐Ÿฆ‹

  • -meb โ€” Generate big-endian code. This is the default for moxie-*-* configurations ๐Ÿ‘‘
  • -mel โ€” Generate little-endian code โœจ
  • -mmul.x โ€” Generate mul.x and umul.x instructions. This is the default for moxiebox-*-* configurations ๐Ÿ”ฅ
  • -mno-crt0 โ€” Don't link in the C run-time initialization object file ๐Ÿซถ

๐Ÿ’œ MSP430 Options ๐Ÿ’œ

These options are defined for the MSP430 ๐Ÿงš

  • -masm-hex โ€” Force assembly output to always use hex constants. Normally those constants are signed decimals, but this option is there for testsuite and/or aesthetic purposes ๐ŸŽ€
  • -mmcu= โ€” Picks the MCU you want to target ๐ŸŽฏ It's turned into a C preprocessor symbol based on the MCU name, converted to upper case and pre- and post-fixed with __. The msp430.h header uses that symbol to choose an MCU-specific supplementary header file.

The option also sets the ISA. If the MCU name belongs to one that only supports the 430 ISA, that's the one selected. Otherwise the 430X ISA gets picked. The generic MCU name msp430 also selects the 430 ISA, and the generic msp430x MCU name selects the 430X ISA.

An MCU-specific linker script also gets added to the linker command line. The script's name is the MCU name with .ld appended. So specifying -mmcu=xxx on the gcc command line defines the C preprocessor symbol "__XXX__" and makes the linker search for a script called xxx.ld ๐Ÿ’–

The ISA and hardware multiply support for the different MCUs is hard-coded into GCC. However, an external devices.csv file can be used to extend device support beyond those that have been hard-coded ๐ŸŒธ

GCC searches for the devices.csv file using the following methods in the given precedence order. The first method beats the second, and the second beats the third:

  1. Include path specified with "-I" and "-L" โ€” devices.csv gets searched for in each of the directories specified by include paths and linker library search paths.
  2. Path specified by the environment variable MSP430_GCC_INCLUDE_DIR โ€” 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 devices.csv. If devices.csv is found, this directory also gets registered as an include path and linker library path. Header files and linker scripts in this directory can therefore be used without manually specifying "-I" and "-L" on the command line ๐Ÿฆ‹
  3. The msp430-elf{,bare}/include/devices directory โ€” Finally, GCC will check 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. As above, this directory also gets 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 to -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 is on by default ๐Ÿ‘€
  • -mcpu= โ€” Specifies the ISA to use. Accepted values are msp430, msp430x and msp430xv2. This option is deprecated, so use -mmcu= to select the ISA instead ๐Ÿ’€
  • -msim โ€” Links to the simulator runtime libraries and linker script. This overrides any scripts that would be selected by the -mmcu= option ๐Ÿงธ
  • -mlarge โ€” Use large-model addressing: 20-bit pointers and a 20-bit "size_t" ๐ŸŒˆ
  • -msmall โ€” Use small-model addressing: 16-bit pointers and a 16-bit "size_t" ๐ŸŒ™
  • -mrelax โ€” This is 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 are none for no hardware multiply, 16bit for the original 16-bit-only multiply supported by early MCUs, 32bit for the 16/32-bit multiply supported by later MCUs, and f5series for the 16/32-bit multiply supported by F5-series MCUs. You can also give a value of auto, which tells GCC to deduce the hardware multiply support from the MCU name provided by the -mmcu option. If no -mmcu option is specified, or the MCU name isn't recognized, then 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, however, the hardware multiplier is invoked inline. This makes for bigger, but faster, code ๐ŸŽ๏ธ

The hardware multiply routines disable interrupts while they run and restore the previous interrupt state when they finish. This makes them safe to use inside interrupt handlers as well as in normal code ๐Ÿซถ

  • -minrt โ€” Enables a minimum runtime environment with no static initializers or constructors. This is meant for memory-constrained devices ๐Ÿง  The compiler includes special symbols in some objects that tell the linker and runtime which code fragments are required.
  • -mtiny-printf โ€” Enables reduced code size "printf" and "puts" library functions โœจ The tiny implementations of these functions are not reentrant, so use them with caution in multi-threaded applications โš ๏ธ

Support for streams has been removed, and the string to be printed will always be sent to stdout via the "write" syscall. The string is not 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= โ€” This 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, like all shifts greater than 1 on the 430 ISA.

Shifts of a 32-bit value are at least twice as costly, so the value 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 ๐Ÿ—บ๏ธ The possible values are "lower", "upper", "either" or "any". The first three behave like the corresponding attribute. The fourth value, "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= โ€” Passes a request to the assembler to enable warning messages when a silicon errata might need to be applied ๐Ÿšจ
  • -mwarn-devices-csv, -mno-warn-devices-csv โ€” Warns if devices.csv is not found or there are problems parsing it (default: on) ๐Ÿ“„

๐ŸŒˆ NDS32 Options ๐ŸŒˆ

These options are defined for NDS32 implementations ๐Ÿ’–

  • -mbig-endian โ€” Generate code in big-endian mode ๐ŸŒธ
  • -mlittle-endian โ€” Generate code in little-endian mode ๐Ÿฆ‹
  • -mreduced-regs โ€” Use reduced-set registers for register allocation โœจ
  • -mfull-regs โ€” Use full-set registers for register allocation ๐Ÿ‘‘
  • -mcmov โ€” Generate conditional move instructions ๐Ÿ”ฅ
  • -mno-cmov โ€” Don't generate conditional move instructions ๐Ÿ™…
  • -mext-perf โ€” Generate performance extension instructions ๐Ÿš€
  • -mno-ext-perf โ€” Don't generate performance extension instructions ๐Ÿ’…
  • -mext-perf2 โ€” Generate performance extension 2 instructions ๐Ÿงš
  • -mno-ext-perf2 โ€” Bestie, this one says NO to performance extension 2 instructions. They won't be generated. ๐Ÿ’…
  • -mext-string โ€” Turns on string extension instructions. โœจ
  • -mno-ext-string โ€” Keeps string extension instructions OFF. ๐Ÿ™ˆ
  • -mv3push โ€” Generates v3 push25/pop25 instructions. ๐ŸŽ€
  • -mno-v3push โ€” No push25/pop25 instructions for you, v3 or otherwise. ๐ŸŒธ
  • -m16-bit โ€” Generates 16-bit instructions. Compact and cute. ๐Ÿฆ‹
  • -mno-16-bit โ€” Skips the 16-bit instructions entirely. ๐Ÿ’€
  • -misr-vector-size=num โ€” Sets the size of each interrupt vector. It has to be either 4 or 16, no in-between vibes. ๐Ÿ‘‘
  • -mcache-block-size=num โ€” Sets the size of each cache block. It must 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 must fit in a 512KB addressing space. The text segment must fit in a 16MB addressing space. ๐Ÿ“
    • medium โ€” The data segment must fit in 512KB, but the read-only data segment can stretch across a 4GB addressing space. The text segment should still stay within 16MB. ๐Ÿซถ
    • large โ€” All the text and data segments can live in a 4GB addressing space. Big main character energy. ๐Ÿ‘‘
  • -mctor-dtor โ€” Enables the constructor/destructor feature. โญ
  • -mrelax โ€” Guides the linker to relax instructions. ๐Ÿ’œ

๐Ÿงš Nios II Options

Okay so these are the options defined for the Altera Nios II processor. Let's gooo. ๐Ÿ”ฅ

  • -G num โ€” Puts global and static objects that are num bytes or smaller into the small data or BSS sections, instead of the normal data or BSS sections. The default value of num is 8. ๐ŸŽ€
  • -mgpopt=option, -mgpopt, -mno-gpopt โ€” Generates (or doesn't generate) GP-relative accesses. These option names are recognized:
    • none โ€” No GP-relative accesses. Not it. ๐Ÿ™ˆ
    • 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 that were explicitly placed in a small data section with a "section" attribute. ๐ŸŒธ
    • global โ€” Same as local, but 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. Don't skip this, bestie. โš ๏ธ
    • data โ€” Generates GP-relative accesses for all data objects in the program. If you use this, the entire data and BSS segments of your program must fit in 64K of memory, and you need an appropriate linker script to allocate them within the addressable range of the global pointer. ๐Ÿฆ‹
    • all โ€” Generates GP-relative addresses for function pointers as well as data pointers. If you use this, the entire text, data, and BSS segments of your program must fit in 64K of memory, and you need an appropriate linker script to allocate them within the addressable range of the global pointer. ๐Ÿงš

-mgpopt is equivalent to -mgpopt=local, and -mno-gpopt is equivalent to -mgpopt=none.

The default is -mgpopt, except when -fpic or -fPIC is specified to generate position-independent code. Heads up: the Nios II ABI does not allow GP-relative accesses from shared libraries. ๐Ÿ’…

You might need to specify -mno-gpopt explicitly when building programs that have lots of small data, including large GOT data sections. In that case, the 16-bit offset for GP-relative addressing may not be big enough to reach the entire small data section. ๐Ÿ˜ญ

  • -mgprel-sec=regexp โ€” This option adds extra 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. ๐ŸŒˆ

It doesn't change how -G behaves. The sections you list are in addition to the standard .sdata and .sbss small-data sections that -mgpopt already recognizes.

  • -mr0rel-sec=regexp โ€” This option names sections that can be reached through a 16-bit offset from r0, meaning the low 32K or high 32K of the 32-bit address space. It's most useful alongside "section" attributes on variable declarations and a custom linker script. The regexp is a POSIX Extended Regular Expression. โœจ

Unlike GP-relative addressing for small data, zero-based addressing is never generated by default. Also, there are no conventional section names used in standard linker scripts for the low or high areas of memory. ๐Ÿ™ˆ

  • -mel, -meb โ€” Generates little-endian (the default) or big-endian (experimental) code, respectively. ๐Ÿซถ
  • -march=arch โ€” Names the target Nios II architecture. GCC uses this name to figure out what kinds of instructions it can emit when generating assembly code. Permissible names are r1 and r2. ๐Ÿ‘‘

The preprocessor macro __nios2_arch__ is available to your programs. Its value is 1 or 2, which tells you the targeted ISA level. ๐Ÿ”ฅ

  • -mbypass-cache, -mno-bypass-cache โ€” Forces all load and store instructions to always bypass the cache by using the I/O variants of the instructions. The default is not to bypass the cache. ๐Ÿฆ‹
  • -mno-cache-volatile, -mcache-volatile โ€” Volatile memory accesses bypass the cache by 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 โ€” Don't use the 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 to not emit div and mulx. ๐Ÿ’œ
  • -mbmx, -mno-bmx, -mcdx, -mno-cdx โ€” Enables or disables generation of Nios II R2 BMX (bit manipulation) and CDX (code density) instructions. Turning these on also requires -march=r2. Since these instructions are optional extensions to the R2 architecture, the default is not to emit them. ๐ŸŒˆ
  • -mcustom-insn=N, -mno-custom-insn โ€” Each -mcustom-insn=N option enables use of a custom instruction with encoding N when generating code that uses insn. For example, -mcustom-fadds=253 generates custom instruction 253 for single-precision floating-point add operations, instead of the default behavior of using a library call. โœจ

These are the supported values of insn. Unless noted otherwise, floating-point operations are expected to use normal IEEE 754 semantics and correspond directly to the C operators or the equivalent GCC built-in functions. ๐Ÿค“

๐ŸŒธ Single-precision floating point

  • fadds, fsubs, fdivs, fmuls โ€” Binary arithmetic operations.
  • fnegs โ€” Unary negation.
  • fabss โ€” Unary absolute value.
  • fcmpeqs, fcmpges, fcmpgts, fcmples, fcmplts, fcmpnes โ€” Comparison operations.
  • fmins, fmaxs โ€” Floating-point minimum and maximum. These instructions are only generated if -ffinite-math-only is specified. ๐Ÿฆ‹
  • fsqrts โ€” Unary square root operation.
  • fcoss, fsins, ftans, fatans, fexps, flogs โ€” Floating-point trigonometric and exponential functions. These instructions are only generated if -funsafe-math-optimizations is also specified. ๐Ÿงš

๐ŸŽ€ Double-precision floating point

  • faddd, fsubd, fdivd, fmuld โ€” Binary arithmetic operations.
  • fnegd โ€” Unary negation.
  • fabsd โ€” Unary absolute value.
  • fcmpeqd, fcmpged, fcmpgtd, fcmpled, fcmpltd, fcmpned โ€” Comparison operations.
  • fmind, fmaxd โ€” Double-precision minimum and maximum. These instructions are only generated if -ffinite-math-only is specified. ๐Ÿ’…
  • fsqrtd โ€” Unary square root operation.
  • fcosd, fsind, ftand, fatand, fexpd, flogd โ€” Double-precision trigonometric and exponential functions. These instructions are only generated if -funsafe-math-optimizations is also specified. ๐Ÿ‘‘

๐Ÿ”ฅ Conversions

  • fextsd โ€” Converts single precision to double precision.
  • ftruncds โ€” Converts 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. ๐Ÿซถ

In addition, all of the following transfer instructions for the internal registers X and Y must be provided to use any of the double-precision floating-point instructions. ๐Ÿง 

Custom instructions that take two double-precision source operands expect the first operand in the 64-bit register X. The other operand (or the only operand of a unary operation) is given to the custom arithmetic instruction with the least significant half in source register src1 and the most significant half in src2. A custom instruction that returns a double-precision result returns the most significant 32 bits in the destination register, and the other half in 32-bit register Y. GCC automatically generates the necessary code sequences to write register X and/or read register Y when double-precision floating-point instructions are used. You don't have to do any of that 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 significant half (respectively) of X and stores it in dest.
  • frdy โ€” Reads the value of Y and stores it into dest.

Note that you can get more local control over the generation of Nios II custom instructions by using the target("custom-insn=N") and target("no-custom-insn") function attributes or pragmas. ๐Ÿ’–

-mcustom-fpu-cfg=name Okay so this option is bestie's go-to for picking a whole pre-made bundle of custom instruction encodings, named and everything ๐Ÿ’… (it builds on the -mcustom-insn stuff from above โœจ). Right now these sets exist:

-mcustom-fpu-cfg=60-1 is the same as: -mcustom-fmuls=252 -mcustom-fadds=253 -mcustom-fsubs=254 -fsingle-precision-constant

-mcustom-fpu-cfg=60-2 is the same as: -mcustom-fmuls=252 -mcustom-fadds=253 -mcustom-fsubs=254 -mcustom-fdivs=255 -fsingle-precision-constant

-mcustom-fpu-cfg=72-3 is the same as: -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 the same as: -mcustom-fabss=224 -mcustom-fnegs=225 -mcustom-fcmpnes=226 -mcustom-fcmpeqs=227 -mcustom-fcmpges=228 -mcustom-fcmpgts=229 -mcustom-fcmples=230 -mcustom-fcmplts=231 -mcustom-fmaxs=232 -mcustom-fmins=233 -mcustom-round=248 -mcustom-fixsi=249 -mcustom-floatis=250 -mcustom-fsqrts=251 -mcustom-fmuls=252 -mcustom-fadds=253 -mcustom-fsubs=254 -mcustom-fdivs=255

Heads up, bestie: any custom instruction you set with an individual -mcustom-insn= option wins over what -mcustom-fpu-cfg= gives you, no matter what order you typed them in on the command line ๐Ÿซถ

Want even more local control? You can pick an FPU configuration just for one spot in your code with the target("custom-fpu-cfg=name") function attribute or pragma ๐Ÿฆ‹

The name fph2 is short for Nios II Floating Point Hardware 2 Component ๐ŸŒธ

Quick warnings, because I love you ๐Ÿ˜ญ:

  • The custom instructions for -mcustom-fmins=233 and -mcustom-fmaxs=234 only get generated if you also use -ffinite-math-only ๐Ÿ™ˆ
  • The custom instruction for -mcustom-round=248 only gets generated if you use -fno-math-errno ๐Ÿ’€
  • Unlike all the other configs, -fsingle-precision-constant is NOT set for fph2 ๐ŸŽ€

โœจ These extra -m options are for the Altera Nios II ELF (bare-metal) target โœจ

These are the extra -m options that work with the Altera Nios II ELF (bare-metal) target ๐Ÿงš

  • -mhal โ€” Links with the HAL BSP ๐Ÿ’– This skips the GCC-provided C runtime startup and termination code, and it's usually paired with -msys-crt0= so you can point to the alternate startup code the HAL BSP brings along.
  • -msmallc โ€” Links with a limited version of the C library, -lsmallc, instead of Newlib ๐ŸŒˆ
  • -msys-crt0=startfile โ€” startfile is the name of the startfile (crt0) you want when linking ๐Ÿ“ This only does anything when you're also using -mhal.
  • -msys-lib=systemlib โ€” systemlib is the name of the library that gives you the low-level system calls the C library needs, like "read" and "write" ๐Ÿฆ‹ You'll usually use this to link against a library from a HAL BSP.

๐Ÿ’œ Nvidia PTX Options ๐Ÿ’œ

These options are defined for Nvidia PTX ๐Ÿ”ฅ

  • -m64 โ€” Ignored, but kept around for backward compatibility ๐Ÿซถ Only the 64-bit ABI is supported.
  • -misa=ISA-string โ€” Generates code for the PTX ISA you pick (like sm_35) โœจ ISA strings have to be lower-case. Valid ones include sm_30 and sm_35, and the default is sm_35.
  • -mmainkernel โ€” Links in code for a __main kernel ๐Ÿ‘‘ This is for stand-alone execution instead of offloading.
  • -moptimize โ€” Applies partitioned execution optimizations ๐Ÿ’… This is the default whenever any level of optimization is turned on.
  • -msoft-stack โ€” Generates code that doesn't use .local memory directly for stack storage ๐ŸŒธ Instead, a per-warp stack pointer is maintained explicitly. This lets you do variable-length stack allocation (with variable-length arrays or "alloca"), and when global memory is the underlying storage, you can access automatic variables from other threads or with atomic instructions ๐Ÿ˜ญ This code generation variant is used for OpenMP offloading, but the option is exposed on its own so the compiler can be tested. If you want code that links 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 memory state and side effects still behave as if only one thread per warp was active outside OpenMP SIMD regions ๐Ÿงš All atomic operations and calls to the runtime (malloc, free, vprintf) only run conditionally (if the current lane index equals the master lane index), and the register being assigned is copied from the master lane with a shuffle instruction. Outside SIMD regions, lane 0 is the master; inside them, each thread sees itself as the master ๐Ÿ’– A shared memory array int __nvptx_uni[] stores all-zeros or all-ones bitmasks for each warp to show the current mode (0 outside SIMD regions). Each thread can bitwise-and the bitmask at position "tid.y" with the current lane index to compute the master lane index ๐Ÿค“
  • -mgomp โ€” Generates code for OpenMP offloading ๐Ÿ“ It turns on -msoft-stack and -muniform-simt and picks the matching multilib variant.

๐ŸŒˆ OpenRISC Options ๐ŸŒˆ

These options are defined for OpenRISC ๐Ÿฆ‹

  • -mboard=name โ€” Configures a board-specific runtime ๐ŸŒธ This gets passed to the linker for newlib board library linking. The default is "or1ksim".
  • -mnewlib โ€” Ignored, it's only here for compatibility ๐Ÿ’… It used to pick linker and preprocessor options for newlib.
  • -msoft-div, -mhard-div โ€” Picks software or hardware divide ("l.div", "l.divu") instructions โœจ The default is hardware divide.
  • -msoft-mul, -mhard-mul โ€” Picks software or hardware multiply ("l.mul", "l.muli") instructions ๐Ÿ’– The default is hardware multiply.
  • -msoft-float, -mhard-float โ€” Picks software or hardware for floating point operations ๐Ÿซถ The default is software.
  • -mdouble-float โ€” When -mhard-float is selected, this turns on generation of double-precision floating point instructions ๐Ÿ”ฅ By default, functions from libgcc handle double-precision floating point operations.
  • -munordered-float โ€” When -mhard-float is selected, this turns on generation of unordered floating point compare and set flag ("lf.sfun*") instructions ๐Ÿงš By default, functions from libgcc handle unordered floating point compare and set flag operations.
  • -mcmov โ€” Turns on generation of conditional move ("l.cmov") instructions ๐ŸŽ€ By default, the equivalent is generated using set and branch.
  • -mror โ€” Turns on generation of rotate right ("l.ror") instructions ๐ŸŒˆ By default, functions from libgcc handle rotate right operations.
  • -mrori โ€” Turns on generation of rotate right with immediate ("l.rori") instructions โญ By default, functions from libgcc handle rotate right with immediate operations.
  • -msext โ€” Turns on generation of sign extension ("l.ext*") instructions ๐Ÿ’… By default, memory loads handle sign extension.
  • -msfimm โ€” Turns on generation of compare and set flag with immediate ("l.sf*i") instructions โœจ By default, extra instructions are generated to store the immediate in a register first.
  • -mshftimm โ€” Turns on generation of shift with immediate ("l.srai", "l.srli", "l.slli") instructions ๐Ÿ“ By default, extra instructions are generated to store the immediate in a register first.

๐Ÿฆ‹ PDP-11 Options ๐Ÿฆ‹

These options are defined for the PDP-11 ๐Ÿงš

  • -mfpu โ€” Uses hardware FPP floating point ๐Ÿ’– This is the default. (FIS floating point on the PDP-11/40 isn't supported, bestie ๐Ÿ˜ญ) Implies -m45.
  • -msoft-float โ€” Doesn't use hardware floating point ๐Ÿซถ
  • -mac0 โ€” Returns floating-point results in ac0 (fr0 in Unix assembler syntax) ๐ŸŒธ
  • -mno-ac0 โ€” Returns floating-point results in memory ๐Ÿ’… This is the default.
  • -m40 โ€” Generates code for a PDP-11/40 โœจ Implies -msoft-float -mno-split.
  • -m45 โ€” Generates code for a PDP-11/45 ๐Ÿ‘‘ This is the default.
  • -m10 โ€” Generates code for a PDP-11/10 ๐ŸŒˆ Implies -msoft-float -mno-split.
  • -mint16, -mno-int32 โ€” Uses 16-bit "int" ๐Ÿ’œ This is the default.
  • -mint32, -mno-int16 โ€” Uses 32-bit "int" ๐Ÿ”ฅ
  • -msplit โ€” The target has split instruction and data space ๐Ÿ“ Implies -m45.
  • -munix-asm โ€” Uses Unix assembler syntax ๐Ÿงš
  • -mdec-asm โ€” Uses DEC assembler syntax ๐ŸŽ€
  • -mgnu-asm โ€” Uses GNU assembler syntax ๐ŸŒธ This is the default.
  • -mlra โ€” Uses the new LRA register allocator ๐Ÿฆ‹ By default, the old "reload" allocator is used.

๐Ÿ“ picoChip Options ๐Ÿ“

These -m options are defined for picoChip implementations ๐Ÿ’–

  • -mae=ae_type โ€” Sets the instruction set, register set, and instruction scheduling parameters for array element type ae_type โœจ Supported values for ae_type are ANY, MUL, and MAC.
    • -mae=ANY picks a completely generic AE type ๐Ÿซถ Code generated with this option runs on any of the other AE types. It's not as efficient as code compiled for a specific AE type, and some operations (e.g., multiplication) don't work properly on all AE types ๐Ÿ˜ญ
    • -mae=MUL picks a MUL AE type ๐Ÿ”ฅ This is the most useful AE type for compiled code, and it's the default.
    • -mae=MAC picks a DSP-style MAC AE ๐Ÿ’€ Code compiled with this option may have poor performance for byte (char) manipulation, since the DSP AE doesn't have hardware support for byte load/stores.
  • -msymbol-as-address โ€” Lets the compiler use a symbol name directly as an address in a load/store instruction, without loading it into a register first ๐ŸŒˆ This usually makes bigger programs that run faster, but the results vary from program to program, so it's a user option instead of being permanently on ๐Ÿ™ˆ
  • -mno-inefficient-warnings โ€” Disables warnings about generating inefficient code ๐Ÿงš These warnings can show up when you compile code that does byte-level memory operations on the MAC AE type. The MAC AE has no hardware support for byte-level memory operations, so every byte load/store has to be synthesized from word load/store operations. That's inefficient, so GCC warns you to rewrite the code to avoid byte operations or to target an AE type with the right hardware support. This option turns those warnings off ๐Ÿ’…

PowerPC Options

These are listed under

โœจ PRU Options โœจ

okay so these command-line options are specifically for the PRU target, so only use them if you're building for PRU ๐Ÿ’…

  • -minrt โ€” Links you with a minimum runtime ๐Ÿงš There's no support for static initializers and constructors, and using it can seriously shrink your final ELF binary. Heads up though, the compiler could still generate code with static initializers and constructors, so it's on you to make sure your source doesn't use those features ๐Ÿซถ
  • -mmcu=mcu โ€” Picks the PRU MCU variant you want. For the full list of supported MCUs, check Newlib ๐Ÿ“–
  • -mno-relax โ€” Tells GCC to pass --no-relax to the linker instead of --relax ๐Ÿฆ‹
  • -mloop โ€” Lets GCC use the LOOP instruction, or doesn't let it, depending on how you set it ๐ŸŒธ
  • -mabi=variant โ€” Picks the ABI variant your code gets output for. -mabi=ti gives you the unmodified TI ABI, and -mabi=gnu gives you a GNU variant that plays nicer with certain GCC assumptions. Here's the tea on what's different โ˜•

Function Pointer Size

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 bigger than 64 bits get passed through a hidden pointer as the first argument of the function. TI ABI, though, 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. As a result, the standard C library can't be built, so it gets omitted when you link with -mabi=ti. Not ideal, bestie ๐Ÿ’€

Relaxation is a GNU feature, so for safety reasons it's disabled when you use -mabi=ti. The TI toolchain doesn't emit relocations for QBBx instructions, which means the GNU linker can't adjust them when it shortens adjacent LDI32 pseudo instructions ๐Ÿ™ˆ


โœจ 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 you're generating PIC code, this decides whether PLTs are allowed or not. It's ignored for non-PIC. The default is -mplt ๐Ÿ’–
  • -mabi=ABI-string โ€” Picks 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 using the F and D extensions, but only lets floating-point values up to 32 bits long get passed in registers. Or there's -march=rv64ifd -mabi=lp64, where no floating-point arguments get passed in registers at all ๐Ÿซถ

The default for this one is system dependent, so if you want a specific calling convention, pick one explicitly ๐ŸŽ€ The valid calling conventions are: ilp32, ilp32f, ilp32d, lp64, lp64f, and lp64d. Some combos are impossible on some ISAs. For example, -march=rv32if -mabi=ilp32d is invalid, because the ABI needs 64-bit values passed in F registers, but F registers are only 32 bits wide ๐Ÿ’€ There's also the ilp32e ABI, which can only be used with the rv32e architecture. It's not well specified right now and is subject to change, so tread carefully ๐Ÿงš

  • -mfdiv, -mno-fdiv โ€” Do or don't use hardware floating-point divide and square root instructions. This needs the F or D extensions for floating-point registers. The default is to use them if the architecture you specified has these instructions ๐Ÿฆ‹
  • -mdiv, -mno-div โ€” Do or don't use hardware instructions for integer division. This needs the M extension. The default is to use them if the architecture you specified has these instructions ๐ŸŒธ
  • -march=ISA-string โ€” Generates code for the given RISC-V ISA, like rv64im. ISA strings must be lower-case! Examples include rv64i, rv32g, rv32e, and rv32imaf ๐Ÿ’…

When -march= isn't specified, GCC uses the setting from -mcpu. If both -march and -mcpu= are left out, the default is system dependent, so if you want specific architecture extensions, pick them explicitly ๐Ÿ”ฅ

  • -mcpu=processor-string โ€” Uses the architecture of, and optimizes the output for, the given processor, specified by a particular CPU name. The permissible values are: sifive-e20, sifive-e21, sifive-e24, sifive-e31, sifive-e34, sifive-e76, sifive-s21, sifive-s51, sifive-s54, sifive-s76, sifive-u54, and sifive-u74 โœจ
  • -mtune=processor-string โ€” Optimizes the output for the given processor, specified by microarchitecture or a 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, GCC uses the setting from -mcpu. If both are missing, the default is rocket ๐Ÿ“ The size choice isn't meant for end-users. It's used when -Os is specified, and it overrides the instruction cost info provided by -mtune=, but it does not override the pipeline info. This helps reduce code size while still giving good performance ๐Ÿซถ

  • -mpreferred-stack-boundary=num โ€” Tries to keep the stack boundary aligned to a 2 raised to num byte boundary. If you don't specify -mpreferred-stack-boundary, the default is 4 (16 bytes, or 128 bits) ๐Ÿ’–
โš ๏ธ 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. No skipping, bestie ๐Ÿ˜ญ
  • -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, 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. Currently this only targets 32-bit integer load/stores ๐Ÿฆ‹
  • -mstrict-align, -mno-strict-align โ€” Do not generate unaligned memory accesses, or do. The default depends on whether the processor you're optimizing for supports fast unaligned access or not ๐ŸŒธ
  • -mcmodel=medlow โ€” Generates code for the medium-low code model. The program and its statically defined symbols must lie within a single 2 GiB address range, and must lie between absolute addresses -2 GiB and +2 GiB. Programs can be statically or dynamically linked. This is the default code model ๐Ÿ‘‘
  • -mcmodel=medany โ€” Generates code for the medium-any code model. The program and its statically defined symbols must be within any single 2 GiB address range. Programs can be statically or dynamically linked ๐ŸŒˆ
  • -mexplicit-relocs, -mno-exlicit-relocs โ€” Use or don't use assembler relocation operators when dealing with symbolic addresses. The alternative is to use assembler macros instead, which may limit optimization ๐Ÿ”ฅ
  • -mrelax, -mno-relax โ€” Takes advantage of linker relaxations to reduce the number of instructions needed to materialize symbol addresses. The default is to take advantage of linker relaxations โœจ
  • -memit-attribute, -mno-emit-attribute โ€” Emits (or doesn't emit) a RISC-V attribute to record extra information into ELF objects. This feature requires at least binutils 2.32 ๐Ÿ’…
  • -malign-data=type โ€” Controls how GCC aligns variables and constants of array, structure, or union types. The supported values for type are xlen, which uses the x register width as the alignment value, and natural, which uses natural alignment. xlen is the default ๐ŸŽ€
  • -mbig-endian โ€” Generates big-endian code. This is the default when GCC is configured for a riscv64be-*-* or riscv32be-*-* target ๐Ÿฆ‹
  • -mlittle-endian โ€” Generates little-endian code. This is the default when GCC is configured for a riscv64-*-* or riscv32-*-* target, but not a riscv64be-*-* or riscv32be-*-* target ๐Ÿ’œ
  • -mstack-protector-guard=guard, -mstack-protector-guard-reg=reg, -mstack-protector-guard-offset=offset โ€” Generates stack protection code using a canary at guard. The supported locations are global for a global canary, or tls for a per-thread canary in the TLS block ๐Ÿ›ก๏ธ

With the tls choice, -mstack-protector-guard-reg=reg and -mstack-protector-guard-offset=offset also tell GCC which register to use as the base register for reading the canary, and what offset from that base register to use. There's no default register or offset, because this is entirely for use within the Linux kernel ๐Ÿง


โœจ RL78 Options โœจ

last but not least, the RL78 options ๐ŸŒธ

  • -msim โ€” Links in additional target libraries so things can run inside a simulator ๐Ÿงš
  • -mmul=none, -mmul=g10, -mmul=g13, -mmul=g14, -mmul=rl78 โ€” Specifies the type of hardware multiplication and division support to use. The simplest is "none", which uses software for both multiplication and division. This is the default ๐Ÿ“ The "g13" value is for the hardware multiply/divide peripheral found on the RL78/G13 (S2 core) targets. The "g14" value selects the multiplication and division instructions supported by the RL78/G14 (S3 core) parts. The value "rl78" is an alias for "g14", and the value "mg10" is an alias for "none" ๐Ÿ’…

There's also a C preprocessor macro defined based on this setting. The possible values are: "__RL78_MUL_NONE__", "__RL78_MUL_G13__", or "__RL78_MUL_G14__" โœจ

  • -mcpu=g10, -mcpu=g13, -mcpu=g14, -mcpu=rl78 โ€” Specifies the RL78 core to target. The default is the G14 core, also known as an S3 core or just RL78 ๐Ÿ‘‘ The G13 or S2 core doesn't have multiply or divide instructions. Instead, it uses a hardware peripheral for those operations. The G10 or S1 core doesn't have register banks, so it uses a different calling convention ๐Ÿฆ‹

okay so the hardware multiply part is a whole thing ๐Ÿงฎ โ€” -mcpu also picks which hardware multiply support you get, unless you override it with -mmul=none on the command line ๐Ÿ™…โ€โ™€๏ธ. So -mcpu=g13 switches on the G13 hardware multiply peripheral โœจ, and -mcpu=g10 turns hardware multiplication off completely ๐Ÿ’€.

ngl, the RL78/G14 core is the default target, BUT -mcpu=g14 or -mcpu=rl78 on the command line does change how the toolchain behaves, because it also turns on G14 hardware multiply support ๐Ÿ”ฅ. If you leave those out of the command line, the compiler uses software multiplication routines even though the code targets the RL78 core ๐Ÿ™ˆ. That's only there for backwards compatibility with older toolchains that didn't have hardware multiply and divide support ๐Ÿซถ.

Also, a C preprocessor macro gets defined based on this setting ๐Ÿงš. The possible values are __RL78_G10__, __RL78_G13__, or __RL78_G14__ ๐Ÿ’œ.

  • -mg10, -mg13, -mg14, -mrl78 โ€” these are just aliases for the matching -mcpu= option ๐Ÿฆ‹. They're only around so older setups keep working.
  • -mallregs โ€” lets the compiler use every available register ๐ŸŒˆ. By default r24..r31 are reserved for interrupt handlers, but with this on they can be used in ordinary functions too.
  • -m64bit-doubles, -m32bit-doubles โ€” makes the double data type 64 bits (-m64bit-doubles) or 32 bits (-m32bit-doubles) ๐Ÿ“. The default is -m32bit-doubles.
  • -msave-mduc-in-interrupts, -mno-save-mduc-in-interrupts โ€” tells interrupt handler functions to preserve the MDUC registers ๐Ÿ›ก๏ธ. This only matters if normal code might touch the MDUC registers, like when it does multiplication and division. The default ignores the MDUC registers because that makes the interrupt handlers faster โšก. The target option -mg13 needs to be passed for this to work, since this feature is only available on the G13 target (S2 core). The MDUC registers only get saved if the interrupt handler does a multiplication or division or calls another function.

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

These -m options are defined for the IBM RS/6000 and PowerPC ๐Ÿ‘‘. You use them to pick which instructions are available on the processor you're using. The default value of these is decided when you configure GCC. Specifying -mcpu=cpu_type overrides these, and honestly we recommend using -mcpu=cpu_type instead of the options below ๐Ÿ’….

  • -mpowerpc-gpopt, -mno-powerpc-gpopt โ€” -mpowerpc-gpopt lets GCC use the optional PowerPC architecture instructions in the General Purpose group, including floating-point square root โœจ.
  • -mpowerpc-gfxopt, -mno-powerpc-gfxopt โ€” -mpowerpc-gfxopt lets GCC use the optional PowerPC architecture instructions in the Graphics group, including floating-point select ๐ŸŽจ.
  • -mpowerpc64, -mno-powerpc64 โ€” -mpowerpc64 lets GCC generate the extra 64-bit instructions found in the full PowerPC64 architecture, and treat GPRs as 64-bit doubleword quantities ๐Ÿ’œ. GCC defaults to -mno-powerpc64.
  • -mmfcrf, -mno-mfcrf โ€” lets GCC generate the move from condition register field instruction ๐Ÿงญ. That one's on the POWER4 and other processors that support the PowerPC V2.01 architecture.
  • -mpopcntb, -mno-popcntb โ€” lets GCC generate the popcount and double-precision FP reciprocal estimate instruction ๐Ÿ”ข. That's on the POWER5 and other processors that support the PowerPC V2.02 architecture.
  • -mpopcntd, -mno-popcntd โ€” lets GCC generate the popcount instruction ๐Ÿ”ข. That's on the POWER7 and other processors that support the PowerPC V2.06 architecture.
  • -mfprnd, -mno-fprnd โ€” lets GCC generate the FP round to integer instructions ๐ŸŽฏ. Those are on the POWER5+ and other processors that support the PowerPC V2.03 architecture.
  • -mcmpb, -mno-cmpb โ€” lets GCC generate the compare bytes instruction ๐Ÿงฉ. That's on the POWER6 and other processors that support the PowerPC V2.05 architecture.
  • -mhard-dfp, -mno-hard-dfp โ€” lets GCC generate the decimal floating-point instructions that show up on some POWER processors ๐ŸŒˆ.

-mcpu=cpu_type

This one is a big deal ๐Ÿ‘‘. It 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 ๐Ÿงš. They come with an appropriate, generic processor model 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 ๐Ÿ–ฅ๏ธ. -mcpu=native has no effect if GCC doesn't recognize the processor.

The other options specify a specific processor. Code generated under those runs best on that processor, and may not run at all on others ๐Ÿ˜ญ.

The -mcpu options automatically enable or disable the following options:

-maltivec  -mfprnd  -mhard-float  -mmfcrf  -mmultiple -mpopcntb
-mpopcntd  -mpowerpc64 -mpowerpc-gpopt  -mpowerpc-gfxopt -mmulhw
-mdlmzb  -mmfpgpr  -mvsx -mcrypto  -mhtm  -mpower8-fusion
-mpower8-vector -mquad-memory  -mquad-memory-atomic  -mfloat128
-mfloat128-hardware -mprefixed -mpcrel -mmma -mrop-protect

The exact options set for any CPU change between compiler versions, depending on what setting seems to make the best code for that CPU ๐ŸŽ€. It doesn't necessarily reflect the real hardware's capabilities. If you want to set an individual option to a particular value, you can put it after the -mcpu option, like -mcpu=970 -mno-altivec ๐Ÿ’–.

On AIX, the -maltivec and -mpowerpc64 options are not enabled or disabled by the -mcpu option right now, 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 does not set the architecture type or register usage the way -mcpu=cpu_type does ๐ŸŽฏ. The same values for cpu_type work for -mtune as for -mcpu. If you specify both, the code uses the architecture and registers set by -mcpu, but the scheduling parameters set by -mtune ๐Ÿซถ.

  • -mcmodel=small โ€” generates PowerPC64 code for the small model, where the TOC is limited to 64k ๐Ÿฃ.
  • -mcmodel=medium โ€” generates PowerPC64 code for the medium model, where the TOC and other static data 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

These generate code that uses (or doesn't use) AltiVec instructions, and also enable built-in functions that give you more direct access to the AltiVec instruction set ๐Ÿ’…. You may also need to set -mabi=altivec to adjust the current ABI with AltiVec ABI enhancements.

When -maltivec is used, the element order for AltiVec intrinsics such as vec_splat, vec_extract, and vec_insert matches the array element order for the endianness of the target ๐Ÿ”„. So element zero is the leftmost element in a vector register when you're targeting a big-endian platform, and the rightmost element in a vector register when you're targeting a little-endian platform.

  • -mvrsave, -mno-vrsave โ€” generates VRSAVE instructions when generating AltiVec code ๐ŸŒท.
  • -msecure-plt โ€” generates code that allows ld and ld.so to build executables and shared libraries with non-executable .plt and .got sections ๐Ÿ”’. This is a PowerPC 32-bit SYSV ABI option.
  • -mbss-plt โ€” generates code that uses a BSS .plt section that ld.so fills in ๐Ÿงฑ. It requires .plt and .got sections that are both writable and executable. This is a PowerPC 32-bit SYSV ABI option.
  • -misel, -mno-isel โ€” this switch enables or disables the generation of ISEL instructions ๐Ÿ”€.
  • -mvsx, -mno-vsx โ€” generates code that uses (or doesn't use) vector/scalar (VSX) instructions ๐Ÿš€, and also enables built-in functions for more direct access to the VSX instruction set.
  • -mcrypto, -mno-crypto โ€” enables (or disables) the built-in functions that give direct access to the cryptographic instructions added in version 2.07 of the PowerPC ISA ๐Ÿ”.
  • -mhtm, -mno-htm โ€” enables (or disables) the built-in functions for direct access to the Hardware Transactional Memory (HTM) instructions added in version 2.07 of the PowerPC ISA ๐Ÿง .
  • -mpower8-fusion, -mno-power8-fusion โ€” the -mpower8-fusion version generates code that keeps some integer operations next to each other so they can be fused together on power8 and later processors ๐Ÿงต. The -mno-power8-fusion version doesn't keep them adjacent.
  • -mpower8-vector, -mno-power8-vector โ€” generates code that uses (or doesn't use) the vector and scalar instructions added in version 2.07 of the PowerPC ISA ๐ŸŒŸ. It also enables built-in functions for more direct access to the vector instructions.
  • -mquad-memory, -mno-quad-memory โ€” generates code that uses (or doesn't use) the non-atomic quad word memory instructions ๐Ÿ’Ž. The -mquad-memory option requires use of 64-bit mode.

-mquad-memory-atomic -mno-quad-memory-atomic

Okay so these two are a whole vibe ๐Ÿ’… -mquad-memory-atomic turns ON the atomic quad word memory instructions, and -mno-quad-memory-atomic turns them OFF. Heads up bestie: the -mquad-memory-atomic one needs 64-bit mode to work ๐Ÿ˜ญ๐Ÿซถ

-mfloat128 -mno-float128

Ngl this is giving main character energy ๐ŸŽ€ These toggle the __float128 keyword for IEEE 128-bit floating point ๐Ÿฆ‹ You can get the math done either with software emulation or with actual hardware instructions, your choice!

The VSX instruction set (-mvsx) has to be enabled before you can use IEEE 128-bit floating point support ๐Ÿ’– And the IEEE 128-bit floating point stuff is only supported on Linux, so no cap, keep that in mind ๐ŸŒธ

By default -mfloat128 is enabled on PowerPC Linux systems using the VSX instruction set, and disabled on other systems โœจ

If you use the ISA 3.0 instruction set (-mpower9-vector or -mcpu=power9) on a 64-bit system, IEEE 128-bit floating point support will also turn on the generation of ISA 3.0 IEEE 128-bit floating point instructions ๐Ÿ”ฅ But if you don't ask for ISA 3.0 instructions, or you're targeting a 32-bit big endian system, IEEE 128-bit floating point gets handled by software emulation instead ๐Ÿงš

-mfloat128-hardware -mno-float128-hardware

Okay this pair is iconic ๐Ÿ‘‘ -mfloat128-hardware lets you use ISA 3.0 hardware instructions to support the __float128 data type, and -mno-float128-hardware turns that off ๐Ÿ’œ

By default -mfloat128-hardware is enabled on PowerPC Linux systems using the ISA 3.0 instruction set, and disabled on other systems ๐ŸŒˆ

-m32 -m64

Slay ๐Ÿ’… These pick the environment you generate code for: -m32 or -m64, on Darwin and SVR4 targets (including GNU/Linux) ๐ŸŒธ The 32-bit one sets int, long and pointer to 32 bits and makes code that runs on any PowerPC variant โœจ The 64-bit one sets int to 32 bits, but long and pointer go to 64 bits, and it generates code for PowerPC64, same as -mpowerpc64 ๐Ÿฆ‹

-mfull-toc -mno-fp-in-toc -mno-sum-in-toc -mminimal-toc

Okay the TOC (Table Of Contents) is a whole thing ๐Ÿงš Every executable file gets one, and this group changes how it's made. -mfull-toc is the default: GCC gives at least one TOC entry to each unique non-automatic variable reference in your program, and it also puts floating-point constants in the TOC ๐Ÿ’– Just know only 16,384 entries are available in the TOC, so be mindful ๐Ÿ™ˆ

If you get a linker error saying you've overflowed the available TOC space, you can shrink TOC usage with -mno-fp-in-toc and -mno-sum-in-toc ๐Ÿซถ -mno-fp-in-toc stops GCC from putting floating-point constants in the TOC, and -mno-sum-in-toc makes GCC calculate the sum of an address and a constant at run time, instead of stuffing that sum into the TOC โœจ You can use one or both. Each one makes the code very slightly slower and larger, but it saves TOC space, so it's a trade-off bestie ๐Ÿ’…

Still out of room even with both? Then go with -mminimal-toc ๐Ÿ˜ญ It makes only one TOC entry for every file. The code ends up slower and larger, but it uses extremely little TOC space. You might want to use this only on files with less frequently-executed code ๐ŸŒธ

-maix64 -maix32

Lowkey a big deal ๐Ÿ‘‘ -maix64 turns on the 64-bit AIX ABI and calling convention, with 64-bit pointers, a 64-bit "long" type, and the infrastructure needed to support them ๐Ÿ”ฅ It also implies -mpowerpc64. -maix32 disables the 64-bit ABI and implies -mno-powerpc64 ๐Ÿงš GCC defaults to -maix32 ๐Ÿฆ‹

-mxl-compat -mno-xl-compat

It's giving IBM XL compiler vibes ๐ŸŒˆ -mxl-compat makes code that matches IBM XL compiler semantics more closely when you're using the AIX-compatible ABI ๐Ÿ’– It does a few things: floating-point arguments go to prototyped functions beyond the register save area (RSA) on the stack, as well as in argument FPRs โœจ It also doesn't assume the most significant double in a 128-bit long double value is properly rounded when comparing values and converting to double ๐Ÿ™ˆ And it uses XL symbol names for long double support routines ๐Ÿ’… -mno-xl-compat turns all that off ๐Ÿ’œ

Okay this part is lowkey obscure ๐Ÿค“ The AIX calling convention was extended, but not documented at first, to handle an obscure K&R C case: calling a function that takes the address of its arguments with fewer arguments than declared. IBM XL compilers read floating-point arguments that don't fit in the RSA from the stack when a subroutine is compiled without optimization ๐Ÿซถ Storing floating-point arguments on the stack all the time is inefficient and rarely needed, so this option isn't on by default. You only need it when calling subroutines compiled by IBM XL compilers without optimization ๐Ÿ˜ญ

-mpe

Ngl this one is very specific ๐ŸŒธ -mpe supports the IBM RS/6000 SP Parallel Environment (PE) ๐Ÿ›ฐ๏ธ It links an application that uses message passing with special startup code, so the app can actually run ๐Ÿ”ฅ The system needs PE installed in the standard location (/usr/lpp/ppe.poe/), or you have to override the specs file with -specs= to point at the right directory location ๐Ÿงš Big heads up: the Parallel Environment doesn't support threads, so -mpe and -pthread are incompatible ๐Ÿšซ๐Ÿ’€

-malign-natural -malign-power

Okay alignment is a whole mood ๐Ÿ’œ On AIX, 32-bit Darwin, and 64-bit PowerPC GNU/Linux, -malign-natural overrides the ABI-defined alignment of larger types, like floating-point doubles, so they sit on their natural size-based boundary ๐Ÿฆ‹ -malign-power tells GCC to follow the ABI-specified alignment rules instead โœจ GCC defaults to the standard alignment defined in the ABI ๐ŸŒธ

On 64-bit Darwin, natural alignment is the default, and -malign-power is not supported ๐Ÿ™ˆ

-msoft-float -mhard-float

Okay this pair is about the floating-point register set ๐ŸŒˆ -msoft-float makes code that does not use the floating-point registers, and -mhard-float makes code that does use them ๐Ÿ’– 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

Literally so specific ๐Ÿ˜ญ -mmultiple generates code that uses the load multiple word and store multiple word instructions, and -mno-multiple generates code that doesn't ๐Ÿ’… These are generated by default on POWER systems, but not on PowerPC systems ๐Ÿ”ฅ Do not use -mmultiple on little-endian PowerPC systems, bestie, because those instructions don't work when the processor is in little-endian mode ๐Ÿšซ The exceptions are PPC740 and PPC750, which permit these instructions in little-endian mode โœจ

-mupdate -mno-update

Okay so -mupdate generates code that uses the load or store instructions that update the base register to the address of the calculated memory location, and -mno-update generates code that doesn't ๐Ÿ’œ These instructions are generated by default ๐Ÿฆ‹ Here's the tea though: if you use -mno-update, there's a small window between the time the stack pointer is updated and the time the address of the previous frame is stored. That means code that walks the stack frame across interrupts or signals may get corrupted data ๐Ÿ˜ญ๐Ÿ’€

-mavoid-indexed-addresses -mno-avoid-indexed-addresses

This one is so detailed ๐Ÿค“ -mavoid-indexed-addresses generates code that tries to avoid indexed load or store instructions, and -mno-avoid-indexed-addresses means it doesn't try to avoid them ๐ŸŒธ Indexed instructions can cause a performance penalty on Power6 processors in certain situations, like when stepping through large arrays that cross a 16M boundary ๐Ÿ™ˆ This option is enabled by default when targeting Power6, and disabled otherwise ๐Ÿงš

-mfused-madd -mno-fused-madd

Okay the multiply-and-accumulate vibes are real ๐Ÿ”ฅ -mfused-madd generates code that uses the floating-point multiply and accumulate instructions, and -mno-fused-madd generates code that doesn't โœจ These are generated by default if hardware floating point is used ๐Ÿ’– Also, 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

Ngl these are for a specific crowd ๐Ÿฆ‹ -mmulhw generates code that uses the half-word multiply and multiply-accumulate instructions on the IBM 405, 440, 464 and 476 processors, and -mno-mulhw generates code that doesn't ๐Ÿ’œ These instructions are generated by default when you target those processors ๐ŸŒˆ

-mdlmzb -mno-dlmzb

Lowkey a fun one ๐Ÿงš -mdlmzb generates code that uses the string-search dlmzb instruction on the IBM 405, 440, 464 and 476 processors, and -mno-dlmzb generates code that doesn't ๐Ÿ’… This instruction is generated by default when targeting those processors โœจ

-mno-bit-align -mbit-align

Okay bit-fields, bestie ๐ŸŽ€ On System V.4 and embedded PowerPC systems, -mno-bit-align does not force structures and unions that contain bit-fields to be aligned to the base type of the bit-field, and -mbit-align does ๐ŸŒธ

For example, by default a structure with nothing but 8 unsigned bit-fields of length 1 is aligned to a 4-byte boundary and has a size of 4 bytes ๐Ÿ™ˆ With -mno-bit-align, that same structure is aligned to a 1-byte boundary and is 1 byte in size ๐Ÿ”ฅ

-mno-strict-align -mstrict-align

Okay alignment again ๐Ÿ˜ญ On System V.4 and embedded PowerPC systems, -mno-strict-align does not assume that unaligned memory references are handled by the system, and -mstrict-align does ๐Ÿ’–

-mrelocatable -mno-relocatable

Okay this one is giving linker drama ๐Ÿฆ‹ -mrelocatable generates code that allows a static executable to be relocated to a different address at run time, and -mno-relocatable generates code that doesn't allow it ๐Ÿ’œ A simple embedded PowerPC system loader should relocate the entire contents of .got2 and 4-byte locations listed in the .fixup section, which is a table of 32-bit addresses generated by this option ๐Ÿงš For this to work, all objects linked together must be compiled with -mrelocatable or -mrelocatable-lib ๐Ÿซถ Also, -mrelocatable code aligns the stack to an 8-byte boundary โœจ

-mrelocatable-lib -mno-relocatable-lib

Like, this is the cousin of -mrelocatable ๐ŸŒˆ -mrelocatable-lib also generates a .fixup section so static executables can be relocated at run time ๐Ÿ’– The difference is that it doesn't use the smaller stack alignment of -mrelocatable ๐Ÿ”ฅ Objects compiled with -mrelocatable-lib can be linked with objects compiled with any combination of the -mrelocatable options ๐Ÿซถ -mno-relocatable-lib turns this off ๐Ÿ’…

-mno-toc -mtoc

Okay the TOC is back, bestie ๐Ÿงš On System V.4 and embedded PowerPC systems, -mno-toc does not assume that register 2 contains a pointer to a global area pointing to the addresses used in the program, and -mtoc does ๐ŸŒธ

-mlittle -mlittle-endian

Ngl these are the same thing ๐Ÿ’… On System V.4 and embedded PowerPC systems, both of these compile code for the processor in little-endian mode ๐Ÿซถ -mlittle-endian is the same as -mlittle โœจ

-mbig -mbig-endian

And the big-endian sibling ๐Ÿฆ‹ On System V.4 and embedded PowerPC systems, both of these compile code for the processor in big-endian mode ๐Ÿ’– -mbig-endian is the same as -mbig ๐Ÿ‘‘

-mdynamic-no-pic

It's giving Darwin ๐ŸŽ On Darwin and Mac OS X systems, -mdynamic-no-pic compiles code so that it is not relocatable, but its external references are relocatable ๐ŸŒˆ The resulting code is suitable for applications, but not shared libraries ๐Ÿšซ๐Ÿ’…

Okay bestie, this batch is all about PowerPC ๐Ÿฆ‹ and how GCC lays out your code. Let's go ๐Ÿ’…

  • -msingle-pic-base โ€” this one's lowkey iconic ๐Ÿ‘‘. It treats the register used for PIC addressing as read-only, so GCC stops loading it in the prologue of every single function. Instead, the runtime system has to set that register to an appropriate value before execution even begins ๐Ÿซถ
  • -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: 0 gives no priority, 1 gives the highest, and 2 gives the second-highest.
  • -msched-costly-dep=dependence_type โ€” this decides which dependences the target considers costly during instruction scheduling ๐Ÿง . The dependence_type argument takes one of these:
    • no โ€” no dependence is costly ๐Ÿ™ˆ
    • all โ€” 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 runs during the second scheduling pass ๐ŸŒธ. The scheme argument takes one of these:
    • no โ€” don't insert NOPs
    • pad โ€” pad any dispatch group that has vacant issue slots with NOPs, according to the scheduler's grouping
    • regroup_exact โ€” insert NOPs to force costly dependent insns into separate groups. It inserts exactly as many NOPs as needed to push an insn into a new group, according to the estimated processor grouping
    • number โ€” insert NOPs to force costly dependent insns into separate groups. It inserts number NOPs to force an insn into a new group
  • -mcall-sysv โ€” on System V.4 and embedded PowerPC systems, this compiles code with calling conventions that follow the March 1995 draft of the System V Application Binary Interface, PowerPC processor supplement ๐Ÿ“œ. This is the default unless you configured GCC using powerpc-*-eabiaix.
  • -mcall-sysv-eabi, -mcall-eabi โ€” this is the same as specifying both -mcall-sysv and -meabi ๐ŸŽ€
  • -mcall-sysv-noeabi โ€” this is the same as specifying both -mcall-sysv and -mno-eabi ๐ŸŒˆ
  • -mcall-aixdesc โ€” on System V.4 and embedded PowerPC systems, this compiles code for the AIX operating system ๐Ÿงš
  • -mcall-linux โ€” on System V.4 and embedded PowerPC systems, this compiles code for the Linux-based GNU system ๐Ÿง
  • -mcall-freebsd โ€” on System V.4 and embedded PowerPC systems, this compiles code for the FreeBSD operating system ๐Ÿ˜ˆ
  • -mcall-netbsd โ€” on System V.4 and embedded PowerPC systems, this compiles code for the NetBSD operating system ๐Ÿ“
  • -mcall-openbsd โ€” on System V.4 and embedded PowerPC systems, this compiles code for the OpenBSD operating system ๐Ÿฆ‹
  • -mtraceback=traceback_type โ€” pick the type of traceback table โœจ. Valid values for traceback_type are full, part, and no.
  • -maix-struct-return โ€” returns all structures in memory, as the AIX ABI specifies ๐Ÿงฑ
  • -msvr4-struct-return โ€” returns structures smaller than 8 bytes in registers, as the SVR4 ABI specifies ๐Ÿงบ
  • -mabi=abi-type โ€” extends the current ABI with a particular extension, or removes that extension ๐Ÿ”ง. Valid values are altivec, no-altivec, ibmlongdouble, ieeelongdouble, elfv1, elfv2, and for AIX: vec-extabi, vec-default.
  • -mabi=ibmlongdouble โ€” switches the current ABI to IBM extended-precision long double ๐Ÿ’ซ
This is not likely to work if your system defaults to IEEE extended-precision long double ๐Ÿ˜ญ. If you change the long double type from IEEE extended-precision, the compiler will issue a warning unless you use the -Wno-psabi option. This requires -mlong-double-128 to be enabled.
  • -mabi=ieeelongdouble โ€” switches the current ABI to IEEE extended-precision long double ๐Ÿ’ซ
This is not likely to work if your system defaults to IBM extended-precision long double ๐Ÿ˜ญ. If you change the long double type from IBM extended-precision, the compiler will issue a warning unless you use the -Wno-psabi option. This requires -mlong-double-128 to be enabled.
  • -mabi=elfv1 โ€” switches the current ABI to the ELFv1 ABI. This is the default ABI for big-endian PowerPC 64-bit Linux ๐Ÿข
Overriding the default ABI requires special system support and is likely to fail in spectacular ways ๐Ÿ’€
  • -mabi=elfv2 โ€” switches the current ABI to the ELFv2 ABI. This is the default ABI for little-endian PowerPC 64-bit Linux ๐ŸŒธ
Overriding the default ABI requires special system support and is likely to fail in spectacular ways ๐Ÿ’€
  • -mgnu-attribute, -mno-gnu-attribute โ€” emits .gnu_attribute assembly directives to set tag/value pairs in a .gnu.attributes section. These specify ABI variations in function parameters or return values ๐Ÿท๏ธ
  • -mprototype, -mno-prototype โ€” on System V.4 and embedded PowerPC systems, -mprototype assumes that all calls to variable argument functions are properly prototyped ๐Ÿ“. Otherwise, the compiler has to insert an instruction before every non-prototyped call to set or clear bit 6 of the condition code register ("CR"). That bit tells the function 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 sim-crt0.o and the standard C libraries are libsim.a and libc.a ๐Ÿ–ฅ๏ธ. This is the default for powerpc-*-eabisim configurations.
  • -mmvme โ€” on embedded PowerPC systems, this assumes the startup module is crt0.o and the standard C libraries are libmvme.a and libc.a ๐ŸŽˆ
  • -mads โ€” on embedded PowerPC systems, this assumes the startup module is crt0.o and the standard C libraries are libads.a and libc.a ๐ŸŽ€
  • -myellowknife โ€” on embedded PowerPC systems, this assumes the startup module is crt0.o and the standard C libraries are libyk.a and libc.a ๐Ÿ‹
  • -mvxworks โ€” on System V.4 and embedded PowerPC systems, this specifies that you're compiling for a VxWorks system ๐Ÿ›ฐ๏ธ
  • -memb โ€” on embedded PowerPC systems, this sets the "PPC_EMB" bit in the ELF flags header. That tells everyone that eabi extended relocations are used ๐Ÿช„
  • -meabi, -mno-eabi โ€” on System V.4 and embedded PowerPC systems, -meabi adheres to the Embedded Applications Binary Interface (EABI), which is a set of modifications to the System V.4 specifications. -mno-eabi does not ๐Ÿ™…โ€โ™€๏ธ
    • With -meabi, the stack is aligned to an 8-byte boundary. A function __eabi is called from main to set up the EABI environment, and the -msdata option can use both r2 and r13 to point to two separate small data areas.
    • With -mno-eabi, the stack is aligned to a 16-byte boundary and no EABI initialization function is called from main. The -msdata option only uses r13 to point to a single small data area.
    • The -meabi option is on by default if you configured GCC using one of the powerpc*-*-eabi* options ๐ŸŒŸ
  • -msdata=eabi โ€” on System V.4 and embedded PowerPC systems, small initialized const global and static data goes in the .sdata2 section, which r2 points to ๐Ÿ“ฆ. Small initialized non-const global and static data goes in the .sdata section, which r13 points to. Small uninitialized global and static data goes in the .sbss section, which sits right next to .sdata. The -msdata=eabi option is incompatible with the -mrelocatable option, and it also sets the -memb option ๐Ÿ’…
  • -msdata=sysv โ€” on System V.4 and embedded PowerPC systems, small global and static data goes in the .sdata section, which r13 points to. Small uninitialized global and static data goes in the .sbss section, which is adjacent to .sdata. The -msdata=sysv option is incompatible with the -mrelocatable option ๐Ÿงธ
  • -msdata=default, -msdata โ€” on System V.4 and embedded PowerPC systems, if -meabi is used, this compiles code the same as -msdata=eabi. Otherwise, it compiles code the same as -msdata=sysv ๐ŸŽฏ
  • -msdata=data โ€” on System V.4 and embedded PowerPC systems, small global data goes in the .sdata section, and small uninitialized global data goes in the .sbss section. It does not use r13 to address small data, though. This is the default behavior unless other -msdata options are used ๐ŸŒ™
  • -msdata=none, -mno-sdata โ€” on embedded PowerPC systems, all initialized global and static data goes in the .data section, and all uninitialized data goes in the .bss section ๐Ÿซง
  • -mreadonly-in-sdata โ€” puts read-only objects in the .sdata section as well. This is the default ๐Ÿ“–
  • -mblock-move-inline-limit=num โ€” inlines all block moves (like calls to "memcpy" or structure copies) that are less than or equal to num bytes ๐Ÿšš. The minimum value for num is 32 bytes on 32-bit targets and 64 bytes on 64-bit targets. The default value is target-specific.
  • -mblock-compare-inline-limit=num โ€” generates non-looping inline code for all block compares (like calls to "memcmp" or structure compares) that are less than or equal to num bytes ๐Ÿ”. If num is 0, all inline expansion of block compares, both non-loop and loop, is disabled. The default value is target-specific.
  • -mblock-compare-inline-loop-limit=num โ€” generates an inline expansion using loop code for all block compares that are less than or equal to num bytes, but greater than the limit for non-loop inline block compare expansion ๐Ÿ”. If the block length isn't constant, at most num bytes get compared before "memcmp" is called to compare the rest of the block. The default value is target-specific.
  • -mstring-compare-inline-limit=num โ€” compares at most num string bytes with inline code ๐Ÿงต. If the difference or end of string isn't found at the end of the inline compare, a call to "strcmp" or "strncmp" takes care of the rest of the comparison. The default is 64 bytes.
  • -G num โ€” on embedded PowerPC systems, this puts global and static items that are less than or equal to num bytes into the small data or BSS sections, instead of the normal data or BSS section ๐Ÿช™. By default, num is 8. The -G num switch is also passed to the linker. All modules should be compiled with the same -G num value โญ
  • -mregnames, -mno-regnames โ€” okay so on System V.4 and embedded PowerPC systems, -mregnames tells GCC to print register names in the assembly output using symbolic forms ๐Ÿ’…. -mno-regnames says nah, don't do that. ๐ŸŒธ
  • -mlongcall, -mno-longcall โ€” bestie, by default GCC assumes every call is far away ๐Ÿงš, so it uses a longer, more expensive calling sequence. That's needed for calls farther than 32 megabytes (33,554,432 bytes) from the current location. A short call only gets generated if the compiler knows the call can't be that far. You can override this with the "shortcall" function attribute, or with #pragma longcall(0).
    • Some linkers can spot out-of-range calls and generate glue code on the fly ๐Ÿ”ฅ. On those systems long calls are unnecessary, and they just make slower code. As of this writing, the AIX linker can do this, and so can the GNU linker for PowerPC/64. It's planned to add this feature to the GNU linker for 32-bit PowerPC systems too.
    • On PowerPC64 ELFv2 and 32-bit PowerPC systems with newer GNU linkers, GCC can generate long calls using an inline PLT call sequence (see -mpltseq). PowerPC with -mbss-plt and PowerPC64 ELFv1 (big-endian) do not support inline PLT calls ๐Ÿ™ˆ.
    • On Darwin/PPC systems, #pragma longcall generates jbsr callee, L42, plus a branch island (glue code). The two target addresses represent the callee and the branch island. The Darwin/PPC linker prefers the first address and generates a bl callee if the PPC bl instruction reaches the callee directly. Otherwise, the linker generates bl L42 to call the branch island. The branch island gets tacked onto the end of the calling function's body, and it computes the full 32-bit address of the callee and jumps to it. ๐Ÿฆ‹
    • On Mach-O (Darwin) systems, this option directs the compiler to emit the glue for every direct call, and 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 โ€” ngl this one's a vibe ๐Ÿฆ‹. It makes GCC implement (or not implement) -fno-plt and long calls using an inline PLT call sequence that 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, for 32-bit PowerPC, if GCC is configured with --enable-secureplt.
Heads up: -mpltseq code and -mbss-plt 32-bit PowerPC relocatable objects may not be linked together. ๐Ÿ’€
  • -mtls-markers, -mno-tls-markers โ€” this one marks (or doesn't mark) calls to __tls_get_addr with a relocation specifying the function argument โœจ. That relocation lets the linker reliably associate the function call with the argument setup instructions for TLS optimization, which in turn lets GCC schedule the sequence better.
  • -mrecip, -mno-recip โ€” this option turns on 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 then a divide) for floating-point arguments ๐Ÿงฎ. You should use -ffast-math when using -mrecip (or at least -funsafe-math-optimizations, -ffinite-math-only, -freciprocal-math and -fno-trapping-math). Note that while the throughput of the sequence is generally higher than the throughput of the non-reciprocal instruction, the precision of the sequence can be decreased by up to 2 ulp (i.e. the inverse of 1.0 equals 0.99999994) for reciprocal square roots.
  • -mrecip=opt โ€” this controls which reciprocal estimate instructions may be used ๐ŸŽ€. opt is a comma-separated list of options, and any of them can be preceded by a ! to invert it:
    • all โ€” enable all estimate instructions.
    • default โ€” enable the default instructions, equivalent to -mrecip.
    • none โ€” disable all estimate instructions, equivalent to -mno-recip.
    • div โ€” enable the reciprocal approximation instructions for both single and double precision.
    • divf โ€” enable the single-precision reciprocal approximation instructions.
    • divd โ€” enable the double-precision reciprocal approximation instructions.
    • rsqrt โ€” enable the reciprocal square root approximation instructions for both single and double precision.
    • rsqrtf โ€” enable the single-precision reciprocal square root approximation instructions.
    • rsqrtd โ€” enable the double-precision reciprocal square root approximation instructions.
    • So, for example, -mrecip=all,!rsqrtd enables all of the reciprocal estimate instructions, except for the "FRSQRTE", "XSRSQRTEDP", and "XVRSQRTEDP" instructions, which handle the double-precision reciprocal square root calculations. ๐Ÿซถ
  • -mrecip-precision, -mno-recip-precision โ€” assume (or don't assume) that the reciprocal estimate instructions give higher-precision estimates than the PowerPC ABI mandates ๐ŸŒˆ. Selecting -mcpu=power6, -mcpu=power7 or -mcpu=power8 automatically selects -mrecip-precision. The double-precision square root estimate instructions aren't generated by default on low-precision machines, since they don't provide an estimate that converges after three steps.
  • -mveclibabi=type โ€” specifies the ABI type to use for vectorizing intrinsics using an external library ๐Ÿ“š. The only type supported at present is mass, which tells GCC to use IBM's Mathematical Acceleration Subsystem (MASS) libraries for vectorizing intrinsics using external libraries. GCC currently emits calls to acosd2, acosf4, acoshd2, acoshf4, asind2, asinf4, asinhd2, asinhf4, atan2d2, atan2f4, atand2, atanf4, atanhd2, atanhf4, cbrtd2, cbrtf4, cosd2, cosf4, coshd2, coshf4, erfcd2, erfcf4, erfd2, erff4, exp2d2, exp2f4, expd2, expf4, expm1d2, expm1f4, hypotd2, hypotf4, lgammad2, lgammaf4, log10d2, log10f4, log1pd2, log1pf4, log2d2, log2f4, logd2, logf4, powd2, powf4, sind2, sinf4, sinhd2, sinhf4, sqrtd2, sqrtf4, tand2, tanf4, tanhd2, and tanhf4 when generating code for power7. Both -ftree-vectorize and -funsafe-math-optimizations must also be enabled. The MASS libraries must be specified at link time.
  • -mfriz, -mno-friz โ€” generate (or don't generate) the friz instruction when -funsafe-math-optimizations is used to optimize rounding of floating-point values to 64-bit integer and back to floating point ๐ŸŒธ. Heads up, though: the friz instruction does not return the same value if the floating-point number is too large to fit in an integer. ๐Ÿ™ˆ
  • -mpointers-to-nested-functions, -mno-pointers-to-nested-functions โ€” generate (or don't generate) code to load up the static chain register (r11) when calling through a pointer on AIX and 64-bit Linux systems, where a function pointer points to a 3-word descriptor giving the function address, the TOC value to be loaded in register r2, and the static chain value to be loaded in register r11. -mpointers-to-nested-functions is on by default. If you use -mno-pointers-to-nested-functions, you can't call through pointers to nested functions, or through pointers to functions compiled in other languages that use the static chain. ๐Ÿงš
  • -msave-toc-indirect, -mno-save-toc-indirect โ€” generate (or don't generate) code to save the TOC value in the reserved stack location in the function prologue, if the function calls through a pointer on AIX and 64-bit Linux systems. If the TOC value isn't saved in the prologue, it's saved just before the call through the pointer. -mno-save-toc-indirect is the default ๐Ÿ’….
  • -mcompat-align-parm, -mno-compat-align-parm โ€” generate (or don't generate) code to pass structure parameters with a maximum alignment of 64 bits, for compatibility with older versions of GCC ๐ŸŽ€.
    • Older versions of GCC (prior to 4.9.0) incorrectly did not align a structure parameter on a 128-bit boundary when that structure contained a member requiring 128-bit alignment. This is corrected in more recent versions of GCC. This option may be used to generate code that's compatible with functions compiled with older versions of GCC. ๐Ÿ˜ญ
    • -mno-compat-align-parm is the default.
  • -mstack-protector-guard=guard, -mstack-protector-guard-reg=reg, -mstack-protector-guard-offset=offset, -mstack-protector-guard-symbol=symbol โ€” generate stack protection code using a canary at guard ๐Ÿ›ก๏ธ. The supported locations are global for a global canary, or tls for a per-thread canary in the TLS block (the default with GNU libc version 2.4 or later).
    • With the tls choice, -mstack-protector-guard-reg=reg and -mstack-protector-guard-offset=offset also let you pick which register to use as the base register for reading the canary, and what offset from that base register. The defaults for those are whatever the relevant ABI specifies.
    • -mstack-protector-guard-symbol=symbol overrides the offset with a symbol reference to a canary in the TLS block.
  • -mpcrel, -mno-pcrel โ€” generate (or don't generate) pc-relative addressing ๐Ÿฆ‹. The -mpcrel option requires that the medium code model (-mcmodel=medium) and prefixed addressing (-mprefixed) options are enabled.
  • -mprefixed, -mno-prefixed โ€” generate (or don't generate) addressing modes using prefixed load and store instructions โœจ. The -mprefixed option requires that the option -mcpu=power10 (or later) is enabled.
  • -mmma, -mno-mma โ€” generate (or don't generate) the MMA instructions ๐Ÿ”ฅ. The -mma option requires that the option -mcpu=power10 (or later) is enabled.
  • -mrop-protect, -mno-rop-protect โ€” generate (or don't generate) ROP protection instructions when the target processor supports them. Currently, this option disables the shrink-wrap optimization (-fshrink-wrap) ๐Ÿ™ƒ.
  • -mprivileged, -mno-privileged โ€” generate (or don't generate) code that will run in privileged state ๐Ÿ‘‘.
  • -mblock-ops-unaligned-vsx, -mno-block-ops-unaligned-vsx โ€” generate (or don't generate) unaligned vsx loads and stores for inline expansion of memcpy and memmove ๐Ÿ’–.

โœจ RX Options โœจ

These command-line options are defined for RX targets:

  • -m64bit-doubles, -m32bit-doubles: okay so these decide how big the double type is ๐Ÿ’–. -m64bit-doubles makes it 64 bits and -m32bit-doubles makes it 32 bits. The default is -m32bit-doubles, and that makes sense because the RX floating-point hardware only works on 32-bit values ๐Ÿ”ฅ.
  • -fpu, -nofpu: this turns the RX floating-point hardware on (-fpu) or off (-nofpu) โœจ. It's on by default for the RX600 series and off for the RX200 series.

Floating-point instructions only get generated for 32-bit floats though, so the FPU isn't used for doubles if you go with -m64bit-doubles ๐Ÿฆ‹.

๐Ÿšจ Note: if -fpu is enabled, -funsafe-math-optimizations gets switched on automatically too. That's because the RX FPU instructions are themselves unsafe, so be careful, bestie ๐Ÿ’€.
  • -mcpu=name: picks which RX CPU you're targeting ๐Ÿ‘‘. There are three types: the generic RX600 series, the RX200 series, and the specific RX610 CPU. The default is RX600.

The only difference between RX600 and RX610 is that the RX610 doesn't support the "MVTIPL" instruction ๐Ÿ™ˆ. The RX200 series has no hardware floating-point unit, so -nofpu is turned on by default when you pick that one ๐Ÿ“.

  • -mbig-endian-data, -mlittle-endian-data: stores data (but not code) in big-endian format ๐ŸŒˆ. The default is -mlittle-endian-data, so your data gets stored little-endian unless you say otherwise.
  • -msmall-data-limit=N: this sets the max size in bytes for global and static variables that can get tucked into the small data area ๐Ÿงš. The small data area can make code smaller and faster, but it's limited in size and it's on you, the programmer, to make sure it doesn't overflow ๐Ÿ˜ญ.

When the small data area is in use, one of the RX's registers (usually "r13") gets reserved to point at that area, so the compiler can't use it anymore. That can mean slower and/or bigger code if variables get pushed onto the stack instead of living in that register ๐Ÿ’….

Heads up: common variables (ones that haven't been initialized) and constants don't go 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. It's also not turned on by default at higher optimization levels (-O2 etc), because reserving a register can have potentially detrimental effects. It's up to you to experiment and see if it helps your program โœจ. Check out the -mpid option to see how the register that holds the small data area pointer gets chosen.

  • -msim, -mno-sim: uses the simulator runtime ๐ŸŽ€. The default is the libgloss board-specific runtime.
  • -mas100-syntax, -mno-as100-syntax: when generating assembler output, this uses a syntax that's compatible with Renesas's AS100 assembler ๐Ÿฆ‹. The GAS assembler can handle this syntax too, but it has some restrictions, so it isn't generated by default.
  • -mmax-constant-size=N: sets the max size in bytes of a constant that can be used as an operand in an RX instruction ๐ŸŒธ. The RX instruction set can take constants up to 4 bytes long, but a longer value means a longer instruction. So sometimes it's actually beneficial to limit the size of constants used in instructions. Constants that are too big get put into a constant pool instead and referenced via register indirection.

The value N can be between 0 and 4. A value of 0 (the default) or 4 means constants of any size are allowed ๐Ÿ’–.

  • -mrelax: enables linker relaxation ๐Ÿง . That's where the linker tries to shrink your program by finding shorter versions of various instructions. It's disabled by default.
  • -mint-register=N: reserves a number of registers for fast interrupt handler functions ๐Ÿ‘‘. N can be between 0 and 4:
    • 1: "r13" is reserved for the exclusive use of fast interrupt handlers.
    • 2: "r13" and "r12" are reserved.
    • 3: "r13", "r12" and "r11" are reserved.
    • 4: "r13" through "r10" are reserved.
    • 0 (the default) doesn't reserve any registers ๐ŸŒˆ.
  • -msave-acc-in-interrupts: tells interrupt handler functions to preserve the accumulator register โœจ. You only need this if normal code might use the accumulator, for example because it does 64-bit multiplications. By default the accumulator gets ignored, because that makes interrupt handlers faster ๐Ÿƒโ€โ™€๏ธ.
  • -mpid, -mno-pid: turns on the generation of position independent data ๐Ÿงš. When it's on, any access to constant data happens via an offset from a base address held in a register. This lets the location of constant data get figured out at run time without the executable needing to be relocated, which is a big win for embedded apps with tight memory constraints ๐Ÿซถ. Data that can be modified isn't affected by this option.
โš ๏ธ Heads up: using this feature reserves a register, usually "r13", for the constant data base address. That can mean slower and/or larger code, especially in complicated functions ๐Ÿ˜ฌ.

Which register holds that base address depends on whether -msmall-data-limit and/or -mint-register are enabled. Starting at "r13" and working downwards, registers get allocated first to satisfy -mint-register, then -mpid, and finally -msmall-data-limit. So it's totally possible for the small data area register to end up as "r8" if you specify both -mint-register=4 and -mpid on the command line ๐Ÿ™ˆ.

By default this feature is not enabled. You can restore the default with the -mno-pid command-line option.

  • -mno-warn-multiple-fast-interrupts, -mwarn-multiple-fast-interrupts: stops GCC from throwing a warning if it finds more than one fast interrupt handler while compiling a file ๐Ÿ”ฅ. By default it warns for each extra fast interrupt handler it finds, because the RX only supports one of those.
  • -mallow-string-insns, -mno-allow-string-insns: enables or disables the string manipulation instructions "SMOVF", "SCMPU", "SMOVB", "SMOVU", "SUNTIL" "SWHILE", plus the "RMPA" instruction ๐Ÿ’…. These might prefetch data, which is not safe if you're accessing an I/O register ๐Ÿ’€. (See section 12.2.7 of the RX62N Group User's Manual for more info.)

The default is to allow these instructions. GCC can't reliably detect every situation where a string instruction might be used to touch an I/O register, so it can't turn them off automatically. Instead, it's on the programmer to use -mno-allow-string-insns if the program accesses I/O space ๐Ÿซถ.

When the instructions are enabled, GCC defines the C preprocessor symbol __RX_ALLOW_STRING_INSNS__. Otherwise it defines __RX_DISALLOW_STRING_INSNS__ โœจ.

  • -mjsr, -mno-jsr: uses only (or not only) "JSR" instructions to access functions ๐Ÿฆ‹. This can come in handy when your code size goes past the range of "BSR" instructions. Note that -mno-jsr doesn't mean "don't use JSR". It just means any type of branch may be used.

Note: the generic GCC command-line option -ffixed-reg has special significance to the RX port when it's used with the "interrupt" function attribute ๐Ÿงš. That attribute marks a function meant to process fast interrupts. GCC makes sure it only uses the registers "r10", "r11", "r12" and/or "r13", and only as long as the normal use of those registers has been restricted via the -ffixed-reg or -mint-register command-line options ๐ŸŒˆ.


โœจ S/390 and zSeries Options โœจ

These are the -m options defined for the S/390 and zSeries architecture ๐Ÿ’œ.

  • -mhard-float, -msoft-float: uses (or doesn't use) the hardware floating-point instructions and registers for floating-point operations ๐Ÿ”ฅ. With -msoft-float, functions in libgcc.a get used to do the floating-point operations. With -mhard-float, the compiler generates IEEE floating-point instructions. This is the default.
  • -mhard-dfp, -mno-hard-dfp: uses (or doesn't use) the hardware decimal-floating-point instructions for decimal-floating-point operations ๐Ÿ“. With -mno-hard-dfp, functions in libgcc.a do the decimal-floating-point work. With -mhard-dfp, the compiler generates decimal-floating-point hardware instructions. This is the default for -march=z9-ec or higher.
  • -mlong-double-64, -mlong-double-128: these switches control the size of the long double type ๐Ÿ‘‘. A size of 64 bits makes long double equivalent to double. This is the default.
  • -mbackchain, -mno-backchain: stores (or doesn't store) the address of the caller's frame as a backchain pointer in the callee's stack frame ๐Ÿง . A backchain might be needed to allow debugging with tools that don't understand DWARF call frame information.

When -mno-packed-stack is in effect, the backchain pointer is stored at the bottom of the stack frame. When -mpacked-stack is in effect, the backchain gets placed into the topmost word of the 96/160 byte register save area ๐ŸŒธ.

In general, code compiled with -mbackchain is call-compatible with code compiled with -mno-backchain. However, using the backchain for debugging purposes usually requires the whole binary to be built with -mbackchain ๐Ÿ’–. Note that the combination of -mbackchain, -mpacked-stack and -mhard-float is not supported. In order to build a Linux kernel, use -msoft-float ๐Ÿซถ.

The default is to not maintain the backchain.

-mpacked-stack, -mno-packed-stack

Okay so this one is all about how the stack gets laid out ๐Ÿฅž -mno-packed-stack tells the compiler to use every field of the 96/160 byte register save area only for its default purpose, which means unused fields still eat up stack space ๐Ÿ˜ญ -mpacked-stack packs the register save slots densely at the top of that area, and unused space gets reused for other stuff, so your stack space goes way further โœจ BUT if -mbackchain is also on, the topmost word of the save area is always used for the backchain, and the return address register is always saved two words below the backchain ๐Ÿ™ˆ

As long as the stack frame backchain isn't used, code made with -mpacked-stack is call-compatible with code made with -mno-packed-stack ๐Ÿซถ Lowkey tricky part: 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 ๐Ÿšซ If you're building a linux kernel, use -msoft-float instead ๐Ÿง

The default is to not use the packed stack layout ๐Ÿ’…


  • -msmall-exec, -mno-small-exec โ€” generate (or skip generating) code that uses the bras instruction for subroutine calls ๐Ÿ“ž This only works reliably if the total executable size doesn't go over 64k, so it's not for chonky programs ๐Ÿ™…โ€โ™€๏ธ The default is the basr instruction instead, which doesn't have that limit ๐ŸŒˆ
  • -m64, -m31 โ€” -m31 makes code compliant with the GNU/Linux for S/390 ABI, and -m64 makes it compliant with the GNU/Linux for zSeries ABI ๐ŸŽ€ This lets GCC generate 64-bit instructions, which is giving main character energy ๐Ÿ‘‘ For the s390 targets the default is -m31, and the s390x targets default to -m64 โœจ
  • -mzarch, -mesa โ€” -mzarch generates code using the instructions available on z/Architecture, and -mesa uses the instructions available on ESA/390 ๐Ÿฆ‹ Heads up: -mesa is NOT possible with -m64 โš ๏ธ When you're making GNU/Linux for S/390 ABI code, the default is -mesa. For GNU/Linux for zSeries ABI code, the default is -mzarch ๐Ÿ’œ
  • -mhtm, -mno-htm โ€” the -mhtm option turns on a set of builtins that use instructions from the transactional execution facility, which came in with the IBM zEnterprise EC12 machine generation, plus S/390 System z Built-in Functions ๐Ÿงš -mhtm is enabled by default when you use -march=zEC12 ๐Ÿ“
  • -mvx, -mno-vx โ€” -mvx generates code using the instructions from the vector extension facility, introduced with the IBM z13 machine generation ๐ŸŒธ This 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 binary with the ABI it used ๐Ÿ“ -mvx is enabled by default when you use -march=z13 ๐Ÿ”ฅ
  • -mzvector, -mno-zvector โ€” -mzvector turns on vector language extensions and builtins, using the same vector extension facility from the IBM z13 machine generation ๐Ÿ’– It lets you use vector as a keyword to define vector type variables and arguments ๐Ÿซง Just know that vector only works when GNU extensions are enabled. It won't expand if you ask for strict standard compliance, like with -std=c99 ๐Ÿ™…โ€โ™€๏ธ On top of the GCC low-level builtins, -mzvector also adds a set of builtins for compatibility with AltiVec-style implementations like Power and Cell ๐ŸŒˆ To use those, 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 info while compiling ๐Ÿ› The default is to not print debug info ๐Ÿ™ˆ
  • -march=cpu-type โ€” generate code that runs on cpu-type, which is the name of a system for a certain processor type ๐Ÿ–ฅ๏ธ The possible values for cpu-type are z900/arch5, z990/arch6, z9-109, z9-ec/arch7, z10/arch8, z196/arch9, zEC12, z13/arch11, z14/arch12, z15/arch13, z16/arch14, and native ๐Ÿ’… The default is -march=z900 ๐Ÿซถ

Picking native as the cpu type selects the best architecture option for the host processor ๐Ÿง  But -march=native does nothing if GCC doesn't recognize the processor ๐Ÿคทโ€โ™€๏ธ

  • -mtune=cpu-type โ€” tunes everything applicable about the generated code to cpu-type, except for the ABI and the set of available instructions โœจ The list of cpu-type values is the same as for -march ๐Ÿ“‹ The default is whatever value is used for -march ๐Ÿ’•
  • -mtpf-trace, -mno-tpf-trace โ€” generate code that adds (or doesn't add) TPF OS specific branches to trace routines in the operating system ๐Ÿ” This is off by default, even when you're compiling for the TPF OS ๐Ÿ˜ค
  • -mtpf-trace-skip, -mno-tpf-trace-skip โ€” generate code that changes (or doesn't change) the default branch targets enabled by -mtpf-trace, so they point to specialized trace routines ๐ŸŽฏ This lets you selectively skip function trace entries for the TPF OS ๐Ÿฆ‹ It's off by default too, even when you're 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 get generated by default if hardware floating point is used ๐Ÿ’ช
  • -mwarn-framesize=framesize โ€” emits a warning if the current function goes over 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 spot functions that most probably cause a stack overflow ๐ŸŒŠ It's super useful in environments with a limited stack size, like the linux kernel ๐Ÿง
  • -mwarn-dynamicstack โ€” emits a warning if the function calls alloca or uses dynamically-sized arrays ๐Ÿšจ This is generally a bad idea with a limited stack size ๐Ÿ˜ฌ
  • -mstack-guard=stack-guard, -mstack-size=stack-size โ€” if you give these options, the S/390 back end adds extra instructions to the function prologue that trigger a trap if the stack size is stack-guard bytes above the stack-size ๐Ÿชค (Remember, the stack on S/390 grows downward, so keep that in mind ๐Ÿ™ƒ) If you leave out stack-guard, the smallest power of 2 larger than the frame size of the compiled function gets picked ๐Ÿงฎ These are meant to help you debug stack overflow problems ๐Ÿž The extra code only adds a little overhead, so it can even be used in production-like systems without a big performance hit ๐Ÿš€

The values have to be exact powers of 2, and stack-size has to be greater than stack-guard without going over 64k ๐Ÿ“ To be efficient, the extra code assumes the stack starts at an address aligned to the value given by stack-size ๐Ÿงฉ Also, -mstack-guard can only be used together with -mstack-size ๐Ÿซถ

  • -mhotpatch=pre-halfwords,post-halfwords โ€” if the hotpatch option is enabled, a "hot-patching" function prologue is generated for all functions in the compilation unit ๐Ÿ”ฅ The function label gets prepended with the given number of two-byte NOP instructions (pre-halfwords, maximum 1000000) ๐Ÿ›Œ After the label, 2 * post-halfwords bytes get appended, using the largest NOP-like instructions the architecture allows (maximum 1000000) ๐Ÿงฑ

If both arguments are zero, hotpatching is disabled ๐Ÿ™…โ€โ™€๏ธ

You can override this for individual functions with the "hotpatch" attribute ๐Ÿ’œ


โœจ Score Options โœจ

These options are defined for Score implementations ๐ŸŒŸ

  • -meb โ€” compile code for big-endian mode ๐Ÿ‘ This is the default ๐Ÿ’…
  • -mel โ€” compile code for little-endian mode ๐ŸŒŠ
  • -mnhwloop โ€” disables generation of bcnz instructions ๐Ÿšซ
  • -muls โ€” enables generation of unaligned load and store instructions ๐Ÿงถ
  • -mmac โ€” enables the use of multiply-accumulate instructions ๐Ÿงฎ Disabled by default ๐Ÿ’ค
  • -mscore5 โ€” specifies SCORE5 as the target architecture ๐ŸŽฏ
  • -mscore5u โ€” specifies SCORE5U as the target architecture ๐ŸŽฏ
  • -mscore7 โ€” specifies SCORE7 as the target architecture ๐Ÿ‘‘ This is the default ๐Ÿ’–
  • -mscore7d โ€” specifies SCORE7D as the target architecture ๐ŸŽฏ

โœจ SH Options โœจ

These -m options are defined for the SH implementations ๐Ÿฆ„

  • -m1 โ€” generate code for the SH1 ๐ŸŒฑ
  • -m2 โ€” generate code for the SH2 ๐ŸŒฟ
  • -m2e โ€” generate code for the SH2e ๐Ÿƒ
  • -m2a-nofpu โ€” generate code for the SH2a without FPU, or for a SH2a-FPU in such a way that the floating-point unit isn't used ๐Ÿ™ˆ
  • -m2a-single-only โ€” generate code for the SH2a-FPU so that no double-precision floating-point operations are used ๐ŸŽ€
  • -m2a-single โ€” generate code for the SH2a-FPU, assuming the floating-point unit is in single-precision mode by default ๐Ÿ”น
  • -m2a โ€” generate code for the SH2a-FPU, assuming the floating-point unit is in double-precision mode by default ๐Ÿ”ท
  • -m3 โ€” generate code for the SH3 ๐ŸŒผ
  • -m3e โ€” generate code for the SH3e ๐ŸŒป
  • -m4-nofpu โ€” generate code for the SH4 without a floating-point unit ๐Ÿ™…โ€โ™€๏ธ
  • -m4-single-only โ€” generate code for the SH4 with a floating-point unit that only supports single-precision arithmetic ๐Ÿซง
  • -m4-single โ€” generate code for the SH4, assuming the floating-point unit is in single-precision mode by default ๐ŸŒท
  • -m4 โ€” generate code for the SH4 ๐ŸŒบ
  • -m4-100 โ€” generate code for SH4-100 ๐Ÿ’ฏ
  • -m4-100-nofpu โ€” generate code for SH4-100 in such a way that the floating-point unit isn't used ๐Ÿ™ˆ
  • -m4-100-single โ€” generate code for SH4-100, assuming the floating-point unit is in single-precision mode by default โœจ
  • -m4-100-single-only โ€” generate code for SH4-100 so that no double-precision floating-point operations are used ๐ŸŽ€
  • -m4-200 โ€” generate code for SH4-200 ๐Ÿš€
  • -m4-200-nofpu: okay so this one makes code for the SH4-200 without touching the floating-point unit at all ๐Ÿ’…
  • -m4-200-single: code for SH4-200, assuming the FPU boots up in single-precision mode by default โœจ
  • -m4-200-single-only: code for SH4-200 that never uses double-precision floating-point operations ๐Ÿฆ‹
  • -m4-300: code for SH4-300 ๐ŸŒธ
  • -m4-300-nofpu: code for SH4-300 that keeps the floating-point unit out of it ๐Ÿซถ
  • -m4-300-single: code for SH4-300 that never uses double-precision floating-point operations ๐Ÿ’œ
  • -m4-300-single-only: same vibe as the one above, the page says the exact same thing for this one too ๐Ÿ™ˆ
  • -m4-340: code for SH4-340, which has no MMU and no FPU ๐Ÿ’€
  • -m4-500: code for SH4-500, no FPU. It also passes -isa=sh4-nofpu to the assembler ๐Ÿ”ฅ
  • -m4a-nofpu: code for the SH4al-dsp, or for a SH4a where the floating-point unit is not used ๐ŸŒˆ
  • -m4a-single-only: code for the SH4a that skips all double-precision floating-point operations ๐Ÿ‘‘
  • -m4a-single: code for the SH4a, assuming the FPU is in single-precision mode by default โญ
  • -m4a: code for the SH4a, full stop ๐Ÿงš
  • -m4al: same as -m4a-nofpu, except it implicitly passes -dsp to the assembler. GCC doesn't generate any DSP instructions rn ๐ŸŽ€
  • -mb: compile for the processor in big-endian mode ๐Ÿ“
  • -ml: compile for the processor in little-endian mode ๐Ÿ’–
  • -mdalign: align doubles at 64-bit boundaries. Heads up bestie: this changes the calling conventions, so some functions from the standard C library won't work unless you recompile it first with -mdalign ๐Ÿ˜ญ
  • -mrelax: shorten some address references at link time, when possible. It uses the linker option -relax โœจ
  • -mbigtable: use 32-bit offsets in "switch" tables. The default is 16-bit offsets ๐Ÿฆ‹
  • -mbitops: enable bit manipulation instructions on SH2A ๐Ÿ’…
  • -mfmovd: enable the fmovd instruction. Check -mdalign for the alignment constraints ๐Ÿซถ
  • -mrenesas: comply with the calling conventions defined by Renesas ๐Ÿ‘‘
  • -mno-renesas: comply with the calling conventions GCC used before the Renesas ones existed. 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: these control the IEEE compliance of floating-point comparisons, which affects how cases where the comparison result is unordered get handled. By default -mieee is implicitly enabled. If -ffinite-math-only is enabled, -mno-ieee gets 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 "icbi" instruction. If the selected option doesn't allow "icbi" and -musermode is not in effect, the inlined code pokes the instruction cache address array directly with an associative write. That not only needs privileged mode at run time, it also fails if the cache line got mapped via the TLB and has since become unmapped ๐Ÿ™ˆ
  • -misize: dump instruction size and location in the assembly code ๐Ÿงš
  • -mpadstruct: this one is deprecated ๐Ÿ’€. It pads structures to a multiple of 4 bytes, which is incompatible with the SH ABI
  • -matomic-model=model: sets the model of atomic operations, plus any extra parameters, as a comma-separated list. For the full scoop on atomic built-in functions, check __atomic Builtins. These are the models and parameters you can pick from โœจ
    • none: disables compiler-generated atomic sequences and emits library calls for atomic operations. This is the default if the target is not "sh*-*-linux*"
    • soft-gusa: generates GNU/Linux compatible gUSA software atomic sequences for the atomic built-in functions. These 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 on by default when the target is "sh*-*-linux*" and SH3* or SH4*. On SH4A it also partly uses the hardware atomic instructions movli.l and movco.l to make the code more efficient, unless strict is specified ๐Ÿฆ‹
    • soft-tcb: generates software atomic sequences that use a variable in the thread control block. It's a variation of the gUSA sequences that also works on SH1* and SH2* targets. These sequences need extra interrupt/exception handling support and are only suitable for single-core systems. When you use this model, the gbr-offset= parameter has to be specified as well ๐ŸŒˆ
    • soft-imask: generates software atomic sequences that temporarily disable interrupts by setting "SR.IMASK = 1111". This model only works when the program runs in privileged mode and is only suitable for single-core systems. No extra interrupt/exception handling support is needed. It's on by default when the target is "sh*-*-linux*" and SH1* or SH2* ๐Ÿ”ฅ
    • hard-llcs: generates hardware atomic sequences using only the movli.l and movco.l instructions. This is only available on SH4A and is suitable for multi-core systems. Since the hardware instructions only support 32-bit atomic variable access, 8-bit and 16-bit variables get emulated with 32-bit accesses. Code compiled with this option is also compatible with other software atomic model interrupt/exception handling systems if it runs on an SH4A system. No extra interrupt/exception support is required for this model ๐Ÿ‘‘
    • gbr-offset=: the offset in bytes of the variable inside the thread control block structure that the generated atomic sequences should use when the soft-tcb model is selected. For other models this parameter is ignored. The value must be an integer multiple of four and in the range 0-1020 โญ
    • strict: stops you from mixing multiple atomic models, even compatible ones, and makes the compiler generate atomic sequences of the specified model only ๐Ÿ’…
  • -mtas: generates the tas.b opcode for __atomic_test_and_set. Notice that depending on your particular hardware and software setup, this can degrade overall performance because of the operand cache line flushes that the tas.b instruction implies ๐Ÿซถ
Careful, bestie! On multi-core SH4A processors, the tas.b instruction has to be used with caution, since it can cause data corruption for certain cache configurations ๐Ÿ˜ญ
  • -mprefergot: when generating position-independent code, emit function calls through the Global Offset Table instead of the Procedure Linkage Table ๐Ÿงš
  • -musermode, -mno-usermode: "Don't allow (allow) the compiler generating privileged mode code," according to the page ๐Ÿ™ˆ. Specifying -musermode also implies -mno-inline-ic_invalidate if the inlined code wouldn't work in user mode. -musermode is the default when the target is "sh*-*-linux*". If the target is SH1* or SH2*, -musermode has no effect, since there's no user mode there ๐Ÿ’œ
  • -multcost=number: sets the cost to assume for a multiply insn ๐ŸŒธ
  • -mdiv=strategy: sets the division strategy used for integer division operations. strategy can be one of these ๐Ÿ”ฅ
    • call-div1: calls a library function that uses the single-step division instruction div1 to do the job. Division 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. Division by zero causes a floating-point exception. This is the default for SHcompact with FPU. Specifying this for targets without a double-precision FPU defaults to call-div1 ๐Ÿ‘‘
    • call-table: calls a library function that uses a lookup table for small divisors and the div1 instruction with case distinction for bigger divisors. Division by zero gives an unspecified result and doesn't trap. This is the default for SH4. Specifying this for targets without dynamic shift instructions defaults to call-div1 โœจ
    • When no division strategy is specified, the default is picked 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 change around conditional code ๐Ÿซถ
  • -mdivsi3_libfunc=name: sets the name of the library function used for 32-bit signed division to name. This only changes the name used in the call division strategies. The compiler still expects the same sets of input, output 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. This is super useful when compiling kernel code ๐Ÿ’–. A register range is written as two registers separated by a dash, and you can list multiple ranges separated by a comma ๐ŸŽ€
  • -mbranch-cost=num โ€” โœจ okay so num is basically the cost you're assigning to a branch instruction ๐Ÿฆ‹. Crank it higher and the compiler will try harder to write branch-free code when it can ๐Ÿ’…. If you don't set it, GCC picks a value based on which processor you're compiling for ๐Ÿงš.
  • -mzdcbranch, -mno-zdcbranch โ€” ๐Ÿ’– These tell the compiler whether zero displacement conditional branches, "bt" and "bf", are fast. With -mzdcbranch it'll prefer those zero displacement branch sequences ๐ŸŒธ. It's already on by default when you're targeting SH4 and SH4A ๐Ÿ‘‘, and you can turn it off explicitly with -mno-zdcbranch ๐Ÿ™ˆ.
  • -mcbranch-force-delay-slot โ€” ๐Ÿ˜ญ This forces conditional branches to use delay slots. If nothing suitable can fill the slot, it gets stuffed with a nop instead ๐Ÿ’€. It's off by default, but you can flip it on to work around hardware bugs found in the original SH7055 ๐Ÿ”ฅ.
  • -mfused-madd, -mno-fused-madd โ€” ๐ŸŒˆ Lowkey this controls whether the floating-point multiply and accumulate instructions get used. They're generated by default when hardware floating point is in play โœจ. Heads up: the machine-dependent -mfused-madd is now mapped to the machine-independent -ffp-contract=fast, and -mno-fused-madd is mapped to -ffp-contract=off ๐Ÿซถ.
  • -mfsca, -mno-fsca โ€” ๐Ÿงš These allow or disallow the compiler from emitting the "fsca" instruction for sine and cosine approximations. You have to pair -mfsca with -funsafe-math-optimizations ๐Ÿ”ฅ. It's on by default for SH4A. And -mno-fsca shuts off those sine and cosine approximations even when -funsafe-math-optimizations is in effect ๐Ÿ™…โ€โ™€๏ธ.
  • -mfsrra, -mno-fsrra โ€” ๐Ÿฆ‹ Same vibe, but for the "fsrra" instruction, which handles reciprocal square root approximations. -mfsrra needs to be used with both -funsafe-math-optimizations and -ffinite-math-only ๐Ÿ’œ. It's enabled by default for SH4A. -mno-fsrra turns off reciprocal square root approximations even if -funsafe-math-optimizations and -ffinite-math-only are both active ๐ŸŽ€.
  • -mpretend-cmove โ€” ๐Ÿ‘‘ This prefers zero-displacement conditional branches for conditional move instruction patterns. It can give you faster code on the SH4 processor โญ.
  • -mfdpic โ€” ๐ŸŒธ Generates code using the FDPIC ABI ๐Ÿ’….

โœจ Solaris 2 Options โœจ

These -m options are supported on Solaris 2 ๐ŸŒˆ:

  • -mclear-hwcap โ€” ๐Ÿซถ This tells the compiler to remove the hardware capabilities that the Solaris assembler generated. You only really need it when object files use ISA extensions that the current machine doesn't support, but the code checks at runtime whether or not to use them ๐Ÿ™ˆ.
  • -mimpure-text โ€” ๐Ÿ”ฅ Used alongside -shared, this tells the compiler not to pass -z text to the linker when it's linking a shared object. With it, you can link position-dependent code into a shared object ๐Ÿงš.
โš ๏ธ Bestie, be careful here. -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 is not 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 that uses global registers 2 through 4, which the SPARC SVR4 ABI reserves for applications ๐Ÿ‘‘. Just like global register 1, each of global registers 2 through 4 is then treated as an allocable register that gets clobbered by function calls. This is the default ๐Ÿ’œ.

If you want to be fully SVR4 ABI-compliant (at the cost of some performance loss), go with -mno-app-regs ๐Ÿซถ. You should compile libraries and system software with this option ๐Ÿ”ฅ.

  • -mflat, -mno-flat โ€” ๐Ÿงš With -mflat, the compiler doesn't generate save/restore instructions and uses a "flat" or single register window model ๐Ÿฆ‹. This model is compatible with the regular register window model. The local registers and the input registers (0--5) are still treated as "call-saved" registers and get saved on the stack as needed โœจ.

With -mno-flat (the default), the compiler generates save/restore instructions, except for leaf functions ๐ŸŒˆ. This is the normal operating mode ๐Ÿ’–.

  • -mfpu, -mhard-float โ€” โญ Generates output containing floating-point instructions. This is the default ๐ŸŽ€.
  • -mno-fpu, -msoft-float โ€” ๐Ÿ˜ญ Generates output containing library calls for floating point instead.
โš ๏ธ Warning, bestie: the requisite libraries are not available for all SPARC targets ๐Ÿ’€. Normally the facilities of the machine's usual C compiler are used, but this can't be done directly in cross-compilation ๐Ÿ™ˆ. You must 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 in order for this to work ๐Ÿซถ.

  • -mhard-quad-float โ€” ๐Ÿ’… Generates output containing quad-word (long double) floating-point instructions ๐ŸŒธ.
  • -msoft-quad-float โ€” ๐Ÿฆ‹ Generates output containing library calls for quad-word (long double) floating-point instructions. The functions called are the ones specified in the SPARC ABI. This is the default ๐Ÿ’œ.

As of this writing, there are no SPARC implementations with hardware support for the quad-word floating-point instructions ๐Ÿ˜ญ. They all invoke a trap handler for one of these instructions, and then the trap handler emulates the effect of the instruction ๐Ÿ’€. Because of that trap handler overhead, this is much slower than calling the ABI library routines ๐Ÿ™ˆ. So -msoft-quad-float is the default โœจ.

  • -mno-unaligned-doubles, -munaligned-doubles โ€” ๐ŸŒˆ Assumes that doubles have 8-byte alignment. This is the default ๐Ÿ’–.

With -munaligned-doubles, GCC assumes doubles have 8-byte alignment only if they're contained in another type, or if they have an absolute address ๐ŸŽ€. Otherwise, it assumes they have 4-byte alignment โญ. Using this option avoids some rare compatibility problems with code generated by other compilers ๐Ÿซถ. It's not the default, though, because it results in a performance loss, especially for floating-point code ๐Ÿ˜ญ.

  • -muser-mode, -mno-user-mode โ€” ๐Ÿ‘‘ Does not generate code that can only run in supervisor mode. This is only relevant for the "casa" instruction emitted for the LEON3 processor ๐Ÿงš. This is the default ๐Ÿ’….
  • -mfaster-structs, -mno-faster-structs โ€” ๐Ÿ”ฅ With -mfaster-structs, the compiler assumes structures should have 8-byte alignment ๐Ÿฆ‹. That lets it use pairs of "ldd" and "std" instructions for copies in structure assignment, in place of twice as many "ld" and "st" pairs โœจ.
โš ๏ธ Bestie, this one is spicy. The use of this changed alignment directly violates the SPARC ABI ๐Ÿ’€. So it's intended only for targets where the developer acknowledges that their resulting code is not directly in line with the rules of the ABI ๐Ÿ˜ญ.
  • -mstd-struct-return, -mno-std-struct-return โ€” ๐ŸŒธ With -mstd-struct-return, the compiler generates checking code in functions returning structures or unions. That code detects size mismatches between the two sides of function calls, as per the 32-bit ABI ๐Ÿ“.

The default is -mno-std-struct-return ๐Ÿ’œ. This option has no effect in 64-bit mode ๐Ÿ™ˆ.

  • -mlra, -mno-lra โ€” ๐Ÿ’– Enables Local Register Allocation. This has been the default for SPARC since GCC 7, so you need to pass -mno-lra if you want the old Reload ๐ŸŽ€.
  • -mcpu=cpu_type โ€” ๐ŸŒˆ Sets the instruction set, register set, and instruction scheduling parameters for machine type cpu_type โœจ. Supported values for cpu_type are v7, cypress, v8, supersparc, hypersparc, leon, leon3, leon3v7, leon5, sparclite, f930, f934, sparclite86x, sparclet, tsc701, v9, ultrasparc, ultrasparc3, niagara, niagara2, niagara3, niagara4, niagara7 and m8 ๐Ÿ‘‘.

Native Solaris and GNU/Linux toolchains also support the value native, which selects the best architecture option for the host processor ๐Ÿซถ. -mcpu=native has no effect if GCC doesn't recognize the processor ๐Ÿ™ˆ.

Default instruction scheduling parameters are used for values that select an architecture and not an implementation ๐Ÿงš. Those are v7, v8, sparclite, sparclet, and v9 ๐Ÿ’….

Here's the lineup of each supported architecture and its supported implementations ๐Ÿฆ‹:

  • v7 โ€” cypress, leon3v7
  • v8 โ€” supersparc, hypersparc, leon, leon3, leon5
  • sparclite โ€” f930, f934, sparclite86x
  • sparclet โ€” tsc701
  • v9 โ€” ultrasparc, ultrasparc3, niagara, niagara2, niagara3, niagara4, niagara7, m8

By default (unless configured otherwise), GCC generates code for the V7 variant of the SPARC architecture ๐ŸŒธ. With -mcpu=cypress, the compiler additionally optimizes it for the Cypress CY7C602 chip, as used in the SPARCStation/SPARCServer 3xx series โœจ. This is also appropriate for the older SPARCStation 1, 2, IPX etc. ๐Ÿ’–.

With -mcpu=v8, GCC generates code for the V8 variant of the SPARC architecture ๐ŸŽ€. The only difference from V7 code is that the compiler emits the integer multiply and integer divide instructions, which exist in SPARC-V8 but not in SPARC-V7 ๐ŸŒˆ. With -mcpu=supersparc, the compiler additionally optimizes it for the SuperSPARC chip, as used in the SPARCStation 10, 1000 and 2000 series โญ.

With -mcpu=sparclite, GCC generates code for the SPARClite variant of the SPARC architecture ๐Ÿ”ฅ. This adds the integer multiply, integer divide step and scan ("ffs") instructions, which exist in SPARClite but not in SPARC-V7 ๐Ÿ˜ญ. With -mcpu=f930, the compiler additionally optimizes it for the Fujitsu MB86930 chip, which is the original SPARClite, with no FPU ๐Ÿงš. With -mcpu=f934, the compiler additionally optimizes it for the Fujitsu MB86934 chip, which is the more recent SPARClite with FPU ๐Ÿ‘‘.

With -mcpu=sparclet, GCC generates code for the SPARClet variant of the SPARC architecture ๐Ÿฆ‹ This adds the integer multiply, multiply/accumulate, integer divide step and scan ("ffs") instructions, which exist in SPARClet but not in SPARC-V7. With -mcpu=tsc701, the compiler also optimizes it for the TEMIC SPARClet chip ๐Ÿ’…

With -mcpu=v9, GCC generates code for the V9 variant of the SPARC architecture โœจ This adds 64-bit integer and floating-point move instructions, 3 additional floating-point condition code registers, and conditional move instructions. With -mcpu=ultrasparc, the compiler also optimizes it for the Sun UltraSPARC I/II/IIi chips ๐Ÿ”ฅ With -mcpu=ultrasparc3, it's optimized for the Sun UltraSPARC III/III+/IIIi/IIIi+/IV/IV+ chips ๐Ÿ‘‘ With -mcpu=niagara, the compiler also optimizes it for Sun UltraSPARC T1 chips ๐ŸŒธ With -mcpu=niagara2, it's optimized for Sun UltraSPARC T2 chips ๐Ÿซถ With -mcpu=niagara3, it's optimized for Sun UltraSPARC T3 chips ๐Ÿ’œ With -mcpu=niagara4, it's optimized for Sun UltraSPARC T4 chips ๐ŸŒˆ With -mcpu=niagara7, the compiler also optimizes it for Oracle SPARC M7 chips โญ And With -mcpu=m8, it's optimized for Oracle M8 chips. Iconic ๐Ÿ˜ญ


  • -mtune=cpu_type โ€” Sets the instruction scheduling parameters for machine type cpu_type, but does not set the instruction set or register set the way -mcpu=cpu_type does ๐ŸŽ€

The same values for -mcpu=cpu_type work here too, but honestly the only useful ones are the ones that select a particular CPU implementation. Those are cypress, supersparc, hypersparc, leon, leon3, leon3v7, leon5, f930, f934, sparclite86x, tsc701, ultrasparc, ultrasparc3, niagara, niagara2, niagara3, niagara4, niagara7 and m8. With native Solaris and GNU/Linux toolchains, native can also be used ๐Ÿงš

  • -mv8plus, -mno-v8plus โ€” With -mv8plus, GCC generates code for the SPARC-V8+ ABI ๐Ÿ’– The difference from the V8 ABI is that the global and out registers are considered 64 bits wide. This is enabled by default on Solaris in 32-bit mode for all SPARC-V9 processors.
  • -mvis, -mno-vis โ€” With -mvis, GCC generates code that takes advantage of the UltraSPARC Visual Instruction Set extensions ๐Ÿฆ‹ The default is -mno-vis.
  • -mvis2, -mno-vis2 โ€” With -mvis2, GCC generates code that takes advantage of version 2.0 of the UltraSPARC Visual Instruction Set extensions. The default is -mvis2 when targeting a cpu that supports such instructions, such as UltraSPARC-III and later. Setting -mvis2 also sets -mvis ๐Ÿ”ฅ
  • -mvis3, -mno-vis3 โ€” With -mvis3, GCC generates code that takes advantage of version 3.0 of the UltraSPARC Visual Instruction Set extensions. The default is -mvis3 when targeting a cpu that supports such instructions, such as niagara-3 and later. Setting -mvis3 also sets -mvis2 and -mvis โœจ
  • -mvis4, -mno-vis4 โ€” With -mvis4, GCC generates code that takes advantage of version 4.0 of the UltraSPARC Visual Instruction Set extensions. The default is -mvis4 when targeting a cpu that supports such instructions, such as niagara-7 and later. Setting -mvis4 also sets -mvis3, -mvis2 and -mvis ๐Ÿ‘‘
  • -mvis4b, -mno-vis4b โ€” With -mvis4b, GCC generates code that takes advantage of version 4.0 of the UltraSPARC Visual Instruction Set extensions, plus the additional VIS instructions introduced in the Oracle SPARC Architecture 2017 ๐ŸŒˆ The default is -mvis4b when targeting a cpu that supports such instructions, such as m8 and later. Setting -mvis4b also sets -mvis4, -mvis3, -mvis2 and -mvis ๐Ÿ’…
  • -mcbcond, -mno-cbcond โ€” With -mcbcond, GCC generates code that takes advantage of the UltraSPARC Compare-and-Branch-on-Condition instructions. The default is -mcbcond when targeting a CPU that supports such instructions, such as Niagara-4 and later ๐Ÿ“
  • -mfmaf, -mno-fmaf โ€” With -mfmaf, GCC generates code that takes advantage of the UltraSPARC Fused Multiply-Add Floating-point instructions. The default is -mfmaf when targeting a CPU that supports such instructions, such as Niagara-3 and later ๐Ÿ’œ
  • -mfsmuld, -mno-fsmuld โ€” With -mfsmuld, GCC generates code that takes advantage of the Floating-point Multiply Single to Double (FsMULd) instruction. The default is -mfsmuld when targeting a CPU supporting the architecture versions V8 or V9 with FPU, except -mcpu=leon ๐Ÿงš
  • -mpopc, -mno-popc โ€” With -mpopc, GCC generates code that takes advantage of the UltraSPARC Population Count instruction. The default is -mpopc when targeting a CPU that supports such an instruction, such as Niagara-2 and later ๐ŸŒธ
  • -msubxc, -mno-subxc โ€” With -msubxc, GCC generates code that takes advantage of the UltraSPARC Subtract-Extended-with-Carry instruction. The default is -msubxc when targeting a CPU that supports such an instruction, such as Niagara-7 and later ๐Ÿฆ‹
  • -mfix-at697f โ€” Enables the documented workaround for the single erratum of the Atmel AT697F processor (which corresponds to erratum #13 of the AT697E processor) ๐Ÿ› ๏ธ
  • -mfix-ut699 โ€” Enables the documented workarounds for the floating-point errata and the data cache nullify errata of the UT699 processor ๐Ÿซถ
  • -mfix-ut700 โ€” Enables the documented workaround for the back-to-back store errata of the UT699E/UT700 processor ๐Ÿ’–
  • -mfix-gr712rc โ€” Enables the documented workaround for the back-to-back store errata of the GR712RC processor โœจ

These -m options are supported in addition to the above 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 the following:
    • medlow โ€” The Medium/Low code model: 64-bit addresses, 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, programs must be linked in the low 44 bits of memory, the text and data segments must be less than 2GB in size and the data segment must be located within 2GB of the text segment ๐Ÿ’œ
    • medany โ€” The Medium/Anywhere code model: 64-bit addresses, programs may be linked anywhere in memory, the text and data segments must be less than 2GB in size and the data segment must be located within 2GB of the text segment ๐ŸŽ€
    • embmedany โ€” The Medium/Anywhere code model for embedded systems: 64-bit addresses, the text and data segments must be less than 2GB in size, both starting anywhere in memory (determined at link time). The global register %g4 points to the base of the data segment. Programs are statically linked and PIC is not supported ๐Ÿงš
  • -mmemory-model=mem-model โ€” Sets the memory model in force on the processor to one of the following:
    • default โ€” The default memory model for the processor and operating system ๐ŸŒธ
    • rmo โ€” Relaxed Memory Order ๐Ÿ“
    • pso โ€” Partial Store Order ๐Ÿฆ‹
    • tso โ€” Total Store Order โœจ
    • sc โ€” Sequential Consistency ๐Ÿ’…

These memory models are formally defined in Appendix D of the SPARC-V9 architecture manual, as set in the processor's "PSTATE.MM" field ๐Ÿค“

  • -mstack-bias, -mno-stack-bias โ€” With -mstack-bias, GCC assumes that the stack pointer, and frame pointer if present, are offset by -2047, which must be added back when making stack frame references. This is the default in 64-bit mode. Otherwise, it assumes no such offset is present ๐Ÿซถ

โœจ Options for System V โœจ

These additional options are available on System V Release 4 for compatibility with other compilers on those systems ๐Ÿ’…

  • -G โ€” Creates a shared object. It is recommended that -symbolic or -shared be used instead ๐Ÿ”ฅ
  • -Qy โ€” Identifies the versions of each tool used by the compiler, in a .ident assembler directive in the output ๐ŸŒˆ
  • -Qn โ€” Refrains from adding .ident directives to the output file (this is the default) ๐Ÿ“
  • -YP,dirs โ€” Searches the directories dirs, and no others, for libraries specified with -l ๐Ÿงš
  • -Ym,dir โ€” Looks in the directory dir to find the M4 preprocessor. The assembler uses this option ๐Ÿฆ‹

โœจ TILE-Gx Options โœจ

These -m options are supported on the TILE-Gx ๐Ÿ’–

  • -mcmodel=small โ€” Generates code for the small model. The distance for direct calls is limited to 500M in either direction. PC-relative addresses are 32 bits. Absolute addresses support the full address range ๐ŸŒธ
  • -mcmodel=large โ€” Generates code for the large model. There is no limitation on call distance, pc-relative addresses, or absolute addresses ๐Ÿ‘‘
  • -mcpu=name โ€” Selects the type of CPU to be targeted. Currently the only supported type is tilegx โœจ
  • -m32, -m64 โ€” Generate 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 โ€” Generate code in big or little endian mode, respectively ๐Ÿ’œ

โœจ TILEPro Options โœจ

These -m options are supported on the TILEPro ๐ŸŽ€

  • -mcpu=name โ€” Selects the type of CPU to be targeted. Currently the only supported type is tilepro ๐Ÿงš
  • -m32 โ€” Generates code for a 32-bit environment, which sets int, long, and pointer to 32 bits. This is the only supported behavior so the flag is essentially ignored ๐ŸŒˆ

โœจ V850 Options โœจ

These -m options are defined for V850 implementations ๐Ÿฆ‹

  • -mlong-calls, -mno-long-calls โ€” Treats all calls as being far away (near). If calls are assumed to be far away, the compiler always loads the function's address into a register and calls indirect through the pointer ๐Ÿ“
  • -mno-ep, -mep โ€” Does not optimize (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 ๐Ÿ’…

โœจ Machine-dependent goodies, continued โœจ

  • -mno-prolog-function, -mprolog-function โ€” bestie, these decide whether the function prologue and epilogue use external helper functions to save and restore registers ๐Ÿซถ -mprolog-function is the default if you optimize. The helpers are slower, but if several functions save the same number of registers, they take up less code space ๐Ÿ’…
  • -mspace โ€” the "make it tiny" button ๐Ÿงš It just switches on -mep and -mprolog-function.
  • -mtda=n โ€” puts static or global variables that are n bytes or smaller into the tiny data area that register ep points to ๐ŸŒธ That area holds up to 256 bytes total, and 128 of those are for byte references.
  • -msda=n โ€” same vibe, but for the small data area that register gp points to ๐ŸŽ€ Variables of n bytes or less go in there, and it can hold up to 64 kilobytes.
  • -mzda=n โ€” variables of n bytes or less get put into the first 32 kilobytes of memory ๐Ÿฆ‹
  • -mv850 โ€” tells GCC your target processor is the V850 ๐Ÿ’œ
  • -mv850e3v5 โ€” your target is the V850E3V5, and the preprocessor constant __v850e3v5__ gets defined when you use this โœจ
  • -mv850e2v4 โ€” heads up, this one is giving confusing energy ๐Ÿ’€ The page says it targets the V850E3V5, and it's just an alias for -mv850e3v5.
  • -mv850e2v3 โ€” your target is the V850E2V3, and __v850e2v3__ gets defined ๐ŸŒˆ
  • -mv850e2 โ€” your target is the V850E2, and __v850e2__ gets defined ๐Ÿ“
  • -mv850e1 โ€” your target is the V850E1, and both __v850e1__ and __v850e__ get defined ๐Ÿ‘‘
  • -mv850es โ€” the V850ES, which is just an alias for -mv850e1 ๐Ÿ”ฅ
  • -mv850e โ€” your target is the V850E, and __v850e__ gets defined ๐Ÿ’–

If none of -mv850, -mv850e, -mv850e1, -mv850e2, -mv850e2v3, or -mv850e3v5 is set, GCC picks a default target processor for you and defines the matching __v850*__ preprocessor constant. No cap, that's a lot of constants ๐Ÿ˜ญ

The preprocessor constants __v850 and __v851__ are always defined, no matter which processor variant you're targeting โœจ

  • -mdisable-callt, -mno-disable-callt โ€” this one stops GCC from generating the CALLT instruction for the v850e, v850e1, v850e2, v850e2v3, and v850e3v5 flavors of the v850 architecture ๐Ÿ™ˆ It's on by default when the RH850 ABI is in use (see -mrh850-abi), and off by default when the GCC ABI is in use. When CALLT instructions are being generated, the C preprocessor symbol __V850_CALLT__ is defined ๐Ÿฆ‹
  • -mrelax, -mno-relax โ€” passes (or doesn't pass) the -mrelax command-line option along to the assembler ๐Ÿซถ
  • -mlong-jumps, -mno-long-jumps โ€” turns off (or turns back on) the generation of PC-relative jump instructions ๐ŸŒธ
  • -msoft-float, -mhard-float โ€” turns off (or back on) the generation of hardware floating point instructions ๐Ÿ’… This only matters when the target architecture is V850E2V3 or higher. If hardware floating point instructions are being generated, the symbol __FPU_OK__ is defined; otherwise __NO_FPU__ is defined.
  • -mloop โ€” enables the use of the e3v5 LOOP instruction ๐Ÿงš It's not enabled by default when the e3v5 architecture is selected, because its use is still experimental, so proceed with a little caution ๐Ÿ‘€
  • -mrh850-abi, -mghs โ€” enables support for the RH850 version of the V850 ABI, and this is the default โœจ With this version, these rules apply:
    • Integer sized structures and unions are returned via a memory pointer instead of a register.
    • Large structures and unions (more than 8 bytes in size) are passed by value.
    • Functions are aligned to 16-bit boundaries.
    • The -m8byte-align command-line option is supported.
    • The -mdisable-callt command-line option is enabled by default. The -mno-disable-callt command-line option is not supported.

When this version of the ABI is enabled, the C preprocessor symbol __V850_RH850_ABI__ is defined ๐Ÿ‘‘

  • -mgcc-abi โ€” enables support for the old GCC version of the V850 ABI ๐Ÿ“ With this version, these rules apply:
    • Integer sized structures and unions are returned in register r10.
    • Large structures and unions (more than 8 bytes in size) are passed by reference.
    • Functions are aligned to 32-bit boundaries, unless you're optimizing for size.
    • The -m8byte-align command-line option is not supported.
    • The -mdisable-callt command-line option is supported but 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 โ€” lets double and long long types get aligned on 8-byte boundaries ๐Ÿ’– The default is to keep 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 that's suitable for big switch tables ๐Ÿ™ˆ Only use this if the assembler or linker complains about out of range branches inside a switch table, because it's a specific fix and not a everyday flex.
  • -mapp-regs โ€” makes the generated code use r2 and r5 ๐Ÿ’… This is the default.
  • -mno-app-regs โ€” treats r2 and r5 as fixed registers so they're left alone ๐Ÿฆ‹

๐Ÿ˜ VAX Options ๐Ÿ˜

These -m options are defined for the VAX ๐ŸŽ€

  • -munix โ€” doesn't output certain jump instructions, like aobleq and so on, because the Unix assembler for the VAX can't handle them across long ranges ๐Ÿซถ
  • -mgnu โ€” does output those jump instructions, on the assumption that you're using the GNU assembler ๐Ÿ”ฅ
  • -mg โ€” outputs code for G-format floating-point numbers instead of D-format ๐Ÿ’œ

๐Ÿ›ธ Visium Options ๐Ÿ›ธ

  • -mdebug โ€” if your program does file I/O and is headed for an MCM target, link it with this option โœจ It causes the libraries libc.a and libdebug.a to get linked. You should run the program on the target under the control of the GDB remote debugging stub.
  • -msim โ€” if your program does file I/O and is headed for the simulator, link it with this option ๐Ÿงš It causes the libraries libc.a and libsim.a to get linked.
  • -mfpu, -mhard-float โ€” generates code containing floating-point instructions ๐ŸŒธ This is the default.
  • -mno-fpu, -msoft-float โ€” generates code containing library calls for floating-point instead ๐ŸŒˆ
โš ๏ธ -msoft-float changes the calling convention in the output file, so it's only useful if you compile all of a program with this option. 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 for cpu_type are mcm, gr5, and gr6.

mcm is a synonym of gr5 that's kept around for backward compatibility ๐Ÿ“

By default (unless it's been configured otherwise), GCC generates code for the GR5 variant of the Visium architecture ๐Ÿ‘‘

With -mcpu=gr6, GCC generates code for the GR6 variant of the Visium architecture. The only difference from GR5 code is that the compiler will generate block move instructions ๐Ÿ”ฅ

  • -mtune=cpu_type โ€” sets the instruction scheduling parameters for the machine type cpu_type, but doesn't touch the instruction set or register set the way -mcpu=cpu_type would ๐Ÿ’…
  • -msv-mode โ€” generates code for supervisor mode, where there are no restrictions on access to general registers ๐Ÿ’œ This is the default.
  • -muser-mode โ€” generates code for user mode, where access to some general registers is forbidden ๐Ÿ™ˆ On the GR5, registers r24 to r31 can't be accessed in this mode. On the GR6, only registers r29 to r31 are affected.

๐ŸŒท VMS Options ๐ŸŒท

These -m options are defined for the VMS implementations ๐Ÿฆ‹

  • -mvms-return-codes โ€” returns VMS condition codes from main. By default, you get POSIX-style condition (like error) codes instead โœจ
  • -mdebug-main=prefix โ€” flags the first routine whose name starts with prefix as the main routine for the debugger ๐Ÿงš
  • -mmalloc64 โ€” defaults to 64-bit memory allocation routines ๐ŸŒˆ
  • -mpointer-size=size โ€” sets the default size of pointers. The possible values for size are 32 or short for 32-bit pointers, 64 or long for 64-bit pointers, and no for supporting only 32-bit pointers. The no option disables pragma pointer_size ๐Ÿ™ˆ

๐ŸŒ€ VxWorks Options ๐ŸŒ€

The options in this section are defined for all VxWorks targets ๐Ÿซถ Options specific to the target hardware are listed with the other options for that target.

  • -mrtp โ€” GCC can generate code for both VxWorks kernels and real time processes (RTPs). This option switches from the former to the latter ๐Ÿ’– It also defines the preprocessor macro __RTP__.
  • -non-static โ€” links an RTP executable against shared libraries instead of static libraries ๐Ÿ“ The options -static and -shared can also be used for RTPs, and -static is the default โœจ
  • -Bstatic, -Bdynamic โ€” these options get passed down to the linker ๐Ÿ‘‘ They're defined for compatibility with Diab.
  • -Xbind-lazy โ€” enables lazy binding of function calls ๐Ÿ”ฅ This is equivalent to -Wl,-z,now and is defined for compatibility with Diab.
  • -Xbind-now โ€” disables lazy binding of function calls ๐Ÿ’… This is the default, and it's defined for compatibility with Diab.

๐Ÿ–ฅ๏ธ x86 Options ๐Ÿ–ฅ๏ธ

These -m options are defined for the x86 family of computers ๐Ÿ’œ

  • -march=cpu-type โ€” generates instructions for the machine type cpu-type ๐Ÿฆ‹ Here's the big difference: -mtune=cpu-type just tunes the generated code for the specified cpu-type, but -march=cpu-type lets GCC generate code that may not run at all on processors other than the one you indicated ๐Ÿ˜ญ Specifying -march=cpu-type implies -mtune=cpu-type, except where noted otherwise.

The choices for cpu-type are:

  • native ๐Ÿ’… โ€” okay so this one picks the CPU by checking the machine that's doing the compiling, like it literally looks at itself in the mirror ๐Ÿชž. With -march=native it turns on every instruction subset the local machine supports, so the result might not run on other machines โš ๏ธ. With -mtune=native you get code tuned for the local machine, but still within whatever instruction set you chose.
  • x86-64 ๐ŸŒธ โ€” a generic CPU with 64-bit extensions, the iconic baseline of the bunch.
  • x86-64-v2, x86-64-v3, x86-64-v4 โœจ โ€” these pick the matching micro-architecture level from the x86-64 psABI. On ABIs other than the x86-64 psABI, they still select the same CPU features the x86-64 psABI documents for that particular level.
    • Since these cpu-type values don't have a matching -mtune setting, using -march with them enables generic tuning. For specific tuning, use -mtune=other-cpu-type with an appropriate other-cpu-type value ๐ŸŽ€.
  • i386 ๐Ÿ‘‘ โ€” the original Intel i386 CPU, the OG ๐Ÿฆ‹.
  • i486 ๐Ÿ“ โ€” Intel i486 CPU. (No scheduling is implemented for this chip, so it's giving unbothered ๐Ÿ’€.)
  • 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 instruction set support.
  • pentium3, pentium3m ๐ŸŒธ โ€” Intel Pentium III CPU, based on the Pentium Pro core with MMX and SSE instruction set support.
  • pentium-m ๐Ÿ’… โ€” Intel Pentium M, a low-power version of the Intel Pentium III CPU with MMX, SSE and SSE2 instruction set support. Used by Centrino notebooks ๐Ÿ’ป.
  • pentium4, pentium4m โœจ โ€” Intel Pentium 4 CPU with MMX, SSE and SSE2 instruction set support.
  • prescott ๐ŸŽ€ โ€” an improved Intel Pentium 4 CPU with MMX, SSE, SSE2 and SSE3 instruction set support.
  • nocona ๐Ÿซถ โ€” an improved Intel Pentium 4 CPU with 64-bit extensions, MMX, SSE, SSE2 and SSE3 instruction set support. Main character glow-up energy ๐Ÿ‘‘.
  • core2 โ˜• โ€” Intel Core 2 CPU with 64-bit extensions, MMX, SSE, SSE2, SSE3 and SSSE3 instruction set support.
  • nehalem ๐ŸŒˆ โ€” Intel Nehalem CPU with 64-bit extensions, MMX, SSE, SSE2, SSE3, SSSE3, SSE4.1, SSE4.2 and POPCNT instruction set support.
  • westmere ๐Ÿ’œ โ€” Intel Westmere CPU with 64-bit extensions, MMX, SSE, SSE2, SSE3, SSSE3, SSE4.1, SSE4.2, POPCNT, AES and PCLMUL instruction set support.
  • sandybridge ๐ŸŒธ โ€” Intel Sandy Bridge CPU with 64-bit extensions, MMX, SSE, SSE2, SSE3, SSSE3, SSE4.1, SSE4.2, POPCNT, AVX, AES and PCLMUL instruction set support.
  • ivybridge ๐Ÿงš โ€” Intel Ivy Bridge CPU with 64-bit extensions, MMX, SSE, SSE2, SSE3, SSSE3, SSE4.1, SSE4.2, POPCNT, AVX, AES, PCLMUL, FSGSBASE, RDRND and F16C instruction set support.
  • haswell ๐Ÿ”ฅ โ€” Intel Haswell CPU with 64-bit extensions, MOVBE, MMX, SSE, SSE2, SSE3, SSSE3, SSE4.1, SSE4.2, POPCNT, AVX, AVX2, AES, PCLMUL, FSGSBASE, RDRND, FMA, BMI, BMI2 and F16C instruction set support.
  • broadwell ๐Ÿฆ‹ โ€” Intel Broadwell CPU with 64-bit extensions, MOVBE, MMX, SSE, SSE2, SSE3, SSSE3, SSE4.1, SSE4.2, POPCNT, AVX, AVX2, AES, PCLMUL, FSGSBASE, RDRND, FMA, BMI, BMI2, F16C, RDSEED, ADCX and PREFETCHW instruction set support.
  • skylake ๐Ÿ‘‘ โ€” Intel Skylake CPU with 64-bit extensions, MOVBE, MMX, SSE, SSE2, SSE3, SSSE3, SSE4.1, SSE4.2, POPCNT, AVX, AVX2, AES, PCLMUL, FSGSBASE, RDRND, FMA, BMI, BMI2, F16C, RDSEED, ADCX, PREFETCHW, CLFLUSHOPT, XSAVEC and XSAVES instruction set support.
  • bonnell ๐Ÿ“ โ€” Intel Bonnell CPU with 64-bit extensions, MOVBE, MMX, SSE, SSE2, SSE3 and SSSE3 instruction set support.
  • silvermont ๐Ÿ’… โ€” Intel Silvermont CPU with 64-bit extensions, MOVBE, MMX, SSE, SSE2, SSE3, SSSE3, SSE4.1, SSE4.2, POPCNT, AES, PREFETCHW, PCLMUL and RDRND instruction set support.
  • goldmont โœจ โ€” Intel Goldmont CPU with 64-bit extensions, MOVBE, MMX, SSE, SSE2, SSE3, SSSE3, SSE4.1, SSE4.2, POPCNT, AES, PREFETCHW, PCLMUL, RDRND, XSAVE, XSAVEC, XSAVES, XSAVEOPT and FSGSBASE instruction set support.
  • goldmont-plus ๐ŸŒˆ โ€” Intel Goldmont Plus CPU with 64-bit extensions, MOVBE, MMX, SSE, SSE2, SSE3, SSSE3, SSE4.1, SSE4.2, POPCNT, AES, PREFETCHW, PCLMUL, RDRND, XSAVE, XSAVEC, XSAVES, XSAVEOPT, FSGSBASE, PTWRITE, RDPID, SGX and UMIP instruction set support.
  • tremont ๐Ÿซถ โ€” Intel Tremont CPU with 64-bit extensions, MOVBE, MMX, SSE, SSE2, SSE3, SSSE3, SSE4.1, SSE4.2, POPCNT, AES, PREFETCHW, PCLMUL, RDRND, XSAVE, XSAVEC, XSAVES, XSAVEOPT, FSGSBASE, PTWRITE, RDPID, SGX, UMIP, GFNI-SSE, CLWB, MOVDIRI, MOVDIR64B, CLDEMOTE and WAITPKG instruction set support.
  • knl ๐ŸŒธ โ€” Intel Knight's Landing CPU with 64-bit extensions, MOVBE, MMX, SSE, SSE2, SSE3, SSSE3, SSE4.1, SSE4.2, POPCNT, AVX, AVX2, AES, PCLMUL, FSGSBASE, RDRND, FMA, BMI, BMI2, F16C, RDSEED, ADCX, PREFETCHW, PREFETCHWT1, AVX512F, AVX512PF, AVX512ER and AVX512CD instruction set support.
  • knm ๐Ÿ”ฅ โ€” Intel Knights Mill CPU with 64-bit extensions, MOVBE, MMX, SSE, SSE2, SSE3, SSSE3, SSE4.1, SSE4.2, POPCNT, AVX, AVX2, AES, PCLMUL, FSGSBASE, RDRND, FMA, BMI, BMI2, F16C, RDSEED, ADCX, PREFETCHW, PREFETCHWT1, AVX512F, AVX512PF, AVX512ER, AVX512CD, AVX5124VNNIW, AVX5124FMAPS and AVX512VPOPCNTDQ instruction set support.
  • skylake-avx512 ๐Ÿ‘‘ โ€” Intel Skylake Server CPU with 64-bit extensions, MOVBE, MMX, SSE, SSE2, SSE3, SSSE3, SSE4.1, SSE4.2, POPCNT, PKU, AVX, AVX2, AES, PCLMUL, FSGSBASE, RDRND, FMA, BMI, BMI2, F16C, RDSEED, ADCX, PREFETCHW, CLFLUSHOPT, XSAVEC, XSAVES, AVX512F, CLWB, AVX512VL, AVX512BW, AVX512DQ and AVX512CD instruction set support.
  • cannonlake ๐Ÿฆ‹ โ€” Intel Cannonlake Server CPU with 64-bit extensions, MOVBE, MMX, SSE, SSE2, SSE3, SSSE3, SSE4.1, SSE4.2, POPCNT, PKU, AVX, AVX2, AES, PCLMUL, FSGSBASE, RDRND, FMA, BMI, BMI2, F16C, RDSEED, ADCX, PREFETCHW, CLFLUSHOPT, XSAVEC, XSAVES, AVX512F, AVX512VL, AVX512BW, AVX512DQ, AVX512CD, AVX512VBMI, AVX512IFMA, SHA and UMIP instruction set support.
  • icelake-client ๐Ÿ’– โ€” Intel Icelake Client CPU with 64-bit extensions, MOVBE, MMX, SSE, SSE2, SSE3, SSSE3, SSE4.1, SSE4.2, POPCNT, PKU, AVX, AVX2, AES, PCLMUL, FSGSBASE, RDRND, FMA, BMI, BMI2, F16C, RDSEED, ADCX, PREFETCHW, CLFLUSHOPT, XSAVEC, XSAVES, AVX512F, AVX512VL, AVX512BW, AVX512DQ, AVX512CD, AVX512VBMI, AVX512IFMA, SHA, CLWB, UMIP, RDPID, GFNI, AVX512VBMI2, AVX512VPOPCNTDQ, AVX512BITALG, AVX512VNNI, VPCLMULQDQ and VAES instruction set support.
  • icelake-server ๐ŸŒˆ โ€” Intel Icelake Server CPU with 64-bit extensions, MOVBE, MMX, SSE, SSE2, SSE3, SSSE3, SSE4.1, SSE4.2, POPCNT, PKU, AVX, AVX2, AES, PCLMUL, FSGSBASE, RDRND, FMA, BMI, BMI2, F16C, RDSEED, ADCX, PREFETCHW, CLFLUSHOPT, XSAVEC, XSAVES, AVX512F, AVX512VL, AVX512BW, AVX512DQ, AVX512CD, AVX512VBMI, AVX512IFMA, SHA, CLWB, UMIP, RDPID, GFNI, AVX512VBMI2, AVX512VPOPCNTDQ, AVX512BITALG, AVX512VNNI, VPCLMULQDQ, VAES, PCONFIG and WBNOINVD instruction set support.
  • cascadelake โญ โ€” Intel Cascadelake CPU with 64-bit extensions, MOVBE, MMX, SSE, SSE2, SSE3, SSSE3, SSE4.1, SSE4.2, POPCNT, PKU, AVX, AVX2, AES, PCLMUL, FSGSBASE, RDRND, FMA, BMI, BMI2, F16C, RDSEED, ADCX, PREFETCHW, CLFLUSHOPT, XSAVEC, XSAVES, AVX512F, CLWB, AVX512VL, AVX512BW, AVX512DQ, AVX512CD and AVX512VNNI instruction set support.
  • cooperlake ๐ŸŽ€ โ€” Intel cooperlake CPU with 64-bit extensions, MOVBE, MMX, SSE, SSE2, SSE3, SSSE3, SSE4.1, SSE4.2, POPCNT, PKU, AVX, AVX2, AES, PCLMUL, FSGSBASE, RDRND, FMA, BMI, BMI2, F16C, RDSEED, ADCX, PREFETCHW, CLFLUSHOPT, XSAVEC, XSAVES, AVX512F, CLWB, AVX512VL, AVX512BW, AVX512DQ, AVX512CD, AVX512VNNI and AVX512BF16 instruction set support.
  • tigerlake ๐Ÿงš โ€” Intel Tigerlake CPU with 64-bit extensions, MOVBE, MMX, SSE, SSE2, SSE3, SSSE3, SSE4.1, SSE4.2, POPCNT, PKU, AVX, AVX2, AES, PCLMUL, FSGSBASE, RDRND, FMA, BMI, BMI2, F16C, RDSEED, ADCX, PREFETCHW, CLFLUSHOPT, XSAVEC, XSAVES, AVX512F, AVX512VL, AVX512BW, AVX512DQ, AVX512CD, AVX512VBMI, AVX512IFMA, SHA, CLWB, UMIP, RDPID, GFNI, AVX512VBMI2, AVX512VPOPCNTDQ, AVX512BITALG, AVX512VNNI, VPCLMULQDQ, VAES, PCONFIG, WBNOINVD, MOVDIRI, MOVDIR64B, AVX512VP2INTERSECT and KEYLOCKER instruction set support.
  • sapphirerapids ๐Ÿ’… โ€” Intel sapphirerapids CPU with 64-bit extensions, MOVBE, MMX, SSE, SSE2, SSE3, SSSE3, SSE4.1, SSE4.2, POPCNT, CX16, SAHF, FXSR, AVX, XSAVE, PCLMUL, FSGSBASE, RDRND, F16C, AVX2, BMI, BMI2, LZCNT, FMA, MOVBE, HLE, RDSEED, ADCX, PREFETCHW, AES, CLFLUSHOPT, XSAVEC, XSAVES, SGX, AVX512F, AVX512VL, AVX512BW, AVX512DQ, AVX512CD, PKU, AVX512VBMI, AVX512IFMA, SHA, AVX512VNNI, GFNI, VAES, AVX512VBMI2, VPCLMULQDQ, AVX512BITALG, RDPID, AVX512VPOPCNTDQ, PCONFIG, WBNOINVD, CLWB, MOVDIRI, MOVDIR64B, AVX512VP2INTERSECT, ENQCMD, CLDEMOTE, PTWRITE, WAITPKG, SERIALIZE, TSXLDTRK, UINTR, AMX-BF16, AMX-TILE, AMX-INT8, AVX-VNNI and AVX512BF16 instruction set support.
  • alderlake ๐Ÿฆ‹ โ€” Intel Alderlake CPU with 64-bit extensions, MOVBE, MMX, SSE, SSE2, SSE3, SSSE3, SSE4.1, SSE4.2, POPCNT, AES, PREFETCHW, PCLMUL, RDRND, XSAVE, XSAVEC, XSAVES, XSAVEOPT, FSGSBASE, PTWRITE, RDPID, SGX, UMIP, GFNI-SSE, CLWB, MOVDIRI, MOVDIR64B, CLDEMOTE, WAITPKG, ADCX, AVX, AVX2, BMI, BMI2, F16C, FMA, LZCNT, PCONFIG, PKU, VAES, VPCLMULQDQ, SERIALIZE, HRESET, KL, WIDEKL and AVX-VNNI instruction set support. ๐Ÿ’–

โœจ OPTIONS โœจ

  • rocketlake โ€” ๐Ÿ’– Intel Rocketlake CPU, and bestie, it is PACKED. You get 64-bit extensions, MOVBE, MMX, SSE, SSE2, SSE3, SSSE3, SSE4.1, SSE4.2, POPCNT, PKU, AVX, AVX2, AES, PCLMUL, FSGSBASE, RDRND, FMA, BMI, BMI2, F16C, RDSEED, ADCX, PREFETCHW, CLFLUSHOPT, XSAVEC, XSAVES, AVX512F, AVX512VL, AVX512BW, AVX512DQ, AVX512CD, AVX512VBMI, AVX512IFMA, SHA, CLWB, UMIP, RDPID, GFNI, AVX512VBMI2, AVX512VPOPCNTDQ, AVX512BITALG, AVX512VNNI, VPCLMULQDQ, and VAES instruction set support. ๐Ÿ”ฅ๐Ÿ‘‘
  • k6 โ€” ๐ŸŽ€ AMD K6 CPU with MMX instruction set support.
  • k6-2, k6-3 โ€” ๐Ÿฆ‹ Upgraded AMD K6 CPUs with MMX and 3DNow! instruction set support.
  • athlon, athlon-tbird โ€” AMD Athlon CPU with MMX, 3dNOW!, enhanced 3DNow! and SSE prefetch instructions support. ๐ŸŒธ
  • athlon-4, athlon-xp, athlon-mp โ€” An improved AMD Athlon CPU with MMX, 3DNow!, enhanced 3DNow! and full SSE instruction set support. โญ
  • k8, opteron, athlon64, athlon-fx โ€” Processors built on the AMD K8 core with x86-64 instruction set support, including the AMD Opteron, Athlon 64, and Athlon 64 FX processors. It's giving main character. ๐Ÿ‘‘ (This supersets MMX, SSE, SSE2, 3DNow!, enhanced 3DNow! and 64-bit instruction set extensions.)
  • k8-sse3, opteron-sse3, athlon64-sse3 โ€” Glow-up versions of the AMD K8 cores with SSE3 instruction set support. โœจ
  • amdfam10, barcelona โ€” CPUs based on AMD Family 10h cores with x86-64 instruction set support. ๐Ÿ’… (This supersets MMX, SSE, SSE2, SSE3, SSE4A, 3DNow!, enhanced 3DNow!, ABM and 64-bit instruction set extensions.)
  • bdver1 โ€” CPUs based on AMD Family 15h cores with x86-64 instruction set support. ๐Ÿงš (This supersets FMA4, AVX, XOP, LWP, AES, PCLMUL, CX16, MMX, SSE, SSE2, SSE3, SSE4A, SSSE3, SSE4.1, SSE4.2, ABM and 64-bit instruction set extensions.)
  • bdver2 โ€” AMD Family 15h core based CPUs with x86-64 instruction set support. ๐Ÿ“ (This supersets BMI, TBM, F16C, FMA, FMA4, AVX, XOP, LWP, AES, PCLMUL, CX16, MMX, SSE, SSE2, SSE3, SSE4A, SSSE3, SSE4.1, SSE4.2, ABM and 64-bit instruction set extensions.)
  • bdver3 โ€” AMD Family 15h core based CPUs with x86-64 instruction set support. ๐Ÿฆ‹ (This supersets BMI, TBM, F16C, FMA, FMA4, FSGSBASE, AVX, XOP, LWP, AES, PCLMUL, CX16, MMX, SSE, SSE2, SSE3, SSE4A, SSSE3, SSE4.1, SSE4.2, ABM and 64-bit instruction set extensions.)
  • bdver4 โ€” AMD Family 15h core based CPUs with x86-64 instruction set support. It's the upgraded one, obviously. ๐Ÿ”ฅ (This supersets BMI, BMI2, TBM, F16C, FMA, FMA4, FSGSBASE, AVX, AVX2, XOP, LWP, AES, PCLMUL, CX16, MOVBE, MMX, SSE, SSE2, SSE3, SSE4A, SSSE3, SSE4.1, SSE4.2, ABM and 64-bit instruction set extensions.)
  • znver1 โ€” AMD Family 17h core based CPUs with x86-64 instruction set support. ๐ŸŒˆ (This supersets BMI, BMI2, F16C, FMA, FSGSBASE, AVX, AVX2, ADCX, RDSEED, MWAITX, SHA, CLZERO, AES, PCLMUL, CX16, MOVBE, MMX, SSE, SSE2, SSE3, SSE4A, SSSE3, SSE4.1, SSE4.2, ABM, XSAVEC, XSAVES, CLFLUSHOPT, POPCNT, and 64-bit instruction set extensions.)
  • znver2 โ€” AMD Family 17h core based CPUs with x86-64 instruction set support. ๐Ÿ’œ (This supersets BMI, BMI2, CLWB, F16C, FMA, FSGSBASE, AVX, AVX2, ADCX, RDSEED, MWAITX, SHA, CLZERO, AES, PCLMUL, CX16, MOVBE, MMX, SSE, SSE2, SSE3, SSE4A, SSSE3, SSE4.1, SSE4.2, ABM, XSAVEC, XSAVES, CLFLUSHOPT, POPCNT, RDPID, WBNOINVD, and 64-bit instruction set extensions.)
  • znver3 โ€” AMD Family 19h core based CPUs with x86-64 instruction set support. ๐Ÿซถ (This supersets BMI, BMI2, CLWB, F16C, FMA, FSGSBASE, AVX, AVX2, ADCX, RDSEED, MWAITX, SHA, CLZERO, AES, PCLMUL, CX16, MOVBE, MMX, SSE, SSE2, SSE3, SSE4A, SSSE3, SSE4.1, SSE4.2, ABM, XSAVEC, XSAVES, CLFLUSHOPT, POPCNT, RDPID, WBNOINVD, PKU, VPCLMULQDQ, VAES, and 64-bit instruction set extensions.)
  • znver4 โ€” AMD Family 19h core based CPUs with x86-64 instruction set support. This one is absolutely unhinged in the best way. ๐Ÿ˜ญ (This supersets BMI, BMI2, CLWB, F16C, FMA, FSGSBASE, AVX, AVX2, ADCX, RDSEED, MWAITX, SHA, CLZERO, AES, PCLMUL, CX16, MOVBE, MMX, SSE, SSE2, SSE3, SSE4A, SSSE3, SSE4.1, SSE4.2, ABM, XSAVEC, XSAVES, CLFLUSHOPT, POPCNT, RDPID, WBNOINVD, PKU, VPCLMULQDQ, VAES, AVX512F, AVX512DQ, AVX512IFMA, AVX512CD, AVX512BW, AVX512VL, AVX512BF16, AVX512VBMI, AVX512VBMI2, AVX512VNNI, AVX512BITALG, AVX512VPOPCNTDQ, GFNI and 64-bit instruction set extensions.)
  • btver1 โ€” CPUs based on AMD Family 14h cores with x86-64 instruction set support. ๐Ÿ“ (This supersets MMX, SSE, SSE2, SSE3, SSSE3, SSE4A, CX16, ABM and 64-bit instruction set extensions.)
  • btver2 โ€” CPUs based on AMD Family 16h cores with x86-64 instruction set support. This one includes MOVBE, F16C, BMI, AVX, PCLMUL, AES, SSE4.2, SSE4.1, CX16, ABM, SSE4A, SSSE3, SSE3, SSE2, SSE, MMX and 64-bit instruction set extensions. ๐Ÿฆ‹
  • winchip-c6 โ€” IDT WinChip C6 CPU, handled the same way as i486, with extra MMX instruction set support. ๐ŸŒธ
  • winchip2 โ€” IDT WinChip 2 CPU, handled the same way as i486, with extra MMX and 3DNow! instruction set support. ๐ŸŒธ
  • c3 โ€” VIA C3 CPU with MMX and 3DNow! instruction set support. No scheduling is implemented for this chip, so keep that in mind. ๐Ÿ™ˆ
  • c3-2 โ€” VIA C3-2 (Nehemiah/C5XL) CPU with MMX and SSE instruction set support. No scheduling is implemented for this chip. ๐Ÿ™ˆ
  • c7 โ€” VIA C7 (Esther) CPU with MMX, SSE, SSE2 and SSE3 instruction set support. No scheduling is implemented for this chip. ๐Ÿ™ˆ
  • samuel-2 โ€” VIA Eden Samuel 2 CPU with MMX and 3DNow! instruction set support. No scheduling is implemented for this chip. ๐Ÿ™ˆ
  • nehemiah โ€” VIA Eden Nehemiah CPU with MMX and SSE instruction set support. No scheduling is implemented for this chip. ๐Ÿ™ˆ
  • esther โ€” VIA Eden Esther CPU with MMX, SSE, SSE2 and SSE3 instruction set support. No scheduling is implemented for this chip. ๐Ÿ™ˆ
  • eden-x2 โ€” VIA Eden X2 CPU with x86-64, MMX, SSE, SSE2 and SSE3 instruction set support. No scheduling is implemented for this chip. ๐Ÿ™ˆ
  • eden-x4 โ€” VIA Eden X4 CPU with x86-64, MMX, SSE, SSE2, SSE3, SSSE3, SSE4.1, SSE4.2, AVX and AVX2 instruction set support. No scheduling is implemented for this chip. ๐Ÿ™ˆ
  • nano โ€” Generic VIA Nano CPU with x86-64, MMX, SSE, SSE2, SSE3 and SSSE3 instruction set support. No scheduling is implemented for this chip. ๐Ÿ™ˆ
  • nano-1000 โ€” VIA Nano 1xxx CPU with x86-64, MMX, SSE, SSE2, SSE3 and SSSE3 instruction set support. No scheduling is implemented for this chip. ๐Ÿ™ˆ
  • nano-2000 โ€” VIA Nano 2xxx CPU with x86-64, MMX, SSE, SSE2, SSE3 and SSSE3 instruction set support. No scheduling is implemented for this chip. ๐Ÿ™ˆ
  • nano-3000 โ€” VIA Nano 3xxx CPU with x86-64, MMX, SSE, SSE2, SSE3, SSSE3 and SSE4.1 instruction set support. No scheduling is implemented for this chip. ๐Ÿ™ˆ
  • nano-x2 โ€” VIA Nano Dual Core CPU with x86-64, MMX, SSE, SSE2, SSE3, SSSE3 and SSE4.1 instruction set support. No scheduling is implemented for this chip. ๐Ÿ™ˆ
  • nano-x4 โ€” VIA Nano Quad Core CPU with x86-64, MMX, SSE, SSE2, SSE3, SSSE3 and SSE4.1 instruction set support. No scheduling is implemented for this chip. ๐Ÿ™ˆ
  • geode โ€” AMD Geode embedded processor with MMX and 3DNow! instruction set support. ๐Ÿงš
  • -mtune=cpu-type โ€” ๐Ÿ’… Okay, this one's about tuning. It tunes everything applicable about the generated code to cpu-type, except for the ABI and the set of available instructions. Picking a specific cpu-type schedules things appropriately for that particular chip, but the compiler won't generate any code that can't run on the default machine type unless you use a -march=cpu-type option. For example, if GCC is configured for i686-pc-linux-gnu, then -mtune=pentium4 generates code that's tuned for Pentium 4 but still runs on i686 machines. ๐Ÿซถ

The choices for cpu-type are the same as for -march. On top of that, -mtune supports 2 extra choices for cpu-type:

generic

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 to use.

As new processors hit the market, the behavior of this option will change. So if you upgrade to a newer version of GCC, the code generation controlled by this option will change to reflect the processors that 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. In contrast, -mtune 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 performs better on both Haswell and Silvermont, this is the one.

As new Intel processors hit the market, the behavior of this option will change. So if you upgrade to a newer version of GCC, the code generation controlled by this option will change to reflect the most current Intel processors when 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. In contrast, -mtune indicates the processor (or, in this case, collection of processors) the code is optimized for. ๐Ÿง 

  • -mcpu=cpu-type โ€” ๐Ÿ’… an old nickname that's just a deprecated synonym for -mtune. It still works, but switch to -mtune ๐Ÿซถ
  • -mfpmath=unit โ€” ๐Ÿ‘‘ this one picks which unit does your floating-point math. The choices for unit are:
    • 387 โ€” the standard 387 floating-point coprocessor, found on most chips and emulated on the rest ๐Ÿงš code built this way runs almost everywhere. Temporary results get computed in 80-bit precision instead of the precision the type asks for, so your answers can come out slightly different from most other chips. See -ffloat-store for the full tea.
      • This is the default choice for non-Darwin x86-32 targets. โœจ
    • sse โ€” uses the scalar floating-point instructions from the SSE instruction set ๐Ÿ’– Pentium III and newer chips have it, and on the AMD side it's Athlon-4, Athlon XP and Athlon MP. The early version of SSE only does single-precision math, so double and extended-precision stuff still goes through 387. A later version, only in Pentium 4 and AMD x86-64 chips, handles double-precision too.
      • For the x86-32 compiler, you need -march=cpu-type, -msse or -msse2 to turn on SSE extensions and make this option work. For the x86-64 compiler, those extensions are on by default.
      • The result should be way faster in most cases and dodge the numerical instability problems of 387 code. But it may break existing code that expects temporaries to be 80 bits ๐Ÿ’€
      • This is the default choice for the x86-64 compiler, Darwin x86-32 targets, and 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 ๐Ÿฆ‹ that effectively doubles the available registers and, on chips with separate execution units for 387 and SSE, the execution resources too. Use 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 โ€” picks the assembly dialect for the output, and also decides which dialect basic asm and extended asm use ๐ŸŒธ supported choices (in dialect order) are att or intel. The default is att. Darwin doesn't support intel.
  • -mieee-fp, -mno-ieee-fp โ€” controls whether the compiler uses IEEE floating-point comparisons, which correctly handle the case where a comparison result 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 instead.
Warning: the requisite libraries are not part of GCC ๐Ÿ˜ฑ Normally the facilities of the machine's usual C compiler get used, but that can't be done directly in cross-compilation. You 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 still be emitted even if -msoft-float is used.

  • -mno-fp-ret-in-387 โ€” don't use the FPU registers for function return values ๐Ÿงš the usual calling convention has functions return float and double values in an FPU register, even if there's no FPU at all, on the idea that the operating system should emulate one. This option makes those values come back in ordinary CPU registers instead.
  • -mno-fancy-math-387 โ€” some 387 emulators don't support the sin, cos and sqrt instructions for the 387 ๐Ÿ’€ use this to avoid generating those instructions. It gets overridden when -march says the target CPU always has an FPU, since that instruction doesn't need emulating then. These instructions aren't 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 on a two-word boundary makes code run somewhat faster on a Pentium, at the expense of more memory.
    • On x86-64, -malign-double is enabled by default.
Warning: if you use -malign-double, structures containing the above types are aligned differently than the published application binary interface specs for x86-32, and they aren't binary compatible with structures in code compiled without that switch.
  • -m96bit-long-double, -m128bit-long-double โ€” these control the size of long double ๐Ÿ’œ the x86-32 ABI specifies 96 bits, so -m96bit-long-double is the default in 32-bit mode.

Modern chips (Pentium and newer) prefer long double aligned to an 8- or 16-byte boundary, but that's not possible in arrays or structures that follow the ABI. So -m128bit-long-double aligns long double to a 16-byte boundary by padding it with an additional 32-bit zero.

In the x86-64 compiler, -m128bit-long-double is the default choice, since its ABI says 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, and also modifies the function calling convention for functions taking long double. So they aren't binary-compatible with code compiled without that switch.
  • -mlong-double-64, -mlong-double-80, -mlong-double-128 โ€” these switches control the size of the long double type ๐ŸŒˆ a size of 64 bits makes long double equivalent to double, and that's the default for the 32-bit Bionic C library. A size of 128 bits makes long double equivalent to __float128, which is the default for the 64-bit Bionic C library.
Warning: if you override the default value for your target ABI, this changes the size of structures and arrays containing long double variables, and also modifies the function calling convention for functions taking long double. So they aren't binary-compatible with code compiled without that switch.
  • -malign-data=type โ€” controls how GCC aligns variables โœจ supported values for type are:
    • compat โ€” uses an increased alignment value compatible with GCC 4.8 and earlier.
    • abi โ€” uses the alignment value specified by the psABI.
    • cacheline โ€” uses an increased alignment value to match the cache line size.

compat is the default.

  • -mlarge-data-threshold=threshold โ€” when -mcmodel=medium is specified, data objects larger than threshold get placed in the large data section ๐Ÿงš this value must be the same across all objects linked into the binary, and it defaults to 65535.
  • -mrtd โ€” switches to a different function-calling convention ๐Ÿฆ‹ functions that take a fixed number of arguments return with the ret num instruction, which pops their arguments as it returns. That saves one instruction in the caller, since it doesn't need to pop the arguments there.

You can make an individual function use this calling sequence with the function attribute stdcall. You can also override the -mrtd option with the function attribute cdecl.

Warning: this calling convention is incompatible with the one normally used on Unix, so you can't use it if you need to call libraries compiled with the Unix compiler.

You must also provide function prototypes for all functions that take variable numbers of arguments (including printf), otherwise incorrect code gets generated for calls to those functions.

In addition, seriously incorrect code results if you call a function with too many arguments. (Normally, extra arguments are harmlessly ignored.) ๐Ÿ’€

  • -mregparm=num โ€” controls how many registers are used to pass integer arguments ๐ŸŒธ by default, no registers are used to pass arguments, and at most 3 registers can be used. You can control this for a specific function with the function attribute regparm.
Warning: if you use this switch and num is nonzero, you must build all modules with the same value, including any libraries. That includes the system libraries and startup modules.
  • -msseregparm โ€” uses SSE register passing conventions for float and double arguments and return values ๐Ÿ’œ you can control this for a specific function with the function attribute sseregparm.
Warning: if you use this switch, you must build all modules with the same value, including any libraries. That includes the system libraries and startup modules.
  • -mvect8-ret-in-mem โ€” returns 8-byte vectors in memory instead of MMX registers ๐Ÿซถ this is the default on VxWorks, to match the ABI of the Sun Studio compilers until version 12. Only use this option if you need to stay compatible with existing code produced by those older compiler versions or older versions of GCC.
  • -mpc32, -mpc64, -mpc80 โ€” set 80387 floating-point precision to 32, 64 or 80 bits ๐Ÿ“ with -mpc32, the significands of floating-point operation results are rounded to 24 bits (single precision). -mpc64 rounds them to 53 bits (double precision), and -mpc80 rounds them to 64 bits (extended double precision), which is the default. When this option is used, floating-point operations in higher precisions aren't available to the programmer unless you set the FPU control word explicitly.

Okay so dropping the rounding precision below the default 80 bits can speed some programs up by 2% or more ๐Ÿš€ but bestie, be careful ๐Ÿ˜ญ some math libraries assume extended-precision (80-bit) floating-point ops are on by default. If you set the precision lower than extended, routines in those libraries can lose a lot of accuracy, usually through so-called "catastrophic cancellation" ๐Ÿ’€

  • -mdaz-ftz โ€” okay this one is about the FTZ (flush-to-zero) and DAZ (denormals-are-zero) flags in the MXCSR register, which control floating-point math โœจ SSE and AVX instructions, scalar and vector, can get a glow-up when you turn on FTZ and DAZ with -mdaz-ftz. And if you use -mno-daz-ftz, GCC won't set those flags at all ๐Ÿซถ
  • -mstackrealign โ€” realign the stack at entry ๐Ÿงš On x86, this gives you an alternate prologue and epilogue that realigns the runtime stack when it needs to. It lets old code that keeps 4-byte stack alignment mix with modern code that keeps 16-byte alignment for SSE compatibility ๐Ÿ’œ See also the attribute force_align_arg_pointer, which works on individual functions.
  • -mpreferred-stack-boundary=num โ€” tries to keep the stack boundary aligned to a 2 raised to num byte boundary ๐ŸŽ€ If you don't specify it, the default is 4, which means 16 bytes (128 bits).
Warning: this one is giving danger ๐Ÿšจ When you generate code for the x86-64 architecture with SSE extensions disabled, -mpreferred-stack-boundary=3 can keep the stack boundary aligned to 8 bytes. But the x86-64 ABI requires 16-byte stack alignment, so this is ABI incompatible ๐Ÿ’€ It's only meant for controlled environments where stack space is a serious limitation. It leads to wrong code when functions compiled with 16-byte stack alignment (like functions from a standard library) get called with a misaligned stack, and then 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. You must build all modules with -mpreferred-stack-boundary=3, including any libraries, and that includes the system libraries and startup modules ๐Ÿ™ˆ
  • -mincoming-stack-boundary=num โ€” assumes the incoming stack is aligned to a 2 raised to num byte boundary ๐Ÿฆ‹ If you don't specify it, GCC uses whatever -mpreferred-stack-boundary says.

On Pentium and Pentium Pro, double and long double values should be aligned to an 8-byte boundary (see -malign-double) or you'll take big run-time performance hits ๐Ÿ˜ฉ On Pentium III, the SSE data type __m128 may not work properly if it isn't 16-byte aligned ๐Ÿ’…

To keep those values properly aligned on the stack, the stack boundary has to be at least as aligned as whatever the stack's most-aligned value needs. Every function also has to be generated so it keeps the stack aligned. So if a function compiled with a higher preferred stack boundary gets called from a function compiled with a lower one, the stack will most likely be misaligned ๐Ÿฅบ Libraries that use callbacks should always stick with the default setting, periodt โœจ

This extra alignment eats up extra stack space and usually makes the code bigger ๐Ÿ“ฆ Code that's sensitive to stack space, like embedded systems and operating system kernels, might want to drop the preferred alignment to -mpreferred-stack-boundary=2 ๐ŸŒธ

  • -mmmx, -msse, -msse2, -msse3, -mssse3, -msse4, -msse4a, -msse4.1, -msse4.2, -mavx, -mavx2, -mavx512f, -mavx512pf, -mavx512er, -mavx512cd, -mavx512vl, -mavx512bw, -mavx512dq, -mavx512ifma, -mavx512vbmi, -msha, -maes, -mpclmul, -mclflushopt, -mclwb, -mfsgsbase, -mptwrite, -mrdrnd, -mf16c, -mfma, -mpconfig, -mwbnoinvd, -mfma4, -mprfchw, -mrdpid, -mprefetchwt1, -mrdseed, -msgx, -mxop, -mlwp, -m3dnow, -m3dnowa, -mpopcnt, -mabm, -madx, -mbmi, -mbmi2, -mlzcnt, -mfxsr, -mxsave, -mxsaveopt, -mxsavec, -mxsaves, -mrtm, -mhle, -mtbm, -mmwaitx, -mclzero, -mpku, -mavx512vbmi2, -mavx512bf16, -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 switches turn on the instruction sets in the MMX, SSE, SSE2, SSE3, SSSE3, SSE4, SSE4A, SSE4.1, SSE4.2, AVX, AVX2, AVX512F, AVX512PF, AVX512ER, AVX512CD, AVX512VL, AVX512BW, AVX512DQ, AVX512IFMA, AVX512VBMI, SHA, AES, PCLMUL, CLFLUSHOPT, CLWB, FSGSBASE, PTWRITE, RDRND, F16C, FMA, PCONFIG, WBNOINVD, FMA4, PREFETCHW, RDPID, PREFETCHWT1, RDSEED, SGX, XOP, LWP, 3DNow!, enhanced 3DNow!, POPCNT, ABM, ADX, BMI, BMI2, LZCNT, FXSR, XSAVE, XSAVEOPT, XSAVEC, XSAVES, RTM, HLE, TBM, MWAITX, CLZERO, PKU, AVX512VBMI2, GFNI, VAES, WAITPKG, VPCLMULQDQ, AVX512BITALG, MOVDIRI, MOVDIR64B, AVX512BF16, ENQCMD, AVX512VPOPCNTDQ, AVX5124FMAPS, AVX512VNNI, AVX5124VNNIW, SERIALIZE, UINTR, HRESET, AMXTILE, AMXINT8, AMXBF16, KL, WIDEKL, AVXVNNI or CLDEMOTE extended instruction sets ๐ŸŒˆ Each one has a matching -mno- option that turns its use off ๐Ÿ™…โ€โ™€๏ธ

These extensions are also available as built-in functions. Check out x86 Built-in Functions for the functions these switches enable and disable ๐Ÿง 

If you want SSE/SSE2 instructions generated automatically from floating-point code (instead of 387 instructions), look at -mfpmath=sse ๐Ÿ’–

GCC depresses SSEx instructions when -mavx is used. Instead, it generates new AVX instructions, or AVX equivalents for all SSEx instructions, when needed ๐Ÿฆ‹

These options let GCC use those extended instructions in the generated code, even without -mfpmath=sse. Applications that do run-time CPU detection have to compile separate files for each supported architecture, using the right flags ๐Ÿซถ The file with the CPU detection code specifically should be compiled without these options โญ

  • -mdump-tune-features โ€” tells GCC to dump the names of the x86 performance tuning features and their default settings ๐Ÿ“‹ You can use those names in -mtune-ctrl=feature-list.
  • -mtune-ctrl=feature-list โ€” fine-grained control over x86 code generation features ๐ŸŽ›๏ธ feature-list is a comma-separated list of feature names. See also -mdump-tune-features. If a feature isn't preceded by ^, it gets turned on. If it is preceded by ^, it gets turned off.
Warning: -mtune-ctrl=feature-list is meant for GCC developers ๐Ÿšง Using it may lead to code paths that aren't covered by testing, and it can potentially cause compiler ICEs or runtime errors ๐Ÿ’€
  • -mno-default โ€” turns off all tunable features ๐ŸŒ™ See also -mtune-ctrl=feature-list and -mdump-tune-features.
  • -mcld โ€” tells GCC to emit a cld instruction in the prologue of functions that use string instructions ๐Ÿงน String instructions depend on the DF flag to pick between autoincrement and autodecrement mode. The ABI says DF should be cleared on function entry, but some operating systems don't clear it in their exception dispatchers ๐Ÿ˜ฌ So the exception handler can get invoked with DF set, which means the wrong direction mode when string instructions are used. This option can be enabled by default on 32-bit x86 targets by configuring GCC with the --enable-cld configure option. In that case, you can suppress generation of cld instructions with the -mno-cld compiler option.
  • -mvzeroupper โ€” emits a vzeroupper instruction before control flow leaves the function โœจ This minimizes the AVX to SSE transition penalty, and it also removes unnecessary zeroupper intrinsics ๐Ÿ’œ
  • -mprefer-avx128 โ€” uses 128-bit AVX instructions instead of 256-bit AVX instructions in the auto-vectorizer ๐ŸŒธ
  • -mprefer-vector-width=opt โ€” tells GCC to use opt-bit vector width in instructions, instead of the default for the selected platform ๐Ÿ“
    • none โ€” no extra limits applied to 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 to do compare-and-exchange operations on 16-byte aligned 128-bit objects ๐Ÿ” This is super useful for atomic updates of data structures bigger than one machine word. The compiler uses this instruction to implement __sync Builtins. For __atomic Builtins operating on 128-bit integers, though, it always uses a library call, so don't expect the instruction there ๐Ÿ™ƒ
  • -msahf โ€” enables generation of SAHF instructions in 64-bit code ๐Ÿงช Early Intel Pentium 4 CPUs with Intel 64 support, before the Pentium 4 G1 step arrived in December 2005, didn't have the LAHF and SAHF instructions that AMD64 supports. These are load and store instructions, respectively, for certain status flags ๐Ÿ—‚๏ธ In 64-bit mode, the SAHF instruction gets used to optimize the fmod, drem, and remainder built-in functions. See Other Builtins for details.
  • -mmovbe โ€” enables use of the movbe instruction to implement __builtin_bswap32 and __builtin_bswap64 ๐Ÿ”„
  • -mshstk โ€” enables shadow stack built-in functions from x86 Control-flow Enforcement Technology (CET) ๐Ÿ›ก๏ธ
  • -mcrc32 โ€” enables the built-in functions __builtin_ia32_crc32qi, __builtin_ia32_crc32hi, __builtin_ia32_crc32si and __builtin_ia32_crc32di so they generate the crc32 machine instruction ๐Ÿงฎ
  • -mmwait โ€” okay so this one turns on the built-in functions __builtin_ia32_monitor and __builtin_ia32_mwait so they can generate the monitor and mwait machine instructions ๐Ÿงšโœจ
  • -mrecip โ€” this one swaps in the RCPSS and RSQRTSS instructions (plus their vectorized buddies RCPPS and RSQRTPS) with an extra Newton-Raphson step for precision, instead of DIVSS and SQRTSS (and their vectorized versions) for single-precision floats ๐Ÿ”ฅ It only kicks in when -funsafe-math-optimizations is on together with -ffinite-math-only and -fno-trapping-math. ngl the sequence has higher throughput than the non-reciprocal version, but the precision can drop by up to 2 ulp (like, the inverse of 1.0 comes out as 0.99999994) ๐Ÿ™ˆ

Also, GCC already turns 1.0f/sqrtf(x) into RSQRTSS (or RSQRTPS) with -ffast-math (or that same option combo), so you don't need -mrecip for that ๐Ÿ’…

And GCC already emits that Newton-Raphson sequence for vectorized single-float division and vectorized sqrtf(x) with -ffast-math (or the same combo), so again, no -mrecip needed ๐Ÿซถ

  • -mrecip=opt โ€” this controls which reciprocal estimate instructions are allowed to be used ๐Ÿ‘‘ opt is a comma-separated list, and any item can get a ! in front to flip it:
    • all โ€” enables all estimate instructions ๐ŸŒˆ
    • default โ€” enables the default instructions, same as -mrecip ๐ŸŽ€
    • none โ€” disables all estimate instructions, same as -mno-recip ๐Ÿ’€
    • div โ€” enables the 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 turns on every reciprocal approximation except square root. Iconic. ๐Ÿ”ฅ

  • -mveclibabi=type โ€” this picks the ABI type for vectorizing intrinsics through an external library ๐Ÿง The supported values for type are svml (the Intel short vector math library) and acml (the AMD math core library). To use it, you need both -ftree-vectorize and -funsafe-math-optimizations turned on, plus an SVML or ACML ABI-compatible library linked in at link time, or it's not gonna work bestie ๐Ÿ˜ญ

GCC currently emits calls to vmldExp2, vmldLn2, vmldLog102, vmldPow2, vmldTanh2, vmldTan2, vmldAtan2, vmldAtanh2, vmldCbrt2, vmldSinh2, vmldSin2, vmldAsinh2, vmldAsin2, vmldCosh2, vmldCos2, vmldAcosh2, vmldAcos2, vmlsExp4, vmlsLn4, vmlsLog104, vmlsPow4, vmlsTanh4, vmlsTan4, vmlsAtan4, vmlsAtanh4, vmlsCbrt4, vmlsSinh4, vmlsSin4, vmlsAsinh4, vmlsAsin4, vmlsCosh4, vmlsCos4, vmlsAcosh4 and vmlsAcos4 for the corresponding function type when -mveclibabi=svml is used. With -mveclibabi=acml, it uses __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 matching function type ๐Ÿ’–

  • -mabi=name โ€” generates code for the calling convention you pick ๐Ÿฆ‹ The allowed values are sysv (the ABI used on GNU/Linux and other systems) and ms (the Microsoft ABI). By default you get the Microsoft ABI when targeting Microsoft Windows and the SysV ABI everywhere else. If you want to override that for specific functions, use the function attributes ms_abi and sysv_abi ๐ŸŽ€
  • -mforce-indirect-call โ€” forces every function call to be indirect โœจ This is handy with Intel Processor Trace, since it gives more precise timing info for function calls ๐Ÿ•ฐ๏ธ
  • -mmanual-endbr โ€” only inserts the ENDBR instruction at function entry when you ask for it with the cf_check function attribute ๐Ÿซถ This is useful alongside -fcf-protection=branch, which lets you control ENDBR insertion at the function entry.
  • -mcall-ms2sysv-xlogues โ€” okay so because of differences in 64-bit ABIs, any Microsoft ABI function that calls a System V ABI function has to treat RSI, RDI and XMM6-15 as clobbered ๐Ÿ˜ญ By default the code for saving and restoring those registers is emitted inline, which makes the prologues and epilogues super lengthy. With -mcall-ms2sysv-xlogues, the prologues and epilogues use stubs in the static portion of libgcc instead, so your functions get smaller, 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, and gnu2 is more efficient, but it may add compile- and run-time requirements that can't be satisfied on all systems, so be careful with that one ๐Ÿ‘€
  • -mpush-args, -mno-push-args โ€” uses PUSH operations to store outgoing parameters ๐ŸŒธ This method is shorter and usually just as fast as the SUB/MOV method, and it's enabled by default. In some cases turning it off may improve performance because of better scheduling and fewer dependencies ๐Ÿ“
  • -maccumulate-outgoing-args โ€” if enabled, the maximum amount of space needed for outgoing arguments gets computed in the function prologue ๐ŸŒˆ This is faster on most modern CPUs because of fewer dependencies, better scheduling and less stack usage when the preferred stack boundary isn't equal to 2. The catch 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 of their code with -mthreads. When compiling, it defines -D_MT, and when linking, it pulls in the special thread helper library -lmingwthrd, which cleans up per-thread exception-handling data ๐Ÿซถ
  • -mms-bitfields, -mno-ms-bitfields โ€” enables or disables bit-field layout that's compatible with the native Microsoft Windows compiler ๐Ÿ’œ

If packed is used on a structure, or if bit-fields are used, the Microsoft ABI may lay out the structure differently than GCC normally does. Especially when you're moving packed data between functions compiled with GCC and the native Microsoft compiler (through a function call or as data in a file), you may need to access either format ๐Ÿ‘‘

This option is on by default for Microsoft Windows targets. You can also control this locally with variable or type attributes. For more info, see x86 Variable Attributes and x86 Type Attributes โœจ

The Microsoft structure layout algorithm is pretty simple, except for bit-field packing ๐Ÿง The padding and alignment of structure members, and whether a bit-field can straddle a storage-unit boundary, are determined by these rules:

  1. Structure members are stored sequentially in the order they're declared: the first member has the lowest memory address and the last member has the highest ๐Ÿฆ‹
  2. Every data object has an alignment requirement. For all data except structures, unions, and arrays, the alignment requirement is either the size of the object or the current packing size (set with either the aligned attribute or the pack pragma), whichever is less. For structures, unions, and arrays, the alignment requirement is the largest alignment requirement of its members. Every object gets an offset so that:
offset % alignment_requirement == 0
  1. Adjacent bit-fields get packed into the same 1-, 2-, or 4-byte allocation unit if the integral types are the same size, and if the next bit-field fits into the current allocation unit without crossing the boundary imposed by the common alignment requirements of the bit-fields ๐ŸŒธ

MSVC interprets zero-length bit-fields in 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. For example:
struct
{
  unsigned long bf_1 : 12;
  unsigned long : 0;
  unsigned long bf_2 : 12;
} t1;

The size of t1 is 8 bytes with the zero-length bit-field. If the zero-length bit-field were removed, t1's size would be 4 bytes ๐Ÿ˜ญ

  1. If a zero-length bit-field is inserted after a bit-field, foo, and the alignment of the zero-length bit-field is greater than that of the member that follows it, bar, then bar is aligned as the type of the zero-length bit-field. For example:
struct
{
  char foo : 4;
  short : 0;
  char bar;
} t2;

struct
{
  char foo : 4;
  short : 0;
  double bar;
} t3;

For t2, bar is placed at offset 2, rather than offset 1. Accordingly, the size of t2 is 4. For t3, the zero-length bit-field doesn't affect the alignment of bar or, as a result, the size of the structure ๐Ÿงš

Taking this into account, it's important to note the following:

  1. If a zero-length bit-field follows a normal bit-field, the type of the zero-length bit-field may affect the alignment of the structure as a whole. For example, t2 has a size of 4 bytes, since the zero-length bit-field follows a normal bit-field and is of type short ๐ŸŽ€
  2. Even if a zero-length bit-field is not followed by a normal bit-field, it may still affect the alignment of the structure:
struct
{
  char foo : 6;
  long : 0;
} t4;

Here, t4 takes up 4 bytes. main character energy ๐ŸŒˆ๐Ÿ’–

  1. Zero-length bit-fields that come after non-bit-field members just get ignored, bestie ๐Ÿ™ˆ๐Ÿงš
struct
 {
   char foo;
   long : 0;
   char bar;
 } t5;

So t5 only takes up 2 bytes. Tiny struct, big energy ๐Ÿ’–

  • -mno-align-stringops โ€” Don't align the destination of inlined string operations ๐Ÿซถ This one shrinks your code and can make things faster when the destination is already aligned, even though GCC doesn't know that yet ๐Ÿ™ƒ
  • -minline-all-stringops โ€” By default GCC only inlines string operations when it knows the destination is aligned to at least a 4-byte boundary ๐ŸŽ€ This turns on more inlining, which makes your code bigger but can 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 with an unknown size, you get run-time checks with inline code for small blocks and a library call for big ones ๐Ÿฆ‹
  • -mstringop-strategy=alg โ€” Overrides GCC's internal decision heuristic and lets you pick the algorithm used for inlining string operations ๐Ÿ‘‘ The allowed values for alg are:
    • rep_byte, rep_4byte, rep_8byte โ€” expand using the i386 rep prefix at the matching size ๐ŸŒธ
    • byte_loop, loop, unrolled_loop โ€” expand into an inline loop ๐Ÿ”
    • libcall โ€” always use a library call ๐Ÿ“ž
  • -mmemcpy-strategy=strategy โ€” Another override for the heuristic, this time deciding whether __builtin_memcpy gets inlined and which inline algorithm to use when the expected copy size is known ๐Ÿง  The strategy is a comma-separated list of alg:max_size:dest_align triplets ๐Ÿ’œ
    • alg is one of the values from -mstringop-strategy.
    • max_size is the max byte size the inline algorithm alg is allowed to handle.
    • The last triplet's max_size must be -1.
    • The max_size values in the list have to go in increasing order.
    • The minimal byte size for alg is 0 for the first triplet, and max_size + 1 of the preceding range for every triplet after that.
  • -mmemset-strategy=strategy โ€” Basically the same vibe as -mmemcpy-strategy=, except this one controls __builtin_memset expansion ๐Ÿ“
  • -momit-leaf-frame-pointer โ€” Don't keep the frame pointer in a register for leaf functions โœจ This skips the instructions that save, set up, and restore frame pointers, and frees up an extra register in leaf functions ๐Ÿ™Œ The option -fomit-leaf-frame-pointer removes the frame pointer for leaf functions too, but heads up, that might make debugging harder ๐Ÿฅฒ
  • -mtls-direct-seg-refs, -mno-tls-direct-seg-refs โ€” Controls whether TLS variables can be accessed with offsets from the TLS segment register (%gs for 32-bit, %fs for 64-bit), or whether the thread base pointer has to be added ๐Ÿงต Whether that's valid depends on your operating system, and on whether it maps the segment to cover the entire TLS area ๐Ÿค”

For systems that use the GNU C Library, the default is on ๐Ÿ’…

  • -msse2avx, -mno-sse2avx โ€” Tells the assembler to encode SSE instructions with a VEX prefix ๐Ÿฆ„ The option -mavx turns this on by default โœจ
  • -mfentry, -mno-fentry โ€” If profiling is active (-pg), this puts 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), this generates a __mcount_loc section full of pointers to each profiling call ๐Ÿ“š It's super useful for automatically patching and out calls ๐Ÿ› ๏ธ
  • -mnop-mcount, -mno-nop-mcount โ€” If profiling is active (-pg), the calls to the profiling functions get generated as NOPs ๐Ÿ˜ด This is handy when they should be patched in later, dynamically ๐Ÿช„ It's likely only useful together with -mrecord-mcount ๐Ÿ’–
  • -minstrument-return=type โ€” Instruments function exit in -pg -mfentry instrumented functions by calling the specified function ๐Ÿšช It 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__ ๐Ÿ“ž
    • nop5 โ€” generate a 5 byte nop ๐ŸŒ™
  • -mrecord-return, -mno-record-return โ€” Generates a __return_loc section pointing to all the return instrumentation code ๐Ÿ—บ๏ธ
  • -mfentry-name=name โ€” Sets the name of the __fentry__ symbol that gets called at function entry for -pg -mfentry functions ๐Ÿท๏ธ
  • -mfentry-section=name โ€” Sets the name of the section where -mrecord-mcount calls get recorded (default __mcount_loc) ๐Ÿ“‚
  • -mskip-rax-setup, -mno-skip-rax-setup โ€” When generating x86-64 code with SSE extensions disabled, -mskip-rax-setup lets you skip setting up the RAX register when no variable arguments are passed in vector registers ๐Ÿงƒ
Warning: this one is DRAMATIC ๐Ÿ’€ RAX is used to avoid unnecessarily saving vector registers on the stack when passing variable arguments, so the impact is that callees may waste some stack space, misbehave, or jump to a random location ๐Ÿ˜ฑ GCC 4.4 or newer don't have those issues, regardless of the RAX register value ๐Ÿซ 
  • -m8bit-idiv, -mno-8bit-idiv โ€” On some processors, like Intel Atom, 8-bit unsigned integer divide is way faster than 32-bit/64-bit integer divide ๐ŸŽ๏ธ This option generates a run-time check. If both the dividend and divisor are within the range of 0 to 255, 8-bit unsigned integer divide gets used instead of 32-bit/64-bit integer divide ๐Ÿงฎ
  • -mavx256-split-unaligned-load, -mavx256-split-unaligned-store โ€” Splits 32-byte AVX unaligned loads and stores into smaller pieces โœ‚๏ธ
  • -mstack-protector-guard=guard, -mstack-protector-guard-reg=reg, -mstack-protector-guard-offset=offset โ€” Generates stack protection code using a canary at guard ๐Ÿค The supported locations are global for a global canary, or tls for a per-thread canary in the TLS block (the default) ๐Ÿงต This only has an effect when -fstack-protector or -fstack-protector-all is specified ๐Ÿ›ก๏ธ

With the latter choice, -mstack-protector-guard-reg=reg and -mstack-protector-guard-offset=offset also tell GCC which segment register (%fs or %gs) to use as the base register for reading the canary, and from what offset from that base register ๐ŸŽฏ The defaults for those are whatever the relevant ABI specifies ๐Ÿ“œ

  • -mgeneral-regs-only โ€” Generates code that only uses the general-purpose registers ๐ŸŽ€ This keeps the compiler away from floating-point, vector, mask, and bound registers ๐Ÿ™…โ€โ™€๏ธ
  • -mindirect-branch=choice โ€” Converts indirect calls and jumps according to choice ๐Ÿฆ‹ The default is keep, which leaves indirect calls and jumps unmodified. Here's the rest of the menu:
    • thunk โ€” converts indirect calls and jumps to a call and return thunk ๐Ÿงฉ
    • thunk-inline โ€” converts them to an inlined call and return thunk ๐Ÿงฉ
    • thunk-extern โ€” converts them to an external call and return thunk that lives in a separate object file ๐Ÿ“ฆ

You can control this for a specific function with the function attribute indirect_branch ๐ŸŽ›๏ธ

Note: -mcmodel=large is incompatible with -mindirect-branch=thunk and -mindirect-branch=thunk-extern, since the thunk function may not be reachable in the large code model ๐Ÿ’”

Note that -mindirect-branch=thunk-extern is compatible with -fcf-protection=branch, since the external thunk can be made to enable control-flow check ๐Ÿ”

  • -mfunction-return=choice โ€” Converts function returns according to choice ๐Ÿ” The default is keep, which leaves function returns unmodified. The other choices are:
    • thunk โ€” converts function returns to a call and return thunk ๐Ÿงฉ
    • thunk-inline โ€” converts them to an inlined call and return thunk ๐Ÿงฉ
    • thunk-extern โ€” converts them to an external call and return thunk provided in a separate object file ๐Ÿ“ฆ

You can control this for a specific function with the function attribute function_return ๐ŸŽ›๏ธ

Note that -mindirect-return=thunk-extern is compatible with -fcf-protection=branch, since the external thunk can be made to enable control-flow check ๐Ÿ”

Note: -mcmodel=large is incompatible with -mfunction-return=thunk and -mfunction-return=thunk-extern, since the thunk function may not be reachable in the large code model ๐Ÿ’”
  • -mindirect-branch-register โ€” Forces indirect calls and jumps to go via a register ๐ŸŽฏ
  • -mharden-sls=choice โ€” Generates code to mitigate straight line speculation (SLS) according to choice ๐Ÿ›ก๏ธ The default is none, which disables all SLS hardening ๐Ÿ™… The other options are:
    • return โ€” enables SLS hardening for function returns ๐Ÿ”
    • indirect-jmp โ€” enables SLS hardening for indirect jumps ๐Ÿฆ˜
    • all โ€” enables all SLS hardening ๐Ÿ’ช
  • -mindirect-branch-cs-prefix โ€” Adds a CS prefix to call and jmp to an indirect thunk with the branch target in the r8-r15 registers ๐Ÿง This makes the call and jmp instructions 6 bytes long, so they can be replaced at run-time with lfence; call *%r8-r15 or lfence; jmp *%r8-r15 ๐Ÿช„

These -m switches are supported in addition to the above on x86-64 processors in 64-bit environments ๐ŸŒˆ

  • -m32, -m64, -mx32, -m16, -miamcu โ€” Generates code for a 16-bit, 32-bit, or 64-bit environment ๐ŸŒธ
    • -m32 sets int, long, and pointer types to 32 bits, and generates code that runs in 32-bit mode ๐Ÿ’œ
    • -m64 sets int to 32 bits and long and pointer types to 64 bits, and generates code for the x86-64 architecture ๐Ÿš€ For Darwin only, the -m64 option also turns off the -fno-pic and -mdynamic-no-pic options ๐ŸŽ
    • -mx32 sets int, long, and pointer types to 32 bits, and generates code for the x86-64 architecture ๐Ÿฆ‹
    • -m16 is the same as -m32, except it outputs the .code16gcc assembly directive at the beginning of the assembly output so the binary can run in 16-bit mode ๐Ÿ•ฐ๏ธ
    • -miamcu generates code that conforms to the Intel MCU psABI ๐Ÿงธ It requires -m32 to be turned on ๐Ÿซถ
  • -mno-red-zone โ€” Don't use a so-called "red zone" for x86-64 code ๐Ÿ™…โ€โ™€๏ธ The red zone is mandated by the x86-64 ABI: it's a 128-byte area beyond the stack pointer that signal or interrupt handlers don't modify, so it can be used for temporary data without adjusting the stack pointer ๐Ÿง  The flag -mno-red-zone disables this red zone ๐Ÿ’…

Okay so the code models are next, and they're lowkey the most serious bit of this whole section ๐Ÿ’…

  • -mcmodel=small โ€” this is the default code model ๐ŸŽ€ the program and its symbols must be linked in the lower 2 GB of the address space. Pointers are 64 bits, and programs can be statically or dynamically linked. No notes.
  • -mcmodel=kernel โ€” the kernel runs in the negative 2 GB of the address space, so this model is the one you have to use for Linux kernel code ๐Ÿ
  • -mcmodel=medium โ€” the program is linked in the lower 2 GB of the address space, and small symbols get placed there too. Symbols with sizes bigger than -mlarge-data-threshold get shoved into large data or BSS sections and can live above 2GB ๐ŸŒˆ programs can be statically or dynamically linked.
  • -mcmodel=large โ€” the big boss model ๐Ÿ‘‘ it makes no assumptions at all about addresses and sizes of sections.
  • -maddress-mode=long โ€” generates code for long address mode. It's 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. It's only supported for 32-bit and x32 environments, and it's the default for 32-bit and x32 environments ๐Ÿฆ‹
  • -mneeded, -mno-needed โ€” emits the GNU_PROPERTY_X86_ISA_1_NEEDED GNU property for the Linux target, which tells you the micro-architecture ISA level needed to run the binary ๐Ÿงš

x86 Windows Options

These extra options are available for Microsoft Windows targets ๐ŸชŸ๐Ÿ’–

  • -mconsole โ€” makes 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 is turned on by default on those targets ๐ŸŒธ
  • -mdll โ€” available for Cygwin and MinGW targets. It makes a DLL---a dynamic link library---and lets you pick the required runtime startup object and entry point ๐ŸŽ€
  • -mnop-fun-dllimport โ€” available for Cygwin and MinGW targets. It tells GCC to ignore the "dllimport" attribute ๐Ÿ™ˆ
  • -mthread โ€” available for MinGW targets. It uses MinGW-specific thread support ๐Ÿงต
  • -municode โ€” available for MinGW-w64 targets. It predefines the "UNICODE" preprocessor macro and picks Unicode-capable runtime startup code ๐ŸŒˆ
  • -mwin32 โ€” available for Cygwin and MinGW targets. It sets the typical Microsoft Windows predefined macros in the preprocessor, but it doesn't change which runtime library or startup code gets chosen ๐Ÿ’…
  • -mwindows โ€” available for Cygwin and MinGW targets. It makes a GUI application by telling the linker to set the PE header subsystem type to match โœจ
  • -fno-set-stack-executable โ€” available for MinGW targets. The executable flag for the stack used by nested functions doesn't get set. This is necessary for binaries running in kernel mode of Microsoft Windows, since the User32 API (the one used to set executable privileges) isn't available there ๐Ÿ˜ญ
  • -fwritable-relocated-rdata โ€” available for MinGW and Cygwin targets. Relocated data in a read-only section gets put into the ".data" section. This is necessary for older runtimes that don't support modifying ".rdata" sections for pseudo-relocation ๐Ÿ”ฅ
  • -mpe-aligned-commons โ€” available for Cygwin and MinGW targets. 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, bestie ๐Ÿฆ‹

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 Tensilica option right now. When it's enabled, "CONST16" instructions are always used in place of the standard "L32R" instructions. It's only enabled by default if the "L32R" instruction isn't available ๐Ÿ’œ
  • -mfused-madd, -mno-fused-madd โ€” 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 enabled. Turning fused instructions off forces the compiler to use separate instructions for the multiply and the add/subtract. This can be a vibe when strict IEEE 754-compliant results are required, because fused multiply add/subtract instructions don't round the intermediate result, so you get more bits of precision than the IEEE standard specifies. Disabling them also makes sure the program output doesn't depend on the compiler's ability to combine multiply and add/subtract operations ๐Ÿค“
  • -mserialize-volatile, -mno-serialize-volatile โ€” when enabled, GCC inserts "MEMW" instructions before "volatile" memory references to guarantee sequential consistency. The default is -mserialize-volatile, and you use -mno-serialize-volatile to leave out the "MEMW" instructions ๐Ÿ”’
  • -mforce-no-pic โ€” for targets like GNU/Linux, where all user-mode Xtensa code has to be position-independent code (PIC), this turns PIC off when compiling kernel code ๐Ÿ‘‘
  • -mtext-section-literals, -mno-text-section-literals โ€” these control how literal pools are treated. The default is -mno-text-section-literals, which puts literals in a separate section in the output file. That lets the literal pool sit in data RAM/ROM, and it also lets the linker combine literal pools from separate object files to kill redundant literals and improve code size. With -mtext-section-literals, the literals get interspersed in the text section so they stay as close as possible to their references. This might be necessary for large assembly files. Literals for each function get placed right before that function ๐Ÿงต
  • -mauto-litpools, -mno-auto-litpools โ€” also control how literal pools are treated. 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 interspersed the literals in the text section itself. GCC doesn't produce 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 create several literal pools per function and assemble very big functions, which might not be possible with -mtext-section-literals ๐ŸŒˆ
  • -mtarget-align, -mno-target-align โ€” when enabled, GCC tells the assembler to automatically align instructions to reduce branch penalties, at the cost of some code density. The assembler tries to widen density instructions to align branch targets and the instructions after call instructions. If there aren't enough safe density instructions before a target to align it, 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 translate direct calls into indirect calls unless it can tell that the target of a 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" instruction into an "L32R" followed by a "CALLX" instruction. The default is -mno-longcalls. Use this option in programs where the call target could be out of range ๐Ÿ“ž
This one is a bit sneaky. -mlongcalls is implemented in the assembler, not the compiler, so the assembly code GCC generates still shows direct call instructions. Check the disassembled object code if you want 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. The permissible values are call0 and windowed. The default ABI is chosen by the Xtensa core configuration ๐ŸŽ€
  • -mabi=call0 โ€” when enabled, function parameters are passed in registers "a2" through "a7", registers "a12" through "a15" are caller-saved, and register "a15" may be used as a frame pointer. When this version of the ABI is enabled, the C preprocessor symbol "__XTENSA_CALL0_ABI__" is defined ๐Ÿ’–
  • -mabi=windowed โ€” when enabled, function parameters are passed in registers "a10" through "a15". The called function rotates the register window by 8 registers on entry, so its arguments are found in registers "a2" through "a7". Register "a7" may be used as a frame pointer. The register window is rotated 8 registers back upon return. When this version of the ABI is enabled, the C preprocessor symbol "__XTENSA_WINDOWED_ABI__" is defined ๐ŸŒธ

zSeries Options

These are listed under

โœจ ENVIRONMENT โœจ

okay so ENVIRONMENT is where GCC checks the vibes around your build ๐Ÿ’… Several environment variables change how GCC works. Some tell it which directories or prefixes to search for files, and others set different parts of the compilation environment ๐ŸŒธ

Quick heads-up, bestie: you can also tell GCC where to search with options like -B, -I and -L. Those beat the environment variables, and the environment variables beat whatever GCC was configured with ๐Ÿซถ

LANG

LC_CTYPE

LC_MESSAGES

LC_ALL

These four are all about localization, which is how GCC handles different national conventions ๐ŸŒˆ GCC looks at the LC_CTYPE and LC_MESSAGES locale categories if it was configured to do that. You can set them 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 โ€” this one handles character classification ๐Ÿ”ค GCC uses it to figure out where characters start and stop in a string. That matters for some multibyte encodings where quote and escape characters could otherwise be read as the end of a string or as an escape.
  • LC_MESSAGES โ€” this sets the language for diagnostic messages, so GCC's error and warning text shows up in your language ๐Ÿ’ฌ
  • LC_ALL โ€” if this is set, it overrides LC_CTYPE and LC_MESSAGES. If it isn't set, LC_CTYPE and LC_MESSAGES fall back to the value of LANG ๐Ÿ‘‘ If none of these are set, GCC defaults to traditional C English behavior.

TMPDIR

If TMPDIR is set, it picks the directory for temporary files ๐Ÿ“ GCC makes temp files to hold the output of one stage that becomes input for the next one. For example, the preprocessor's output is the input to the compiler proper โœจ

GCC_COMPARE_DEBUG

Setting GCC_COMPARE_DEBUG is nearly the same as passing -fcompare-debug to the compiler driver ๐Ÿ” Check that option's docs if you want the full tea.

GCC_EXEC_PREFIX

If GCC_EXEC_PREFIX is set, it gives a prefix for the names of the subprograms the compiler runs ๐Ÿงš No slash gets added when the prefix is joined with a subprogram name, so if you want a slash, end your prefix with one.

If GCC_EXEC_PREFIX isn't set, GCC tries to work out a good prefix from the pathname it was invoked with ๐Ÿฆ‹ If it can't find a subprogram with the prefix you gave, it checks the usual places instead.

The default value of GCC_EXEC_PREFIX is prefix/lib/gcc/, where prefix is the prefix of the installed compiler. In lots of cases, prefix is whatever you passed as "prefix" when you ran the configure script ๐ŸŒธ

Prefixes given with -B beat this one. This prefix is also how GCC finds files like crt0.o that it needs for linking ๐Ÿ”—

Now, here's the unusual part, so pay attention ๐Ÿ‘€ The prefix also changes where GCC looks 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 right before it searches the standard /usr/local/lib/bar ๐Ÿ’… If a standard directory starts with the configured prefix, GCC replaces that prefix with the value of GCC_EXEC_PREFIX when it hunts for headers.

COMPILER_PATH

COMPILER_PATH is a colon-separated list of directories, kind of like PATH ๐Ÿ›ค๏ธ If GCC can't find a subprogram through GCC_EXEC_PREFIX, it tries these directories when searching for subprograms.

LIBRARY_PATH

LIBRARY_PATH is also a colon-separated list of directories, very much like PATH ๐Ÿ“š On a native compiler, GCC checks these directories for special linker files if it can't find them through GCC_EXEC_PREFIX. Linking with GCC also searches these directories for ordinary libraries used with the -l option, but anything you pass with -L goes first ๐Ÿฅ‡

LANG

Okay, LANG again, because it has a whole second job ๐ŸŒ This one passes locale info to the compiler. One thing the compiler uses it for is picking the character set for character literals, string literals and comments when it parses C and C++. If the compiler is set up to allow multibyte characters, it recognizes these LANG values:

  • 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 some other value, 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 ๐Ÿฉน The -fdiagnostics-parseable-fixits and -fno-diagnostics-parseable-fixits options win over this environment variable, so they're the boss here ๐Ÿ‘‘

  • fixits-v1 โ€” emits parseable fix-it hints, the same as -fdiagnostics-parseable-fixits ๐Ÿงพ Columns are counted in bytes, starting at byte 1 for the first column.
  • fixits-v2 โ€” same as fixits-v1, except the columns are counted as display columns, like -fdiagnostics-column-unit=display ๐Ÿ“

Some more environment variables change how the preprocessor behaves ๐Ÿงšโ€โ™€๏ธ

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, a lot like PATH ๐Ÿ—‚๏ธ That special character is called "PATH_SEPARATOR". It's target-dependent and gets decided when GCC is built. On Microsoft Windows-based targets it's a semicolon, and on almost everything else it's a colon.

CPATH searches its directories as if you'd passed them with -I, but only after any paths given with -I on the command line. It gets used no matter which language is being preprocessed ๐ŸŒˆ

The other three only apply when preprocessing their specific language. Each one searches its directories as if you'd used -isystem, but after any paths given with -isystem on the command line ๐Ÿ’œ

In all of these variables, an empty element tells the compiler to search its current working directory ๐Ÿ“ Empty elements can show up at the start or the end of a path. For example, if CPATH is ":/special/include", that does the exact same thing as -I. -I/special/include โœจ

DEPENDENCIES_OUTPUT

If this variable is set, its value says how to output Make dependencies based on the non-system header files the compiler processes ๐Ÿ› ๏ธ System header files get ignored in the dependency output, so no judgement there ๐Ÿ™ˆ

The value can be just a file name. In that case, the Make rules get written to that file, and GCC guesses the target name from the source file name. Or the value can look like file target, which writes the rules to file and uses target as the target name ๐ŸŽฏ

Basically, this env var is the same as combining -MM and -MF, with an optional -MT thrown in too ๐Ÿ’…

SUNPRO_DEPENDENCIES

This one is the same as DEPENDENCIES_OUTPUT (see above), except system header files are not ignored. So it implies -M instead of -MM ๐ŸŒ€ The one catch is that the dependence on the main input file gets left out ๐Ÿซ 

SOURCE_DATE_EPOCH

If SOURCE_DATE_EPOCH is set, its value is a UNIX timestamp that replaces the current date and time in the __DATE__ and __TIME__ macros ๐Ÿ•ฐ๏ธ That way your embedded timestamps are reproducible, which is a whole vibe for builds ๐Ÿ”

The value has to be a UNIX timestamp, meaning the number of seconds (leap seconds don't count) since 01 Jan 1970 00:00:00, written in ASCII. It's the same output you'd get from date +%s on GNU/Linux and other systems that support the %s extension in the date command ๐Ÿงฎ

The value should be a known timestamp, like the last modification time of your source or package, and your build process should be the one that sets it ๐Ÿ› ๏ธ

๐Ÿ› BUGS ๐Ÿ›

For instructions on reporting bugs, check out <file:///usr/share/doc/gcc-11/README.Bugs> ๐Ÿชฒ Go tell the devs what broke, bestie!

๐Ÿ“ 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 ๐Ÿซง
โš ๏ธ Heads up, bestie: skipping the right flags can cause subtle defects, so this footnote is not one to skim ๐Ÿ˜ญ

๐Ÿ”— SEE ALSO ๐Ÿ”—

Want to go deeper? Check out gpl(7), gfdl(7), fsf-funding(7), cpp(1), gcov(1), as(1), ld(1), gdb(1), dbx(1), and the Info entries for gcc, cpp, as, ld, binutils and gdb ๐Ÿ“–๐ŸŒธ

๐Ÿ‘ฉโ€๐Ÿ’ป AUTHOR ๐Ÿ‘ฉโ€๐Ÿ’ป

See the Info entry for gcc, or <http://gcc.gnu.org/onlinedocs/gcc/Contributors.html>, for the contributors to GCC ๐Ÿซถ They're the real MVPs ๐Ÿ‘‘

Copyright (c) 1988-2021 Free Software Foundation, Inc. ๐ŸŒˆ

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

And that's the whole page, bestie ๐Ÿฆ‹ Stay curious, keep those environment variables tidy, and go give the GCC folks some love ๐Ÿ’œโœจ

๐Ÿ“ฆ where this page comes from