GCC(1)

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

โœจ GCC(1) from GNU โœจ

Okay bestie, welcome to the GCC(1) manual page from GNU ๐Ÿ’– This is the official lore for the compiler, and I'm about to spill all of it ๐Ÿงš

โœจ NAME โœจ

gcc - GNU project C and C++ compiler ๐ŸŒธ That's the whole vibe: the GNU project's C and C++ compiler, no cap ๐Ÿ’…

โœจ SYNOPSIS โœจ

Here's the core lineup of options. The rest come later ๐Ÿ‘€

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

Only the most useful options are listed here, so see below for the remainder ๐ŸŽ€ And g++ takes mostly the same options as gcc, so you're basically already fluent โœจ

โœจ DESCRIPTION โœจ

So when you invoke GCC, it normally runs the whole pipeline: preprocessing, compilation, assembly, and linking ๐Ÿ”ฅ The "overall options" let you hit pause at an intermediate stage. For example, -c tells it not to run the linker, so what you get back are object files straight from the assembler ๐Ÿฆ‹

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

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

The usual way to run GCC is the executable called gcc, or machine-gcc when you're cross-compiling, or machine-gcc-version if you want one specific version of GCC. When you compile C++ programs, 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 stack single-letter options together. -dv is very different from -d -v, so don't get it twisted ๐Ÿ’€

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

Lots of options have long names starting with -f or with -W---for, like -fmove-loop-invariants, -Wformat, and so on โœจ Most of these have both positive and negative forms, and the negative form of -ffoo is -fno-foo. This manual only documents one of the two forms, whichever one isn't the default ๐Ÿซถ

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

Arguments to options that set a size threshold can be arbitrarily large decimal or hexadecimal integers, followed by a byte size suffix for a multiple of bytes. That includes kB and KiB for kilobyte and kibibyte, MB and MiB for megabyte and mebibyte, and GB and GiB for gigabyte and gigibyte, and so on ๐Ÿ“ In the following text, these are called byte-size arguments. For the full listing and explanation of the binary and decimal byte size prefixes, check the NIST, IEC, and other relevant national and international standards โญ

โœจ OPTIONS โœจ

๐ŸŒธ Option Summary

Here's a summary of all the options, grouped by type. The explanations live in the following sections, so keep scrolling, bestie ๐Ÿ’…

Overall Options

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

C Language Options

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

C++ Language Options

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

Objective-C and Objective-C++ Language Options

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

Diagnostic Message Formatting Options

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

โš ๏ธ Warning Options โš ๏ธ

okay bestie, this is the warning buffet ๐Ÿ“ every flag in here is a way of asking GCC to speak up about sus code, so grab a plate and get ready to be overwhelmed ๐Ÿ’…

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

๐Ÿ” Static Analyzer Options ๐Ÿ”

the analyzer flags are giving detective energy ๐Ÿ•ต๏ธโ€โ™€๏ธ these are the ones you pull out when you want GCC to go deep on your code flow โœจ

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

๐Ÿง  C and Objective-C-only Warning Options ๐Ÿง 

these ones are C and Objective-C only, so they won't show up for every language, babe ๐Ÿซถ

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

okay the debugging flags are where the magic happens ๐Ÿช„ this is the list you reach for when you want GCC to leave you breadcrumbs for your debugger ๐Ÿžโœจ

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

โœจ Optimization Options โœจ

okay bestie, this is the big optimization drawer ๐Ÿ’… so many flags, so many vibes. here's the whole lineup, no cap ๐Ÿ”ฅ

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

๐ŸŒˆ Program Instrumentation Options ๐ŸŒˆ

this is the tracking-and-protection squad ๐Ÿซถ these are the flags for profiling, coverage, sanitizers, and stack protection. main character energy โœจ

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

๐Ÿ’œ Preprocessor Options ๐Ÿ’œ

okay the preprocessor is where the macros and includes get handled ๐ŸŽ€ so many little knobs, let's go

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

๐Ÿฆ‹ Assembler Options ๐Ÿฆ‹

  • -Wa,option
  • -Xassembler option

๐Ÿ“ Linker Options ๐Ÿ“

linking time, bestie ๐Ÿ”— objects, libraries, and all the static-vs-shared drama

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

๐ŸŒธ Directory Options ๐ŸŒธ

where gcc goes looking for stuff ๐Ÿงš search paths, prefixes, sysroots, the whole map

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

๐Ÿซง Code Generation Options ๐Ÿซง

this is the section for how the actual machine code gets generated ๐Ÿ’– exceptions, unwinding, PIC/PIE, visibility, and more

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

๐Ÿ”ฅ Developer Options ๐Ÿ”ฅ

the deep-dive, debugging, and dump-everything section ๐Ÿ™ˆ ngl this one is a lot, but we got this ๐Ÿ’…

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

๐Ÿ‘‘ Machine-Dependent Options ๐Ÿ‘‘

last stop, the target-specific flags ๐ŸŒˆ these depend on which machine you're building for

๐Ÿฆ‹ 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, first up is the Adapteva Epiphany crew ๐Ÿฆ‹ Here's the whole squad:

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

Next, the AMD GCN options ๐Ÿ’… Only three, but they're iconic:

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

โœจ ARC Options โœจ

Now we're going into the ARC options, and this list is LONG ๐Ÿ˜ญ Lowkey the most options in the whole group chat ๐Ÿ”ฅ

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

โœจ ARM Options โœจ

ARM time ๐ŸŒธ This group is a whole vibe, so buckle up:

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

AVR options are up next ๐Ÿงš

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

Blackfin next ๐Ÿ”ฅ Pay attention to the -mcpu=cpu[-sirevision] one, it has a little bracket situation going on:

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

Quick one: the C6X options ๐Ÿ’–

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

โœจ CRIS Options โœจ

CRIS is giving main character energy ๐Ÿ‘‘

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

โœจ CR16 Options โœจ

CR16 options, bestie ๐ŸŽ€

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

โœจ C-SKY Options โœจ

C-SKY next ๐Ÿฆ‹ This list is giving "I have a lot of opinions about endianness" energy:

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

โœจ Darwin Options โœจ

Darwin options are a whole mood ๐ŸŒˆ Lots of them, so grab a snack:

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

โœจ DEC Alpha Options โœจ

DEC Alpha ๐Ÿ’œ Some of these are a little old school, but they're still iconic:

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

โœจ eBPF Options โœจ

eBPF is so cute rn ๐Ÿงš

-mbig-endian -mlittle-endian -mkernel=version
-mframe-limit=bytes -mxbpf

โœจ FR30 Options โœจ

FR30 options, short and sweet ๐Ÿ“

-msmall-model  -mno-lsim

โœจ FT32 Options โœจ

FT32 next ๐ŸŒธ

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

โœจ FRV Options โœจ

FRV options! Literally a wall of flags, not gonna lie ๐Ÿ’€

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

GNU/Linux options ๐Ÿซถ

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

โœจ H8/300 Options โœจ

H8/300 next ๐ŸŽ€

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

โœจ HPPA Options โœจ

HPPA options, and yes, they're all lowercase vibes ๐Ÿ’…

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

โœจ IA-64 Options โœจ

IA-64, the big one ๐ŸŒˆ Scroll slowly, there are a LOT of scheduling flags in here:

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

โœจ LM32 Options โœจ

LM32 options ๐Ÿงš

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

โœจ M32R/D Options โœจ

M32R/D next ๐Ÿ’–

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

M32C, quick and easy ๐Ÿ“

-mcpu=cpu  -msim  -memregs=number

โœจ M680x0 Options โœจ

M680x0 is a whole era ๐Ÿ‘‘ Lots of CPU and CPU-variant flags, so take your time:

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

โœจ MCore Options โœจ

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

MeP options, the final stretch ๐Ÿฆ‹

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

And last but not least, MicroBlaze ๐Ÿซถ We made it, bestie ๐Ÿ˜ญ

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

Okay bestie, MIPS has a whole buffet of flags ๐Ÿฆ‹ Here's the full spread ๐Ÿ’…

  • -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, MMIX ๐ŸŒˆ

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

โœจ MN10300 Options โœจ

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

โœจ Moxie Options โœจ

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

โœจ MSP430 Options โœจ

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

โœจ NDS32 Options โœจ

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

โœจ Nios II Options โœจ

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

โœจ Nvidia PTX Options โœจ

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

โœจ OpenRISC Options โœจ

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

โœจ PDP-11 Options โœจ

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

โœจ picoChip Options โœจ

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

โœจ PowerPC Options โœจ

Just go check the RS/6000 and PowerPC section, it's got everything ๐Ÿ’– See RS/6000 and PowerPC Options.

โœจ PRU Options โœจ

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

โœจ RISC-V Options โœจ

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

โœจ RL78 Options โœจ

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

โœจ RS/6000 and PowerPC Options โœจ

This one's a monster, bestie ๐Ÿ˜ญ Grab a snack, here we go ๐Ÿ“

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

โœจ RX Options โœจ

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

โœจ S/390 and zSeries Options โœจ

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

โœจ Score Options โœจ

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

โœจ SH Options โœจ

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

โœจ Solaris 2 Options โœจ

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

โœจ SPARC Options โœจ

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

โœจ System V Options โœจ

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

โœจ TILE-Gx Options โœจ

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

โœจ TILEPro Options โœจ

  • -mcpu=cpu
  • -m32

โœจ V850 Options โœจ

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

โœจ VAX Options โœจ

  • -mg
  • -mgnu
  • -munix

๐Ÿ’– Visium Options ๐Ÿ’–

okay bestie, these are the Visium flags, and they're giving main character energy ๐Ÿฆ‹

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

๐ŸŒธ VMS Options ๐ŸŒธ

the VMS crew gets its own set โœจ

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

๐Ÿงš VxWorks Options ๐Ÿงš

and now the VxWorks ones, which are lowkey iconic ๐Ÿ’…

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

๐Ÿ‘‘ x86 Options ๐Ÿ‘‘

the x86 list is LONG and it is not playing ๐Ÿ˜ญ but every single one is here, no cap ๐Ÿ”ฅ

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

๐ŸชŸ x86 Windows Options ๐ŸชŸ

the Windows flags, bestie, and yes the last one is a whole mouthful ๐Ÿ™ˆ

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

๐Ÿ“ Xstormy16 Options ๐Ÿ“

just one for the Xstormy16 crew ๐Ÿ’œ

-msim

๐ŸŒˆ Xtensa Options ๐ŸŒˆ

the Xtensa list is a whole vibe, ngl ๐Ÿ’…

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

๐ŸŽ€ zSeries Options ๐ŸŽ€

the zSeries stuff lives somewhere else, so go check there ๐Ÿซถ

See S/390 and zSeries Options.


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

okay so compilation can have up to four stages: preprocessing, compilation proper, assembly and linking, always in that order ๐Ÿ”ฅ GCC can preprocess and compile several files into several assembler input files, or into one assembler input file. Then each assembler input file produces an object file, and linking combines all the object files (the newly compiled ones and the ones you specified as input) into an executable file ๐Ÿ’–

For any given input file, the file name suffix decides what kind of compilation happens. Here's the whole lineup ๐Ÿฆ‹

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

You can also spell out the input language yourself with the -x option ๐Ÿ’…

  • -x language โ€” Explicitly sets the language for the following input files, instead of letting the compiler guess from the file name suffix. This option applies to all following input files until the next -x option. Possible values for language are:
c  c-header  cpp-output
c++  c++-header  c++-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 get handled by their file name suffixes (same as if -x was never used at all) ๐Ÿซถ

If you only want some of the stages, use -x (or filename suffixes) to tell gcc where to start, and one of -c, -S, or -E to say where gcc should stop. Heads up though, some combos (like -x cpp-output -E) make gcc do absolutely nothing at all ๐Ÿ’€

Heads up: -x cpp-output -E instructs gcc to do nothing at all, so don't be confused if nothing happens!
  • -c โ€” Compiles or assembles the source files, but does not link. The linking stage simply is not done, so the ultimate output is an object file for each source file. By default, the object file name for a source file is made by replacing the suffix .c, .i, .s, etc., with .o. Unrecognized input files, which don't need compilation or assembly, are ignored.
  • -S โ€” Stops after the compilation proper stage and doesn't 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 doesn't 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 output in file. This applies to whatever sort of output is being produced, whether that's an executable, an object file, an assembler file, or preprocessed C code. If -o isn't specified, the default is 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 โœจ
  • -v โ€” Prints (on standard error output) the commands executed to run the stages of compilation. It also prints the version number of the compiler driver program and of the preprocessor and the compiler proper ๐Ÿ”ฅ
  • -### โ€” Like -v, except the commands are not executed, and arguments get quoted unless they contain only alphanumeric characters or "./-_". This is super useful for shell scripts that want to capture the driver-generated command lines ๐Ÿงš
  • --help โ€” Prints (on the standard output) a description of the command-line options gcc understands. If -v is also specified, then --help is passed on to the various processes gcc invokes, so they can show the command-line options they accept. If -Wextra was also specified (before the --help option), then command-line options that have no documentation are displayed too ๐Ÿ‘‘
  • --target-help โ€” Prints (on the standard output) a description of the target-specific command-line options for each tool. For some targets, extra target-specific information may also be printed ๐Ÿ’–
  • --help={class|[^]qualifier}[,...] โ€” okay bestie, this one is a whole vibe ๐Ÿ’… It prints (to standard output) a rundown of every command-line option the compiler understands that fits into all the classes and qualifiers you list. These are the supported classes:
    • optimizers โ€” every optimization option the compiler supports โœจ
    • warnings โ€” every option that controls the warning messages the compiler produces ๐Ÿ”ฅ
    • target โ€” target-specific options. Unlike --target-help, this one skips the target-specific options of the linker and assembler, because those tools don't support the extended --help= syntax yet ๐Ÿงš
    • params โ€” the values that --param recognizes ๐Ÿ’œ
    • language โ€” the options supported for language, where language is one of the languages in this version of GCC. If an option works for every language, you need to pick the common class ๐ŸŒธ
    • common โ€” the options shared by all languages ๐Ÿซถ

These are the supported qualifiers:

  • undocumented โ€” only the options that have no documentation ๐Ÿ™ˆ
  • joined โ€” options that take an argument hanging off an equal sign in the same continuous chunk of text, like --help=target ๐Ÿฆ‹
  • separate โ€” options that take an argument as their own separate word right after the option, like -o output-file ๐Ÿ“

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

--help=target,undocumented

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

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

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

--help=target,optimizers

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

If the -Q option shows up on the command line before the --help= option, the descriptive text displayed by --help= changes. Instead of describing the options, it tells you whether each one is enabled, disabled or set to a specific value (assuming the compiler knows that at the point where --help= is used) โœจ

Here is a truncated example from the ARM port of gcc:

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

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

-Q -O2 --help=optimizers

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

gcc -c -Q -O3 --help=optimizers > /tmp/O3-opts
gcc -c -Q -O2 --help=optimizers > /tmp/O2-opts
diff /tmp/O2-opts /tmp/O3-opts | grep enabled
  • --version โ€” shows the version number and copyrights of the GCC you invoked ๐ŸŽ€
  • -pass-exit-codes โ€” okay so, normally the gcc program exits with the code of 1 if any phase of the compiler returns a non-success return code. With -pass-exit-codes, it instead returns the numerically highest error produced by any phase that reported an error ๐Ÿ“ˆ The C, C++, and Fortran front ends return 4 if they hit an internal compiler error.
  • -pipe โ€” uses pipes instead of temporary files to pass data between the various stages of compilation ๐Ÿฆ‹ Heads up: this fails on some systems where the assembler can't read from a pipe. The GNU assembler has no trouble with it though ๐Ÿ’…
  • -specs=file โ€” processes file after the compiler reads in the standard specs file. This lets you override the defaults the gcc driver uses when deciding which switches to pass to cc1, cc1plus, as, ld, etc. ๐Ÿ”ง You can give more than one -specs=file on the command line, and they get processed in order, from left to right.
  • -wrapper โ€” runs all subcommands under a wrapper program. You pass the wrapper's name and its parameters as a comma separated list. Like this:
gcc -c t.c -wrapper gdb,--args

That invokes all the subprograms of gcc under gdb --args, so the call to cc1 becomes gdb --args cc1 .... ๐Ÿงš

  • -ffile-prefix-map=old=new โ€” when compiling files living in directory old, any references to them in the compilation result get recorded as if the files lived in directory new instead ๐Ÿ—บ๏ธ Setting this is the same as setting all the individual -f*-prefix-map options. It's a great way to make reproducible builds that don't depend on location. See also -fmacro-prefix-map and -fdebug-prefix-map.
  • -fplugin=name.so โ€” loads the plugin code from name.so, which should 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 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 matching Go declarations in file. You get Go const, type, var, and func declarations, which can be a handy head start if you're writing a Go interface to code written in some other language ๐Ÿน
  • @file โ€” reads command-line options from file. The options read get inserted in place of the original @file option. If file doesn't exist or can't be read, the option is treated literally and doesn't get removed ๐Ÿซ  Options inside file are separated by whitespace. You can include a whitespace character in an option by wrapping the whole option in single or double quotes. Any character (backslash included) can be included by putting a backslash in front of it. The file can even contain more @file options of its own, and those get processed recursively ๐ŸŒ€

โœจ Compiling C++ Programs โœจ

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

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

When you compile C++ programs, you can use lots of the same command-line options you'd use for programs in any language, options meaningful for C and related languages, or options that only matter for C++ programs ๐Ÿฆ‹


โœจ Options Controlling C Dialect โœจ

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

  • -ansi โ€” in C mode, this is the same as -std=c90. In C++ mode, it's the same as -std=c++98 ๐Ÿ“œ

This turns off certain GCC features that clash with ISO C90 (when compiling C code) or standard C++ (when compiling C++ code). Think the asm and typeof keywords, and predefined macros like unix and vax that identify the type of system you're on. It also enables the undesirable and rarely used ISO trigraph feature. For the C compiler, it also disables recognition of C++ style // comments, plus the inline keyword ๐Ÿ™ˆ

The alternate keywords __asm__, __extension__, __inline__ and __typeof__ keep working even with -ansi. You wouldn't want to use them in an ISO C program, of course, but they're useful in header files that might get included in compilations done with -ansi. Alternate predefined macros like __unix__ and __vax__ are also available, with or without -ansi ๐Ÿ’…

The -ansi option doesn't reject non-ISO programs left and right. For that, you need -Wpedantic in addition to -ansi ๐Ÿง

The macro __STRICT_ANSI__ is predefined when -ansi is used. Some header files might notice this macro and hold back from declaring certain functions or defining certain macros that the ISO standard doesn't call for. This avoids messing with programs that use those names for other things ๐Ÿซถ

Functions that are normally built in but don't have semantics defined by ISO C (like alloca and ffs) are not built-in functions when -ansi is used ๐Ÿšซ

  • -std= โ€” determines the language standard. This option is currently only supported when compiling C or C++ ๐ŸŒธ

okay so bestie, -std is where things get spicy ๐ŸŒถ๏ธโœจ you can pick a base standard like c90 or c++98, or a GNU dialect of one like gnu90 or gnu++98 ๐Ÿ’… with a base standard, GCC takes every program that follows that standard, plus any GNU extensions that don't clash with it ๐ŸŽ€ for example, -std=c90 switches off GCC features that aren't ISO C90 compatible, like the asm and typeof keywords ๐Ÿ™ˆ but it keeps other GNU extensions that don't mean anything in ISO C90, like leaving out the middle term of a ?: expression ๐Ÿ’–

then there's the GNU dialect side, and it's lowkey a different vibe ๐Ÿ˜ญ when you pick one, every feature the compiler supports gets turned on, even the ones that change what the base standard means ๐Ÿ”ฅ so, ngl, some strict-conforming programs might get rejected ๐Ÿ’€ -Wpedantic uses whichever standard you picked to decide which features count as GNU extensions ๐Ÿฆ‹ so -std=gnu90 -Wpedantic will warn you about C++ style // comments, but -std=gnu99 -Wpedantic won't ๐ŸŒˆ

you must give this option a value, and these are your choices ๐Ÿซถ

  • c90, c89, iso9899:1990 โ€” full ISO C90 support, with the GNU extensions that clash with ISO C90 switched off ๐Ÿ’… this is the same as -ansi for C code โœจ
  • iso9899:199409 โ€” ISO C90 with amendment 1 baked in ๐ŸŒธ
  • c99, c9x, iso9899:1999, iso9899:199x โ€” ISO C99 ๐Ÿฆ‹ it's substantially completely supported, modulo bugs and floating-point issues (mostly, but not entirely, around optional C99 features from Annexes F and G) ๐Ÿ™ˆ check <http://gcc.gnu.org/c99status.html> for the tea โ˜• the names c9x and iso9899:199x are deprecated, so retire them, bestie ๐Ÿ’€
  • c11, c1x, iso9899:2011 โ€” ISO C11, the 2011 revision ๐Ÿ‘‘ also substantially completely supported, modulo bugs and floating-point issues (mostly around optional C11 features from Annexes F and G) plus the optional Annexes K (Bounds-checking interfaces) and L (Analyzability) ๐ŸŽ€ c1x is deprecated ๐Ÿ’–
  • c17, c18, iso9899:2017, iso9899:2018 โ€” ISO C17, the 2017 revision (published in 2018) ๐ŸŒˆ it's the same as C11 except for defect corrections (all of which are also applied with -std=c11) and a new value of __STDC_VERSION__ โœจ so it gets the same level of support as C11 ๐Ÿซถ
  • c2x โ€” the next version of ISO C, still cooking ๐Ÿงš support is experimental and incomplete, so be careful ๐Ÿ™ˆ
  • gnu90, gnu89 โ€” the GNU dialect of ISO C90, which also picks up some C99 features ๐Ÿ“
  • gnu99, gnu9x โ€” the GNU dialect of ISO C99 ๐Ÿ’œ gnu9x is deprecated ๐Ÿ’€
  • gnu11, gnu1x โ€” the GNU dialect of ISO C11 ๐Ÿ”ฅ gnu1x is deprecated ๐Ÿ™ˆ
  • gnu17, gnu18 โ€” the GNU dialect of ISO C17 ๐Ÿ‘‘ this is the default for C code ๐Ÿ’…
  • gnu2x โ€” the next ISO C version plus GNU extensions ๐ŸŒธ support is experimental and incomplete โœจ
  • c++98, c++03 โ€” the 1998 ISO C++ standard plus the 2003 technical corrigendum and some extra defect reports ๐Ÿฆ‹ this is the same as -ansi for C++ code ๐ŸŽ€
  • gnu++98, gnu++03 โ€” the GNU dialect of -std=c++98 ๐ŸŒˆ
  • c++11, c++0x โ€” the 2011 ISO C++ standard plus amendments ๐Ÿ’– c++0x is deprecated, so switch over ๐Ÿ’…
  • gnu++11, gnu++0x โ€” the GNU dialect of -std=c++11 ๐Ÿซถ gnu++0x is deprecated โœจ
  • c++14, c++1y โ€” the 2014 ISO C++ standard plus amendments ๐Ÿ“ c++1y is deprecated ๐Ÿ’€
  • gnu++14, gnu++1y โ€” the GNU dialect of -std=c++14 ๐Ÿ‘‘ this is the default for C++ code ๐Ÿ”ฅ gnu++1y is deprecated ๐Ÿ™ˆ
  • c++17, c++1z โ€” the 2017 ISO C++ standard plus amendments ๐ŸŒˆ c++1z is deprecated ๐Ÿ’œ
  • gnu++17, gnu++1z โ€” the GNU dialect of -std=c++17 โœจ gnu++1z is deprecated ๐ŸŽ€
  • c++20, c++2a โ€” the next revision of ISO C++, planned for 2020 ๐Ÿงš support is highly experimental, and it will almost certainly change in incompatible ways in future releases ๐Ÿ’€
  • gnu++20, gnu++2a โ€” the GNU dialect of -std=c++20 ๐Ÿฆ‹ support is highly experimental too, and it'll almost certainly change in incompatible ways in future releases ๐Ÿ™ˆ

-fgnu89-inline

okay, so this one tells GCC to use the traditional GNU semantics for inline functions when you're in C99 mode ๐ŸŒธ using it is roughly the same as slapping the gnu_inline function attribute on every inline function ๐Ÿซถ

-fno-gnu89-inline does the opposite and tells GCC to use the C99 semantics for inline when you're in C99 or gnu99 mode ๐Ÿ’… (it's the default behavior, so it's basically just being explicit ๐ŸŽ€) and it's not supported in -std=c90 or -std=gnu90 mode ๐Ÿ’€

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

-fpermitted-flt-eval-methods=style

ISO/IEC TS 18661-3 adds new allowed values for FLT_EVAL_METHOD ๐Ÿฆ‹ these say that operations and constants with a semantic type that's an interchange or extended format should be evaluated to the precision and range of that type โœจ the new values are a superset of what C99/C11 allows, and C99/C11 doesn't say what any other positive values of FLT_EVAL_METHOD mean ๐Ÿ™ˆ so code that follows C11 might never have expected the new values, bestie ๐Ÿ˜ญ

-fpermitted-flt-eval-methods lets you decide whether the compiler only allows the FLT_EVAL_METHOD values from C99/C11, or the extended set from ISO/IEC TS 18661-3 ๐ŸŒˆ

style is either c11 or ts-18661-3, whichever fits ๐Ÿ’œ

the default in a standards compliant mode (like -std=c11 or similar) is -fpermitted-flt-eval-methods=c11 ๐ŸŽ€ the default in a GNU dialect (like -std=gnu11 or similar) is -fpermitted-flt-eval-methods=ts-18661-3 ๐Ÿ‘‘

-aux-info filename

this one writes prototyped declarations for every function declared and/or defined in a translation unit into the given filename ๐Ÿงš that includes functions in header files too ๐Ÿ’– it's silently ignored in any language that isn't C ๐Ÿซถ

the file also has comments telling you where each declaration came from (source file and line) ๐Ÿ“ the character right after the line number and colon tells you whether the declaration was implicit, prototyped, or unprototyped: I, N for new, or O for old, respectively ๐Ÿ“ the character after that tells you whether it came from a declaration or a definition: C or F, respectively ๐ŸŒธ for function definitions, you also get a K&R-style list of arguments followed by their declarations, tucked inside comments after the declaration ๐Ÿฆ‹

-fallow-parameterless-variadic-functions

this one accepts variadic functions without named parameters โœจ you can define one, but it's not very useful because you can't read the arguments ๐Ÿ™ˆ it's only supported for C, since C++ already allows this construct ๐ŸŒˆ

-fno-asm

this stops GCC from treating asm, inline, or typeof as keywords, so your code can use those words as identifiers ๐Ÿ’… you can 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 there ๐Ÿ”ฅ you might want to use -fno-gnu-keywords instead, which has the same effect ๐Ÿ’– in C99 mode (-std=c99 or -std=gnu99), it only affects the asm and typeof keywords, since inline is a standard keyword in ISO C99 ๐Ÿฆ‹

-fno-builtin, -fno-builtin-function

this tells GCC not to recognize built-in functions that don't start with the prefix __builtin_ ๐Ÿซถ

GCC usually generates special code for certain built-in functions so they run faster ๐Ÿš€ for example, calls to alloca can turn into single instructions that adjust the stack directly, and calls to memcpy can become inline copy loops ๐ŸŒธ the code is often smaller and faster, but since those calls don't show up as calls anymore, you can't set a breakpoint on them, and you can't change what they do by linking with a different library ๐Ÿ˜ญ also, once a function counts as built-in, GCC can use that info to warn you about problems with calls to it, or to generate better code, even if the result still contains calls to that function ๐Ÿ’œ for example, you get -Wformat warnings for bad calls to printf when printf is built in, and strlen is known not to modify global memory ๐Ÿ‘‘

with -fno-builtin-function, only that one built-in function gets disabled ๐ŸŽ€ function must not begin with __builtin_ ๐Ÿ’… if the function you name isn't built-in in this version of GCC, the option is just ignored โœจ there's no matching -fbuiltin-function option, so if you want to pick built-in functions one at a time with -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

this enables parsing of function definitions marked with __GIMPLE ๐Ÿงช it's an experimental feature that lets you unit test GIMPLE passes ๐Ÿ”ฅ

-fhosted

this asserts that compilation targets a hosted environment, and it implies -fbuiltin ๐ŸŒˆ a hosted environment is one where the entire standard library is available, and main has a return type of int ๐Ÿซถ think basically everything except a kernel ๐Ÿ’… this is equivalent to -fno-freestanding ๐ŸŽ€

-ffreestanding

this asserts that compilation targets a freestanding environment, and it implies -fno-builtin ๐Ÿฆ‹ a freestanding environment is one where the standard library might not exist, and program startup might not necessarily begin at main ๐Ÿ˜ญ the most obvious example is an OS kernel ๐Ÿ‘‘ this is equivalent to -fno-hosted ๐Ÿ’–

  • -fopenacc โ€” okay so this one turns on handling for OpenACC directives, which means #pragma acc in C/C++ and !$acc in Fortran ๐Ÿ’…. With it on, the compiler generates accelerated code following the OpenACC Application Programming Interface v2.6 <https://www.openacc.org>. It also implies -pthread, so it only works on targets that support -pthread ๐Ÿงš
  • -fopenacc-dim=geom โ€” bestie, this sets the default compute dimensions for parallel offload regions that don't specify their own ๐ŸŒˆ geom is a triple of sizes separated by :, in the order gang, worker and vector. You can leave any size out to get a target-specific default โœจ
  • -fopenmp โ€” this one enables handling of OpenMP directives, #pragma omp in C/C++ and !$omp in Fortran ๐Ÿ”ฅ With it on, the compiler generates parallel code following the OpenMP Application Program Interface v4.5 <https://www.openmp.org>. It implies -pthread, so again, only on targets that support -pthread. It also implies -fopenmp-simd ๐Ÿ’œ
  • -fopenmp-simd โ€” the lowkey version of the above ๐Ÿฆ‹ It turns on handling of OpenMP's SIMD directives written as #pragma omp in C/C++ and !$omp in Fortran. Every other OpenMP directive just gets ignored ๐Ÿ™ˆ
  • -fgnu-tm โ€” this is the transactional memory one ๐ŸŽ€ With -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). Heads up, it's experimental, so the interface might change in future GCC versions as the official spec changes. Also not every architecture supports it, so check before you get attached ๐Ÿ’€

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

Note that the transactional memory feature is not supported with non-call exceptions (-fnon-call-exceptions).
  • -fms-extensions โ€” accept some non-standard constructs that show up in Microsoft header files ๐Ÿ’… In C++ code, this lets member names in structures match earlier type declarations, which is giving chaotic but valid. Like this:
typedef int UOW;
struct ABC {
  UOW UOW;
};

Some cases of unnamed fields in structures and unions only get accepted with this option ๐Ÿซถ Also, this option is off for all targets except x86 targets using ms-abi.

  • -fplan9-extensions โ€” accept some non-standard constructs from Plan 9 code ๐ŸŒธ This turns on -fms-extensions, lets you pass pointers to structures with anonymous fields into functions that expect pointers to elements of the field's type, and lets you refer to anonymous fields declared with a typedef. It's only supported for C, not C++, so don't try it in your C++ era ๐Ÿ™…โ€โ™€๏ธ
  • -fcond-mismatch โ€” allow conditional expressions with mismatched types in the second and third arguments ๐Ÿ“ The value of that kind of expression is void. Not supported for C++ ๐Ÿ’–
  • -flax-vector-conversions โ€” allow implicit conversions between vectors with different numbers of elements and/or incompatible element types ๐Ÿ˜ญ This option should not be used for new code, so save it for the old stuff.
  • -funsigned-char โ€” let the type char be unsigned, like unsigned char ๐Ÿ‘‘ Every 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 always uses signed char or unsigned char whenever it cares about signedness. But plenty of programs were written with plain char and expect it to be signed or unsigned depending on the machine they were built for. This option and its inverse let you make those programs work with the opposite default ๐Ÿงš The type char is always its own distinct type from both signed char and unsigned char, even though it behaves exactly like one of them.
  • -fsigned-char โ€” let the type char be signed, like signed char โœจ This is equivalent to -fno-unsigned-char, which is the negative form of -funsigned-char. And the other way around: -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, a bit-field is signed, and that's honestly the consistent choice, since basic integer types like int are signed too ๐Ÿ’…
  • -fsso-struct=endianness โ€” set the default scalar storage order of structures and unions to the endianness you pick ๐Ÿ”ฅ The accepted values are big-endian, little-endian, and native, which is the native endianness of the target and also the default. This option is not supported for C++ ๐Ÿ™ˆ
Warning: the -fsso-struct switch causes GCC to generate code that is not binary compatible with code generated without it if the specified endianness is not the native endianness of the target. Read that twice, bestie ๐Ÿ’€

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

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

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

In that example, only -fstrict-enums is 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 โ€” use version n of the C++ ABI ๐Ÿ’œ The default is version 0.
    • Version 0 refers to the version that conforms most closely to the C++ ABI specification. Because of that, the ABI you get with version 0 will change across G++ versions 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, 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, which first appeared in G++ 7, corrects the mangling of sizeof... expressions and operator names. For multiple entities with the same name within a function that are declared in different scopes, the mangling now changes starting with the twelfth occurrence. It also implies -fnew-inheriting-ctors ๐Ÿซถ
    • Version 12, which first appeared in G++ 8, corrects the calling conventions for empty classes on the x86_64 target and for classes with only deleted copy/move constructors. It accidentally changes the calling convention for classes with a deleted copy constructor and a trivial move constructor ๐Ÿ˜ญ
    • Version 13, which first appeared in G++ 8.2, fixes the accidental change in version 12 ๐Ÿ™Œ
    • Version 14, which first appeared in G++ 10, corrects the mangling of the nullptr expression ๐Ÿ’–

See also -Wabi.

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

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

If you don't give this option but do give -Wabi=n, that version gets used for the compatibility aliases. If you give this option along with -Wabi (without a version), the version from this option is used for the warning ๐Ÿ’œ

  • -fno-access-control โ€” turns off all access checking ๐Ÿ™ˆ This switch is mainly useful for working around bugs in the access control code, so it's more of a last-resort move ๐Ÿ’€
  • -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 numeric argument like -faligned-new=32 to say how much alignment (in bytes) that function provides, but very 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 โ€” enable support for char8_t as adopted for C++2a ๐ŸŒˆ This adds a brand-new char8_t fundamental type, changes the types of UTF-8 string and character literals, adds new signatures for user-defined literals, comes with standard library updates, and adds the new __cpp_char8_t and __cpp_lib_char8_t feature test macros ๐ŸŽ€

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

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

and it introduces new signatures for user-defined literals:

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

The UTF-8 literal change is a real heads-up, bestie ๐Ÿซถ It breaks code that compiles fine under ISO C++11 and later, and that includes these lines once -fchar8_t is on:

char ca[] = u8"xx";     // error: char-array initialized from wide
                        //        string
const char *cp = u8"xx";// error: invalid conversion from
                        //        `const char8_t*' to `const char*'
int f(const char*);
auto v = f(u8"xx");     // error: invalid conversion from
                        //        `const char8_t*' to `const char*'
std::string s{u8"xx"};  // error: no matching function for call to
                        //        `std::basic_string<char>::basic_string()'
using namespace std::literals;
s = u8"xx"s;            // error: conversion from
                        //        `basic_string<char8_t>' to non-scalar
                        //        type `basic_string<char>' requested

โœจ OPTIONS (continued) โœจ

  • -fcheck-new โ€” ๐ŸŽ€ This makes G++ check that the pointer operator new hands back isn't null before it starts writing into that storage. Honestly you usually don't need it, because the standard says operator new only returns 0 when it's declared throw(), and in that case the compiler checks the return value anyway, even without this flag. For every other case, when operator new has a non-empty exception specification, running out of memory gets signalled by throwing std::bad_alloc instead. See also new (nothrow) ๐Ÿงš
  • -fconcepts, -fconcepts-ts โ€” ๐Ÿฆ‹ Below -std=c++2a, -fconcepts turns on support for the C++ Extensions for Concepts Technical Specification, ISO 19217 (2015). With -std=c++2a and above, Concepts are officially part of the language, so -fconcepts is on by default. The standard version of Concepts is quite different from the TS though, so a few things the TS allowed but the standard dropped can still be turned on with -fconcepts-ts ๐Ÿ’…
  • -fconstexpr-depth=n โ€” ๐ŸŒˆ Sets the maximum nested evaluation depth for C++11 constexpr functions to n. The limit is what catches endless recursion while constant expressions are being evaluated. The standard's minimum is 512 โœจ
  • -fconstexpr-cache-depth=n โ€” ๐Ÿ’œ Sets the deepest nesting level of C++11 constexpr function evaluation that gets cached, to n. It's a heuristic balancing compile speed (the cache skips repeated work) against memory (the cache can balloon with really recursive evaluations). The default is 8. Very few people need to touch it, but if your code does heavy constexpr math, feel free to experiment and see which value slaps the hardest for you ๐Ÿ”ฅ
  • -fconstexpr-loop-limit=n โ€” ๐Ÿ“ Sets the maximum number of iterations for a loop in C++14 constexpr functions to n. This is the safety net that catches infinite loops during constant expression evaluation. The default is 262144 (1<<18) ๐ŸŒธ
  • -fconstexpr-ops-limit=n โ€” ๐Ÿซง Sets the maximum number of operations allowed during a single constexpr evaluation. The loop limit above still applies per loop, but you can end up with several nested loops that each stay under that limit and still take forever together. Or a loop body, or even code outside any loop, can have so many expressions to evaluate that the whole constexpr evaluation drags on too long. This flag is there to cap that. The default is 33554432 (1<<25) ๐Ÿ˜ญ
  • -fcoroutines โ€” ๐Ÿงช Turns on support for the C++ coroutines extension. It's experimental, so be a little careful with it ๐Ÿ’€
  • -fno-elide-constructors โ€” ๐Ÿ™ˆ The C++ standard lets an implementation skip making a temporary that only exists to initialize another object of the same type. This flag turns that optimization off and makes G++ call the copy constructor every single time. It also makes G++ call trivial member functions that would otherwise get expanded inline. In C++17, the compiler is required to skip these temporaries, but this flag still affects trivial member functions ๐Ÿ‘‘
  • -fno-enforce-eh-specs โ€” ๐Ÿงƒ Skips generating the code that checks for exception specification violations at run time. This goes against the C++ standard, but it can be useful for shrinking code size in production builds, kind of like defining NDEBUG. It doesn't give your code permission to throw exceptions that break the exception specifications, though. The compiler still optimizes based on those specs, so if you throw an unexpected exception, you get undefined behavior at run time. Yikes ๐Ÿ˜ฌ
  • -fextern-tls-init, -fno-extern-tls-init โ€” ๐Ÿงต The C++11 and OpenMP standards let thread_local and threadprivate variables have dynamic (run-time) initialization. To make that work, any use of such a variable goes through a wrapper function that does whatever initialization is needed. When the use and the definition are in the same translation unit, the compiler can optimize that overhead away. But when the use is in a different translation unit, there's a big overhead even if the variable never actually needs dynamic initialization. If you can be sure that no use in a non-defining TU needs to trigger the dynamic initialization (because the variable is statically initialized, or because a use in the defining TU always runs before any use in another TU), you can skip the overhead with -fno-extern-tls-init. On targets that support symbol aliases, the default is -fextern-tls-init. On targets that don't support symbol aliases, the default is -fno-extern-tls-init โœจ
  • -fno-gnu-keywords โ€” ๐ŸŽˆ Stops typeof from being treated as a keyword, so 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, like -ansi, -std=c++98, -std=c++11, and so on ๐Ÿ’…
  • -fno-implicit-templates โ€” ๐ŸŽฏ Never emits code for non-inline templates that get instantiated implicitly (that is, by use). Only explicit instantiations get code emitted. If you use this, you have to be careful to structure your code so it includes all the explicit instantiations you need, or you'll get undefined symbols at link time ๐Ÿ˜ต
  • -fno-implicit-inline-templates โ€” ๐ŸŒ™ Doesn't emit code for implicit instantiations of inline templates either. By default, inlines are handled differently so that compiles with and without optimization need the same set of explicit instantiations ๐Ÿฆข
  • -fno-implement-inlines โ€” ๐Ÿชถ To save space, this skips emitting out-of-line copies of inline functions controlled by #pragma implementation. Heads-up: if those functions don't get inlined everywhere they're called, you'll get linker errors ๐Ÿ”—
  • -fms-extensions โ€” ๐ŸชŸ Disables -Wpedantic warnings about constructs used in MFC, like implicit int and getting a pointer to a member function through non-standard syntax ๐Ÿ’ผ
  • -fnew-inheriting-ctors โ€” ๐Ÿงฌ Enables the P0136 change 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 -fabi-version=10 or lower is specified ๐ŸŒŸ
  • -fnew-ttp-matching โ€” ๐ŸŽญ Enables the P0522 resolution to Core issue 150, which covers template template parameters and default arguments. It lets a template with default template arguments be passed as an argument for a template template parameter that has fewer template parameters. This flag is on by default for -std=c++17 ๐Ÿงฉ
  • -fno-nonansi-builtins โ€” ๐Ÿšซ Disables the built-in declarations of functions that aren't mandated by ANSI/ISO C. These include ffs, alloca, _exit, index, bzero, conjf, and other related functions ๐Ÿƒ
  • -fnothrow-opt โ€” ๐Ÿช„ Treats a throw() exception specification as if it were a noexcept specification. That can reduce or wipe out the text size overhead compared to a function with no exception specification. If the function has local variables with types that have non-trivial destructors, the exception specification actually makes the function smaller, since the EH cleanups for those variables can be optimized away. The semantic effect is that an exception thrown out of a function with this kind of exception specification calls terminate instead of unexpected ๐Ÿšจ
  • -fno-operator-names โ€” ๐Ÿ”ค Stops the operator name keywords and, bitand, bitor, compl, not, or, and xor from being treated as synonyms for the operators they stand for ๐Ÿ™…โ€โ™€๏ธ
  • -fno-optional-diags โ€” ๐Ÿ”• Disables diagnostics that the standard says a compiler doesn't need to issue. Right now, the only one G++ issues in that category is the one for a name that has multiple meanings within a class ๐Ÿซฅ
  • -fpermissive โ€” ๐Ÿง Downgrades some diagnostics about nonconformant code from errors to warnings. So -fpermissive lets some nonconforming code compile, which is a little bit of a bend-the-rules move ๐Ÿ˜‰
  • -fno-pretty-templates โ€” ๐Ÿ–๏ธ When an error message points at a specialization of a function template, the compiler normally prints the template's signature, followed by the template arguments and any typedefs or typenames in that signature. For example, you'd see void f(T) [with T = int] instead of void f(int), so it's clear which template is involved. When an error message points at a specialization of a class template, the compiler leaves out any template arguments that match that template's default arguments. If either of those behaviors makes errors harder to read instead of easier, use -fno-pretty-templates to turn them off ๐Ÿ“
  • -fno-rtti โ€” ๐Ÿง  Disables generating the run-time type information for every class with virtual functions, which the C++ run-time type identification features (dynamic_cast and typeid) use. If you don't use those parts of the language, this flag can save some space. Exception handling uses the same information, but G++ generates it only when it's needed. The dynamic_cast operator still works for casts that don't need run-time type information, meaning 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 โ€” okay bestie, this one is giving global deallocation ๐Ÿงนโœจ It turns on the built-in global declarations introduced in C++14, which are:
void operator delete (void *, std::size_t) noexcept;
void operator delete[] (void *, std::size_t) noexcept;

These are so useful for your own replacement deallocation functions, like ones that use the object's size to make deallocation faster ๐ŸŽ๏ธ๐Ÿ’จ. It's enabled by default under -std=c++14 and above. And -Wsized-deallocation is the warning that calls out places that might want to add a definition ๐Ÿ‘€.

  • -fstrict-enums โ€” the compiler gets to optimize while assuming a value of an enumerated type can only be one of the enumeration's values ๐Ÿ’…. This follows the C++ standard, so basically it's a value that fits in the minimum number of bits needed to represent all the enumerators. Heads up though: this assumption may not hold if the program uses a cast to turn some arbitrary integer into the enumerated type ๐Ÿ’€.
  • -fstrong-eval-order โ€” this slays ๐Ÿ”ฅ It evaluates member access, array subscripting, and shift expressions left-to-right, and assignment right-to-left, as adopted for C++17. It's on by default with -std=c++17. -fstrong-eval-order=some only enables the ordering of member access and shift expressions, and it's the default without -std=c++17.
  • -ftemplate-backtrace-limit=n โ€” sets the max number of template instantiation notes for a single warning or error to n ๐Ÿ“œ. The default is 10.
  • -ftemplate-depth=n โ€” sets the max instantiation depth for template classes to n ๐ŸŒ€. You need a limit here so the compiler can catch endless recursions during template class instantiation. ANSI/ISO C++ conforming programs must not rely on a maximum depth greater than 17 (changed to 1024 in C++11) ๐Ÿ™…โ€โ™€๏ธ. The default is 900, because the compiler can run out of stack space before hitting 1024 in some situations ๐Ÿฅž.
  • -fno-threadsafe-statics โ€” no extra code for thread-safe initialization of local statics via the routines from the C++ ABI ๐Ÿงต๐Ÿšซ. Use this to shave a little code size off code that doesn't need to be thread-safe ๐ŸŒธ.
  • -fuse-cxa-atexit โ€” registers destructors for objects with static storage duration using __cxa_atexit instead of atexit ๐Ÿฆ‹. This is required for fully standards-compliant handling of static destructors, but it only works if your C library supports __cxa_atexit.
  • -fno-use-cxa-get-exception-ptr โ€” don't use the __cxa_get_exception_ptr runtime routine ๐Ÿ™ˆ. This makes std::uncaught_exception incorrect, but it's necessary if the runtime routine isn't available.
  • -fvisibility-inlines-hidden โ€” this switch is a promise ๐Ÿคž that you won't compare pointers to inline functions or methods where the addresses of the two functions are taken in different shared objects.

The effect is that GCC may effectively mark inline methods with __attribute__ ((visibility ("hidden"))), so they don't show up in the export table of a DSO and don't need a PLT indirection when used within the DSO ๐Ÿงš. Enabling this option 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 the methods as 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 tries to use visibility settings to make GCC's C++ linkage model compatible with Microsoft Visual Studio ๐ŸชŸ๐Ÿ’œ. 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're permitted when this option isn't used.

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

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

  • -fno-weak โ€” don'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, since it results in inferior code and has no benefits ๐Ÿฅ€. It may be removed in a future release of G++.
  • -fext-numeric-literals (C++ and Objective-C++ only) โ€” accepts imaginary, fixed-point, or machine-defined literal number suffixes as GNU extensions โœจ. When this option is turned off, these suffixes are treated as C++11 user-defined literal numeric suffixes. This is on by default for all pre-C++11 dialects and all GNU dialects: -std=c++98, -std=gnu++98, -std=gnu++11, -std=gnu++14. It's off by default for ISO C++11 onwards (-std=c++11, ...).
  • -nostdinc++ โ€” don't search for header files in the standard directories specific to C++, but do still search the other standard directories ๐Ÿ“. (This option is used when building the C++ library ๐Ÿ—๏ธ.)

In addition, these warning options have meanings only for C++ programs: ๐Ÿ’œ

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

Enabled by default with -std=c++2a.

  • -Wctor-dtor-privacy (C++ and Objective-C++ only) โ€” warns when a class seems unusable because all of its constructors or destructors are private, and it has neither friends nor public static member functions ๐Ÿ”’. It also warns if there are no non-private methods, and there's at least one private member function that isn't a constructor or destructor.
  • -Wdelete-non-virtual-dtor (C++ and Objective-C++ only) โ€” warns when delete is used to destroy an instance of a class that has virtual functions and a non-virtual destructor ๐Ÿ’€. It's unsafe to delete an instance of a derived class through a pointer to a base class if the base class doesn't have a virtual destructor. This warning is enabled by -Wall.
  • -Wdeprecated-copy (C++ and Objective-C++ only) โ€” warns that the implicit declaration of a copy constructor or copy assignment operator is deprecated if the class has a user-provided copy constructor or copy assignment operator, in C++11 and up ๐Ÿ“‹. This warning is enabled by -Wextra. With -Wdeprecated-copy-dtor, it also deprecates the implicit declaration if the class has a user-provided destructor.
  • -Wno-init-list-lifetime (C++ and Objective-C++ only) โ€” don't warn about uses of std::initializer_list that are likely to leave you with dangling pointers ๐Ÿซฃ. The underlying array for an initializer_list is handled like a normal C++ temporary object, so it's easy to accidentally keep a pointer to the array past the end of the array's lifetime. For example:
    • If a function returns a temporary initializer_list, or a local initializer_list variable, the array's lifetime ends at the end of the return statement, so the value returned has a dangling pointer.
    • If a new-expression creates an initializer_list, the array only lives until the end of the enclosing full-expression, so the initializer_list in the heap has a dangling pointer.
    • When an initializer_list variable is assigned from a brace-enclosed initializer list, the temporary array created for the right side of the assignment only lives until the end of the full-expression, so at the next statement the initializer_list variable has a dangling pointer.
// li's initial underlying array lives as long as li
std::initializer_list<int> li = { 1,2,3 };
// assignment changes li to point to a temporary array
li = { 4, 5 };
// now the temporary is gone and li has a dangling pointer
int i = li.begin()[0] // undefined behavior
  • 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.
  • -Wno-literal-suffix (C++ and Objective-C++ only) โ€” don't warn when a string or character literal is followed by a ud-suffix that doesn't begin with an underscore ๐Ÿ™Š. As a conforming extension, GCC treats such suffixes as separate preprocessing tokens, in order to maintain backwards compatibility with code that uses formatting macros from <inttypes.h>. For example:
#define __STDC_FORMAT_MACROS
#include <inttypes.h>
#include <stdio.h>
int main() {
  int64_t i64 = 123;
  printf("My int64: %" PRId64"\n", i64);
}

Look at that, bestie ๐ŸŽ€ In this case, PRId64 gets treated as its own separate preprocessing token ๐Ÿงš

This option also keeps an eye on user-defined literal operators that get declared with a literal suffix identifier which doesn't start with an underscore ๐Ÿ‘€ Those names are reserved for future standardization, so GCC is basically like "hey, hands off" ๐Ÿ’…

These warnings are enabled by default โœจ

  • -Wno-narrowing (C++ and Objective-C++ only) โ€” okay so, for C++11 and later, GCC catches narrowing conversions by default, because the standard says so ๐Ÿ˜ค A narrowing conversion from a constant is an error, and a narrowing conversion from a non-constant is a warning. -Wno-narrowing shuts that diagnostic up ๐Ÿ™ˆ Just know that this doesn't change what well-formed code means. Narrowing conversions are still ill-formed in SFINAE contexts, so no sneaky loopholes, periodt ๐Ÿ’€
  • -Wnarrowing (C++ and Objective-C++ only) โ€” in C++98, this one warns when a narrowing conversion that C++11 prohibits happens inside { }. Like this:
int i = { 2.2 }; // error: narrowing from double to int

This flag is included in -Wall and -Wc++11-compat ๐Ÿฆ‹

  • -Wnoexcept (C++ and Objective-C++ only) โ€” 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's throw() or "noexcept"), even though the compiler knows it never actually throws ๐ŸŒธ Main character drama, but make it compiler-approved.
  • -Wnoexcept-type (C++ and Objective-C++ only) โ€” warns if the C++17 feature that makes noexcept part of a function type changes the mangled name of a symbol compared to C++14. It's enabled by -Wabi and -Wc++17-compat ๐Ÿ”ฅ

Here's the example they gave:

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>. Iconic glow-up, no cap โœจ

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

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

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

GCC rearranges the initializers for i and j to match the declaration order of the members, and emits a warning about it. This warning is enabled by -Wall ๐ŸŽ€

  • -Wno-pessimizing-move (C++ and Objective-C++ only) โ€” this warning goes off when a call to std::move prevents copy elision. Copy elision typically happens when you return from a function with a class return type, the expression being returned is the name of a non-volatile automatic object (and not a function parameter), and it has the same type as the function's return type. Here's the example:
struct T {
...
};
T fn()
{
  T t;
  ...
  return std::move (t);
}

In this example, the std::move call prevents copy elision, so it's pessimizing your code ๐Ÿ˜ค This warning is enabled by -Wall.

  • -Wno-redundant-move (C++ and Objective-C++ only) โ€” this warning calls out redundant std::move calls, meaning a move would have happened even without the std::move. It happens because the compiler gets forced to treat an object as an rvalue in certain situations, like returning a local variable where copy elision doesn't apply. Consider:
struct T {
...
};
T fn(T t)
{
  ...
  return std::move (t);
}

Here, the std::move call is redundant ๐Ÿ’… Because G++ implements Core Issue 1579, there's another example:

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. Even so, G++ treats the return value as if it were designated by an rvalue ๐Ÿฆ‹ This warning is enabled by -Wextra.

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

But in this example, there's no warning, because the keyword is needed to avoid confusion with the function:

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

This option also enables -Wnon-virtual-dtor, which is also one of the effective C++ recommendations. However, the check is extended to warn about the lack of a virtual destructor in accessible non-polymorphic base classes too ๐Ÿซถ Heads up, though: the standard library headers don't obey all of these guidelines, so when you select this option, use grep -v to filter out those warnings ๐Ÿ™ˆ

  • -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, because NULL is defined to __null. Even though it's a null pointer constant rather than a null pointer, it's guaranteed to be the same size as a pointer. But this use isn't portable across different compilers, so GCC wants you to know ๐Ÿ‘€
  • -Wno-non-template-friend (C++ and Objective-C++ only) โ€” disables warnings when non-template friend functions get declared within a template. In very old versions of GCC that predate the ISO standard implementation, declarations like friend int foo(int), where the friend's name is an unqualified-id, could be interpreted as a particular specialization of a template function. The warning exists to diagnose compatibility problems, and it's enabled by default ๐ŸŒธ
  • -Wold-style-cast (C++ and Objective-C++ only) โ€” 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 ๐Ÿ” Glow up your casts, bestie ๐Ÿ’…
  • -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);
};

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

B* b;
b->f();

fails to compile ๐Ÿ’€

  • -Wno-pmf-conversions (C++ and Objective-C++ only) โ€” disables the diagnostic for converting a bound pointer to member function into a plain pointer ๐Ÿฆ‹
  • -Wsign-promo (C++ and Objective-C++ only) โ€” okay so this one watches overload resolution ๐Ÿ‘€ It warns when the compiler picks a promotion from an unsigned or enumerated type to a signed type, instead of a conversion to an unsigned type of the same size. Older G++ versions tried to keep the unsignedness, but the standard literally mandates the current behavior, so that's the vibe now ๐Ÿ™ƒ
  • -Wtemplates (C++ and Objective-C++ only) โ€” warns whenever a primary template declaration shows up ๐Ÿšซ If your coding rules ban templates, this is how you enforce it. It stays quiet inside system headers like the STL, so you can still use the STL ๐Ÿ’– You're also free to instantiate or specialize templates โœจ
  • -Wmismatched-tags (C++ and Objective-C++ only) โ€” warns for declarations of structs, classes, and class templates (plus their specializations) whose class-key doesn't match the definition, or the first declaration if no definition is provided ๐Ÿง

For example, the declaration of struct Object in the argument list of draw triggers the warning. To avoid it, either remove the redundant struct or swap it for class to match the definition:

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

Using struct to declare a class isn't wrong, as the example above shows ๐Ÿคทโ€โ™€๏ธ This option just helps you keep a consistent style for class declarations. In code meant to be portable to Windows-based compilers, it also helps prevent unresolved references caused by the different symbol mangling of different class-keys ๐Ÿฆ‹ You can use -Wmismatched-tags on its own or together with -Wredundant-tags.

  • -Wmultiple-inheritance (C++ and Objective-C++ only) โ€” warns when a class is defined with multiple direct base classes ๐Ÿ™…โ€โ™€๏ธ Some coding rules disallow multiple inheritance, so this is your enforcer. It's inactive inside system headers like the STL, so the STL is still fair game ๐ŸŒธ You can also define classes that indirectly use multiple inheritance.
  • -Wvirtual-inheritance โ€” warns when a class is defined with a virtual direct base class ๐Ÿงš Some coding rules disallow multiple inheritance, so use this to enforce that rule. It's inactive inside system headers like the STL, so you can still use the STL ๐Ÿ’œ You can also define classes that indirectly use virtual inheritance.
  • -Wno-virtual-move-assign โ€” suppresses warnings about inheriting from a virtual base that has a non-trivial C++11 move assignment operator ๐Ÿ™ˆ
๐Ÿ’€ This one is dangerous, bestie. If the virtual base is reachable along more than one path, it gets moved multiple times, which can mean both objects end up in the moved-from state.

If your move assignment operator is written to avoid moving from a moved-from object, this warning can be disabled ๐Ÿซถ

  • -Wnamespaces โ€” warns when a namespace definition is opened ๐Ÿ—‚๏ธ Some coding rules disallow namespaces, and this is how you enforce that. It's inactive inside system headers like the STL, so the STL keeps working for you ๐ŸŽ€ You can still use using directives and qualified names ๐Ÿ’…
  • -Wno-terminate (C++ and Objective-C++ only) โ€” disables the warning about a throw-expression that will immediately result in a call to "terminate" ๐Ÿ™ƒ
  • -Wno-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. Those conversion functions will never be called, so the warning is just noise ๐Ÿ’€
  • -Wvolatile (C++ and Objective-C++ only) โ€” warns about deprecated uses of the volatile qualifier ๐Ÿ“‰ That covers:
    • postfix and prefix ++ and -- expressions on volatile-qualified types
    • simple assignments where the left operand is a volatile-qualified non-class type, where the value gets used
    • compound assignments where the left operand is a volatile-qualified non-class type
    • volatile-qualified function return types
    • volatile-qualified parameter types
    • structured bindings of a volatile-qualified type
โš ๏ธ This usage was deprecated in C++20, so it's time to let those old habits go ๐Ÿ˜ญ

Enabled by default with -std=c++2a.

  • -Wzero-as-null-pointer-constant (C++ and Objective-C++ only) โ€” warns when a literal 0 is used as a null pointer constant ๐Ÿ“ Super handy if you're 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 too small for the object's type ๐Ÿงฑ For example, this placement new 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 ๐ŸŒŸ At this level, the warning skips some strictly undefined constructs that GCC allows as extensions for compatibility with legacy code. For example, the following new expression isn't diagnosed here, even though it's 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 everything from level 1, plus a diagnostic for placement new expressions that construct an object in the last member of a struct, where that member is an array of a single element and its size is less than the size of the object being constructed ๐Ÿงจ The previous example gets diagnosed here, but the following construct uses the flexible member array extension to dodge the warning at level 2:
struct S { int n, a[]; };
S *s = (S *)malloc (sizeof *s + 32 * sizeof s->a[0]);
new (s->a)int [32]();
  • -Wcatch-value, -Wcatch-value=n (C++ and Objective-C++ only) โ€” warns about catch handlers that don't catch via reference ๐ŸŽฃ
    • -Wcatch-value=1 (or just -Wcatch-value for short) warns about polymorphic class types that are caught by value
    • -Wcatch-value=2 warns about all class types that are caught by value
    • -Wcatch-value=3 warns about all types that 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 ๐Ÿ™ˆ
๐Ÿ’€ Deleting a pointer to an incomplete type 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 class derived from it due to ambiguity ๐Ÿ•ต๏ธ This warning is enabled by default. Note that the warning for ambiguous virtual bases is enabled by the -Wextra option.
struct A { int a; };

struct B : A { };

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

The restrictions on offsetof may be relaxed in a future version of the C++ standard ๐Ÿ”ฎ

  • -Wsized-deallocation (C++ and Objective-C++ only) โ€” warns about a definition of an unsized deallocation function ๐Ÿ—‘๏ธ
void operator delete (void *) noexcept;
void operator delete[] (void *) noexcept;

without a definition of the corresponding sized deallocation function:

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

or vice versa. This is enabled by -Wextra along with -fsized-deallocation.

  • -Wsuggest-final-types โ€” warns about types with virtual methods where code quality would be improved if the type were declared with the C++11 final specifier, or, if possible, declared in an anonymous namespace ๐Ÿง  This lets GCC devirtualize polymorphic calls more aggressively. It's more effective with link-time optimization, where the information about the class hierarchy graph is more complete.
  • -Wsuggest-final-methods โ€” warns about virtual methods where code quality would be improved if the method were declared with the C++11 final specifier, or, if possible, if its type were declared in an anonymous namespace or with the final specifier ๐Ÿ’… This is also more effective with link-time optimization, where the class hierarchy graph info is more complete. It's recommended to first consider the suggestions of -Wsuggest-final-types, then rebuild with new annotations ๐Ÿ“
  • -Wsuggest-override โ€” warns about overriding virtual functions that aren't marked with the override keyword ๐Ÿท๏ธ
  • -Wuseless-cast (C++ and Objective-C++ only) โ€” warns when an expression is cast to its own type ๐Ÿงน
  • -Wno-conversion-null (C++ and Objective-C++ only) โ€” bestie, this one tells GCC to stop warning about conversions between NULL and non-pointer types ๐Ÿ™ˆ Heads up: -Wconversion-null is already on by default, so this is the flag that quiets it ๐Ÿ’…

๐Ÿฆ‹ Options Controlling Objective-C and Objective-C++ Dialects ๐Ÿฆ‹

NOTE: okay so this manual does NOT teach you the Objective-C and Objective-C++ languages themselves ๐Ÿ™ˆ It's only about the flags!

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

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

In that example, -fgnu-runtime is an option meant only for Objective-C and Objective-C++ programs, but the other options work with any language GCC supports โœจ

Since Objective-C is an extension of the C language, Objective-C compiles may also use options specific to the C front-end (e.g., -Wtraditional) ๐ŸŒธ Similarly, Objective-C++ compiles 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, iykyk ๐Ÿซถ

  • -fconstant-string-class=class-name โ€” okay so this tells GCC which class to instantiate for each literal string written as "@"..."" ๐ŸŽ€ The default is "NXConstantString" if the GNU runtime is being used, and "NSConstantString" if the NeXT runtime is being used (see below). If you also pass -fconstant-cfstrings, it wins over -fconstant-string-class and makes "@"..."" literals get laid out as constant CoreFoundation strings ๐Ÿ‘‘
  • -fgnu-runtime โ€” generates object code that's compatible with the standard GNU Objective-C runtime. This is the default for most types of 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 โ€” assumes that every Objective-C message dispatch ([receiver message:arg]) in this translation unit makes sure the receiver is not nil โญ This lets the runtime use more efficient entry points. It's only available 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. 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 if 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, which runs those non-trivial default constructors on the instance variables, in order, and then returns self. Similarly, if any instance variable is a C++ object with a non-trivial destructor, GCC synthesizes a special - (void) .cxx_destruct method that runs all such 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 responsibility of the Objective-C runtime to invoke all such methods in an object's inheritance hierarchy ๐Ÿซถ The - (id) .cxx_construct methods are invoked by the runtime immediately after a new object instance is allocated, and the - (void) .cxx_destruct methods are invoked immediately before the runtime deallocates an object instance ๐Ÿ˜ญ

As of this writing, only the NeXT runtime on Mac OS X 10.4 and later has support for invoking the - (id) .cxx_construct and - (void) .cxx_destruct methods ๐Ÿ“

  • -fobjc-direct-dispatch โ€” allows fast jumps to the message dispatcher โšก On Darwin, this is accomplished via the comm page ๐ŸŒธ
  • -fobjc-exceptions โ€” enables syntactic support for structured exception handling in Objective-C, kind of like what C++ offers ๐ŸŽ€ You need this option to use the Objective-C keywords @try, @throw, @catch, @finally and @synchronized ๐Ÿ‘‘ It's available with both the GNU runtime and the NeXT runtime, but NOT with the NeXT runtime on Mac OS X 10.2 and earlier ๐Ÿ’€
  • -fobjc-gc โ€” enables garbage collection (GC) in Objective-C and Objective-C++ programs ๐Ÿ—‘๏ธ This is only available with the NeXT runtime. The GNU runtime has a different garbage collection implementation that doesn't need any special compiler flags ๐Ÿงน
  • -fobjc-nilcheck โ€” for the NeXT runtime with version 2 of the ABI, 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 recognized by GCC 4.0 ๐Ÿ“œ This only affects the Objective-C additions to the C/C++ language. It does NOT affect conformance to C/C++ standards, which is controlled by the separate C/C++ dialect option flags ๐Ÿ™…โ€โ™€๏ธ When this option is used with the Objective-C or Objective-C++ compiler, any Objective-C syntax that GCC 4.0 doesn't recognize gets rejected. This is useful if you need to make sure your Objective-C code can be compiled with older versions of GCC ๐Ÿซถ
  • -freplace-objc-classes โ€” emits a special marker that tells ld(1) not to statically link in the resulting object file, and lets dyld(1) load it at run time instead โœจ This gets used with the Fix-and-Continue debugging mode, where the object file might be recompiled and dynamically reloaded while the program is running, without restarting the whole program ๐Ÿ”„ Right now, Fix-and-Continue is only available with the NeXT runtime on Mac OS X 10.3 and later ๐ŸŽ
  • -fzero-link โ€” when compiling for the NeXT runtime, the compiler normally swaps calls to objc_getClass("...") (when the class name is known at compile time) for static class references that get initialized at load time, which boosts run-time performance ๐Ÿš€ Specifying -fzero-link suppresses that behavior and keeps the calls to objc_getClass("...") ๐Ÿง This is useful in Zero-Link debugging mode, since it lets you modify individual class implementations during program execution ๐Ÿช„ The GNU runtime currently 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 from within the methods of the class they're declared in ๐Ÿ‘€ This can cause shadowing between instance variables and other variables declared locally inside a class method, or globally, with the same name ๐Ÿ˜ฌ Specifying -fno-local-ivars turns this behavior off, so you avoid those variable shadowing issues ๐Ÿ’–
  • -fivar-visibility=[public|protected|private|package] โ€” sets the default instance variable visibility to the option you pick ๐ŸŽ€ Instance variables declared outside the scope of any access modifier directives will default to that visibility ๐Ÿฆ‹
  • -gen-decls โ€” dumps the interface declarations for all classes seen in the source file to a file named sourcename.decl ๐Ÿ“
  • -Wassign-intercept (Objective-C and Objective-C++ only) โ€” 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 ๐Ÿ™ˆ
  • -Wno-protocol (Objective-C and Objective-C++ only) โ€” if a class is declared to implement a protocol, GCC warns for every method in that protocol that the class doesn't implement ๐Ÿ“‹ By default, you get a warning for every method not explicitly implemented in the class, even if the implementation is inherited from the superclass ๐Ÿค” With -Wno-protocol, methods inherited from the superclass count as implemented, so no warning is issued for them ๐Ÿซถ
  • -Wselector (Objective-C and Objective-C++ only) โ€” warns if multiple methods of different types for the same selector are found during compilation ๐Ÿ”Ž The check runs on the list of methods in the final stage of compilation. There's also a check for each selector appearing in a @selector(...) expression, if a corresponding method for that selector was found during compilation ๐Ÿ’… Because these checks only scan the method table at the very end, these warnings aren't produced if the final stage of compilation isn't reached. That can happen because an error was found during compilation, or because -fsyntax-only is being used ๐Ÿ˜ญ
  • -Wstrict-selector-match (Objective-C and Objective-C++ only) โ€” warns if multiple methods with differing argument and/or return types are found for a given selector when you try to send a message using that selector to a receiver of type id or Class ๐Ÿ“ฃ When this flag is off (which is the default behavior), the compiler skips such warnings if the differences are confined to types that share the same size and alignment ๐ŸŒธ
  • -Wundeclared-selector (Objective-C and Objective-C++ only) โ€” okay bestie, this one is a whole vibe check on your @selector(...) expressions ๐Ÿ’… It warns when a @selector(...) points at a selector nobody 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 the second it spots a @selector(...), while -Wselector waits until the final stage of compilation ๐Ÿ”ฅ It also enforces the coding style rule that methods and selectors must be declared before they get used. Literally main character energy ๐Ÿ‘‘
  • -print-objc-runtime-info โ€” this one generates a C header describing the largest structure that gets passed by value, if there is one ๐Ÿงš

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

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

  • -fmessage-length=n โ€” this tries to format error messages so they fit on lines of about n characters. If n is zero, no line-wrapping happens and each error message sits on a single line. This is the default for all front ends ๐Ÿ“
Note: this option also affects how #error and #warning pre-processor directives get displayed, plus the deprecated function/type/variable attribute. It does not affect pragma GCC warning and pragma GCC error pragmas, so don't get confused ๐Ÿ’€
  • -fdiagnostics-show-location=once โ€” only meaningful in line-wrapping mode โœจ This tells the diagnostic reporter to emit source location info once. So if a message is too long and gets wrapped, the location isn't slapped on as a prefix over and over on each continuation line. This is the default behavior ๐Ÿ’–
  • -fdiagnostics-show-location=every-line โ€” also only meaningful in line-wrapping mode ๐ŸŒˆ This makes the reporter emit the same source location info (as a prefix) for every physical line that comes out of breaking up a message that's too long to fit on one line.
  • -fdiagnostics-color[=WHEN], -fno-diagnostics-color โ€” this 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 present, and auto otherwise. auto only uses color when standard error is a terminal and you're not running in an emacs shell ๐Ÿง  The forms -fdiagnostics-color and -fno-diagnostics-color are just aliases for -fdiagnostics-color=always and -fdiagnostics-color=never, respectively ๐Ÿ’…

The colors are controlled by the GCC_COLORS environment variable ๐ŸŒธ Its value is a colon-separated list of capabilities and Select Graphic Rendition (SGR) substrings. SGR commands are interpreted by your terminal or terminal emulator, so check your text terminal's docs for the permitted values and what they mean as character attributes. These substring values are integers in decimal form, and they can be stuck together with semicolons. Common ones 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

Where 01;31 is bold red, 01;35 is bold magenta, 01;36 is bold cyan, 32 is green, 34 is blue, 01 is bold, and 31 is red ๐Ÿ’ Setting GCC_COLORS to the empty string disables colors. Here are the supported capabilities:

  • "error=" โ€” the SGR substring for error: markers ๐Ÿšจ
  • "warning=" โ€” the SGR substring for warning: markers โš ๏ธ
  • "note=" โ€” the SGR substring for note: markers ๐Ÿ“
  • "path=" โ€” the SGR substring for colorizing paths of control-flow events printed via -fdiagnostics-path-format=, like the identifiers of individual events and the lines showing interprocedural calls and returns ๐Ÿฆ‹
  • "range1=" โ€” the SGR substring for the first additional range ๐ŸŽ€
  • "range2=" โ€” the SGR substring for the second additional range ๐ŸŽ€
  • "locus=" โ€” the SGR substring for location info, like file:line or file:line:column etc. ๐Ÿ“
  • "quote=" โ€” the SGR substring for info printed within quotes ๐Ÿ’ฌ
  • "fixit-insert=" โ€” the SGR substring for fix-it hints suggesting text to be inserted or replaced โž•
  • "fixit-delete=" โ€” the SGR substring for fix-it hints suggesting text to be deleted โž–
  • "diff-filename=" โ€” the SGR substring for filename headers within generated patches ๐Ÿงพ
  • "diff-hunk=" โ€” the SGR substring for the starts of hunks within generated patches ๐Ÿงฉ
  • "diff-delete=" โ€” the SGR substring for deleted lines within generated patches โŒ
  • "diff-insert=" โ€” the SGR substring for inserted lines within generated patches โœ…
  • "type-diff=" โ€” the SGR substring for highlighting mismatching types within template arguments in the C++ frontend ๐Ÿ”
  • -fdiagnostics-urls[=WHEN] โ€” this uses escape sequences to embed URLs in diagnostics ๐Ÿ”— For example, when -fdiagnostics-show-option shows the command-line option controlling 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 that's known to be incompatible with this feature (see below) ๐Ÿ™ƒ

The default depends on how the compiler was configured, and it can be any of the above WHEN options. GCC can also be configured (via the --with-diagnostics-urls=auto-if-env configure-time option) so the default is affected by environment variables. Under that configuration, GCC defaults to auto if either the GCC_URLS or TERM_URLS environment variables are present and non-empty in the compiler's environment, or never if neither one is ๐ŸŒธ

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

  • If GCC_URLS is set to empty or no, URLs are not embedded in diagnostics ๐Ÿ™…
  • If set to st, URLs use ST escape sequences ๐Ÿ’œ
  • If set to bel, which is the default, URLs use BEL escape sequences ๐Ÿ””
  • Any other non-empty value enables the feature โœจ

If GCC_URLS isn't set, TERM_URLS is used as a fallback. Quick side note: ST is an ANSI escape sequence, the string terminator ESC \. BEL is an ASCII character, CTRL-G, which usually sounds like a beep ๐Ÿ”Š

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

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

This option suppresses those labels (so in the example above, the vertical bars and the char * and long int text go away) ๐Ÿงน

  • -fno-diagnostics-show-cwe โ€” diagnostic messages can optionally have an associated CWE identifier (https://cwe.mitre.org/index.html) ๐Ÿ›ก๏ธ GCC itself only provides this metadata for some of the -fanalyzer diagnostics, 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 printing that metadata ๐Ÿ™…โ€โ™€๏ธ
  • -fno-diagnostics-show-line-numbers โ€” by default, when printing source code (via -fdiagnostics-show-caret), a left margin showing line numbers is printed ๐Ÿ”ข This option suppresses that left margin.
  • -fdiagnostics-minimum-margin-width=width โ€” 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, perfect for IDEs ๐Ÿค– For each fix-it, a line gets printed after the relevant diagnostic, starting with the string fix-it:. For example:
fix-it:"test.c":{45:3-45:21}:"gtk_widget_show_all"

okay so the location is a half-open range ๐ŸŽ€ measured as a count of bytes, and it starts at byte 1 for the initial column (not 0, so pay attention ๐Ÿ™ˆ). In the example below, bytes 3 through 20 of line 45 of "test.c" are getting swapped out for the replacement string โœจ

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

The filename and replacement string escape a backslash as "\\", a tab as "\t", a newline as "\n", and a double quote as "\"". Non-printable characters get written in octal, so a vertical tab becomes "\013" ๐Ÿฆ‹

An empty replacement string means the range gets deleted ๐Ÿ—‘๏ธ and an empty range like "45:3-45:3" means the string gets inserted right at that spot ๐Ÿ’–


โœจ -fdiagnostics-generate-patch โœจ

This one prints fix-it hints to stderr as a unified diff ๐Ÿงพ and it shows up after any diagnostics have been printed. Here's what it looks like:

                   --- 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 ๐ŸŒˆ and it follows the same rules as regular diagnostics (see -fdiagnostics-color).


โœจ -fdiagnostics-show-template-tree โœจ

In the C++ frontend, when diagnostics show mismatching template types, you get something like this ๐Ÿ˜ญ

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

Using -fdiagnostics-show-template-tree turns on a tree-like view that shows the common and differing parts of the types, like this ๐ŸŒณ

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

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


โœจ -fno-elide-type โœจ

By default, when the C++ frontend shows mismatching template types, the common parts get squished down into "[...]" so the error message isn't a total wall of text ๐Ÿ’… Here's the same example from before:

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

If you pass -fno-elide-type, that squishing behavior gets turned off ๐Ÿ™…โ€โ™€๏ธ This flag also changes the output of -fdiagnostics-show-template-tree, so keep that in mind ๐Ÿซถ


โœจ -fdiagnostics-path-format=KIND โœจ

This one decides how paths of control-flow events get printed for diagnostics that have a path attached ๐Ÿ›ค๏ธ

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

  • none โ€” means no diagnostic paths get printed at all ๐Ÿ™ˆ
  • separate-events โ€” prints a separate "note" diagnostic for each event inside the diagnostic. It looks like this:
                   test.c:29:5: error: passing NULL as argument 1 to 'PyList_Append' which requires a non-NULL parameter
                   test.c:25:10: note: (1) when 'PyList_New' fails, returning NULL
                   test.c:27:3: note: (2) when 'i < count'
                   test.c:29:5: note: (3) when calling 'PyList_Append', passing NULL from (1) as argument 1
  • inline-events โ€” prints the events "inline" right inside the source code ๐Ÿงš It tries to group events that are close together into runs and labels them as ranges in the source. The same events from above might show up like this:
                     '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 (where the path jumps between functions) gets shown by grouping the events by stack frame ๐Ÿงฉ Indentation shows how the 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 tied to a diagnostic ๐Ÿ” If you give this option, the stack depth gets printed for each run of events within -fdiagnostics-path-format=separate-events.

It's mainly meant for GCC developers and plugin developers who are debugging diagnostics that report interprocedural control flow ๐Ÿ› ๏ธ


โœจ -fno-show-column โœจ

This one stops column numbers from showing up in diagnostics ๐Ÿ™…โ€โ™€๏ธ You might need it if a program that scans the diagnostics doesn't understand column numbers, such as dejagnu ๐Ÿค–


โœจ -fdiagnostics-format=FORMAT โœจ

FORMAT can be text or json, and the default is text ๐Ÿ“

The json format is a top-level JSON array full of JSON objects, and each object represents one diagnostic ๐Ÿ’œ The JSON gets emitted as one single line with no formatting. The examples below have been formatted only so they're easier to read โœจ

Diagnostics can have child diagnostics too. Take 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;
                         |     ^

After formatting, it might be printed in JSON form like this ๐Ÿฅฐ

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

Here the "note" is a child of the "warning" ๐Ÿซง

A diagnostic has a "kind". If that kind is "warning", there's also an "option" key that describes the command-line option controlling the warning โš ๏ธ

A diagnostic can have zero or more locations. Each location can have up to three positions: a "caret" position, plus optional "start" and "finish" positions. A location can also have an optional "label" string ๐Ÿท๏ธ For example, this error:

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

has three locations, bestie ๐Ÿ’– Its primary one is the + token sitting at column 23. It also has two secondary locations for the left and right-hand sides of the expression, and both of those come with labels ๐ŸŽ€ It might be printed in JSON form like this:

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

If a diagnostic has fix-it hints, it gets a "fixits" array made of half-open intervals, kinda like what -fdiagnostics-parseable-fixits spits out ๐Ÿฆ‹ For example, here's a diagnostic with a replacement fix-it hint:

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

And that one might be printed in JSON form as:

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

Here the fix-it hint basically says to replace the text from "start" up to but not including "next" with the value of "string" โœจ Deletions are expressed with an empty value for "string", and insertions are done by having "start" equal "next" ๐Ÿงš

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

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

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

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

Okay so, warnings are the "hmm, that's sus" messages ๐Ÿ‘€ They flag constructions that aren't straight-up wrong, but that are risky or that suggest there might have been a mistake somewhere ๐Ÿ’…

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

  • -fsyntax-only โ€” Checks your code for syntax errors, and that's it. It doesn't go any further than that ๐ŸŽ€
  • -fmax-errors=n โ€” Caps the number of error messages at n, and then GCC bails instead of trying to keep going ๐Ÿ’€ If n is 0 (the default), there's no limit on how many error messages get produced. If -Wfatal-errors is also specified, then -Wfatal-errors takes precedence over this option.
  • -w โ€” Inhibits all warning messages. Silence is golden ๐Ÿคซ
  • -Werror โ€” Turns every warning into an error. No more "eh, it's just a warning" ๐Ÿ˜ค
  • -Werror= โ€” Turns one specific warning into an error. You append the warning's specifier, so for example -Werror=switch turns the warnings controlled by -Wswitch into errors ๐Ÿ”ฅ
    • This switch also has a negative form, which you use to undo -Werror for specific warnings. For example, -Wno-error=switch makes -Wswitch warnings not be errors, even when -Werror is in effect ๐Ÿ™…โ€โ™€๏ธ
    • Every controllable warning's message includes the option that controls it, and you can use that option with -Werror= and -Wno-error= the same way. (Printing of the option in the warning message can be disabled with the -fno-diagnostics-show-option flag, if you hate that vibe ๐Ÿ™ˆ)
    • Heads up: specifying -Werror=foo automatically implies -Wfoo. However, -Wno-error=foo does not imply anything ๐Ÿง 
  • -Wfatal-errors โ€” Aborts compilation on the first error that occurs, instead of trying to keep going and printing more error messages ๐Ÿ›‘

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

Some options, like -Wall and -Wextra, turn on other options, like -Wunused, which may turn on even more options, like -Wunused-value. The combined effect of positive and negative forms is that more specific options win over less specific ones, no matter where they sit on the command-line. For options of the same specificity, the last one takes effect. Options enabled or disabled via pragmas take effect as if they appeared at the end of the command-line ๐Ÿ’–

When you request an unrecognized warning option (e.g., -Wunknown-warning), GCC emits a diagnostic saying the option isn't recognized. The -Wno- form acts a little differently though: 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 doesn't 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 that specifies the required version of ISO C. Without this option, though, certain GNU extensions and traditional C and C++ features are supported too. With this option, they get rejected ๐Ÿ™…โ€โ™€๏ธ

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

Some users try to use -Wpedantic to check programs for strict ISO C conformance, and then they soon find it doesn't do quite what they want ๐Ÿ˜ญ It finds some non-ISO practices, but not all---only the ones where 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 okay, bestie, that would take a LOT of extra work and would be a totally different vibe from -Wpedantic ๐Ÿ˜ญ. We don't have plans to support something like that anytime soon ๐Ÿ™ˆ

Where the standard you pick with -std is a GNU extended dialect, like gnu90 or gnu99, there's a matching base standard: the version of ISO C that the GNU dialect is built on ๐ŸŒธ. -Wpedantic warnings show up wherever that base standard requires them. It wouldn't make sense to warn only about features outside the GNU dialect you picked, since by definition the GNU dialects include every feature the compiler supports with that option, so there would be nothing to warn about ๐Ÿ’…


-pedantic-errors

Give an error whenever the base standard (see -Wpedantic) requires a diagnostic. This also covers some cases with undefined behavior at compile-time, and some other cases that don't stop programs that are valid according to the standard from compiling โœจ Heads up: this is not the same as -Werror=pedantic, since there are errors this option turns on that the other one doesn't, and vice versa ๐Ÿšจ


-Wall

This turns on a big bundle of warnings about constructions that some users find questionable, and that are easy to avoid (or tweak to dodge the warning), even when macros are involved ๐Ÿง It also turns on 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) -Wbool-compare
-Wbool-operation -Wc++11-compat  -Wc++14-compat -Wcatch-value (C++
and Objective-C++ only) -Wchar-subscripts -Wcomment
-Wduplicate-decl-specifier (C and Objective-C only) -Wenum-compare
(in C/ObjC; this is on by default in C++) -Wenum-conversion in
C/ObjC; -Wformat -Wformat-overflow -Wformat-truncation
-Wint-in-bool-context -Wimplicit (C and Objective-C only)
-Wimplicit-int (C and Objective-C only)
-Wimplicit-function-declaration (C and Objective-C only) -Winit-self
(only for C++) -Wlogical-not-parentheses -Wmain (only for C/ObjC and
unless -ffreestanding) -Wmaybe-uninitialized -Wmemset-elt-size
-Wmemset-transposed-args -Wmisleading-indentation (only for C/C++)
-Wmissing-attributes -Wmissing-braces (only for C/ObjC)
-Wmultistatement-macros -Wnarrowing (only for C++) -Wnonnull
-Wnonnull-compare -Wopenmp-simd -Wparentheses -Wpessimizing-move
(only for C++) -Wpointer-sign -Wreorder -Wrestrict -Wreturn-type
-Wsequence-point -Wsign-compare (only in C++) -Wsizeof-pointer-div
-Wsizeof-pointer-memaccess -Wstrict-aliasing -Wstrict-overflow=1
-Wswitch -Wtautological-compare -Wtrigraphs -Wuninitialized
-Wunknown-pragmas -Wunused-function -Wunused-label -Wunused-value
-Wunused-variable -Wvolatile-register-var -Wzero-length-bounds

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


-Wextra

This enables some extra warning flags that 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.)

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

The option -Wextra also prints warning messages for the following cases:

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

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

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

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

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

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

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

You should rewrite your code to avoid these warnings if you're concerned that code generated by G++ may 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 does not allow for overloading of functions taking vectors of different sizes. The mangling was changed in -fabi-version=4.
  • __attribute ((const)) and noreturn were mangled as type qualifiers, and decltype of a plain declaration was folded away. These mangling issues were fixed in -fabi-version=5.
  • Scoped enumerators passed as arguments to a variadic function are promoted like unscoped enumerators, causing va_arg to complain. On most targets this doesn't actually affect the parameter passing ABI, since there's no way to pass an argument smaller than int. Also, the ABI changed the mangling of template argument packs, const_cast, static_cast, prefix increment/decrement, and a class scope function used as a template argument. These issues were corrected in -fabi-version=6.
  • Lambdas in default argument scope were mangled incorrectly, and the ABI changed the mangling of nullptr_t. These issues were corrected in -fabi-version=7.
  • When mangling a function type with function-cv-qualifiers, the un-qualified function type was incorrectly treated as a substitution candidate. This was fixed in -fabi-version=8, the default for GCC 5.1.
  • decltype(nullptr) incorrectly had an alignment of 1, leading to unaligned accesses. Note that this did not affect the ABI of a function with a nullptr_t parameter, as parameters have a minimum alignment. This was fixed in -fabi-version=9, the default for GCC 5.2.
  • Target-specific attributes that affect the identity of a type, such as ia32 calling conventions on a function type (stdcall, regparm, etc.), did not affect the mangled name, leading to name collisions when function pointers were used as template arguments. This was fixed in -fabi-version=10, the default for GCC 6.1.

This option also enables warnings about psABI-related changes ๐Ÿ’œ The known psABI changes at this point include:

  • For SysV/x86-64, unions with long double members 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

Warn if an array subscript has type char ๐Ÿ“ This is a super common mistake, since programmers often forget that this type is signed on some machines. This warning is enabled by -Wall.


-Wno-coverage-mismatch

Warn 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 such as 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) Suppress warning messages emitted by #warning directives ๐ŸŒˆ

๐Ÿ’– -Wdouble-promotion (C, C++, Objective-C and Objective-C++ only)

okay bestie, this one is a vibe check for your float math ๐Ÿ’… It gives you a warning when a float gets implicitly promoted to a double. Why do we care? Some CPUs have a 32-bit single-precision floating-point unit, which handles float in hardware, but double gets emulated in software ๐Ÿ˜ญ So on those machines, doing math with double values is way more expensive because of all that software emulation overhead.

It is so easy to do this by accident because floating-point literals are implicitly double, no cap ๐Ÿ™ˆ Check this out:

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

The compiler does the entire computation in double because that floating-point literal is a double. Main character energy, but make it expensive ๐Ÿ’€

๐ŸŒธ -Wduplicate-decl-specifier (C and Objective-C only)

Lowkey simple: this warns if a declaration has a duplicate const, volatile, restrict or _Atomic specifier. Messy, bestie ๐Ÿ™„ This warning is enabled by -Wall, so you get it for free โœจ

๐Ÿฆ‹ -Wformat

okay this one is the queen of the format checks ๐Ÿ‘‘ It checks calls to printf and scanf, etc., to make sure the arguments you pass have types that match the format string, and that the conversions in the format string actually make sense. It covers the standard functions plus anything else marked with format attributes, in the printf, scanf, strftime and strfmon families (strfmon is an X/Open extension, so it's not in the C standard, fr fr) or other target-specific families. Which functions get checked without any format attributes depends on the standard version you pick, and those extra checks get turned off by -ffreestanding or -fno-builtin.

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

  • -Wformat=1, -Wformat โ€” -Wformat is the same thing as -Wformat=1, and -Wno-format is the same as -Wformat=0. Since -Wformat also checks for null format arguments in several functions, it also implies -Wnonnull. Some parts of this level can be turned off with -Wno-format-contains-nul, -Wno-format-extra-args, and -Wno-format-zero-length. -Wformat is enabled by -Wall ๐ŸŽ€
  • -Wformat=2 โ€” turns on -Wformat plus extra format checks. Right now that's the same as -Wformat -Wformat-nonliteral -Wformat-security -Wformat-y2k ๐Ÿ”ฅ

๐Ÿงš -Wno-format-contains-nul

If you've got -Wformat on, this tells GCC to chill and not warn about format strings that contain NUL bytes ๐Ÿซถ

๐ŸŒˆ -Wno-format-extra-args

With -Wformat on, this stops GCC from complaining about extra arguments passed to a printf or scanf format function. The C standard says those extra args just get ignored, so it's not really a problem ๐Ÿ’…

There's a catch though ๐Ÿ‘€ If the unused arguments sit between used arguments that have $ operand number specifications, GCC still warns, because the implementation couldn't know what type to pass to va_arg to skip the unused ones. BUT for scanf formats, this option suppresses that warning when the unused arguments are all pointers, since the Single Unix Specification says those unused arguments are allowed.

โญ -Wformat-overflow / -Wformat-overflow=level

This one warns about calls to formatted output functions like sprintf and vsprintf that might overflow the destination buffer ๐Ÿ˜ญ When GCC can't figure out at compile time exactly how many bytes a format directive writes, it estimates using heuristics based on the level and on optimization. Turning on optimization usually makes the warning more accurate, but it can also cause false positives, so keep that in mind bestie โœจ

  • -Wformat-overflow, -Wformat-overflow=1 โ€” Level 1 is enabled by -Wformat and is super conservative. It only warns about calls that most likely overflow the buffer. At this level, numeric arguments with unknown values are assumed to be one, and strings of unknown length are assumed to be empty. Numeric arguments known to be bounded to a subrange of their type, or string arguments whose output is bounded by their directive's precision or by a finite set of string literals, are assumed to take whichever value in range results in the most bytes of output. For example, this sprintf call gets diagnosed, because even with both a and b equal to zero, the terminating NUL character ('\0') that the function appends gets written past the end of the buffer ๐Ÿ’€ Making the buffer one byte bigger is enough to dodge the warning, though it might not be enough to avoid the actual 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 even more dramatic ๐Ÿ”ฅ It also warns about calls that might overflow the destination buffer given an argument of sufficient length or magnitude. At level 2, unknown numeric arguments are assumed to have the minimum representable value for signed types with a precision greater than 1, and the maximum representable value otherwise. Unknown string arguments that can't be assumed bounded (by the directive's precision, by a finite set of string literals they might evaluate to, or by the character array they might point to) are assumed to be 1 character long.

At level 2, the call in the example above gets diagnosed again, but this time because if a is a 32-bit INT_MIN, the first %i directive writes some of its digits past the end of the buffer. To make the call safe no matter what the two variables are, the destination buffer has to be at least 34 bytes. GCC even includes the minimum buffer size in an informational note after the warning, which is so helpful ๐Ÿฅน

Another option instead of growing the buffer is to constrain the range of the formatted values. You can bound the max length of string arguments by specifying the precision in the format directive. And 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 reduces the required buffer size. For example, if a and b in the example above can be assumed to fit in the short int type, then using either the %hi format directive or casting the argument to short reduces the max required buffer size to 24 bytes.

void f (int a, int b)
{
  char buf [23];
  sprintf (buf, "a = %hi, b = %i\n", a, (short)b);
}

๐Ÿซง -Wno-format-zero-length

With -Wformat on, this tells GCC not to warn about zero-length formats. The C standard says zero-length formats are allowed, so you're all good bestie ๐ŸŒธ

๐Ÿ“ -Wformat-nonliteral

If -Wformat is on, this also warns if the format string isn't a string literal, which means GCC can't check it. The exception is when the format function takes its format arguments as a va_list, since then it's not something GCC can warn about in this way ๐Ÿ™ƒ

๐Ÿšจ -Wformat-security

Ngl, this one matters ๐Ÿ˜ค If -Wformat is on, this also warns about uses of format functions that could be security problems. Right now, it warns about calls to printf and scanf functions where the format string isn't a string literal and there are no format arguments, like printf (foo);. This can be a security hole if that format string came from untrusted input and contains %n. (This is currently a subset of what -Wformat-nonliteral warns about, but future warnings might get added to -Wformat-security that aren't in -Wformat-nonliteral, so stay tuned ๐Ÿ‘€)

๐ŸŒท -Wformat-signedness

With -Wformat on, this also warns if the format string needs an unsigned argument and you pass a signed one, and vice versa ๐Ÿ’œ

๐Ÿช„ -Wformat-truncation / -Wformat-truncation=level

This is the cousin of -Wformat-overflow, but for functions like snprintf and vsnprintf that might truncate the output โœ‚๏ธ Same deal as before: when the exact number of bytes can't be determined at compile time, GCC estimates it using heuristics that depend on the level and on optimization. Optimization usually helps accuracy but can also bring false positives. Unless noted otherwise, this option uses the same logic as -Wformat-overflow.

  • -Wformat-truncation, -Wformat-truncation=1 โ€” Level 1 is enabled by -Wformat and is conservative. It only warns about calls to bounded functions whose return value is unused and that will most likely result in truncation ๐Ÿฆ‹
  • -Wformat-truncation=2 โ€” also warns about calls to bounded functions whose return value is used, and that might truncate given an argument of sufficient length or magnitude โœจ

๐ŸŽ€ -Wformat-y2k

If -Wformat is on, this also warns about strftime formats that might only give you a two-digit year ๐Ÿ“… Very much a "we don't do that anymore" energy ๐Ÿ’…

๐Ÿ”ฅ -Wnonnull

This one warns about passing a null pointer for arguments that the nonnull function attribute says must be non-null ๐Ÿšซ

-Wnonnull is included in both -Wall and -Wformat. You can turn it off with the -Wno-nonnull option.

๐Ÿ‘€ -Wnonnull-compare

This warns when you compare an argument marked with the nonnull function attribute against null inside the function. Like, why are you checking for something that's already promised not to be null? ๐Ÿ™ˆ

-Wnonnull-compare is included in -Wall. You can disable it with the -Wno-nonnull-compare option.

  • -Wnull-dereference โ€” okay bestie, this one is the null pointer watchdog ๐Ÿซฃ GCC warns if it spots a path that triggers erroneous or undefined behavior by dereferencing a null pointer. It's only active when -fdelete-null-pointer-checks is active, which optimizations turn on in most targets ๐Ÿ’€. How precise the warnings are depends on the optimization options you use.
  • -Winit-self (C, C++, Objective-C and Objective-C++ only) โ€” this warns about uninitialized variables that get initialized with themselves ๐Ÿ™ˆ It can only be used alongside -Wuninitialized, so keep that in mind. Look at this:
int f()
{
  int i = i;
  return i;
}

GCC only warns about i being uninitialized in that snippet when -Winit-self has been specified. This warning is enabled by -Wall in C++.

  • -Wno-implicit-int (C and Objective-C only) โ€” this controls warnings when a declaration doesn't specify a type โœจ It's enabled by default in C99 and later dialects of C, and also by -Wall.
  • -Wno-implicit-function-declaration (C and Objective-C only) โ€” this controls warnings when a function gets used before it's declared ๐Ÿ’… It's enabled by default in C99 and later dialects of C, and also by -Wall. Also, -pedantic-errors turns this warning into an error, so be careful ๐Ÿ˜ญ
  • -Wimplicit (C and Objective-C only) โ€” same as -Wimplicit-int and -Wimplicit-function-declaration ๐ŸŒธ It's enabled by -Wall.
  • -Wimplicit-fallthrough โ€” -Wimplicit-fallthrough is the same as -Wimplicit-fallthrough=3, and -Wno-implicit-fallthrough is the same as -Wimplicit-fallthrough=0.
  • -Wimplicit-fallthrough=n โ€” okay, the big fallthrough one ๐Ÿฆ‹ It warns when a switch case falls through. Like this:
switch (cond)
  {
  case 1:
    a = 1;
    break;
  case 2:
    a = 2;
  case 3:
    a = 3;
    break;
  }

It doesn't warn when the last statement of a case can't fall through, 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, so it only warns when it's actually appropriate. E.g.:

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

Sometimes a fallthrough is totally intentional, so GCC gives you an attribute, __attribute__ ((fallthrough)), to use along with a null statement to suppress the warning that would normally show up ๐Ÿซถ

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

C++17 gives you a standard way to suppress the -Wimplicit-fallthrough warning with [[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 given regular expressions. The option argument n decides which kinds of comments are accepted:

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

The comment needs to come right after optional whitespace and other comments, followed by a case or default keyword, or by a user label that precedes some case or default label. Like so:

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

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

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

In the case of mixed tabs and spaces, the warning uses the -ftabstop= option to determine if the statements line up (defaulting to 8). The warning is not issued for code involving multiline preprocessor logic, like this:

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

The warning is also not issued after a #line directive, since this typically indicates autogenerated code, and no assumptions can be made about the layout of the file that the directive references. This warning is enabled by -Wall in C and C++ ๐Ÿฆ‹

  • -Wmissing-attributes โ€” warns when a function declaration is missing one or more attributes that a related function is declared with, and whose absence might mess with the correctness or efficiency of the generated code ๐Ÿงš For example, the warning gets issued for declarations of aliases that use attributes to specify less restrictive requirements than those of their targets. This usually represents a potential optimization opportunity. By contrast, -Wattribute-alias=2 controls warnings issued when the alias is more restrictive than the target, which could lead to incorrect code generation. The attributes considered include alloc_align, alloc_size, cold, const, hot, leaf, malloc, nonnull, noreturn, nothrow, pure, returns_nonnull, and returns_twice.

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

You can use the copy attribute to apply the same set of attributes to a declaration as the one on another declaration, without explicitly enumerating the attributes. This attribute can be applied to declarations of functions, variables, or types. -Wmissing-attributes is enabled by -Wall.

For example, since the declaration of the primary function template below makes use of both the malloc and alloc_size attributes, the declaration of the explicit specialization of the template is diagnosed because it's missing one of them ๐Ÿ™ˆ

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

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

This warning is enabled by -Wall.

  • -Wmissing-include-dirs (C, C++, Objective-C and Objective-C++ only) โ€” warns if a user-supplied include directory doesn't exist ๐ŸŒธ
  • -Wno-missing-profile โ€” okay so this one is the profile watchdog ๐Ÿ‘€. It warns you when profile feedback is missing while you're using -fprofile-use. It catches the sneaky stuff, like when you add a new function or a new file between compiling with -fprofile-generate and -fprofile-use and never regenerate the profiles. Then the profile feedback data files have no info about that new function or file. The same goes if the profile count data (.gcda) files get deleted, because then GCC can't use any profile feedback. Every one of those cases gets a warning that's basically saying "bestie, it's time for a profile generation step" ๐Ÿซถ. Ignore it and your code can come out poorly optimized ๐Ÿ’€. -Wno-missing-profile turns the warning off, but it's not recommended, and you should only do it when having non-existent profile data is actually justified ๐Ÿ™ˆ.
  • -Wmultistatement-macros โ€” this one is about macros that lie to you ๐ŸŽ€. It warns about unsafe macros with multiple statements that look guarded by an if, else, for, switch, or while, when only the first statement is actually guarded after the macro expands. Check out the drama:
#define DOIT x++; y++
if (c)
  DOIT;

That will increment y unconditionally, not just when c holds ๐Ÿ˜ญ. This usually gets fixed by wrapping the macro in a do-while loop:

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

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

  • -Wparentheses โ€” parentheses are not optional, bestie ๐Ÿ’…. It warns when parentheses get left out in certain contexts, like an assignment where a truth value is expected, or when operators are nested in ways people often mix up ๐Ÿ“. It also warns if you write a comparison like x<=y<=z. That's equivalent to (x<=y ? 1 : 0) <= z, which is NOT what ordinary math notation means, so it's giving major confusion ๐Ÿ’€. It also flags dangerous uses of the GNU extension to ?: with the middle operand omitted. When the condition is a boolean expression, the omitted value is always 1, but programmers usually 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 tried 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 โ€” this is the chaos one, so buckle up ๐ŸŒช๏ธ. It warns about code that may have undefined semantics because of violations of the sequence point rules in the C and C++ standards. Sequence points are the partial ordering of when parts of your program run: the stuff before a sequence point and the stuff after it. They show up after a full expression finishes (one that isn't part of a bigger expression), after the first operand of &&, ||, ? :, or the , (comma) operator, before a function is called (but after its arguments and the expression naming the called function are evaluated), and in a few other places. Outside of those rules, the order that subexpressions get evaluated in is not specified. Since it's only a partial order, if two functions are called inside one expression with no sequence point between them, the order they run in is unspecified. The standards committee did rule that function calls don't overlap, though ๐Ÿซถ.

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

Examples of undefined behavior are a = a++;, a[n] = b[n++], and a[i++] = i;. Some more complicated cases don't get diagnosed by this option, and it may give the occasional false positive. Overall though, it's been found pretty effective at catching this kind of problem in programs โœจ.

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

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

This warning is enabled by -Wall for C and C++ ๐Ÿ’œ.

  • -Wno-return-local-addr โ€” no yelling about returning stuff that dies ๐Ÿฆ‹. It stops the warning about returning a pointer (or, in C++, a reference) to a variable that goes out of scope once the function returns.
  • -Wreturn-type โ€” returns are a whole vibe โœจ. It warns whenever a function is defined with a return type that defaults to int. It also warns about any return statement with no return value in a function whose return type isn't void (falling off the end of the function body counts as returning without a value). For C only, it warns about a return statement with an expression in a function whose return type is void, unless the expression's type is also void. As a GNU extension, that latter case is accepted without a warning unless -Wpedantic is used. Trying to use the return value of a non-void function other than main that flows off the end by reaching the closing curly brace is undefined ๐Ÿ’€.

In C++, flowing off the end of a non-void function other than main results in undefined behavior even when the function's value isn't used. Unlike C, C++ is not chill about it ๐Ÿ˜ค.

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

  • -Wno-shift-count-negative โ€” negative shift counts, not it โญ. It controls warnings if a shift count is negative. This warning is enabled by default.
  • -Wno-shift-count-overflow โ€” shifts that go too far ๐ŸŒˆ. It controls warnings if a shift count is greater than or equal to the bit width of the type. This warning is enabled by default.
  • -Wshift-negative-value โ€” left shifting a negative is cursed ๐Ÿ’€. It warns if you left shift a negative value. This warning is enabled by -Wextra in C99 (and newer) and in C++11 to C++17 modes.
  • -Wno-shift-overflow, -Wshift-overflow=n โ€” left shift overflow, the full saga ๐ŸŒˆ. These options control warnings about left shift overflows. There are two levels you can pick from:
    • -Wshift-overflow=1 โ€” this is the default level ๐Ÿ“. It's the warning level for -Wshift-overflow and is 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++2A mode (and newer), since signed left shifts always wrap.
    • -Wshift-overflow=2 โ€” the stricter, extra-dramatic level ๐Ÿ˜ค. This level also warns about left-shifting 1 into the sign bit, unless C++14 mode (or newer) is active.
  • -Wswitch โ€” every case deserves a seat at the table ๐Ÿ’…. It warns whenever a switch statement has an index of enumerated type and lacks a case for one or more of the named codes of that enumeration. (Having a default label prevents this warning.) case labels outside the enumeration range also trigger warnings with this option, even if there's a default label. This warning is enabled by -Wall ๐Ÿซถ.
  • -Wswitch-default โ€” no default? no vibes ๐Ÿงš. It warns whenever a switch statement doesn't have a default case.
  • -Wswitch-enum โ€” the strictest switch check, iykyk ๐Ÿ‘‘. It warns whenever a switch statement has an index of enumerated type and lacks a case for one or more of the named codes of that enumeration. case labels outside the enumeration range also trigger warnings. 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 โ€” booleans don't need to be dramatic ๐ŸŒธ. It stops the warning when a switch statement has an index of boolean type and the case values are outside the range of a boolean type. You can suppress this warning by casting the controlling expression to a type other than bool. For example:
switch ((int) (a == 4))
  {
  ...
  }

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

  • -Wno-switch-outside-range โ€” case values that are way out of bounds ๐Ÿฆ‹. This option controls warnings when a switch case has a value outside of its respective type range. This warning is enabled by default for C and C++ programs.
  • -Wno-switch-unreachable โ€” code that never runs is literally wasted ๐Ÿ™ˆ. It stops the warning when a switch statement contains statements between the controlling expression and the first case label that will never be executed. For example:
switch (cond)
  {
   i = 15;
  ...
   case 5:
  ...
  }

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

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

This warning is enabled by default for C and C++ programs โœจ.

  • -Wsync-nand (C and C++ only) โ€” this one is outdated, be warned โš ๏ธ. It warns when the __sync_fetch_and_nand and __sync_nand_and_fetch built-in functions are used. These functions changed semantics in GCC 4.4 ๐Ÿ’€.
  • -Wunused-but-set-parameter โ€” assigned but never used, bestie ๐Ÿซถ. It warns whenever a function parameter is assigned to but otherwise unused (aside from its declaration) ๐ŸŒˆ.

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

This warning also turns on with -Wunused together with -Wextra. Iykyk ๐Ÿ’…

  • -Wunused-but-set-variable: wait, I already covered this one, so skip ahead. (Ignore this line, it's a stray note and not part of the page.)

Let me restart that bullet cleanly. Here is the continuation from the top of this part:

  • -Wunused-function โ€” okay so this one yells whenever a static function is declared but never defined, or when a non-inline static function just sits there unused ๐Ÿ’€ This warning is enabled by -Wall.
  • -Wunused-label โ€” warns when a label is declared but never used ๐Ÿท๏ธ This is enabled by -Wall. To suppress it, use the "unused" attribute.
  • -Wunused-local-typedefs (C, Objective-C, C++ and Objective-C++ only) โ€” warns when a typedef defined locally inside a function never gets used. This is enabled by -Wall.
  • -Wunused-parameter โ€” warns whenever a function parameter goes unused past its declaration. To suppress it, use the "unused" attribute.
  • -Wno-unused-result โ€” no warning if a caller of a function marked with the attribute "warn_unused_result" doesn't use its return value. The default is -Wunused-result.
  • -Wunused-variable โ€” warns whenever a local or static variable is unused past its declaration. This option implies -Wunused-const-variable=1 for C, but not for C++. It's enabled by -Wall. To suppress it, use the "unused" attribute.
  • -Wunused-const-variable / -Wunused-const-variable=n โ€” warns whenever a constant static variable is unused past its declaration. -Wunused-const-variable=1 is enabled by -Wunused-variable for C, but not for C++. In C this declares variable storage, but in C++ it's not an error, since const variables take the place of "#define"s. To suppress it, use the "unused" attribute.
    • -Wunused-const-variable=1 โ€” the level that -Wunused-variable turns on for C. It only warns about unused static const variables defined in the main compilation unit, not about static const variables declared in any header included.
    • -Wunused-const-variable=2 โ€” 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 might be harder to clean up all the headers included.
  • -Wunused-value โ€” warns whenever a statement computes a result that is explicitly not used. To suppress it, cast the unused expression to void. This includes an expression-statement or the left-hand side of a comma expression that contains no side effects. For example, an expression such as x[i,j] causes a warning, while x[(void)i,j] does not. This is enabled by -Wall.
  • -Wunused โ€” all the above -Wunused options combined. To get a warning about an unused function parameter, you must either specify -Wextra -Wunused (note that -Wall implies -Wunused), or separately specify -Wunused-parameter.
  • -Wuninitialized โ€” warns if an automatic variable is used without first being initialized. In C++, it also warns if a non-static reference or non-static "const" member appears in a class without constructors.
    • If you want to warn about code that uses the uninitialized value of the variable in its own initializer, use the -Winit-self option.
    • These warnings occur for individual uninitialized elements of structure, union or array variables, as well as for variables that are uninitialized as a whole. They do not occur for variables or elements declared "volatile". Because these warnings depend on optimization, the exact variables or elements that get warnings depend on the precise optimization options and version of GCC used.
    • There may be no warning about a variable that is used only to compute a value that itself is never used, because such computations may be deleted by data flow analysis before the warnings are printed.
  • -Wno-invalid-memory-model โ€” controls warnings for invocations of __atomic Builtins, __sync Builtins, and the C11 atomic generic functions with a memory consistency argument that is either invalid for the operation or outside the range of values of the "memory_order" enumeration. For example, since the "__atomic_store" and "__atomic_store_n" built-ins are only defined for the relaxed, release, and sequentially consistent memory orders, the following code is diagnosed:
void store (int *i)
{
  __atomic_store_n (i, 0, memory_order_consume);
}

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

  • -Wmaybe-uninitialized โ€” for an automatic (i.e. local) variable, if there exists a path from the function entry to a use of the variable that is initialized, but there exist some other paths for which the variable is not initialized, the compiler emits a warning if it cannot prove the uninitialized paths are not executed at run time.

These warnings are only possible in optimizing compilation, because otherwise GCC does not keep track of the state of variables.

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

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

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

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

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

This warning is enabled by -Wall or -Wextra.

  • -Wunknown-pragmas โ€” warns when a #pragma directive is encountered that is not understood by GCC. If this command-line option is used, warnings are even issued for unknown pragmas in system header files. This is not the case if the warnings are only enabled by the -Wall command-line option.
  • -Wno-pragmas โ€” doesn't warn about misuses of pragmas, such as incorrect parameters, invalid syntax, or conflicts between pragmas. See also -Wunknown-pragmas.
  • -Wno-prio-ctor-dtor โ€” doesn't warn if a priority from 0 to 100 is used for a constructor or destructor. The use of constructor and destructor attributes lets you assign a priority to the constructor/destructor to control its order of execution before main is called or after it returns. The priority values must be greater than 100, as the compiler reserves priority values between 0--100 for the implementation.
  • -Wstrict-aliasing โ€” only active when -fstrict-aliasing is active. It warns about code that might break the strict aliasing rules that the compiler is using for optimization. The warning does not catch all cases, but it does attempt to catch the more common pitfalls. It is included in -Wall. It is equivalent to -Wstrict-aliasing=3.
  • -Wstrict-aliasing=n โ€” only active when -fstrict-aliasing is active. It warns about code that might break the strict aliasing rules that the compiler is using for optimization. Higher levels correspond to higher accuracy (fewer false positives). Higher levels also correspond to more effort, similar to the way -O works. -Wstrict-aliasing is equivalent to -Wstrict-aliasing=3.
    • Level 1: Most aggressive, quick, least accurate. Possibly useful when higher levels do not warn but -fstrict-aliasing still breaks the code, as it has very few false negatives. However, it has many false positives. Warns for all pointer conversions between possibly incompatible types, even if never dereferenced. Runs in the front end only.
    • Level 2: Aggressive, quick, not too precise. May still have many false positives (not as many as level 1 though), and few false negatives (but possibly more than level 1). Unlike level 1, it only warns when an address is taken. Warns about incomplete types. Runs in the front end only.
    • Level 3 (default for -Wstrict-aliasing): Should have very few false positives and few false negatives. Slightly slower than levels 1 or 2 when optimization is enabled. Takes care of the common pun+dereference pattern in the front end: *(int*)&some_float. If optimization is enabled, it also runs in the back end, where it deals with multiple statement cases using flow-sensitive points-to information. Only warns when the converted pointer is dereferenced. Does not warn about incomplete types.
  • -Wstrict-overflow / -Wstrict-overflow=n โ€” this option is only active when signed overflow is undefined. It warns about cases where the compiler optimizes based on the assumption that signed overflow does not occur. Note that it does not warn about all cases where the code might overflow: it only warns about cases where the compiler implements some optimization. Thus this warning depends on the optimization level.

An optimization that assumes signed overflow never happens is perfectly safe, as long as the variables involved never actually overflow ๐Ÿ’… So this warning can totally give a false positive, which is a warning about code that isn't actually a problem ๐Ÿ™ˆ To help us focus on what matters, GCC has several warning levels โœจ No warnings are issued for undefined signed overflow while the compiler is estimating how many iterations a loop needs, especially when it's figuring out whether a loop runs at all ๐Ÿ”„

-Wstrict-overflow=1

Warn about cases that are both questionable and easy to avoid ๐ŸŽ€ For example, the compiler simplifies x + 1 > x to 1. This level of -Wstrict-overflow is turned on by -Wall. Higher levels aren't, so you have to ask for them yourself ๐Ÿ™‹โ€โ™€๏ธ

-Wstrict-overflow=2

Also warn about other cases where a comparison gets 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 warn about other cases where a comparison is simplified ๐ŸŒธ For example, x + 1 > 1 is simplified to x > 0.

-Wstrict-overflow=4

Also warn about other simplifications that aren't covered by the cases above โœจ For example, (x * 10) / 5 is simplified to x * 2.

-Wstrict-overflow=5

Also warn about cases where the compiler shrinks the magnitude of a constant in a comparison ๐Ÿ˜ญ For example, x + 2 > y is simplified to x + 1 >= y. This one is only reported at the highest warning level, because this simplification applies to so many comparisons that this level gives a very large number of false positives ๐Ÿ’€


-Wstring-compare

GCC will side-eye any strcmp and strncmp call whose result is locked in as zero or non-zero during an equality test ๐Ÿ‘€ That happens when one argument is longer than the array the other argument is stored in (or the bound, in the case of strncmp). Those calls could be mistakes ๐Ÿ’œ In the example below, the strcmp call gets flagged because its result has to be non-zero no matter what's stored in the array a.

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

-Wstring-compare is enabled by -Wextra ๐Ÿ”ฅ


-Wstringop-overflow, -Wstringop-overflow=type

GCC warns about calls to string manipulation functions like memcpy and strcpy that are going to overflow the destination buffer ๐Ÿงš The optional argument is one greater than the type of Object Size Checking to use when figuring out the size of the destination. That argument only matters for functions that work on character arrays. Raw memory functions like memcpy always use Object Size type-0. The option also warns about calls that specify a size bigger than the largest possible object, or at most SIZE_MAX / 2 bytes. It works best with optimization turned on. It can still catch a small subset of simple buffer overflows without optimization, in calls to GCC built-in functions like __builtin_memcpy that match the standard functions. Either way, it only warns about a subset of the overflows that the matching overflow-checking built-ins can detect ๐Ÿ’– For example, the option warns about the strcpy call below, because it copies at least 5 characters (the string "blue" including the terminating NUL) into a buffer of size 4.

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

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

Heads up: -Wstringop-overflow=2 is enabled by default ๐Ÿ‘‘

-Wstringop-overflow, -Wstringop-overflow=1

The -Wstringop-overflow=1 option uses type-zero Object Size Checking to figure out the sizes of destination objects ๐ŸŒˆ This is the default setting of the option. At this setting, it doesn't warn about writes past the end of subobjects of larger objects accessed through pointers, unless the size of the largest surrounding object is known. When the destination might be one of several objects, it's assumed to be the largest one of them. On Linux systems, when optimization is enabled at this setting, the option warns about the same code as when the _FORTIFY_SOURCE macro is defined to a non-zero value ๐Ÿซถ

-Wstringop-overflow=2

The -Wstringop-overflow=2 option uses type-one Object Size Checking to figure out the sizes of destination objects. At this setting, it warns about overflows when writing to members of the largest complete objects whose exact size is known ๐Ÿ“ It does not warn about excessive writes to the same members of unknown objects referenced by pointers, since those pointers may point to arrays with an unknown number of elements.

-Wstringop-overflow=3

The -Wstringop-overflow=3 option uses type-two Object Size Checking to figure out the sizes of destination objects. At this setting, it warns about overflowing the smallest object or data member. This is the most restrictive setting of the option that may result in warnings for safe code ๐Ÿ˜ฌ

-Wstringop-overflow=4

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


-Wno-stringop-truncation

Don't warn about calls to bounded string manipulation functions like strncat, strncpy, and stpncpy that might either truncate the copied string or leave the destination unchanged ๐Ÿ’…

In the following example, the call to strncat specifies a bound that's less than the length of the source string. That means the copy gets truncated, so the call is diagnosed. To avoid the warning, use bufsize - strlen (buf) - 1) as the bound โœจ

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

Another example: the following call to strncpy copies just the characters before the terminating NUL into d, without appending the NUL to the end. Assuming the result of strncpy is always a NUL-terminated string is a super common mistake, so the call is diagnosed ๐Ÿ˜ญ To avoid the warning when the result isn't supposed to be NUL-terminated, call memcpy instead.

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

In the following example, the call to strncpy uses the size of the destination buffer as the bound. If the length of the source string is equal to or greater than that size, the copy won't be NUL-terminated. So, the call is also diagnosed ๐Ÿ™ƒ To avoid the warning, specify sizeof buf - 1 as the bound and set the last element of the buffer to NUL.

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

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


-Wsuggest-attribute=[pure|const|noreturn|format|cold|malloc]

Warn about cases where adding an attribute might be beneficial โœจ The attributes currently supported are listed below.

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

Warn about functions that might be good candidates for the attributes pure, const, noreturn, or malloc ๐Ÿ‘‘ The compiler only warns about functions that are visible in other compilation units, or (for pure and const) if it can't prove that the function returns normally. A function returns normally if it doesn't contain an infinite loop, and doesn't return abnormally by throwing, calling abort, or trapping. This analysis requires 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

Warn 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 are used in assignments, initializations, parameter passing, or return statements should have a matching format attribute in the resulting type. In other words, the left-hand side of the assignment or initialization, the type of the parameter variable, or the return type of the containing function should also have a format attribute to avoid the warning, respectively ๐Ÿ’–

okay so GCC also warns about function definitions that might be candidates for format attributes ๐Ÿ‘€ and bestie, these are ONLY possible candidates, not confirmed ones ๐Ÿซถ GCC guesses that a format attribute might fit any function that calls something like vprintf or vscanf, but that's not always the case ๐Ÿ’€. Some functions where a format attribute is actually right might not get flagged at all ๐Ÿ™ˆ

  • -Wsuggest-attribute=cold โ€” โ„๏ธ GCC warns about functions that might be candidates for the cold attribute. This is based on static detection, so it generally only warns about functions that always lead to a call to another cold function, like wrappers around C++ throw or fatal error reporting functions that lead to abort.
  • -Walloc-zero โ€” ๐Ÿซง GCC warns about calls to allocation functions decorated with the alloc_size attribute that ask for zero bytes. This includes the built-in forms of aligned_alloc, alloca, calloc, malloc, and realloc. What these functions do with a zero size differs between implementations (and realloc has been deprecated for it), so relying on that behaviour can cause subtle portability bugs. Avoid it, periodt ๐Ÿ’…
  • -Walloc-size-larger-than=byte-size โ€” ๐Ÿ“ GCC warns about calls to functions decorated with the alloc_size attribute that try to allocate objects bigger than the number of bytes you specify. It also warns if the result of the size computation, done in an integer type with infinite precision, would go over PTRDIFF_MAX on the target. -Walloc-size-larger-than=PTRDIFF_MAX is on by default. You can turn these warnings off by giving a byte-size of SIZE_MAX or more, or by using -Wno-alloc-size-larger-than.
  • -Wno-alloc-size-larger-than โ€” ๐Ÿšซ Disables -Walloc-size-larger-than= warnings. It's the same as -Walloc-size-larger-than=SIZE_MAX or larger.
  • -Walloca โ€” ๐Ÿ” Warns on every use of alloca in your source. No exceptions, bestie.
  • -Walloca-larger-than=byte-size โ€” ๐Ÿง  Warns on calls to alloca whose integer argument is either zero, or isn't bounded by a controlling predicate that limits it to at most byte-size. It also warns when the bound is unknown. Arguments of non-integer types count as unbounded, even if they look like they're in the expected 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);
            }
        }

In the above example, n could be negative, causing a larger than expected argument to be implicitly cast into the alloca call. Wild, right? ๐ŸŒ€

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

-Walloca-larger-than=PTRDIFF_MAX is enabled by default, but it's usually only effective when -ftree-vrp is active (default for -O2 and above). โœจ

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

  • -Wno-alloca-larger-than โ€” ๐Ÿšซ Disables -Walloca-larger-than= warnings. It's equivalent to -Walloca-larger-than=SIZE_MAX or larger.
  • -Warith-conversion โ€” ๐Ÿ”ข Warns about implicit conversions from arithmetic operations, even when converting the operands to the same type can't change their values. This affects warnings from -Wconversion, -Wfloat-conversion, and -Wsign-conversion.
        void f (char c, int i)
        {
          c = c + i; // warns with -Wconversion
          c = c + 1; // only warns with -Warith-conversion
        }
  • -Warray-bounds, -Warray-bounds=n โ€” ๐Ÿงบ This option is only active when -ftree-vrp is active (default for -O2 and above). It warns about subscripts to arrays that are always out of bounds. It's enabled by -Wall.
    • -Warray-bounds=1 โ€” ๐ŸŒท This is the warning level of -Warray-bounds and is enabled by -Wall. Higher levels aren't, so you have to ask for them explicitly.
    • -Warray-bounds=2 โ€” ๐Ÿ•ต๏ธ This level also warns about out of bounds access for arrays at the end of a struct, and for arrays accessed through pointers. It may give a bigger pile of false positives, so it's deactivated by default. ๐Ÿ˜ญ
  • -Wattribute-alias=n, -Wno-attribute-alias โ€” ๐Ÿชž Warns about declarations using the alias and similar attributes whose target is incompatible with the type of the alias.
    • -Wattribute-alias=1 โ€” ๐Ÿฅฐ The default level. It diagnoses incompatibilities between the type of the alias declaration and that of its target. These are usually a sign of bugs.
    • -Wattribute-alias=2 โ€” ๐Ÿง At this level, -Wattribute-alias also diagnoses cases where the attributes of the alias declaration are more restrictive than the attributes applied to its target. These mismatches can lead to incorrect code generation. Other times they're harmless, and you can fix them just by adding the missing attribute to the target. For comparison, see the -Wmissing-attributes option, which controls diagnostics when the alias declaration is less restrictive than the target, rather than more.

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

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

  • -Wbool-compare โ€” โš–๏ธ Warns about a boolean expression being compared with an integer value other than true or false. For instance, the following 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 warning catches cases like:
        if (p != NULL)
          return 0;
        else
          return 0;

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

          int i = x ? *p : *p;
  • -Wduplicated-cond โ€” ๐Ÿ‘€ Warns about duplicated conditions in an if-else-if chain. For instance, it warns for the following code:
        if (p->q != NULL) { ... }
        else if (p->q != NULL) { ... }
  • -Wframe-address โ€” ๐ŸชŸ Warns when __builtin_frame_address or __builtin_return_address is called with an argument greater than 0. Those calls may return indeterminate values or crash the program. This warning is included in -Wall. ๐Ÿ’€
  • -Wno-discarded-qualifiers (C and Objective-C only) โ€” ๐Ÿ”“ Stops GCC from warning when type qualifiers on pointers are being discarded. Normally the compiler warns if a const char * variable gets passed to a function that takes a char * parameter. This option suppresses that warning.
  • -Wno-discarded-array-qualifiers (C and Objective-C only) โ€” ๐Ÿ”“ Stops GCC from warning when type qualifiers on arrays that are pointer targets are being discarded. Normally the compiler warns if a const int (*)[] variable gets passed to a function that takes an int (*)[] parameter. This option suppresses that warning.
  • -Wno-incompatible-pointer-types (C and Objective-C only) โ€” ๐Ÿซ  Stops GCC from warning when there's a conversion between pointers with incompatible types. This covers cases not handled by -Wno-pointer-sign, which warns about pointer argument passing or assignment with different signedness.
  • -Wno-int-conversion (C and Objective-C only) โ€” ๐Ÿ” Stops GCC from warning about incompatible integer-to-pointer and pointer-to-integer conversions. This warning is about implicit conversions. For explicit conversions, you can use -Wno-int-to-pointer-cast and -Wno-pointer-to-int-cast instead.
  • -Wzero-length-bounds โ€” ๐ŸŽˆ Warns about accesses to elements of zero-length array members that might overlap other members of the same object. Declaring interior zero-length arrays is discouraged, because accesses to them are undefined. See

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's beyond the bounds of the enclosing object. ๐Ÿงธ

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

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

Option -Wzero-length-bounds is enabled by -Warray-bounds. and that's the vibe, bestie ๐ŸŒธ

-Wdiv-by-zero... wait, let's get into the flags ๐Ÿ’…

  • -Wno-div-by-zero โ€” okay so this one tells GCC to stop yelling about integer division by zero that it can spot at compile time ๐Ÿ™ˆ Floating-point division by zero doesn't get flagged either, bc dividing by zero with floats can be a totally legit way to get infinities and NaNs โœจ
  • -Wsystem-headers โ€” normally GCC zips its lips about warnings from system header files, bc those usually aren't real problems and would just make the output messier ๐ŸŒธ With this flag it treats system header warnings like they came from your own code ๐Ÿ‘€ ngl but heads up: using -Wall with this still won't warn about unknown pragmas in system headers. For that you also need -Wunknown-pragmas ๐Ÿซถ
  • -Wtautological-compare โ€” warns when you compare something to itself and it's always true or always false ๐Ÿ’€ like int i = 1; then if (i > i) { ... } is giving nothing but mistakes ๐Ÿ˜ญ It also catches bitwise comparisons that are always true or false, like if ((a & 16) == 10) { ... } which will always be false ๐Ÿ™…โ€โ™€๏ธ This one is enabled by -Wall ๐Ÿ’–
  • -Wtrampolines โ€” warns about trampolines made for pointers to nested functions ๐Ÿงš A trampoline is a little bit of data or code created at run time on the stack when you take the address of a nested function, and it's used to call that nested function indirectly ๐Ÿฆ‹ For some targets it's just data and needs no special treatment, but for most targets it's code, which means the stack has to be made executable for the program to work properly ๐Ÿ”ฅ
  • -Wfloat-equal โ€” warns when floating-point values get used in equality comparisons ๐ŸŽ€ The vibe is that sometimes you treat floats like approximations of real numbers, and then you need to figure out the max (or likely max) error your computation introduces and allow for it ๐Ÿ’œ Instead of testing for equality, check whether the two values' ranges overlap, which is done with the relational operators, so equality comparisons are probably mistaken ๐Ÿ™ˆ
  • -Wtraditional (C and Objective-C only) โ€” warns about constructs that act differently in traditional C vs ISO C, plus ISO C stuff that has no traditional equivalent and problematic stuff you should avoid ๐ŸŒˆ Here's the full list of what it looks out for:
    • Macro parameters inside string literals in the macro body ๐Ÿ“ Traditional C does replacement inside string literals, but ISO C doesn't.
    • Some preprocessor directives didn't exist in traditional C. Traditional preprocessors only treated a line as a directive if the # was in column 1, so -Wtraditional warns about directives traditional C understands but ignores because the # isn't the first character on the line ๐Ÿซ  It also suggests indenting directives like #pragma that traditional C doesn't understand ๐Ÿ“ Some traditional implementations don't recognize #elif, so this option suggests avoiding it altogether ๐Ÿ™…โ€โ™€๏ธ
    • A function-like macro that shows up without arguments ๐Ÿงฉ
    • The unary plus operator โž•
    • The U integer constant suffix, or the F or L floating-point constant suffixes. (Traditional C does support the L suffix on integer constants.) Heads up, these suffixes show up in macros defined in system headers on most modern systems, like the _MIN/_MAX macros in <limits.h> ๐Ÿ’… Using those macros in your own code could 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 that block ends ๐ŸŒ™
    • A switch statement whose operand is 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 only gets issued if the constant's base is ten, so hexadecimal or octal values (which usually represent bit patterns) aren't warned about ๐Ÿ”ข
    • ISO string concatenation ๐Ÿงต
    • 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, bc the assumption is that a zero initializer appears conditioned on something like __STDC__ to avoid missing-initializer warnings and relies on default zeroing in traditional C ๐Ÿซถ
    • Conversions by prototypes between fixed-point and floating-point values, and vice versa. Missing these prototypes when compiling with traditional C causes serious problems ๐Ÿ’€ This is a subset of the possible conversion warnings; for the full set use -Wtraditional-conversion ๐Ÿ”—
    • ISO C style function definitions. This one is intentionally not issued for prototype declarations or variadic functions, bc 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, bc that's already a GCC extension and isn't relevant to traditional C compatibility ๐Ÿ’–
  • -Wtraditional-conversion (C and Objective-C only) โ€” warns if a prototype causes a type conversion that's different from what would happen to the same argument without a prototype ๐Ÿ‘‘ That includes fixed-to-floating and floating-to-fixed conversions, plus conversions that change the width or signedness of a fixed-point argument, except when it matches the default promotion ๐Ÿง
  • -Wdeclaration-after-statement (C and Objective-C only) โ€” warns when a declaration shows up after a statement in a block ๐Ÿ™‹โ€โ™€๏ธ This came from C++ and was introduced with ISO C99, and GCC allows it by default. ISO C90 doesn't support it ๐Ÿ•ฐ๏ธ
  • -Wshadow โ€” warns whenever a local variable or type declaration shadows another variable, parameter, type, class member (in C++), or instance variable (in Objective-C), or whenever a built-in function gets shadowed ๐Ÿชž In C++, the compiler warns if a local variable shadows an explicit typedef, but not if it shadows a struct, class, or enum ๐Ÿง When this warning is on, it also includes all instances of local shadowing, which means -Wno-shadow=local and -Wno-shadow=compatible-local get 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 shadowing variable's type. In C++, "compatible" means the shadowing variable's type can be converted to the shadowed variable's type ๐Ÿซง The idea behind this flag (on top of -Wshadow=local) is that when a local variable shadows one of an incompatible type, it's most likely intentional and not a bug or typo. Like in this example:
for (SomeIterator i = SomeObj.begin(); i != SomeObj.end(); ++i)
{
  for (int i = 0; i < N; ++i)
  {
    ...
  }
  ...
}

Since the two i variables in that example have incompatible types, enabling only -Wshadow=compatible-local doesn't emit a warning ๐Ÿ™Œ Bc their types are incompatible, if a programmer accidentally uses one in place of the other, type checking is expected to catch it and emit an error or warning ๐Ÿ›ก๏ธ Using this flag instead of -Wshadow=local can reduce the number of warnings triggered by intentional shadowing ๐ŸŒŸ Also, shadowing const char *i with char *i does not emit a warning ๐Ÿค

This warning is also enabled by -Wshadow=local ๐Ÿ’…

  • -Wlarger-than=byte-size โ€” warns whenever an object is defined whose size is bigger than byte-size ๐Ÿ“ -Wlarger-than=PTRDIFF_MAX is enabled by default. You can disable these warnings by specifying a byte-size of SIZE_MAX or more, or by using -Wno-larger-than ๐Ÿ™…โ€โ™€๏ธ
  • -Wno-larger-than โ€” disables -Wlarger-than= warnings. It's the same as -Wlarger-than=SIZE_MAX or larger ๐ŸŒˆ
  • -Wframe-larger-than=byte-size โ€” warns if the size of a function frame exceeds byte-size ๐Ÿ–ผ๏ธ The stack frame size calculation is approximate and not conservative, so the actual requirements might be somewhat bigger than byte-size even if you don't get a warning ๐Ÿ˜ฌ Also, space allocated with alloca, variable-length arrays, or related constructs isn't counted when GCC decides whether to warn ๐Ÿซ  -Wframe-larger-than=PTRDIFF_MAX is enabled by default. Disable these warnings by specifying a byte-size of SIZE_MAX or more, or with -Wno-frame-larger-than ๐Ÿฆ‹
  • -Wno-frame-larger-than โ€” disables -Wframe-larger-than= warnings. Same as -Wframe-larger-than=SIZE_MAX or larger ๐Ÿ’–
  • -Wno-free-nonheap-object โ€” don't warn when someone tries to free an object that wasn't allocated on the heap ๐Ÿงน
  • -Wstack-usage=byte-size โ€” okay so this one warns bestie if a function's stack usage might go over byte-size ๐Ÿ“šโœจ. The math is super cautious on purpose ๐Ÿซถ. The compiler counts space from alloca, variable-length arrays, and related constructs too when deciding whether to warn ๐Ÿ’….

The message matches what -fstack-usage prints ๐ŸŽ€, and there are three flavours:

  • If the stack usage is fully static but goes over the limit, you get warning: stack usage is 1120 bytes ๐Ÿ˜ญ
  • If it's partly dynamic but bounded, you get warning: stack usage might be 1648 bytes ๐ŸŒธ
  • If it's partly dynamic and unbounded, you get warning: stack usage might be unbounded ๐Ÿ’€

-Wstack-usage=PTRDIFF_MAX is on by default ๐Ÿ”ฅ. To silence these warnings, give a byte-size of SIZE_MAX or more, or just use -Wno-stack-usage ๐Ÿ™ˆ.

  • -Wno-stack-usage โ€” the "I'm not doing this rn" option ๐Ÿงš. It turns off -Wstack-usage= warnings and is the same as -Wstack-usage=SIZE_MAX or larger ๐ŸŒˆ.
  • -Wunsafe-loop-optimizations โ€” warns when a loop can't be optimised because the compiler can't assume anything about its index bounds ๐Ÿ‘€. With -funsafe-loop-optimizations, it instead warns when the compiler does make those assumptions ๐Ÿ’œ.
  • -Wno-pedantic-ms-format (MinGW targets only) โ€” ngl, this one's very specific ๐ŸชŸ. Used together with -Wformat and -pedantic without GNU extensions, it stops the warnings about the non-ISO printf and scanf width specifiers I32, I64, and I on Windows targets, since those depend on the MS runtime ๐Ÿฆ‹.
  • -Wpointer-arith โ€” warns about anything that depends on the "size of" a function type or of void ๐ŸŒท. GNU C gives those types a size of 1 so void * pointers and function pointers are easier to do maths with ๐Ÿ“. In C++, it also warns when an arithmetic operation involves NULL โญ. This one gets switched on by -Wpedantic too ๐Ÿซง.
  • -Wno-pointer-compare โ€” stops the warning for comparing a pointer with a zero character constant ๐Ÿ’–. That usually means the pointer was supposed to get dereferenced, so the warning is actually helpful, but you can turn it off here ๐Ÿ™ˆ. Check out this example:
const char *p = foo ();
if (p == '\0')
  return 42;
Heads up: the code above is invalid in C++11 ๐Ÿ’€.

This warning is enabled by default ๐Ÿ’….

  • -Wtype-limits โ€” warns if a comparison is always true or always false because of the limited range of the data type ๐ŸŒˆ. Constant expressions don't get this warning ๐ŸŽ€. For example, it warns if an unsigned variable is compared against zero with < or >= ๐Ÿ‘‘. This one is also turned on by -Wextra โœจ.
  • -Wabsolute-value (C and Objective-C only) โ€” calls to standard absolute-value functions get flagged when there's a better function for the job ๐Ÿฆ‹. For example, abs(3.14) triggers it because fabs is the right call for a double ๐Ÿ’…. It also triggers when the argument has an unsigned type ๐Ÿซถ. You can suppress it with an explicit type cast, and -Wextra turns it on too ๐ŸŒธ.
  • -Wcomment, -Wcomments โ€” warns whenever a /* comment-start sequence shows up inside a /* comment, or whenever a backslash-newline appears in a // comment ๐Ÿ“. It's enabled by -Wall ๐Ÿ”ฅ.
  • -Wtrigraphs โ€” warns if any trigraphs pop up that might change what the program means ๐Ÿงš. Trigraphs inside comments don't get warned about, except the ones that would form escaped newlines ๐Ÿ’œ.

-Wall implies this option ๐Ÿ‘‘. If -Wall isn't given, it's still enabled unless trigraphs are enabled ๐Ÿ™ˆ. If you want trigraph conversion without the warnings but still want the other -Wall warnings, use -trigraphs -Wall -Wno-trigraphs ๐ŸŒˆ.

  • -Wundef โ€” warns if an undefined identifier gets evaluated in an #if directive โœจ. Those identifiers get replaced with zero ๐Ÿซง.
  • -Wexpansion-to-defined โ€” warns whenever defined shows up in a macro's expansion, including when the macro is expanded by an #if directive ๐ŸŒธ. That kind of usage isn't portable, so it's a red flag ๐Ÿšฉ. This warning is also enabled by -Wpedantic and -Wextra ๐Ÿ’….
  • -Wunused-macros โ€” warns about macros defined in the main file that never get used ๐Ÿฆ‹. A macro counts as used if it gets expanded or tested for existence at least once ๐Ÿ’–. The preprocessor also warns if the macro hasn't been used by the time it gets redefined or undefined ๐Ÿ˜ญ.

Built-in macros, macros defined on the command line, and macros defined in include files are not 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 can improve the scope of the macro's definition, like moving it into the first skipped block ๐ŸŒท. Or you could provide a dummy use, something like this:

#if defined the_macro_causing_the_warning
#endif
  • -Wno-endif-labels โ€” stops the warning for when an #else or #endif is followed by text ๐Ÿ“. This happens in older programs with code that looks like this ๐Ÿ•ฐ๏ธ:
#if FOO
...
#else FOO
...
#endif FOO

The second and third FOO are supposed to be in comments ๐Ÿ™ˆ. This warning is on by default ๐Ÿ’….

  • -Wbad-function-cast (C and Objective-C only) โ€” warns when a function call gets cast to a non-matching type ๐ŸŽ€. For example, it warns if a call to a function returning an integer type is cast to a pointer type ๐Ÿ‘€.
  • -Wc90-c99-compat (C and Objective-C only) โ€” warns about features that are in ISO C99 but not in ISO C90 ๐ŸŒˆ. Think variable length arrays, the long long type, the bool type, compound literals, designated initializers, and so on โœจ. This option doesn't depend on the standards mode ๐Ÿงš. Warnings are disabled in the expression that follows __extension__ ๐Ÿซง.
  • -Wc99-c11-compat (C and Objective-C only) โ€” same energy, but for features in ISO C11 that aren't in ISO C99 ๐Ÿ’œ. Think anonymous structures and unions, the _Atomic type qualifier, the _Thread_local storage-class specifier, the _Alignas specifier, the Alignof operator, the _Generic keyword, and so on ๐Ÿ‘‘. It's independent of the standards mode too ๐Ÿฆ‹, and warnings are disabled in the expression that follows __extension__ ๐Ÿ’….
  • -Wc11-c2x-compat (C and Objective-C only) โ€” features in ISO C11 that aren't in ISO C2X get flagged here ๐ŸŒธ. For instance, omitting the string in _Static_assert, using [[]] attribute syntax, and using decimal floating-point types ๐Ÿ”ฅ. Again, it doesn't care about 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, implicitly converting from void * to a pointer to a non-void type ๐Ÿ’–.
  • -Wc++11-compat (C++ and Objective-C++ only) โ€” warns about C++ constructs whose meaning changes between ISO C++ 1998 and ISO C++ 2011 ๐ŸŒˆ. For example, identifiers that were fine in ISO C++ 1998 but are keywords in ISO C++ 2011 ๐Ÿ’…. This one turns on -Wnarrowing and is enabled by -Wall ๐Ÿงš.
  • -Wc++14-compat (C++ and Objective-C++ only) โ€” same vibe, but for constructs that differ between ISO C++ 2011 and ISO C++ 2014 ๐ŸŽ€. Enabled by -Wall ๐Ÿซง.
  • -Wc++17-compat (C++ and Objective-C++ only) โ€” constructs that differ between ISO C++ 2014 and ISO C++ 2017 ๐Ÿฆ‹. Enabled by -Wall ๐Ÿ’œ.
  • -Wc++20-compat (C++ and Objective-C++ only) โ€” constructs that differ between ISO C++ 2017 and ISO C++ 2020 โญ. Enabled by -Wall ๐ŸŒธ.
  • -Wcast-qual โ€” warns whenever a pointer gets cast in a way that removes a type qualifier from the target type ๐Ÿ™ˆ. For example, it warns if a const char * is cast to a plain 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 is cast so that the required alignment of the target goes up ๐ŸŒท. For example, it warns if a char * is cast to an int * on machines where integers can only be accessed at two- or four-byte boundaries ๐Ÿ“.
  • -Wcast-align=strict โ€” same idea, but stricter ๐Ÿ”ฅ. It warns whenever the required alignment goes up regardless of the target machine ๐Ÿ’–. For example, it warns if a char * is cast to an int * no matter what ๐Ÿ’….
  • -Wcast-function-type โ€” warns when a function pointer is cast to an incompatible function pointer ๐Ÿงš. For casts involving function types with a variable argument list, only the types of the initial arguments that are provided get considered ๐Ÿซง. Any parameter of pointer type matches any other pointer type ๐ŸŒˆ. Benign differences in integral types are ignored, like int vs. long on ILP32 targets ๐Ÿฆ‹. Type qualifiers are ignored too ๐Ÿซถ.

The function type void (*) (void) is special and matches everything, so you can use it to suppress this warning โœจ. For casts involving pointer to member types, this warning goes off whenever the cast changes the pointer to member type ๐Ÿ‘‘. It's enabled by -Wextra ๐Ÿ’œ.

  • -Wwrite-strings โ€” when compiling C, string constants get the type const char[length] ๐ŸŽ€. That way, copying the address of one into a non-const char * pointer gives you a warning ๐Ÿ‘€. These warnings help you catch, at compile time, code that might try to write into a string constant ๐Ÿซถ. But they only really work if you've been super careful with const in declarations and prototypes ๐Ÿ˜ญ. Otherwise, honestly, they're just a nuisance ๐Ÿ™ˆ. That's why -Wall doesn't request these warnings ๐ŸŒธ.

When compiling C++, it warns about the deprecated conversion from string literals to char * ๐Ÿ’…. This warning is enabled by default for C++ programs ๐Ÿ”ฅ.

  • -Wclobbered โ€” warns for variables that might be changed by longjmp or vfork ๐Ÿงš. This one is also enabled by -Wextra โญ.
  • -Wconversion โ€” okay bestie, this one is all about sneaky implicit conversions that might quietly change a value ๐Ÿ‘€ It catches real-to-integer swaps like abs (x) when x is double, signed-to-unsigned drama like unsigned ui = -1, and squishing things into smaller types like sqrtf (M_PI) ๐Ÿซฃ

NGL the good news is it won't flag explicit casts like abs ((int) x) or ui = (unsigned) -1 ๐Ÿ’… and it skips anything where the value doesn't actually change, like abs (2.0) ๐Ÿ™ˆ Warnings about signed/unsigned integer conversions can be switched off with -Wno-sign-conversion ๐Ÿซถ

For C++ it's a whole different vibe ๐Ÿ”ฅ It also warns about confusing overload resolution for user-defined conversions, plus conversions that never use a type conversion operator: conversions to void, the same type, a base class, or a reference to them. 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 type only show up with -Warith-conversion ๐Ÿฆ‹

  • -Wdangling-else โ€” heads up, this one catches constructions where it's unclear which if statement an else branch belongs to ๐Ÿ™ˆ Check out this sus example:
{
  if (a)
    if (b)
      foo ();
  else
    bar ();
}

Here's the tea โ˜• 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 when this flag is specified. To eliminate the warning, add explicit braces around the innermost if statement so there's no way the else can belong to the enclosing if. The fixed code looks like this:

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

This warning is enabled by -Wparentheses โœจ

  • -Wdate-time โ€” this one warns when the macros __TIME__, __DATE__ or __TIMESTAMP__ show up, because they might stop your compilations from being bit-wise-identical and reproducible ๐Ÿ•ฐ๏ธ
  • -Wempty-body โ€” warns if an empty body shows up in an if, else or do while statement ๐Ÿซฅ This warning is also enabled by -Wextra ๐ŸŒˆ
  • -Wno-endif-labels โ€” the vibe here is "chill": it stops GCC from warning 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 (C, Objective-C only) โ€” warns when a value of enumerated type gets implicitly converted to a different enumerated type ๐Ÿ“ This warning is enabled by -Wextra โœจ
  • -Wjump-misses-init (C, Objective-C only) โ€” this one is for when a goto or switch statement jumps forward across the initialization of a variable, or jumps backward to a label after that variable has already been initialized ๐ŸŒ€ It only warns about variables that are initialized when they're declared. It's only supported for C and Objective-C, because in C++ this sort of branch is an error anyway ๐Ÿ™…โ€โ™€๏ธ

-Wjump-misses-init is included in -Wc++-compat ๐Ÿ’œ and it can be disabled with the -Wno-jump-misses-init option ๐Ÿซถ

  • -Wsign-compare โ€” warns when a comparison between signed and unsigned values could give you an incorrect result, because the signed value gets converted to unsigned ๐Ÿ˜ญ In C++, this warning is also enabled by -Wall. In C, it's enabled by -Wextra ๐ŸŒธ
  • -Wsign-conversion โ€” warns about implicit conversions that might change the sign of an integer value, like assigning a signed integer expression to an unsigned integer variable ๐Ÿ”„ An explicit cast silences the warning. In C, this option is also enabled by -Wconversion ๐Ÿ‘‘
  • -Wfloat-conversion โ€” warns about implicit conversions that reduce the precision of a real value ๐Ÿ“‰ That includes 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 โ€” stops GCC from warning on suspicious constructs involving reverse scalar storage order ๐Ÿงš
  • -Wsizeof-pointer-div โ€” warns about suspicious divisions of two sizeof expressions that divide the pointer size by the element size. That's the usual way to compute an array size, but it won't work out correctly with pointers ๐Ÿ™ƒ This warning warns e.g. 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 ๐Ÿง It triggers for example for memset (ptr, 0, sizeof (ptr)); if ptr is not an array but a pointer, and it suggests a possible fix. It also flags stuff like memcpy (&foo, ptr, sizeof (&foo));.

-Wsizeof-pointer-memaccess also warns about calls to bounded string copy functions like strncat or strncpy that specify the bound as a sizeof expression of the source array. For example, in the following function the call to strncat specifies the size of the source string as the bound. That's almost certainly a mistake, so the call is 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 โ€” do not warn when the sizeof operator is applied to a parameter that's declared as an array in a function definition ๐Ÿซถ This warning is enabled by default for C and C++ programs ๐ŸŒˆ
  • -Wmemset-elt-size โ€” warns about suspicious calls to the memset built-in function if the first argument references an array, and the third argument is a number equal to the number of elements, but not equal to the size of the array in memory ๐Ÿงฎ This usually means you forgot to multiply by the element size ๐Ÿ˜ญ This warning is enabled by -Wall ๐Ÿ’…
  • -Wmemset-transposed-args โ€” warns about suspicious calls to the memset built-in function where the second argument is not zero and the third argument is zero ๐Ÿ”€ For example, the call memset (buf, sizeof buf, 0) gets diagnosed because memset (buf, 0, sizeof buf) was what you 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, it's far less likely the arguments got mistakenly transposed, 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, such as void func(void); if (func), and comparisons against the memory address of a string literal, such as if (x == "abc").

These uses typically 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 result in 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 โ€” do not 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 ๐Ÿง  This includes using logical operators in contexts where a bit-wise operator is likely to be 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 โ€” warns about logical not used on the left hand side operand of a comparison ๐Ÿ™ƒ This option does not warn if the right operand is considered to be a boolean expression. Its purpose is to detect suspicious code like the following:
int a;
...
if (!a > 1) { ... }

You can suppress the warning by wrapping the LHS 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 elicits a warning.)
  • -Wno-aggressive-loop-optimizations โ€” warns if, in a loop with a constant number of iterations, the compiler detects undefined behavior in some statement during one or more of the iterations ๐Ÿ’€ Undefined behavior is no joke, bestie ๐Ÿซฃ
  • -Wno-attributes โ€” do not warn if an unexpected __attribute__ is used, such as unrecognized attributes, function attributes applied to variables, etc. ๐Ÿท๏ธ This does not stop errors for incorrect use of supported attributes โ—
  • -Wno-builtin-declaration-mismatch โ€” warns if a built-in function is declared with an incompatible signature or as a non-function, or when a built-in function declared with a type that doesn't include a prototype is called with arguments whose promoted types don't match those expected by the function ๐Ÿงฉ When -Wextra is specified, it also warns when a built-in function that takes arguments is declared without a prototype. The -Wbuiltin-declaration-mismatch warning is enabled by default. To avoid the warning, include the appropriate header to bring the prototypes of built-in functions into scope ๐Ÿ“š

Check out this example: the call to memset below gets diagnosed because the function expects a value of type size_t as its argument, but the type of 32 is int. With -Wextra, the declaration of the function is diagnosed as well ๐Ÿ”

extern void* memset ();
void f (void *d)
{
  memset (d, '\0', 32);
}
  • -Wno-builtin-macro-redefined โ€” okay so this one stops GCC from yelling when certain built-in macros get redefined. That covers __TIMESTAMP__, __TIME__, __DATE__, __FILE__, and __BASE_FILE__. ๐Ÿ’…
  • -Wstrict-prototypes (C and Objective-C only) โ€” this warns if a function is declared or defined without spelling out its argument types. An old-style definition gets a pass with no warning if an earlier declaration already listed the argument types. ๐ŸŽ€
  • -Wold-style-declaration (C and Objective-C only) โ€” this flags obsolescent declarations, going by the C Standard. For example, it warns if storage-class specifiers like static aren't the very first thing in a declaration. It's also turned on by -Wextra. โœจ
  • -Wold-style-definition (C and Objective-C only) โ€” this warns whenever an old-style function definition shows up, even if there's already a prototype. A definition using () doesn't count as old-style in C2X mode, since it means the same thing as (void) there. For older standards, though, it does count as old-style. ๐Ÿฆ‹
  • -Wmissing-parameter-type (C and Objective-C only) โ€” this catches a parameter declared without a type specifier in K&R-style functions, like this:
void foo(bar) { }

It's also enabled by -Wextra. ๐ŸŒธ

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

It 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, it also doesn't warn about the universal zero initializer { 0 }:

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

And in C++, the empty { } initializer gets a pass too:

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

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

  • -Wno-multichar โ€” don't warn when a multicharacter constant like 'FOOF' shows up. These usually mean there's a typo in your code, since their values are implementation-defined, so you shouldn't use them in portable code anyway. ๐Ÿ™ˆ
  • -Wnormalized=[none|id|nfc|nfkc] โ€” okay, this one is a whole vibe. 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 sequences that look exactly the same. The ISO 10646 standard has normalization rules that turn look-alike sequences into the same sequence, and GCC can warn you if your identifiers haven't been normalized. 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, and it's equivalent to -Wnormalized.

Here's the tea: some characters that ISO C and ISO C++ allow in identifiers aren't allowed in identifiers once they've been turned into NFC. That means there's no way to use these symbols in portable ISO C or C++ and still have every identifier in NFC. -Wnormalized=id suppresses the warning for those characters. The hope is that future versions of the standards will fix this, which is why it isn't the default. ๐Ÿซถ

You can switch the warning off for all characters with -Wnormalized=none or -Wno-normalized. Only do this if you're using some other normalization scheme (like "D"), because otherwise you can easily create bugs that are literally impossible to see. ๐Ÿ˜ญ

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

  • -Wno-attribute-warning โ€” don't warn about usage of functions declared with the warning attribute. This warning is on by default. Use -Wno-attribute-warning to turn off the warning, or -Wno-error=attribute-warning to turn off the error when you compile with the -Werror flag. ๐ŸŽ€
  • -Wno-deprecated โ€” don't warn about usage of deprecated features. ๐Ÿฆ‹
  • -Wno-deprecated-declarations โ€” don't warn about uses of functions, variables, and types marked as deprecated with the deprecated attribute. โœจ
  • -Wno-overflow โ€” don't warn about compile-time overflow in constant expressions. ๐Ÿ’–
  • -Wno-odr โ€” this one warns about One Definition Rule violations during link-time optimization. It's enabled by default. ๐Ÿ‘‘
  • -Wopenmp-simd โ€” this warns if the vectorizer cost model overrides the OpenMP simd directive that you set. If you want to loosen the cost model, you can use -fsimd-cost-model=unlimited. ๐Ÿ”ฅ
  • -Woverride-init (C and Objective-C only) โ€” this warns if an initialized field without side effects gets overridden when you're using designated initializers. It's included in -Wextra. To get the other -Wextra warnings without this one, use -Wextra -Wno-override-init. ๐Ÿ’…
  • -Wno-override-init-side-effects (C and Objective-C only) โ€” don't warn if an initialized field with side effects gets overridden when you're using designated initializers. This is enabled by default. ๐ŸŒธ
  • -Wpacked โ€” this warns if a structure is given the packed attribute but that attribute has no effect on the layout or size of the structure. Structures like that can end up misaligned for little benefit. In the example below, the variable f.x in struct bar is misaligned, even though struct bar doesn't have the packed attribute itself:
struct foo {
  int x;
  char a, b, c, d;
} __attribute__((packed));
struct bar {
  char z;
  struct foo f;
};
  • -Wnopacked-bitfield-compat โ€” the 4.1, 4.2, and 4.3 series of GCC ignored the packed attribute on bit-fields of type char. That got fixed in GCC 4.4, but the change can lead to differences in structure layout. GCC tells you when the offset of such a field has changed in GCC 4.4. For example, there's no longer a 4-bit padding between field a and field b in this structure:
struct foo
{
  char a:4;
  char b:8;
} __attribute__ ((packed));

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

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

This warning is enabled by -Wall. ๐Ÿซถ

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

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

  • -Wnested-externs (C and Objective-C only) โ€” this warns if an extern declaration is encountered inside a function. ๐Ÿ‘‘
  • -Winline โ€” okay so this one yells at you if a function you marked inline doesn't actually get inlined ๐Ÿ˜ญ. Heads up though, even with this on, the compiler won't warn about failed inlining in functions declared in system headers ๐Ÿ™ˆ. GCC uses a bunch of heuristics to decide, like how big the function is and how much inlining has already happened in the current function. So ngl, tiny edits to your source can make these warnings pop up or disappear out of nowhere ๐Ÿซ โœจ
  • -Wint-in-bool-context โ€” this is the vibe check for integers that are pretending to be booleans ๐Ÿ’…. It flags sketchy stuff like conditional expressions (?:) using non-boolean integer constants in a boolean context, such as if (a <= b ? 2 : 3). It also catches left shifting signed integers in a boolean context, like for (a = 0; 1 << a; a++);, and likewise for all kinds of multiplications no matter the data type ๐Ÿงš. This one is switched on by -Wall ๐ŸŒธ
  • -Wno-int-to-pointer-cast โ€” the "nah, don't tell me about it" option ๐Ÿ™„. It hushes the warnings for casts to a pointer type from an integer of a different size. Just so you know, in C++ casting to a pointer type of smaller size is an error, not a warning ๐Ÿ’€. Wint-to-pointer-cast is turned on by default ๐ŸŽ€
  • -Wno-pointer-to-int-cast (C and Objective-C only) โ€” same energy, different direction ๐Ÿ’œ. This one silences warnings for casts from a pointer to an integer type of a different size ๐Ÿฆ‹
  • -Winvalid-pch โ€” warns you when a precompiled header is sitting in the search path but can't actually be used ๐Ÿ˜ญ๐Ÿซถ
  • -Wlong-long โ€” flags any use of the "long long" type ๐Ÿ‘‘. It gets turned on by either -Wpedantic or -Wtraditional in ISO C90 and C++98 modes. If you want those messages gone, reach for -Wno-long-long ๐Ÿ“
  • -Wvariadic-macros โ€” this one calls out variadic macros when you're in ISO C90 mode, or when the GNU alternate syntax shows up in ISO C99 mode ๐ŸŒˆ. It's enabled by either -Wpedantic or -Wtraditional, and you can shush it with -Wno-variadic-macros ๐Ÿคซ
  • -Wno-varargs โ€” tells GCC to stop side-eyeing questionable usage of the macros that handle variable arguments, like va_start ๐Ÿ™ƒ. These warnings are already on by default, so this is the off switch ๐Ÿ’…
  • -Wvector-operation-performance โ€” warns when a vector operation isn't being handled by the SIMD capabilities of your architecture โญ. It's mostly useful when you're doing performance tuning ๐Ÿ”ฅ. There are three ways a vector operation can get implemented, and the compiler is judging them all:
    • "piecewise" means the scalar operation runs on every single vector element ๐Ÿงฉ
    • "in parallel" means the vector operation is done using scalars of a wider type, which is usually more performance efficient ๐Ÿš€
    • "as a single scalar" means the vector fits into a scalar type ๐Ÿซง
  • -Wvla โ€” warns if a variable-length array shows up anywhere in the code ๐ŸŒท. -Wno-vla stops the -Wpedantic warning about variable-length arrays, so you can keep your peace โœŒ๏ธ
  • -Wvla-larger-than=byte-size โ€” okay this one is a whole mood ๐ŸŒŠ. If you use it, the compiler warns about declarations of variable-length arrays whose size is either unbounded, or bounded by an argument that lets the array size go past byte-size bytes ๐Ÿ“. It's similar to how -Walloca-larger-than=byte-size works, just for variable-length arrays instead ๐Ÿฆ‹

Also, GCC might optimize small variable-length arrays with a known value into plain arrays, so this warning might not fire for those ๐Ÿ™ˆ

-Wvla-larger-than=PTRDIFF_MAX is enabled by default, but it's typically only effective when -ftree-vrp is active, which happens by default for -O2 and above ๐Ÿ’…

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

  • -Wno-vla-larger-than โ€” turns off the -Wvla-larger-than= warnings ๐Ÿ›‘. It's the same as -Wvla-larger-than=SIZE_MAX or larger ๐Ÿ’–
  • -Wvolatile-register-var โ€” warns if a register variable gets declared volatile ๐Ÿคจ. Here's the tea: the volatile modifier doesn't stop every optimization that might remove reads and/or writes to register variables ๐Ÿต. This warning is enabled by -Wall โœจ
  • -Wdisabled-optimization โ€” warns when a requested optimization pass gets turned off ๐Ÿ› ๏ธ. Real talk, this doesn't usually mean your code is wrong ๐Ÿซถ. It just means GCC's optimizers can't handle the code well ๐Ÿฅบ. Often your code is just too big or too complex, and GCC refuses to optimize programs when the optimization would take inordinate amounts of time โณ
  • -Wpointer-sign (C and Objective-C only) โ€” flags pointer argument passing or assignment where the signedness is different ๐Ÿง. This option is only supported for C and Objective-C ๐Ÿ’œ. It's implied by -Wall and by -Wpedantic, and you can disable it with -Wno-pointer-sign ๐Ÿ™…โ€โ™€๏ธ
  • -Wstack-protector โ€” this one is only active when -fstack-protector is active ๐Ÿ›ก๏ธ. It warns about functions that aren't protected against stack smashing ๐Ÿ’€
  • -Woverlength-strings โ€” warns about string constants that are longer than the "minimum maximum" length the C standard specifies ๐Ÿ“œ. Modern compilers are chill about much longer strings, but if you want your code to be super portable, you should avoid them ๐ŸŒ

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 turn it off 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 pair it with -Wsystem-headers, it also warns about those constants in system header files ๐Ÿงพ. This can be super handy when you're getting code ready 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 tells GCC not to warn about type mismatches in global declarations from different compilation units ๐Ÿค. It requires -flto to be enabled, and it's enabled by default ๐Ÿ’…
  • -Wno-designated-init (C and Objective-C only) โ€” silences the warnings when a positional initializer is used to initialize a structure that's been marked with the "designated_init" attribute ๐Ÿ™ˆ๐Ÿ’–
  • -Wno-hsa โ€” stops the warnings for when HSAIL can't be emitted for the compiled function or OpenMP construct ๐Ÿซง. These warnings are enabled by default, so this is how you mute them ๐Ÿ”‡

โœจ Options That Control Static Analysis โœจ

  • -fanalyzer โ€” this turns on a static analysis of program flow ๐Ÿ”. It hunts for "interesting" interprocedural paths through your code and issues warnings for any problems it finds on them ๐Ÿ•ต๏ธโ€โ™€๏ธ. Warning: this analysis is much more expensive than other GCC warnings, so it's not gonna be instant ๐Ÿข๐Ÿ’€

Enabling this option effectively turns on all of these warnings too:

-Wanalyzer-double-fclose -Wanalyzer-double-free
-Wanalyzer-exposure-through-output-file -Wanalyzer-file-leak
-Wanalyzer-free-of-non-heap -Wanalyzer-malloc-leak
-Wanalyzer-possible-null-argument
-Wanalyzer-possible-null-dereference -Wanalyzer-null-argument
-Wanalyzer-null-dereference -Wanalyzer-stale-setjmp-buffer
-Wanalyzer-tainted-array-index
-Wanalyzer-unsafe-call-within-signal-handler
-Wanalyzer-use-after-free
-Wanalyzer-use-of-pointer-in-stale-stack-frame

This option is only available if GCC was configured with analyzer support enabled ๐Ÿ› ๏ธ

  • -Wanalyzer-too-complex โ€” if -fanalyzer is enabled, the analyzer uses a bunch of heuristics to explore the control flow and data flow in your program ๐Ÿง . But sufficiently complicated code can totally defeat them ๐Ÿ˜ตโ€๐Ÿ’ซ. By default, if the code is too complicated and the analyzer hits an internal limit, it just quietly stops ๐Ÿคซ. This option warns you when that happens ๐Ÿ“ฃ
  • -Wno-analyzer-double-fclose โ€” this warning requires -fanalyzer, which enables it, and you can use -Wno-analyzer-double-fclose to disable it ๐Ÿ™…โ€โ™€๏ธ. It warns for paths through the code where a "FILE *" can have fclose called on it more than once ๐Ÿ“
  • -Wno-analyzer-double-free โ€” this warning requires -fanalyzer, which enables it, and you can use -Wno-analyzer-double-free to disable it ๐Ÿšซ. It warns for paths through the code where a pointer can have free called on it more than once ๐Ÿ’ฅ
  • -Wno-analyzer-exposure-through-output-file โ€” this warning requires -fanalyzer, which enables it, and you can use -Wno-analyzer-exposure-through-output-file to disable it ๐Ÿ”. It warns for paths through the code where a security-sensitive value gets written to an output file, like writing a password to a log file ๐Ÿ™ˆ๐Ÿ“
  • -Wno-analyzer-file-leak โ€” this warning requires -fanalyzer, which enables it, and you can use -Wno-analyzer-file-leak to disable it ๐Ÿ’ง. It warns for paths through the code where a "<stdio.h>" "FILE *" stream object is leaked ๐Ÿซ—
  • -Wno-analyzer-free-of-non-heap โ€” this warning requires -fanalyzer, which enables it, and you can use -Wno-analyzer-free-of-non-heap to disable it ๐Ÿงน. It warns for paths through the code where free is called on a non-heap pointer, like an on-stack buffer or a global ๐Ÿฅด
  • -Wno-analyzer-malloc-leak โ€” this warning requires -fanalyzer, which enables it, and you can use -Wno-analyzer-malloc-leak to disable it ๐Ÿซ . It warns for paths through the code where a pointer allocated via malloc is leaked ๐Ÿฉธ
  • -Wno-analyzer-possible-null-argument โ€” this warning requires -fanalyzer, which enables it, and you can use -Wno-analyzer-possible-null-argument to disable it ๐Ÿคž. It warns for paths through the code where a possibly-NULL value gets passed to a function argument marked with __attribute__((nonnull)) as needing a non-NULL value ๐Ÿซฃ
  • -Wno-analyzer-possible-null-dereference โ€” this warning requires -fanalyzer, which enables it, and you can use -Wno-analyzer-possible-null-dereference to disable it ๐Ÿ™ƒ. It warns for paths through the code where a possibly-NULL value gets dereferenced ๐Ÿ‘€
  • -Wno-analyzer-null-argument โ€” this warning requires -fanalyzer, which enables it, and you can use -Wno-analyzer-null-argument to disable it ๐Ÿšท. It warns for paths through the code where a value known to be NULL gets passed to a function argument marked with __attribute__((nonnull)) as needing a non-NULL value โŒ
  • -Wno-analyzer-null-dereference โ€” this warning requires -fanalyzer, which enables it, and you can use -Wno-analyzer-null-dereference to disable it ๐Ÿซถ

Okay so the analyzer has a whole squad of warnings, and this next bit is where we get into the spicy ones ๐Ÿ”ฅ

This one yells when there's a path through your code where a value that's known to be NULL gets dereferenced ๐Ÿ’€

  • -Wno-analyzer-stale-setjmp-buffer โ€” ๐Ÿฆ‹ This warning needs -fanalyzer to be on, which turns it on for you. If you want it gone, use -Wno-analyzer-stale-setjmp-buffer. It's bestie-level important: it flags paths where longjmp is used to rewind to a jmp_buf tied to a setjmp call, but the function that made that setjmp call has already returned. When setjmp records a rewind location on a jmp_buf, it saves the stack frame, and that frame goes invalid once the function containing the setjmp call returns. Trying to rewind there with longjmp would reference a stack frame that no longer exists, and that's likely to lead to a crash (or worse ๐Ÿ˜ญ).
  • -Wno-analyzer-tainted-array-index โ€” ๐Ÿ”’ This one needs both -fanalyzer and -fanalyzer-checker=taint to be enabled. To turn it off, use -Wno-analyzer-tainted-array-index. It warns about 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 warning requires -fanalyzer, which enables it. Disable it with -Wno-analyzer-unsafe-call-within-signal-handler. It catches paths where a function that's known to be async-signal-unsafe (like fprintf) gets called from inside a signal handler.
  • -Wno-analyzer-use-after-free โ€” ๐Ÿ—‘๏ธ This one needs -fanalyzer, which enables it. Use -Wno-analyzer-use-after-free to disable it. It flags paths where a pointer gets used after free has already been called on it. Iykyk ๐Ÿ’…
  • -Wno-analyzer-use-of-pointer-in-stale-stack-frame โ€” ๐Ÿ‘ป This warning requires -fanalyzer, which enables it. Use -Wno-analyzer-use-of-pointer-in-stale-stack-frame to disable it. It warns about paths where a pointer gets dereferenced while it points at a variable in a stale stack frame.

Okay, so if you want to tweak how the analyzer explores your code, these are the pertinent parameters ๐Ÿงš --param analyzer-bb-explosion-factor=value, --param analyzer-max-enodes-per-program-point=value, --param analyzer-max-recursion-depth=value, and --param analyzer-min-snodes-for-call-summary=value.

The following options control the analyzer ๐Ÿ’–

  • -fanalyzer-call-summaries โ€” ๐ŸŒธ 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. If it's enabled, call summaries only get used for functions with more than one call site, and that are sufficiently complicated (as per --param analyzer-min-snodes-for-call-summary=value).
  • -fanalyzer-checker=name โ€” ๐ŸŽฏ Restricts the analyzer to run just the checker you name, and enables it. Some checkers are disabled by default (even with -fanalyzer), like the "taint" checker that implements -Wanalyzer-tainted-array-index. You need this option to turn them on.
  • -fanalyzer-fine-grained โ€” ๐Ÿ”ฌ This one is for analyzer developers. Internally, the analyzer builds an "exploded graph" that combines control flow graphs with data flow information. By default, an edge in this graph can contain the effects of a run of multiple statements within a basic block. With -fanalyzer-fine-grained, each statement gets its own edge.
  • -fanalyzer-show-duplicate-count โ€” ๐Ÿงฎ Also for analyzer developers. If multiple diagnostics have been detected as duplicates of each other, this emits a note when reporting the best diagnostic, giving the number of additional diagnostics that were suppressed by the deduplication logic.
  • -fno-analyzer-state-merge โ€” ๐Ÿซ  For analyzer developers, again. By default the analyzer tries to simplify things by merging sufficiently similar states at each program point as it builds its "exploded graph". With -fno-analyzer-state-merge, that merging gets suppressed, which is handy for debugging state-handling issues.
  • -fno-analyzer-state-purge โ€” ๐Ÿงน Developer territory. By default, the analyzer simplifies analysis by purging aspects of state at a program point that seem no longer relevant, e.g. the values of locals that aren't accessed later in the function and that aren't relevant to leak analysis. With -fno-analyzer-state-purge, that purging gets suppressed, for debugging state-handling issues.
  • -fanalyzer-transitivity โ€” ๐Ÿ”— Turns on transitivity of constraints within the analyzer.
  • -fanalyzer-verbose-edges โ€” ๐Ÿ“œ For analyzer developers. It enables more verbose, lower-level detail in the descriptions of control flow within diagnostic paths.
  • -fanalyzer-verbose-state-changes โ€” ๐Ÿ“œ Also for analyzer developers. It enables more verbose, lower-level detail in the descriptions of events relating to state machines within diagnostic paths.
  • -fanalyzer-verbosity=level โ€” ๐ŸŽš๏ธ This controls how complex the control flow paths are that get emitted for analyzer diagnostics. The level can be one of:
    • 0 โ€” At this level, interprocedural call and return events get displayed, along with the most pertinent state-change events relating to a diagnostic. For example, for a double-"free" diagnostic, both calls to "free" will be shown.
    • 1 โ€” Same as the previous level, but also shows events for the entry to each function.
    • 2 โ€” Same as the previous level, but also shows events relating to control flow that are significant to triggering the issue (e.g. "true path taken" at a conditional). This level is the default ๐Ÿ‘‘
    • 3 โ€” Same as the previous level, but shows all control flow events, not just the significant ones.
    • 4 โ€” For analyzer developers. It adds various other events intended for debugging the analyzer ๐Ÿงช
  • -fdump-analyzer โ€” ๐Ÿ—‚๏ธ Dumps internal details about what the analyzer is doing to file.analyzer.txt. This option is overridden by -fdump-analyzer-stderr.
  • -fdump-analyzer-stderr โ€” ๐Ÿ–ฅ๏ธ Dumps internal details about what the analyzer is doing to stderr. This option overrides -fdump-analyzer.
  • -fdump-analyzer-callgraph โ€” ๐Ÿ•ธ๏ธ Dumps a representation of the call graph, suitable for viewing with GraphViz, to file.callgraph.dot.
  • -fdump-analyzer-exploded-graph โ€” ๐ŸŽจ Dumps a representation of the "exploded graph", suitable for viewing with GraphViz, to file.eg.dot. Nodes are color-coded based on state-machine states to emphasize state changes.
  • -fdump-analyzer-exploded-nodes โ€” ๐Ÿ“ Emits diagnostics showing where nodes in the "exploded graph" sit in relation to the program source.
  • -fdump-analyzer-exploded-nodes-2 โ€” ๐Ÿ“ Dumps a textual representation of the "exploded graph" to file.eg.txt.
  • -fdump-analyzer-exploded-nodes-3 โ€” ๐Ÿ“š Dumps a textual representation of the "exploded graph" to one dump file per node, named file.eg-id.txt. Heads up, this is typically a large number of dump files ๐Ÿ™ˆ
  • -fdump-analyzer-state-purge โ€” ๐Ÿงพ As per -fdump-analyzer-supergraph, this dumps a representation of the "supergraph" suitable for viewing with GraphViz, but annotates the graph with information on what state will be purged at each node. The graph is written to file.state-purge.dot.
  • -fdump-analyzer-supergraph โ€” ๐ŸŒ Dumps representations of the "supergraph" suitable for viewing with GraphViz to file.supergraph.dot and 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 contains annotations showing nodes in the "exploded graph" and the diagnostics associated with them.

๐Ÿ› Options for Debugging Your Program ๐Ÿ›

To tell GCC to emit extra information for a debugger, in almost all cases you only need to add -g to your other options ๐ŸŽ€

GCC lets you use -g with -O. Fair warning, though: the shortcuts taken by optimized code can be a little surprising. Some variables you declared may not exist at all, flow of control may briefly move somewhere you didn't expect, some statements may not be executed because they compute constant results or their values are already at hand, and some statements may execute in different places because they've been moved out of loops. Still, it's possible to debug optimized output, which makes it reasonable to use the optimizer for programs that might have bugs โœจ

If you're not using some other optimization option, consider using -Og with -g. With no -O option at all, some compiler passes that collect information 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 enables extra debugging information that only GDB can use. That extra information makes debugging work better in GDB, but it probably makes other debuggers crash or refuse to read the program. If you want to control for certain whether the extra information gets generated, use -gstabs+, -gstabs, -gxcoff+, -gxcoff, or -gvms (see below).
  • -ggdb โ€” ๐Ÿ’œ Produces debugging information for GDB. This means using the most expressive format available (DWARF, stabs, or the native format if neither of those is supported), including GDB extensions if at all possible.
  • -gdwarf, -gdwarf-version โ€” ๐ŸŒˆ Produces debugging information in DWARF format (if that's supported). The value of version may be 2, 3, 4 or 5, and the default version for most targets is 4. DWARF Version 5 is only experimental, so proceed with a little caution ๐Ÿงช

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

Version 4 may require GDB 7.0 and -fvar-tracking-assignments for maximum benefit.

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) retain a reference to DWARF Version 2 in their names, but they apply to all currently-supported versions of DWARF.

  • -gstabs โ€” okay so this one makes debug info in stabs format (if your setup even supports it) but with no GDB extras ๐Ÿงš. It's the format DBX uses on most BSD systems. Heads up bestie: on MIPS, Alpha, and System V Release 4 systems, this makes stabs output that DBX can't read ๐Ÿ’€. On System V Release 4 you also need the GNU assembler.
  • -gstabs+ โ€” same stabs format (if supported), but now with GNU extensions that only the GNU debugger (GDB) understands ๐Ÿฆ‹. Heads up: other debuggers might crash or refuse to read your program ๐Ÿ˜ญ.
  • -gxcoff โ€” XCOFF format (if supported) ๐ŸŒธ, the one DBX uses on IBM RS/6000 systems.
  • -gxcoff+ โ€” XCOFF format (if supported) with GNU extensions that only GDB gets ๐Ÿ”ฅ. Other debuggers may crash or refuse to read it, and assemblers that aren't the GNU assembler (GAS) might throw an error ๐Ÿ™ˆ.
  • -gvms โ€” Alpha/VMS debug format (if supported) ๐Ÿ’œ. This is the one DEBUG uses on Alpha/VMS systems.
  • -glevel, -ggdblevel, -gstabslevel, -gxcofflevel, -gvmslevel โ€” ask for debug info and choose how much with level โœจ. The default level is 2.
    • Level 0 gives zero debug info, so -g0 negates -g ๐Ÿ™….
    • Level 1 is minimal, just enough for backtraces in parts of your program you don't plan to debug ๐Ÿชต. It includes function and external variable descriptions plus line number tables, but no info about local variables.
    • Level 3 adds extra goodies, like all the macro definitions in your program ๐ŸŽ€. Some debuggers can expand macros when you use -g3.
    • If you stack up multiple -g options, with or without level numbers, the last one wins ๐Ÿ‘‘.
    • -gdwarf doesn't accept a stuck-on level, so it doesn't get mixed up with -gdwarf-level. Use an extra -glevel option to change the debug level for DWARF instead ๐Ÿงฉ.
  • -fno-eliminate-unused-debug-symbols โ€” by default, no debug info gets made for symbols that never actually get used ๐Ÿ™ˆ. Use this if you want debug info for all symbols ๐Ÿ’–.
  • -femit-class-debug-always โ€” instead of emitting debug info for a C++ class in only one object file, emit it in every object file that uses the class ๐Ÿง. Only reach for this with debuggers that can't handle the normal way GCC emits class debug info, because it can make the debug info up to as much as a factor of two bigger ๐Ÿ“ฆ.
  • -fno-merge-debug-strings โ€” tells the linker to not merge together identical strings in debug info across different object files ๐Ÿงต. Not every assembler or linker supports merging. Merging shrinks the debug info in the output file but makes link processing take longer โณ. Merging is enabled by default โœ….
  • -fdebug-prefix-map=old=new โ€” when compiling files living in directory old, debug info describes them as if they lived in directory new instead ๐Ÿ—บ๏ธ. This is handy for swapping a build-time path for an install-time path. You can also turn an absolute path into a relative one by using . for new. This can give more reproducible builds, which are location independent ๐ŸŒˆ, but you might need an extra command to tell GDB where to find the source files. See also -ffile-prefix-map.
  • -fvar-tracking โ€” runs the variable tracking pass, which figures out where variables are stored at each position in the code ๐Ÿ”. Better debug info gets generated from that (if your debug info format supports it). It's enabled by default when compiling with optimization (-Os, -O, -O2, ...), with debug info (-g), and when the debug info 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 ๐Ÿช„, 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 thrown away at the end. By default this flag is enabled together with -fvar-tracking, except when selective scheduling is enabled.
  • -gsplit-dwarf โ€” separates as much DWARF debug info as possible into its own output file with the extension .dwo ๐Ÿ“‚. This lets the build system avoid linking files that have debug info. To be useful, you'll need a debugger that can read .dwo files ๐Ÿซถ.
  • -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" sections in a format that's suitable for converting into a GDB index ๐Ÿ“. It's 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 go into their own ".debug_types" section instead of being part of ".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" sections yet, and on some objects ".debug_types" makes the debug info larger instead of smaller ๐Ÿ˜ญ.
  • -grecord-gcc-switches, -gno-record-gcc-switches โ€” this one tacks the command-line options used to invoke the compiler (the ones that may affect code generation) onto the DW_AT_producer attribute in DWARF debug info ๐Ÿ“. The options get concatenated 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 selected with -gdwarf-version ๐Ÿšซ. On most targets, 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 ๐Ÿ› ๏ธ. The compiler may then use them so the assembler generates DWARF2+ line number tables. This is usually desirable, because assembler-generated line number tables are a lot more compact than the ones the compiler can make itself ๐Ÿค. This option is enabled by default if the assembler was found to support those directives at GCC configure time.
  • -gno-as-loc-support โ€” forces GCC to generate DWARF2+ line number tables internally, if DWARF2+ line number tables are going to be generated ๐Ÿง .
  • -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 GCC's configure step found the assembler supports 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 information into DWARF debug info, not 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 ๐Ÿšฉ, and keep them roughly in place throughout compilation. Those markers guide the output of "is_stmt" markers in the line number table. This is enabled by default when compiling with optimization (-Os, -O, -O2, ...) and outputting DWARF 2 debug info at the normal level ๐ŸŒŸ.
  • -gvariable-location-views, -gvariable-location-views=incompat5, -gno-variable-location-views โ€” augments variable location lists with progressive view numbers implied from the line number table ๐Ÿ”ญ. This lets debug info consumers inspect state at certain points of the program, even if no instructions tied to those source locations exist there ๐Ÿ•ต๏ธ. If the assembler lacks support for view numbers in line number tables, the compiler will emit the line number table, which makes them somewhat less compact ๐Ÿ“. The augmented line number tables and location lists are fully backward-compatible, so older consumers can 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.
Careful, bestie ๐Ÿšจ: if assembler support isn't available and -ginternal-reset-location-views isn't enabled, that will most certainly lead to silently mismatching location views ๐Ÿ˜ฑ.

There's a proposed representation for view numbers that is not backward compatible with the location list format introduced in DWARF 5. You can enable it with -gvariable-location-views=incompat5 ๐Ÿงช. This option may be removed in the future, and it's only provided as a reference implementation of the proposed representation.

Also a big warning ๐Ÿ™…: debug info consumers aren't expected to support this extended format, and they would be unable to decode location lists that use it.

Okay so the debug flags are next, bestie, and they get a little spicy ๐ŸŒธ

  • -ginternal-reset-location-views, -gno-internal-reset-location-views โ€” this one tries to figure out which location views can be left out of location view lists ๐Ÿฆ‹. It needs the compiler to have super accurate insn length estimates, and ngl that isn't always the case ๐Ÿ˜ญ. If the estimates are off and you're using an assembler that doesn't support location view lists, it can silently generate incorrect view lists ๐Ÿ™ˆ. The GNU assembler will flag any of these with a "view number mismatch" error. It only gets turned on for ports that define a reliable estimation function ๐Ÿ’….
  • -ginline-points, -gno-inline-points โ€” generates extended debug info for inlined functions โœจ. Location view tracking markers get inserted at inlined entry points, so address and view numbers can be computed and output in the debug info. You can enable this on its own without location views, and then the view numbers just won't be output ๐Ÿงš. It can only be enabled along with statement frontiers, though, and it's only on by default if location views are on.
  • -gz[=type] โ€” produces compressed debug sections in DWARF format, if that's supported ๐Ÿ—œ๏ธ. If you don't give a type, the default depends on what your assembler and linker can handle. The type can be none (don't compress debug sections), zlib (zlib compression in ELF gABI format), or zlib-gnu (zlib compression in traditional GNU format). If the linker can't write compressed debug sections, the option gets rejected ๐Ÿ’€. Otherwise, if the assembler doesn't support them, -gz is silently ignored when producing object files.
  • -femit-struct-debug-baseonly โ€” struct-like types only get debug info when the base name of the compilation source file matches the base name of the file where the struct is defined ๐ŸŽ€. This one seriously shrinks your debug info, but it can cost you a lot of type information for the debugger ๐Ÿ˜ฌ. If you want something less aggressive, check out -femit-struct-debug-reduced, and for more detailed control, look at -femit-struct-debug-detailed. Heads up: this only works with DWARF debug output.
  • -femit-struct-debug-reduced โ€” struct-like types only get debug info when the base name of the compilation source file matches the base name of the file where the type is defined, unless the struct is a template or defined in a system header ๐Ÿ’œ. It still shrinks debug info a lot, with some possible loss of type info for the debugger. For a more aggressive version, see -femit-struct-debug-baseonly, and for finer control, see -femit-struct-debug-detailed. This also works only with DWARF debug output.
  • -femit-struct-debug-detailed[=spec-list] โ€” lets you pick exactly which struct-like types get debug info ๐Ÿงšโ€โ™€๏ธ. The whole point is to cut down on duplicate struct debug info across different object files in the same program. It's a detailed version of -femit-struct-debug-reduced and -femit-struct-debug-baseonly, and honestly that covers most needs. A specification follows this syntax:
    • [dir:|ind:] โ€” the optional first word limits things to structs used directly (dir:) or used indirectly (ind:). A struct is used directly when it's the type of a variable or member. Indirect uses come through pointers to structs, meaning when using an incomplete struct is valid, the use is indirect. For example: struct one direct; struct two * indirect;
    • [ord:|gen:] โ€” the optional second word limits things to ordinary structs (ord:) or generic structs (gen:). Generic structs are a bit of a mouthful ๐Ÿ™ƒ. 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.
    • (any|sys|base|none) โ€” the third word picks which source files the structs should come from. none and any mean what you'd expect. base means the base of the name of the file where the type declaration appears has to match the base of the name of the main compilation file. So when compiling foo.c, debug info gets generated for types declared in that file and foo.h, but not other header files ๐Ÿ“. sys means those types satisfying base or declared in system or compiler headers.

You might need to experiment to find the best settings for your app ๐Ÿ”. The default is -femit-struct-debug-detailed=all. This option works only with DWARF debug output.

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

โšก Options That Control Optimization

Okay, this section is all about the optimization flags, and these are the ones that make your code go brrr ๐Ÿ”ฅ. These options control various sorts of optimizations.

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

Turning on optimization flags makes the compiler try to improve performance and/or code size, but at the expense of compilation time and possibly your ability to debug the program ๐Ÿ˜ญ. The compiler optimizes based on what it knows about the program. Compiling multiple files at once to a single output file lets the compiler use info gathered from all of the files when compiling each of them ๐Ÿง .

Not every optimization is controlled by a flag, so only the optimizations that have a flag are listed in this section ๐Ÿฆ‹.

Most optimizations are completely disabled at -O0, or if an -O level isn't set on the command line, even if you specify individual optimization flags. Similarly, -Og suppresses many optimization passes ๐Ÿ™…โ€โ™€๏ธ.

A slightly different set of optimizations may be enabled at each -O level depending on the target and how GCC was configured, so it might not match what's listed here ๐ŸŒธ. If you want the exact set for each level, invoke GCC with -Q --help=optimizers.

๐ŸŒธ -O and -O1

Optimize! Optimizing compilation takes somewhat more time, and a lot more memory for a large function ๐Ÿงš.

With -O, the compiler tries to reduce code size and execution time, without doing any optimizations that take a great deal of compilation time โœจ. -O turns on the following optimization flags:

-fauto-inc-dec -fbranch-count-reg -fcombine-stack-adjustments
-fcompare-elim -fcprop-registers -fdce -fdefer-pop -fdelayed-branch
-fdse -fforward-propagate -fguess-branch-probability -fif-conversion
-fif-conversion2 -finline-functions-called-once -fipa-profile
-fipa-pure-const -fipa-reference -fipa-reference-addressable
-fmerge-constants -fmove-loop-invariants -fomit-frame-pointer
-freorder-blocks -fshrink-wrap -fshrink-wrap-separate
-fsplit-wide-types -fssa-backprop -fssa-phiopt -ftree-bit-ccp
-ftree-ccp -ftree-ch -ftree-coalesce-vars -ftree-copy-prop
-ftree-dce -ftree-dominator-opts -ftree-dse -ftree-forwprop
-ftree-fre -ftree-phiprop -ftree-pta -ftree-scev-cprop -ftree-sink
-ftree-slsr -ftree-sra -ftree-ter -funit-at-a-time

๐ŸŒธ -O2

Optimize even more! ๐Ÿ’– GCC does nearly all supported optimizations that don't involve a space-speed tradeoff. Compared to -O, this option increases both compilation time and the performance of the generated code ๐Ÿš€.

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

-falign-functions  -falign-jumps -falign-labels  -falign-loops
-fcaller-saves -fcode-hoisting -fcrossjumping -fcse-follow-jumps
-fcse-skip-blocks -fdelete-null-pointer-checks -fdevirtualize
-fdevirtualize-speculatively -fexpensive-optimizations
-ffinite-loops -fgcse  -fgcse-lm -fhoist-adjacent-loads
-finline-functions -finline-small-functions -findirect-inlining
-fipa-bit-cp  -fipa-cp  -fipa-icf -fipa-ra  -fipa-sra  -fipa-vrp
-fisolate-erroneous-paths-dereference -flra-remat
-foptimize-sibling-calls -foptimize-strlen -fpartial-inlining
-fpeephole2 -freorder-blocks-algorithm=stc
-freorder-blocks-and-partition  -freorder-functions
-frerun-cse-after-loop -fschedule-insns  -fschedule-insns2
-fsched-interblock  -fsched-spec -fstore-merging -fstrict-aliasing
-fthread-jumps -ftree-builtin-call-dce -ftree-pre
-ftree-switch-conversion  -ftree-tail-merge -ftree-vrp
Bestie, please note the warning under -fgcse about invoking -O2 on programs that use computed gotos. It's giving danger ๐Ÿ’€.
NOTE: In Ubuntu 8.10 and later versions, -D_FORTIFY_SOURCE=2 is set by default, and it's activated when -O is set to 2 or higher. This enables extra compile-time and run-time checks for several libc functions ๐Ÿ›ก๏ธ. To disable it, specify either -U_FORTIFY_SOURCE or -D_FORTIFY_SOURCE=0.

๐ŸŒธ -O3

Optimize yet more! ๐Ÿ”ฅ -O3 turns on all optimizations specified by -O2 and also turns on the following optimization flags:

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

๐ŸŒธ -O0

Reduce compilation time and make debugging produce the expected results ๐ŸŽ€. This is the default ๐Ÿ‘‘.

๐ŸŒธ -Os

Optimize for size! ๐Ÿงธ -Os enables all -O2 optimizations except those that often increase code size:

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

Okay so this bit is giving code-size glow-up ๐Ÿงš It also turns on -finline-functions, tells the compiler to tune for code size instead of execution speed, and runs extra optimizations that shrink your binary โœจ

  • -Ofast โ€” Okay the spicy one ๐ŸŒถ๏ธ -Ofast throws strict standards compliance out the window ๐Ÿ’€ It enables all -O3 optimizations, plus optimizations that aren't valid for every standard-compliant program, so proceed with caution bestie ๐Ÿ˜ญ 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 debugging experience ๐Ÿฆ‹ -Og is the level of choice 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 information are disabled at -O0 ๐Ÿซถ

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

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

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


Okay, so -fflag options are the machine-independent flags ๐ŸŒธ Most of them come in positive and negative forms, and the negative form of -ffoo is -fno-foo. The list below only shows one form, the one you'll usually reach for. To get the other, just remove no- or add it ๐Ÿ’…

The following options control specific optimizations. They're either switched on by -O options or closely related to ones that are. Use these flags in the rare moments when you want to fine-tune which optimizations happen ๐Ÿ”

  • -fno-defer-pop โ€” For machines that have to pop arguments after a function call, pop them as soon as each function returns ๐Ÿงน At -O1 and higher, -fdefer-pop is the default. That lets the compiler stack up arguments across several function calls and pop them all in one go ๐Ÿฅž
  • -fforward-propagate โ€” Runs a forward propagation pass on RTL โœจ It tries to combine two instructions and checks whether the result can be simplified. If loop unrolling is active, two passes run, and the second one is scheduled after loop unrolling ๐Ÿฆ‹ Enabled by default at optimization levels -O, -O2, -O3, -Os.
  • -ffp-contract=style โ€” Controls floating-point expression contraction ๐Ÿงฎ
    • -ffp-contract=off disables it completely ๐Ÿ™…
    • -ffp-contract=fast enables it, like forming fused multiply-add operations, if the target has native support for them ๐Ÿš€
    • -ffp-contract=on enables it if the language standard allows. 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 that save, set up and restore the frame pointer, and on many targets it also frees up an extra register ๐ŸŒˆ

On some targets this flag does nothing, because the standard calling sequence always uses a frame pointer, so it can't be left out ๐Ÿ˜ญ

Heads up: -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 โ€” Doesn't expand any functions inline, except the ones marked with the always_inline attribute ๐Ÿ™…โ€โ™€๏ธ This is the default when not optimizing. Single functions can be exempted from inlining by marking them with the noinline attribute ๐ŸŽ€
  • -finline-small-functions โ€” Integrates functions into their callers when their body is smaller than the code for the function call itself, so the overall program gets smaller ๐Ÿ“‰ The compiler heuristically decides which functions are simple enough for this. It applies to all functions, even ones not declared inline ๐Ÿ’… Enabled at levels -O2, -O3, -Os.
  • -findirect-inlining โ€” Inlines indirect calls that are known at compile time thanks to earlier inlining ๐Ÿง  This only does anything when inlining is already on, via -finline-functions or -finline-small-functions ๐Ÿซถ Enabled at levels -O2, -O3, -Os.
  • -finline-functions โ€” Considers all functions for inlining, even ones not declared inline ๐Ÿ”ฅ The compiler heuristically decides which ones are worth integrating. If every call to a given function is integrated and the function is declared static, it normally isn't 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 that are called once for inlining into their caller, even if they aren't marked inline ๐ŸŽฏ If a call to a given function is 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 way cheaper and usually makes inlining faster on programs with huge chains of nested wrapper functions ๐Ÿ’– Enabled by default.
  • -fipa-sra โ€” Performs interprocedural scalar replacement of aggregates, removes unused parameters, and replaces parameters passed by reference with parameters passed by value ๐Ÿงฉ Enabled at levels -O2, -O3 and -Os.
  • -finline-limit=n โ€” By default GCC limits how big a function can be and still get 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. -finline-limit=n sets some of them like this:
    • max-inline-insns-single โ€” is set to n/2.
    • max-inline-insns-auto โ€” is set to n/2.

See below for documentation of the individual inlining parameters and their defaults ๐Ÿ“š

Note: there may be no value to -finline-limit that results in default behavior. ๐Ÿ™ƒ
Note: a pseudo instruction, in this context, is an abstract measurement of a function's size. It in no way represents a count of assembly instructions, so what it means could change from one release to another. โš ๏ธ
  • -fno-keep-inline-dllexport โ€” A more fine-grained version of -fkeep-inline-functions, which only applies to functions declared with the dllexport attribute or declspec ๐Ÿฆ‹
  • -fkeep-inline-functions โ€” In C, emits static functions declared inline into the object file, even if they've been inlined into all of their callers ๐Ÿซง This doesn't affect functions using the extern inline extension in GNU C90. In C++, it emits any and all inline functions into the object file ๐Ÿ’œ
  • -fkeep-static-functions โ€” Emits static functions into the object file, even if they're never used ๐Ÿ“ฆ
  • -fkeep-static-consts โ€” Emits variables declared static const when optimization isn't turned on, even if they aren't referenced ๐ŸŒท GCC enables this option by default. If you want the compiler to check whether a variable is referenced no matter whether optimization is on, use -fno-keep-static-consts ๐Ÿ™Œ
  • -fmerge-constants โ€” Tries to merge identical constants (string constants and floating-point constants) across compilation units ๐Ÿงฉ This is the default for optimized compilation if the assembler and linker support it. Use -fno-merge-constants to stop this behavior ๐Ÿ›‘ Enabled at levels -O, -O2, -O3, -Os.
  • -fmerge-all-constants โ€” Tries to merge identical constants and identical variables ๐Ÿงฌ This option implies -fmerge-constants. On top of that, it also considers things like constant initialized arrays or initialized constant variables with integral or floating-point types ๐ŸŒˆ
โš ๏ธ Danger zone: C and C++ require each variable, including multiple instances of the same variable in recursive calls, to have distinct locations. Using this option results in non-conforming behavior, so it's not conformant, bestie ๐Ÿ’€
  • -fmodulo-sched โ€” Performs swing modulo scheduling right before the first scheduling pass ๐ŸŒ€ It looks at the innermost loops and reorders their instructions by overlapping different iterations ๐ŸŽ 
  • -fmodulo-sched-allow-regmoves โ€” 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 only works when -fmodulo-sched is enabled. ๐Ÿ’œ
  • -fno-branch-count-reg โ€” Disables the pass that hunts for chances to use "decrement and branch" instructions on a count register, instead of sequences that decrement a register, compare it to zero, and then branch based on the result ๐Ÿ”ข This is only meaningful on architectures that support such instructions, which include x86, PowerPC, IA-64 and S/390 ๐Ÿ–ฅ๏ธ Heads up: -fno-branch-count-reg doesn't remove the decrement and branch instructions that other optimization passes introduced into the generated instruction stream ๐Ÿซถ

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

  • -fno-function-cse โ€” okay so this one turns OFF putting function addresses in registers ๐Ÿฆ‹ Instead, every instruction that calls a constant function spells out the function's address right there.

This makes the code less efficient ๐Ÿ˜ญ but some strange hacks that tweak the assembler output can get confused by the optimizations you get when this option isn't used, so it's there if you need it.

The default is -ffunction-cse ๐ŸŒธ

  • -fno-zero-initialized-in-bss โ€” if the target has a BSS section, GCC normally tosses variables that start out as zero into BSS, which can save space ๐Ÿงš

This option turns that behavior off, because some programs actually rely on variables living in the data section. Like, so the executable can find the beginning of that section, and/or make assumptions based on it ๐Ÿ™ˆ

The default is -fzero-initialized-in-bss.

  • -fthread-jumps โ€” this one checks whether a jump lands somewhere another comparison (one that the first comparison subsumes) is found ๐Ÿ‘€ If so, the first branch gets redirected to either the destination of the second branch or the spot right after it, depending on whether the condition is known to be true or false.

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

  • -fsplit-wide-types โ€” when a type takes up multiple registers, like "long long" on a 32-bit system, this splits the registers apart and allocates them independently. It 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 does nothing unless -fsplit-wide-types is turned on ๐Ÿซถ

This is the default on some targets.

  • -fcse-follow-jumps โ€” in common subexpression elimination (CSE), it scans through jump instructions when the jump's target isn't reached by any other path. For example, when CSE hits an "if" statement with an "else" clause, it follows the jump when the condition tested is false ๐Ÿฆ‹

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

  • -fcse-skip-blocks โ€” this is similar to -fcse-follow-jumps, but it makes CSE follow jumps that conditionally skip over blocks. When CSE hits a simple "if" statement with no else clause, -fcse-skip-blocks makes CSE follow the jump around the body of the "if" ๐Ÿ’…

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

  • -frerun-cse-after-loop โ€” re-runs common subexpression elimination after the loop optimizations are done ๐Ÿ”

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

  • -fgcse โ€” performs a global common subexpression elimination pass. This pass also does global constant and copy propagation โœจ
Note: When compiling a program using computed gotos, a GCC extension, you may get better run-time performance if you disable the global common subexpression elimination pass by adding -fno-gcse to the command line. ๐Ÿ’€

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

  • -fgcse-lm โ€” when -fgcse-lm is enabled, global CSE tries to move loads that are only killed by stores into themselves. This lets a loop containing a load/store sequence become a load outside the loop, plus a copy/store inside the loop ๐ŸŒˆ

Enabled by default when -fgcse is enabled.

  • -fgcse-sm โ€” when -fgcse-sm is enabled, a store motion pass runs after global CSE. It tries to move stores out of loops. Used together with -fgcse-lm, loops containing a load/store sequence can become a load before the loop and a store after the loop ๐Ÿง 

Not enabled at any optimization level.

  • -fgcse-las โ€” when -fgcse-las is enabled, the global CSE pass wipes out redundant loads that come after stores to the same memory location, both partial and full redundancies ๐Ÿงน

Not enabled at any optimization level.

  • -fgcse-after-reload โ€” when -fgcse-after-reload is enabled, a redundant load elimination pass runs after reload. Its whole purpose is to clean up redundant spilling ๐Ÿงฝ

Enabled by -fprofile-use and -fauto-profile.

  • -faggressive-loop-optimizations โ€” this tells the loop optimizer to use language constraints to figure out bounds for the number of iterations of a loop ๐Ÿ”ฅ It assumes that loop code doesn't invoke undefined behavior, by for example causing signed integer overflows or out-of-bound array accesses. Those bounds guide loop unrolling and peeling and loop exit test optimizations.

This option is enabled by default.

  • -funconstrained-commons โ€” tells the compiler that variables declared in common blocks (e.g. Fortran) may later get overridden with longer trailing arrays. This stops certain optimizations that depend on knowing the array bounds ๐Ÿ™…โ€โ™€๏ธ
  • -fcrossjumping โ€” performs cross-jumping. This unifies equivalent code and saves code size. The resulting code may or may not perform better than without cross-jumping ๐Ÿคทโ€โ™€๏ธ

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

  • -fauto-inc-dec โ€” combines increments or decrements of addresses with memory accesses. This pass is always skipped on architectures that don't have instructions to support this ๐Ÿƒโ€โ™€๏ธ

Enabled by default at -O and higher on architectures that support this.

  • -fdce โ€” performs dead code elimination (DCE) on RTL ๐Ÿ—‘๏ธ

Enabled by default at -O and higher.

  • -fdse โ€” performs dead store elimination (DSE) on RTL ๐Ÿ—‘๏ธ

Enabled by default at -O and higher.

  • -fif-conversion โ€” attempts to transform conditional jumps into branch-less equivalents. This includes conditional moves, min, max, set flags and abs instructions, and some tricks doable 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 available) to transform conditional jumps into branch-less equivalents ๐Ÿช„

Enabled at levels -O, -O2, -O3, -Os, but not with -Og.

  • -fdeclone-ctor-dtor โ€” okay, the C++ ABI requires multiple entry points for constructors and destructors: one for a base subobject, one for a complete object, and one for a virtual destructor that calls operator delete afterwards ๐Ÿงฉ For a hierarchy with virtual bases, the base and complete variants are clones, which means two copies of the function. With this option, those variants become thunks that call a common implementation.

Enabled by -Os.

  • -fdelete-null-pointer-checks โ€” assumes that programs can't safely dereference null pointers, and that no code or data element lives at address zero ๐Ÿ™ƒ This option enables simple constant folding optimizations at all optimization levels. On top of that, other optimization passes in GCC use this flag to control global dataflow analyses that eliminate useless checks for null pointers. Those analyses assume that a memory access to address zero always results in a trap, so if a pointer is checked after it has already been dereferenced, it can't be null.
Note however that in some environments this assumption is not true. Use -fno-delete-null-pointer-checks to disable this optimization for programs that depend on that behavior. โš ๏ธ

This option is enabled by default on most targets. On Nios II ELF, it defaults to off. On AVR, CR16, and MSP430, this option is completely disabled.

Passes that use the dataflow information are enabled independently at different optimization levels.

  • -fdevirtualize โ€” attempts to convert calls to virtual functions into direct calls ๐Ÿ“ž This is done both within a procedure and interprocedurally, as part of indirect inlining (-findirect-inlining) and interprocedural constant propagation (-fipa-cp).

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

  • -fdevirtualize-speculatively โ€” attempts to convert calls to virtual functions into speculative direct calls ๐ŸŽฏ Based on the analysis of the type inheritance graph, it figures out the set of likely targets for a given call. If the set is small, preferably of size 1, the call becomes a conditional that decides between a direct and an indirect call. The speculative calls enable more optimizations, like inlining. When they seem useless after further optimization, they get converted back into their original form.
  • -fdevirtualize-at-ltrans โ€” streams the extra information needed for aggressive devirtualization when running the link-time optimizer in local transformation mode ๐Ÿ“ฆ This enables more devirtualization, but it significantly increases the size of the streamed data. For this reason it's disabled by default.
  • -fexpensive-optimizations โ€” performs a bunch of minor optimizations that are relatively expensive ๐Ÿ’ธ

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

  • -free โ€” attempts to remove redundant extension instructions ๐Ÿงน This is especially helpful for the x86-64 architecture, which implicitly zero-extends in 64-bit registers after writing to their lower 32-bit half.

Enabled for Alpha, AArch64 and x86 at levels -O2, -O3, -Os.

  • -fno-lifetime-dse โ€” in C++, the value of an object is only affected by changes within its lifetime. When the constructor begins, the object has an indeterminate value, and any changes during the object's lifetime are dead once it's destroyed โณ Normally dead store elimination takes advantage of this. If your code relies on the value of the object storage persisting beyond the object's lifetime, you can use this flag to disable the optimization.

To keep stores made before the constructor starts (e.g. because your operator new clears the object storage) but still treat the object as dead after the destructor, you can use -flifetime-dse=1. The default behavior can be explicitly selected with -flifetime-dse=2. -flifetime-dse=0 is equivalent to -fno-lifetime-dse ๐ŸŽ€

  • -flive-range-shrinkage โ€” attempts to decrease register pressure through register live range shrinkage ๐ŸŒท This is helpful for fast processors with small or moderate-size register sets.
  • -fira-algorithm=algorithm โ€” okay so this lets you pick the coloring algorithm for the integrated register allocator ๐ŸŽจ. priority gives you Chow's priority coloring, and CB gives you Chaitin-Briggs coloring. Chaitin-Briggs isn't built for every architecture, but on the targets that do support it, it's the default because it makes better code ๐Ÿ’…
  • -fira-region=region โ€” pick which regions the integrated register allocator uses ๐Ÿฆ‹ The region argument should be one of these:
    • all โ€” every loop becomes a register allocation region. This can give the best results on machines with a small and/or irregular register set ๐Ÿ‘‘
    • mixed โ€” every loop except the ones with small register pressure becomes a region. This is usually the best pick for most cases and most architectures, and it's on by default when you compile with optimization for speed (-O, -O2, ...) โœจ
    • one โ€” all functions get treated as a single region. This typically gives the smallest code size, and it's the default for -Os or -O0 ๐Ÿงš
  • -fira-hoist-pressure โ€” use IRA to check register pressure during the code hoisting pass when deciding whether to hoist expressions ๐ŸŒธ This usually gives you smaller code, but it can slow the compiler down ๐Ÿข

This option is enabled at level -Os for all targets.

  • -fira-loop-pressure โ€” use IRA to check register pressure inside loops when deciding whether to move loop invariants ๐Ÿ’œ This usually gives faster and smaller code on machines with big 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 โ€” turns off sharing of stack slots used to save call-used hard registers that live through a call ๐Ÿ™… Every hard register gets its own stack slot, so function stack frames end up bigger.
  • -fno-ira-share-spill-slots โ€” turns off sharing of stack slots allocated for pseudo-registers ๐Ÿซถ Every pseudo-register that doesn't get a hard register gets its own stack slot, so function stack frames end up bigger.

  • -flra-remat โ€” turns on CFG-sensitive rematerialization in LRA ๐Ÿ”ฅ Instead of reloading the values of spilled pseudos, LRA tries to rematerialize (recalculate) them when that's profitable.

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

  • -fdelayed-branch โ€” if the target machine supports it, the compiler tries to reorder instructions so it can use the instruction slots available after delayed branch instructions ๐ŸŽ€

Enabled at levels -O, -O2, -O3, -Os, but not at -Og.

  • -fschedule-insns โ€” if the target machine supports it, the compiler reorders instructions to dodge execution stalls caused by data that isn't ready yet โณ This helps machines with slow floating point or memory load instructions, since other instructions can get issued while the load or floating-point result is still on its way.

Enabled at levels -O2, -O3.

  • -fschedule-insns2 โ€” basically the same vibe as -fschedule-insns, but it asks for an extra round of instruction scheduling after register allocation is done ๐ŸŒˆ This is especially useful on machines with a relatively small number of registers where memory load instructions take more than one cycle.

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

  • -fno-sched-interblock โ€” turns off instruction scheduling across basic blocks ๐Ÿšซ This is normally on when scheduling happens before register allocation, i.e. with -fschedule-insns or at -O2 or higher.
  • -fno-sched-spec โ€” turns off speculative motion of non-load instructions ๐Ÿ™ˆ This is normally on when scheduling happens before register allocation, i.e. with -fschedule-insns or at -O2 or higher.
  • -fsched-pressure โ€” enables register pressure sensitive instruction scheduling before register allocation ๐Ÿ’… This only makes sense when pre-allocation scheduling is turned on, i.e. with -fschedule-insns or at -O2 or higher. It can improve the generated code and shrink its size by stopping register pressure from climbing above the number of available hard registers, which means fewer spills later in register allocation.
  • -fsched-spec-load โ€” allows speculative motion of some load instructions ๐Ÿ“ This only makes sense when scheduling happens before register allocation, i.e. with -fschedule-insns or at -O2 or higher.
  • -fsched-spec-load-dangerous โ€” allows speculative motion of more load instructions ๐Ÿ’€ This only makes sense when scheduling happens before register allocation, i.e. with -fschedule-insns or at -O2 or higher.
  • -fsched-stalled-insns, -fsched-stalled-insns=n โ€” controls how many instructions (if any) can be moved early from the queue of stalled instructions into the ready list during the second scheduling pass โญ
    • -fno-sched-stalled-insns means no instructions get moved early.
    • -fsched-stalled-insns=0 means there's no limit on how many queued instructions can be moved early.
    • -fsched-stalled-insns without a value is the same as -fsched-stalled-insns=1.
  • -fsched-stalled-insns-dep, -fsched-stalled-insns-dep=n โ€” defines how many instruction groups (cycles) get checked for a dependency on a stalled instruction that's a candidate for being moved early ๐Ÿ” This only has an effect during the second scheduling pass, and only if -fsched-stalled-insns is used.
    • -fno-sched-stalled-insns-dep is the same as -fsched-stalled-insns-dep=0.
    • -fsched-stalled-insns-dep without a value is the same as -fsched-stalled-insns-dep=1.
  • -fsched2-use-superblocks โ€” when scheduling after register allocation, use superblock scheduling ๐Ÿš€ This allows motion across basic block boundaries, which can give faster schedules.
โš ๏ธ This option is experimental! Not all machine descriptions GCC uses model the CPU closely enough to avoid unreliable results from the algorithm, so be careful bestie ๐Ÿซฃ

This only makes sense when scheduling after register allocation, i.e. 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, i.e. 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, i.e. with -fschedule-insns or -fschedule-insns2 or at -O2 or higher.
  • -fsched-spec-insn-heuristic โ€” enables the speculative instruction heuristic in the scheduler ๐ŸŽฏ This one favors speculative instructions with greater dependency weakness. It's on by default when scheduling is enabled, i.e. with -fschedule-insns or -fschedule-insns2 or at -O2 or higher.
  • -fsched-rank-heuristic โ€” enables the rank heuristic in the scheduler ๐Ÿ‘‘ This one favors the instruction that belongs to a basic block with greater size or frequency. It's on by default when scheduling is enabled, i.e. with -fschedule-insns or -fschedule-insns2 or at -O2 or higher.
  • -fsched-last-insn-heuristic โ€” enables the last-instruction heuristic in the scheduler ๐Ÿซง This one favors the instruction that depends less on the last instruction scheduled. It's on by default when scheduling is enabled, i.e. with -fschedule-insns or -fschedule-insns2 or at -O2 or higher.
  • -fsched-dep-count-heuristic โ€” enables the dependent-count heuristic in the scheduler ๐Ÿ“ˆ This one favors the instruction that has more instructions depending on it. It's on by default when scheduling is enabled, i.e. with -fschedule-insns or -fschedule-insns2 or at -O2 or higher.
  • -freschedule-modulo-scheduled-loops โ€” modulo scheduling happens before traditional scheduling ๐Ÿ” If a loop is 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 ๐Ÿงฉ Selective scheduling 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, also pipeline the outer loops too ๐Ÿช† This option has no effect unless -fsel-sched-pipelining is turned on.

  • -fsemantic-interposition โ€” okay, this one is a whole vibe ๐ŸŒท Some object formats, like ELF, let the dynamic linker interpose symbols. That means that for symbols exported from the DSO, the compiler can't do interprocedural propagation, inlining, or other optimizations, because the function or variable might get swapped out for something else. This is super useful for stuff like rewriting memory allocation functions with a debugging implementation, but it's pricey 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 for functions explicitly declared inline, where interposition is never allowed to change semantics, and it has no effect for symbols explicitly declared weak.

  • -fshrink-wrap โ€” emits function prologues only before the parts of the function that actually need them, instead of at the very top of the function ๐ŸŽ This flag is enabled by default at -O and higher.
  • -fshrink-wrap-separate โ€” shrink-wraps the prologue and epilogue parts separately, so each part only runs when it's needed ๐Ÿ’– This option is on by default, but it has no effect unless -fshrink-wrap is also turned on and the target supports this.
  • -fcaller-saves โ€” okay so this one lets GCC park values in registers that function calls would normally trash ๐Ÿ’…, and then it sneaks in extra instructions to save and restore those registers around the calls. It only does this when it seems to give better code, so no pointless drama โœจ

This option is always on by default on certain machines, usually the ones with no call-preserved registers to use instead ๐ŸŒธ

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

  • -fcombine-stack-adjustments โ€” it keeps track of stack adjustments (pushes and pops) plus stack memory references, then tries to smoosh them together into something neater ๐Ÿงš

Enabled by default at -O1 and higher.

  • -fipa-ra โ€” this one lets GCC use the caller-save registers for allocation as long as none of the functions being called are using them ๐Ÿฆ‹. That means no need to save and restore them around calls.

This only works if the called functions are in the same compilation unit as the current function and they get compiled first ๐Ÿ’œ

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

  • -fconserve-stack โ€” the vibe here is "save every byte" ๐ŸŽ€. GCC tries to use less stack space, even if the program ends up running 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 โ€” code hoisting tries to move the evaluation of expressions that run on all paths to the function exit as early as possible โญ It's especially useful as a code size optimization, but it often helps code speed too ๐Ÿ’–

This flag is enabled by default at -O2 and higher.

  • -ftree-pre โ€” performs partial redundancy elimination (PRE) on trees ๐Ÿงš Enabled by default at -O2 and -O3.
  • -ftree-partial-pre โ€” makes partial redundancy elimination (PRE) more aggressive ๐Ÿ˜ค Enabled by default at -O3.
  • -ftree-forwprop โ€” performs forward propagation on trees ๐Ÿฆ‹ Enabled by default at -O and higher.
  • -ftree-fre โ€” performs full redundancy elimination (FRE) on trees ๐Ÿ’… The difference between FRE and PRE is that FRE only considers expressions computed on all paths leading to the redundant computation. This analysis is faster than PRE, though it exposes fewer redundancies.

Enabled by default at -O and higher.

  • -ftree-phiprop โ€” performs hoisting of loads from conditional pointers on trees ๐Ÿ“ This pass is enabled by default at -O and higher.
  • -fhoist-adjacent-loads โ€” speculatively hoists loads from both branches of an if-then-else, but only if the loads come from adjacent locations in the same structure and the target architecture has a conditional move instruction ๐Ÿซถ

This flag is enabled by default at -O2 and higher.

  • -ftree-copy-prop โ€” performs copy propagation on trees, which basically means it cleans up unnecessary copy operations ๐Ÿงน This pass is enabled by default at -O and higher.
  • -fipa-pure-const โ€” discovers which functions are pure or constant ๐Ÿ”ฎ Enabled by default at -O and higher.
  • -fipa-reference โ€” discovers which static variables don't escape the compilation unit ๐Ÿ™ˆ Enabled by default at -O and higher.
  • -fipa-reference-addressable โ€” discovers read-only, write-only, and non-addressable static variables ๐ŸŒธ Enabled by default at -O and higher.
  • -fipa-stack-alignment โ€” reduces stack alignment on call sites where possible ๐ŸŽ€ Enabled by default.
  • -fipa-pta โ€” performs interprocedural pointer analysis and interprocedural modification and reference analysis ๐Ÿง 
This one can cause excessive memory and compile-time usage on large compilation units, so be careful, bestie ๐Ÿ’€

It is not enabled by default at any optimization level.

  • -fipa-profile โ€” performs interprocedural profile propagation ๐ŸŒˆ Functions called only from cold functions get marked as cold. Functions executed once (such as "cold", "noreturn", static constructors or destructors) are also identified. Cold functions and loop-less parts of functions executed once are then optimized for size ๐Ÿ“ฆ

Enabled by default at -O and higher.

  • -fipa-cp โ€” performs interprocedural constant propagation ๐Ÿ‘‘ This one analyzes the program to figure out when values passed to functions are constants, and then optimizes accordingly. It can substantially increase performance if the application has constants passed to functions ๐Ÿ”ฅ

This flag is enabled by default at -O2, -Os, and -O3. It is also enabled by -fprofile-use and -fauto-profile.

  • -fipa-cp-clone โ€” performs function cloning to make interprocedural constant propagation stronger โœจ When enabled, interprocedural constant propagation clones a function 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) ๐Ÿ“ˆ

This flag is enabled by default at -O3. It is also enabled by -fprofile-use and -fauto-profile.

  • -fipa-bit-cp โ€” when enabled, performs interprocedural bitwise constant propagation ๐Ÿงฉ This flag is enabled by default at -O2 and by -fprofile-use and -fauto-profile. It requires that -fipa-cp is enabled.
  • -fipa-vrp โ€” when enabled, performs interprocedural propagation of value ranges ๐Ÿ“ This flag is enabled by default at -O2. It requires that -fipa-cp is enabled.
  • -fipa-icf โ€” performs Identical Code Folding for functions and read-only variables ๐Ÿชž This shrinks code size, but it may disturb unwind stacks by replacing a function with an equivalent one that has a different name ๐Ÿ˜ต The optimization works more effectively with link-time optimization enabled.

Although the behavior is similar to the Gold Linker's ICF optimization, GCC ICF works on different levels, so the optimizations aren't the same. There are equivalences that only GCC finds, and equivalences that only Gold finds ๐Ÿค“

This flag is enabled by default at -O2 and -Os.

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

Okay, so if the compiler's optimization uses a function's body (or info pulled from its 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 be patched too ๐Ÿซถ

The impacted functions are determined by the compiler's interprocedural optimizations. For example, a caller is impacted when a function gets inlined into it, when a function is cloned and its caller is changed to call the new clone, or when a function's pureness or constness info is extracted to optimize its direct or indirect callers.

Usually, the more IPA optimizations are enabled, the bigger the number of impacted functions for each function. To control that number and make the list of impacted functions easier to compute, IPA optimizations can be partially enabled at two different levels.

The level argument should be one of the following:

  • inline-clone โ€” only enables inlining and cloning optimizations, which includes inlining, cloning, interprocedural scalar replacement of aggregates, and partial inlining. As a result, when patching a function, all its callers and its clones' callers are impacted, so they need to be patched 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

  • inline-only-static โ€” only enables inlining of static functions. As a result, when patching a static function, all its callers are impacted and so need to be patched too ๐ŸŒท

In addition to all the flags that -flive-patching=inline-clone disables, -flive-patching=inline-only-static disables these extra optimization flags: -fipa-cp-clone -fipa-sra -fpartial-inlining -fipa-cp

When -flive-patching is specified without any value, the default value is inline-clone ๐Ÿง

This flag is disabled by default.

Note that -flive-patching is not supported with link-time optimization (-flto). Don't mix them, babe ๐Ÿ™…โ€โ™€๏ธ
  • -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 the erroneous or undefined behavior into a trap ๐Ÿชค

This flag is enabled by default at -O2 and higher, and it depends on -fdelete-null-pointer-checks also being enabled.

  • -fisolate-erroneous-paths-attribute โ€” detects paths that trigger erroneous or undefined behavior because a null value is used in a way forbidden by a "returns_nonnull" or "nonnull" attribute ๐Ÿšซ It isolates those paths from the main control flow and turns the statement with the erroneous or undefined behavior into a trap.

This is not currently enabled, but it may be enabled by -O2 in the future ๐Ÿ‘€

  • -ftree-sink โ€” performs forward store motion on trees ๐Ÿšš Enabled by default at -O and higher.
  • -ftree-bit-ccp โ€” performs sparse conditional bit constant propagation on trees and propagates pointer alignment information ๐Ÿ”ข This pass only operates on local scalar variables and is enabled by default at -O1 and higher, except for -Og. It requires that -ftree-ccp is enabled.
  • -ftree-ccp โ€” performs sparse conditional constant propagation (CCP) on trees ๐ŸŒŸ This pass only operates on local scalar variables and is enabled by default at -O and higher.
  • -fssa-backprop โ€” propagates information about uses of a value up the definition chain so the definitions can be simplified ๐Ÿช„ For example, this pass strips sign operations if the sign of a value never matters. Enabled by default at -O and higher.
  • -fssa-phiopt โ€” okay so this one does pattern matching on SSA PHI nodes to tidy up conditional code โœจ It's on by default at -O1 and higher, except for -Og ๐ŸŒธ
  • -ftree-switch-conversion โ€” it turns simple initializations inside a switch into initializations from a scalar array ๐ŸŽ€ On by default at -O2 and higher ๐Ÿ’–
  • -ftree-tail-merge โ€” this one hunts for identical code sequences ๐Ÿ‘ฏ When it finds a match, it replaces one copy with a jump to the other. This is called tail merging or cross jumping ๐Ÿฆ‹ On by default at -O2 and higher. You can cap how long this pass runs with the max-tail-merge-comparisons parameter and the max-tail-merge-iterations parameter โฑ๏ธ
  • -ftree-dce โ€” dead code elimination (DCE) on trees, aka getting rid of code that never actually does anything ๐Ÿ’€ 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 โ€” this assumes a loop with an exit will eventually take the exit and won't loop forever ๐Ÿ” That lets the compiler remove loops that have no side effects, without treating endless looping as one ๐Ÿ‘‘ This option is on by default at -O2 for C++ with -std=c++11 or higher ๐ŸŒˆ
  • -ftree-dominator-opts โ€” a bunch of simple scalar cleanups โœจ That's constant/copy propagation, redundancy elimination, range propagation and expression simplification, all 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 โ€” dead store elimination (DSE) on trees ๐Ÿ’… A dead store is a store into a memory location that gets overwritten by another store later, with no loads in between ๐Ÿ˜ญ The earlier store can be deleted ๐Ÿ—‘๏ธ On by default at -O and higher.
  • -ftree-ch โ€” loop header copying on trees ๐Ÿš€ It's beneficial because it boosts code motion optimizations, and it saves one jump too. On by default at -O and higher, but it's not enabled for -Os, since it usually increases code size ๐Ÿ™…
  • -ftree-loop-optimize โ€” loop optimizations on trees ๐Ÿ”„ On by default at -O and higher.
  • -ftree-loop-linear, -floop-strip-mine, -floop-block โ€” loop nest optimizations, same as -floop-nest-optimize ๐Ÿงต To use this transformation, GCC has to be configured with --with-isl so the Graphite loop transformation infrastructure is enabled โš™๏ธ
  • -fgraphite-identity โ€” enables the identity transformation for graphite ๐Ÿชž For every SCoP, we generate the polyhedral representation and transform it back to gimple. With this one you can check the costs or benefits of the GIMPLE -> GRAPHITE -> GIMPLE transformation ๐Ÿ” Some minimal optimizations also happen in the code generator isl, like index splitting and dead code elimination in loops ๐Ÿง 
  • -floop-nest-optimize โ€” turns on the isl based loop nest optimizer ๐Ÿงฉ It's a generic loop nest optimizer based on the Pluto optimization algorithms, and it calculates a loop structure that's optimized for data-locality and parallelism ๐ŸŒ This option is experimental โš ๏ธ
  • -floop-parallelize-all โ€” uses Graphite data dependence analysis to identify loops that can be parallelized ๐Ÿงต It parallelizes all the loops that can be analyzed as not containing loop carried dependences, without checking whether it's actually profitable to do so ๐Ÿซ 
  • -ftree-coalesce-vars โ€” when transforming the program out of SSA form, this tries to cut down on copying by coalescing versions of different user-defined variables, not just compiler temporaries ๐Ÿงฉ In the negated form, this flag prevents SSA coalescing of user variables ๐Ÿ™… It's on by default if optimization is enabled, and does very little otherwise ๐Ÿ’ค
Heads up, bestie: this may severely limit your ability to debug an optimized program compiled with -fno-var-tracking-assignments ๐Ÿ˜ญ
  • -ftree-loop-if-convert โ€” tries to transform conditional jumps in the innermost loops into branch-less equivalents ๐ŸŒ€ The goal is to remove control flow from the innermost loops so the vectorization pass can handle them better ๐Ÿ’ช It's enabled by default if vectorization is enabled ๐ŸŒธ
  • -ftree-loop-distribution โ€” performs loop distribution ๐Ÿฐ This can improve cache performance on big loop bodies and open the door for further loop optimizations, like parallelization or vectorization ๐Ÿšช Check out this glow-up, where the loop:
DO I = 1, N
  A(I) = B(I) + C
  D(I) = E(I) * F
ENDDO

gets transformed into:

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

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

  • -ftree-loop-distribute-patterns โ€” performs loop distribution of patterns that can be code generated with calls to a library ๐Ÿ“š This flag is enabled by default at -O2 and higher, and by -fprofile-use and -fauto-profile ๐Ÿซถ

This pass distributes the initialization loops and generates a call to memset zero ๐Ÿงธ For example, 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's 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 let vectorization and other loop optimizations take place ๐Ÿ’… For example, this loop:
for (int i = 0; i < N; i++)
  for (int j = 0; j < N; j++)
    for (int k = 0; k < N; k++)
      c[i][j] = c[i][j] + a[i][k]*b[k][j];

is transformed to:

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

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

  • -floop-unroll-and-jam โ€” applies unroll and jam transformations on feasible loops ๐Ÿฅช In a loop nest, this unrolls the outer loop by some factor and fuses the resulting multiple inner loops ๐Ÿซง This flag is enabled by default at -O3. It's also enabled by -fprofile-use and -fauto-profile ๐Ÿ’–
  • -ftree-loop-im โ€” performs loop invariant motion on trees ๐Ÿšš This pass only moves invariants that are hard to handle at the RTL level, like function calls or operations that expand into nontrivial sequences of insns ๐Ÿ“ฆ With -funswitch-loops, it also moves operands of conditions that are invariant out of the loop, so we can use just trivial invariantness analysis in loop unswitching ๐Ÿง  The pass also includes store motion ๐ŸŽ€
  • -ftree-loop-ivcanon โ€” creates a canonical counter for the number of iterations in loops where figuring that out takes complicated analysis ๐Ÿ”ข Later optimizations may then determine the number easily, which is especially useful with unrolling ๐Ÿ™Œ
  • -ftree-scev-cprop โ€” performs final value replacement โœจ If a variable is modified in a loop in such a way that its value when exiting can be determined using only its initial value and the number of loop iterations, the uses of the final value get replaced by that computation, provided it's sufficiently cheap ๐Ÿ’ธ This reduces data dependencies and may unlock more simplifications ๐Ÿฆ‹ Enabled by default at -O and higher.
  • -fivopts โ€” performs induction variable optimizations (strength reduction, induction variable merging and induction variable elimination) on trees ๐Ÿ”
  • -ftree-parallelize-loops=n โ€” parallelizes loops, meaning it splits their iteration space to run in n threads ๐Ÿงต This is only possible for loops whose iterations are independent and can be arbitrarily reordered ๐Ÿ”€ It's only profitable on multiprocessor machines, for 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 ๐ŸŽฏ On by default at -O1 and higher, except for -Og ๐Ÿ’•
  • -ftree-sra โ€” performs scalar replacement of aggregates ๐Ÿงฉ It swaps structure references for scalars so structures don't get committed to memory too early ๐Ÿ˜ค On by default at -O1 and higher, except for -Og ๐ŸŒธ
  • -fstore-merging โ€” merges narrow stores to consecutive memory addresses ๐Ÿ“ฆ It squishes contiguous stores of immediate values that are narrower than a word into fewer, wider stores to cut down on instructions โœ‚๏ธ On by default at -O2 and higher, as well as -Os ๐Ÿ’œ
  • -ftree-ter โ€” performs temporary expression replacement during the SSA->normal phase ๐Ÿ” Single use/single def temporaries get replaced at their use location with their defining expression ๐ŸŽฏ This results in non-GIMPLE code, but it gives the expanders much more complex trees to work on, which leads to better RTL generation โœจ 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 ๐ŸŒˆ This flag is enabled by default at -O3, and by -ftree-vectorize, -fprofile-use, and -fauto-profile too ๐Ÿ‘‘
  • -ftree-slp-vectorize โ€” okay bestie, this one turns on basic block vectorization on trees ๐ŸŒธ It's on by default at -O3, and you also get it from -ftree-vectorize, -fprofile-use, and -fauto-profile โœจ
  • -fvect-cost-model=model โ€” this lets you change the cost model GCC uses for vectorization ๐Ÿ’… The model has to be unlimited, dynamic, or cheap:
    • unlimited assumes the vectorized code path is profitable, no questions asked ๐Ÿš€
    • dynamic puts a runtime check in front of the vectorized path so it only runs for iteration counts that will likely go faster than the original scalar loop ๐Ÿฆ‹
    • cheap skips vectorizing loops where that would be cost-prohibitive, like when it needs runtime checks for data dependence or alignment. Otherwise it's the same as dynamic ๐Ÿซถ

The default cost model depends on your other optimization flags, and it's either dynamic or cheap ๐Ÿ”ฅ

  • -fsimd-cost-model=model โ€” same energy, but for loops marked with the OpenMP simd directive ๐ŸŽ€ The model can be unlimited, dynamic, or cheap, and all of them mean exactly what they do in -fvect-cost-model ๐Ÿ’– By default, if you've set a cost model with -fvect-cost-model, that's the one it uses โœจ
  • -ftree-vrp โ€” enables Value Range Propagation on trees ๐Ÿงš It's kind of like constant propagation, except instead of tracking single values it propagates whole ranges of values ๐Ÿ‘‘ That lets the optimizers yeet unnecessary range checks, like array bound checks and null pointer checks ๐Ÿ’€ It's enabled by default at -O2 and higher.

Heads up: null pointer check elimination only happens if -fdelete-null-pointer-checks is enabled ๐Ÿ™ˆ

  • -fsplit-paths โ€” splits paths leading to loop backedges ๐Ÿ“ This can improve dead code elimination and common subexpression elimination ๐Ÿ’œ It's enabled by default at -O3 and above โœจ
  • -fsplit-ivs-in-unroller โ€” okay so this one lets the compiler express the values of induction variables in later iterations of an unrolled loop, using the value from the first iteration ๐Ÿฆ‹ It's lowkey genius, because it breaks long dependency chains, which makes the scheduling passes more efficient ๐Ÿ”ฅ

Real talk, a combination of -fweb and CSE is often enough to get the same effect ๐ŸŒธ But it's not reliable when the loop body is more complicated than a single basic block ๐Ÿ™ƒ And it doesn't work at all on some architectures because of restrictions in the CSE pass ๐Ÿ’€

This optimization is enabled by default โœจ

  • -fvariable-expansion-in-unroller โ€” when unrolling a loop, this 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 โ€” performs predictive commoning, which is basically reusing computations (especially memory loads and stores) from previous iterations of loops ๐Ÿง 

It's enabled at level -O3. It's also enabled by -fprofile-use and -fauto-profile ๐ŸŽ€

  • -fprefetch-loop-arrays โ€” if the target machine supports it, this generates instructions to prefetch memory, which can help loops that access large arrays go brr ๐ŸŽ๏ธ

This option may generate better or worse code. The results are highly dependent on the structure of the loops in your source code ๐Ÿ˜ญ

Disabled at level -Os ๐Ÿ™…

  • -fno-printf-return-value โ€” don't substitute constants for the known return value of formatted output functions like "sprintf", "snprintf", "vsprintf", and "vsnprintf" (but not "printf" or "fprintf") ๐Ÿ™ˆ This lets GCC optimize or even eliminate branches based on the known return value, when the arguments are constant or their values are known to be in a range that makes the exact return value possible โœจ

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

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

The -fprintf-return-value option relies on other optimizations and yields the best results with -O2 and above. It works in tandem with the -Wformat-overflow and -Wformat-truncation options. The -fprintf-return-value option is enabled by default ๐ŸŒธ

  • -fno-peephole, -fno-peephole2 โ€” disables any machine-specific peephole optimizations ๐Ÿฆ‹ The difference between them is in how they're implemented in the compiler. Some targets use one, some use the other, and a few use both ๐Ÿงš

-fpeephole is enabled by default. -fpeephole2 is enabled at levels -O2, -O3, -Os โœจ

  • -fno-guess-branch-probability โ€” don't guess branch probabilities using heuristics ๐Ÿ”ฎ

GCC uses heuristics to guess branch probabilities when they aren't provided by profiling feedback (-fprofile-arcs) ๐Ÿ“Š These heuristics are based on the control flow graph ๐Ÿ—บ๏ธ If some branch probabilities are specified by "__builtin_expect", then the heuristics are used to guess branch probabilities for the rest of the control flow graph, taking the "__builtin_expect" info into account ๐Ÿซถ The interactions between the heuristics and "__builtin_expect" can get pretty complex, so sometimes it's useful to disable the heuristics so the effects of "__builtin_expect" are easier to understand ๐Ÿ™ˆ

It's also possible to 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 can be simple, which doesn't increase code size (except sometimes due to secondary effects like alignment), or 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 and -Os, and stc at levels -O2 and -O3 ๐Ÿ’–

  • -freorder-blocks-and-partition โ€” in addition to reordering basic blocks, this partitions hot and cold basic blocks into separate sections of the assembly and .o files, to improve paging and cache locality performance ๐Ÿ 

This optimization is automatically turned off in the presence of exception handling or unwind tables (on targets using setjump/longjump or target specific scheme), for linkonce sections, for functions with a user-defined section attribute, and on any architecture that doesn't support named sections ๐Ÿšซ

When -fsplit-stack is used, this option isn't enabled by default (to avoid linker errors), but it may be enabled explicitly if you're using a working linker ๐Ÿงต

Enabled for x86 at levels -O2, -O3, -Os ๐Ÿฆ‹

  • -freorder-functions โ€” reorders functions in the object file to improve code locality ๐Ÿ—‚๏ธ This is done using special subsections: .text.hot for the most frequently executed functions and .text.unlikely for the unlikely-executed ones ๐Ÿ”ฅ

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 turns on optimizations based on the type of expressions. An object of one type is assumed to never reside at the same address as an object of a different type, unless the types are almost the same. For example, 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;
}

The practice of reading from a different union member than the one most recently written to (called "type-punning") is common. Even with -fstrict-aliasing, type-punning is allowed, provided the memory is accessed through the union type. So, the code above works as expected. However, this code might not:

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

Similarly, access by taking the address, casting the resulting pointer, and dereferencing the result has undefined behavior, even if the cast uses a union type, e.g.:

int f() {
  double d = 3.0;
  return ((union a_union *) &d)->i;
}
Careful, bestie: that last one has undefined behavior ๐Ÿ’€

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, n2:m2, gives you a secondary alignment ๐Ÿ’…โœจ So -falign-functions=64:7:32:3 means: go to the next 64-byte boundary if you can get there by skipping 6 bytes or fewer, and otherwise go to the next 32-byte boundary if that only costs you 2 bytes or fewer ๐Ÿฆ‹. If m2 isn't specified, it just defaults to n2 ๐Ÿซถ.

Some assemblers only accept this flag when n is a power of two ๐Ÿค“. When that's the case, the value gets rounded up ๐ŸŒธ.

-fno-align-functions and -falign-functions=1 are the same thing, and both mean functions don't get aligned at all ๐Ÿ™…โ€โ™€๏ธ.

If n isn't specified or is zero, you get a machine-dependent default ๐Ÿงš. The biggest n you can use is 65536 ๐Ÿ‘‘.

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

  • -flimit-function-alignment โ€” If this is on, the compiler tries not to overalign functions for no reason ๐Ÿ™ˆ. It asks the assembler to align by whatever -falign-functions says, but it won't skip more bytes than the size of the function itself ๐Ÿ’€.

-falign-labels

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

Aligns all branch targets to a power-of-two boundary ๐ŸŽ€.

The parameters work just like -falign-functions ๐Ÿฆ‹. -fno-align-labels and -falign-labels=1 are equivalent and mean labels don't get aligned ๐Ÿ™…โ€โ™€๏ธ.

If -falign-loops or -falign-jumps apply and their values are bigger than this one, then their values get used instead ๐Ÿ‘‘.

If n isn't specified or is zero, you get a machine-dependent default that's very likely to be 1, which means no alignment at all ๐Ÿงš. The maximum allowed n is 65536.

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

-falign-loops

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

Aligns loops to a power-of-two boundary ๐Ÿ”. If the loops run a ton of times, the padding instructions that get executed are totally worth it ๐Ÿ’œ.

If -falign-labels is bigger than this value, then its value gets used instead ๐Ÿ‘‘.

The parameters are analogous to -falign-functions โœจ. -fno-align-loops and -falign-loops=1 are equivalent and mean loops don't get aligned ๐Ÿ™…โ€โ™€๏ธ. The maximum allowed 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

Aligns branch targets to a power-of-two boundary ๐Ÿฆ‹, but only for the ones that can only be reached by jumping. In that case, no dummy operations need to run ๐Ÿง.

If -falign-labels is bigger than this value, then its value gets used instead ๐Ÿ‘‘.

The parameters are analogous to -falign-functions ๐ŸŒˆ. -fno-align-jumps and -falign-jumps=1 are equivalent and mean that loops are not aligned ๐Ÿ™ˆ. If n isn't specified or is zero, you get a machine-dependent default ๐Ÿงš. The maximum allowed n is 65536.

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

  • -fno-allocation-dce โ€” Don't remove unused C++ allocations during dead code elimination ๐Ÿ—‘๏ธโœจ.
  • -fallow-store-data-races โ€” Lets the compiler introduce brand-new data races on stores ๐Ÿ˜ญ. Enabled at level -Ofast.
Bestie, new data races are not a vibe ๐Ÿ’€. Only turn this on if you really know what you're doing.
  • -funit-at-a-time โ€” This one's just here for compatibility reasons ๐Ÿ•ฐ๏ธ. -funit-at-a-time has no effect, but -fno-unit-at-a-time implies -fno-toplevel-reorder and -fno-section-anchors. Enabled by default ๐Ÿ’….
  • -fno-toplevel-reorder โ€” Don't reorder top-level functions, variables, and asm statements ๐Ÿ“œ. They get output in the same order they show up in the input file. With this on, unreferenced static variables are not removed ๐Ÿ™ˆ. It's meant for existing code that depends on a specific ordering. For new code, it's better to use attributes when you can ๐Ÿซถ.

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

  • -fweb โ€” Constructs webs like the ones commonly used for register allocation, and gives each web its own individual pseudo register ๐Ÿ•ธ๏ธ. This lets the register allocation pass work on pseudos directly, and it also strengthens a few other optimization passes, like CSE, the loop optimizer, and the trivial dead code remover ๐Ÿ’ช. Enabled by default with -funroll-loops ๐ŸŒธ.
Heads up, babe: this one can make debugging basically impossible, since variables no longer stay in a "home register" ๐Ÿ˜ญ.
  • -fwhole-program โ€” Assumes the current compilation unit is the whole program being compiled ๐Ÿ‘‘. All public functions and variables, except main and anything merged by the attribute externally_visible, become static functions and get optimized more aggressively by interprocedural optimizers ๐Ÿ”ฅ.
Don't combine this with -flto ๐Ÿ™…โ€โ™€๏ธ. Relying on a linker plugin instead should give you safer and more precise information.

-flto[=n]

This option 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 back from those ELF sections and instantiated as if they were part of the same translation unit ๐Ÿซถ.

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

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

The first two invocations save a bytecode representation of GIMPLE into special ELF sections inside foo.o and bar.o ๐Ÿ’–. The final invocation reads that GIMPLE bytecode from foo.o and bar.o, merges the two files into a single internal image, and compiles the result as usual ๐Ÿง. Since both get merged into one image, all the interprocedural analyses and optimizations in GCC work across the two files as if they were a single one ๐ŸŒˆ. So, for example, the inliner can inline functions from bar.o into functions in foo.o and vice-versa ๐Ÿ”ฅ.

Another (simpler) way to turn on link-time optimization is:

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

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

The big thing to remember is that you need to use the GCC driver to do the link step ๐Ÿงš. GCC automatically performs link-time optimization if any of the objects involved were compiled with the -flto command-line option ๐Ÿ’œ. You can always override that automatic decision by passing -fno-lto to the link command ๐Ÿ™…โ€โ™€๏ธ.

To make whole program optimization actually effective, you have to make certain whole program assumptions ๐Ÿค“. The compiler needs to know which functions and variables can be accessed by libraries and runtime outside of the link-time optimized unit ๐Ÿ‘€. When the linker supports it, the linker plugin (see -fuse-linker-plugin) passes that 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 those assumptions, which leads to more aggressive optimization decisions ๐Ÿ”ฅ.

When a file is compiled with -flto and without -fuse-linker-plugin, the generated object file is bigger than a regular one ๐Ÿ“ฆ. That's because it contains GIMPLE bytecodes and the usual final code (see -ffat-lto-objects). This means object files with LTO information can be linked as normal object files ๐Ÿซถ. If -fno-lto is passed to the linker, though, no interprocedural optimizations get applied ๐Ÿ˜ญ.

Note that when -fno-fat-lto-objects is enabled, the compile stage is faster, but you cannot perform a regular, non-LTO link on them ๐Ÿ’€.

When producing the final binary, GCC only applies link-time optimizations to the files that contain bytecode ๐Ÿง . So you can mix and match object files and libraries with GIMPLE bytecodes and final object code ๐ŸŒธ. GCC automatically picks which files get optimized in LTO mode and which ones just get linked without any further processing โœจ.

Generally, options given at link time override the ones given at compile time ๐Ÿ‘‘. In some cases, though, 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, then GCC uses the highest optimization level used when compiling the object files ๐Ÿง. Also, it's generally ineffective to specify an optimization level only at link time and not at compile time ๐Ÿ™ˆ, for two reasons. First, compiling without optimization suppresses the compiler passes that gather the info needed for effective optimization at link time ๐Ÿ˜ญ. Second, some early optimization passes can only be performed at compile time and 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: -fPIC, -fpic, -fpie, -fcommon, -fexceptions, -fnon-call-exceptions, -fgnu-tm and all the -m target flags ๐ŸŒˆ.

Certain ABI-changing flags have to match in all compilation units, and 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, such as -ffp-contract, -fno-strict-overflow, -fwrapv, -fno-trapv or -fno-strict-aliasing, get passed through to the link stage and merged conservatively for conflicting translation units ๐Ÿฆ‹. Specifically, -fno-strict-overflow, -fwrapv and -fno-trapv take precedence, and for example -ffp-contract=off takes precedence over -ffp-contract=fast ๐Ÿ‘‘. You can override them at link time โœจ.

Okay so bestie, diagnostic options like -Wstringop-overflow get passed through to the link stage ๐Ÿ’…, and their setting matches the compile step at function granularity ๐Ÿฆ‹. ngl this only matters for diagnostics emitted during optimization โœจ. Also, code transforms like inlining can switch warnings on or off for regions of code that don't match the setting used at compile time ๐Ÿ™ˆ, so keep an eye out.

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

To turn on debug info generation, you need to supply -g at compile time ๐Ÿ”. If any input files at link time were built with debug info generation enabled, the link will turn on debug info generation too โœจ. Fancy debug info settings, like the dwarf level -gdwarf-5, need to be explicitly repeated on the linker command line, and mixing different settings across translation units is discouraged ๐Ÿ˜ญ.

If LTO runs into objects with C linkage declared with incompatible types in 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 no cheating ๐Ÿ™…. Similar diagnostics may be raised for other languages.

Another feature of LTO is that you can apply interprocedural optimizations to files written in different languages ๐ŸŒˆ:

gcc -c -flto foo.c
g++ -c -flto bar.cc
gfortran -c -flto baz.f90
g++ -o myprog -flto -O3 foo.o bar.o baz.o -lgfortran

Notice that the final link is done with g++ to get the C++ runtime libraries, and -lgfortran gets added to get 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 that work with LTO, use gcc-ar and gcc-ranlib instead of ar and ranlib, and to show the symbols of object files with GIMPLE bytecode, use gcc-nm. Those commands require that ar, ranlib and nm have been compiled with plugin support. At link time, use the flag -fuse-linker-plugin so the library participates in the LTO optimization process:

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

With the linker plugin enabled, the linker extracts the needed GIMPLE files from libfoo.a and passes them to the running GCC so they become part of the aggregated GIMPLE image to be optimized โœจ.

If you're not using a linker with plugin support and/or don't enable the linker plugin ๐Ÿฅฒ, the objects inside libfoo.a are extracted and linked as usual, but they do not 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 in order to work ๐ŸŒธ. 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. Using -fwhole-program isn't needed when the linker plugin is active (see -fuse-linker-plugin).

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

Link-time optimization doesn't play nicely with generating debugging information on systems other than those using a combination of ELF and DWARF ๐Ÿ˜ญ.


If you specify the optional n, the optimization and code generation done at link time runs in parallel using n jobs by utilizing an installed make program ๐Ÿƒโ€โ™€๏ธ. Want a different make? The environment variable MAKE lets you override the program used ๐Ÿ”ง.

You can also specify -flto=jobserver to use GNU make's job server mode to figure out 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 โ€” Pick the partitioning algorithm the link-time optimizer uses ๐Ÿงฉ. The value is either 1to1, which mirrors the original source files, balanced, which splits things into equally sized chunks (whenever possible), or max, which creates a new partition for every symbol where possible. Specifying none as the algorithm disables partitioning and streaming completely. The default value is balanced. 1to1 can be used as a workaround for various code ordering issues, but max partitioning is intended for internal testing only ๐Ÿ™ˆ. The value one specifies that exactly one partition should be used, while the value none bypasses partitioning and runs the link-time optimization step directly from the WPA phase.
  • -flto-compression-level=n โ€” Sets how much compression gets used for the intermediate language written to LTO object files ๐Ÿ—œ๏ธ. This is only meaningful together with LTO mode (-flto). Valid values are 0 (no compression) to 9 (maximum compression). Values outside this range are clamped to either 0 or 9. If you don't give the option, a default balanced compression setting is used.
  • -fuse-linker-plugin โ€” Turns on 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 enables the extraction of object files with GIMPLE bytecode out of library archives, which improves optimization quality by exposing more code to the link-time optimizer. This also tells the optimizer which symbols can be accessed externally (by a non-LTO object or during dynamic linking). The code quality improvements 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 compiling with -flto, and it's ignored at link time.

-fno-fat-lto-objects improves compilation time over plain LTO, but it requires the complete toolchain to be aware of LTO ๐Ÿ› ๏ธ. It requires a linker with linker plugin support for basic functionality. Additionally, nm, ar and ranlib need to support linker plugins to allow a full-featured build environment (capable of building static libraries, etc). GCC provides the gcc-ar, gcc-nm, 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 identifies 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. Enabled at levels -O, -O2, -O3, -Os.
  • -fcprop-registers โ€” After register allocation and post-register-allocation instruction splitting, this runs a copy-propagation pass to try to reduce scheduling dependencies and occasionally eliminate the copy ๐Ÿ“‹. Enabled at levels -O, -O2, -O3, -Os.
  • -fprofile-correction โ€” Profiles collected using an instrumented binary for multi-threaded programs can be inconsistent because of missed counter updates ๐Ÿงต. When you specify 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 portions of programs not executed during the train run get optimized aggressively for size rather than speed ๐Ÿ“. In some cases it's not practical to train every possible hot path in the program. (For example, a program may contain functions specific to a given hardware, and training may not cover every hardware configuration the program runs on.) With -fprofile-partial-training, profile feedback is ignored for all functions not executed during the train run, so they get 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 โ€” Enable profile feedback-directed optimizations, plus the following optimizations, many of which are generally only profitable when profile feedback is available ๐Ÿ”ฅ:

And here's the rest of the squad that -fprofile-use brings along for the ride ๐Ÿงš:

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

Before you can use this option, you must first generate profiling information. No skipping that step, bestie ๐Ÿ™…โ€โ™€๏ธ

By default, GCC gets big mad ๐Ÿ’€ and throws an error if the feedback profiles don't match your source code. If you're feeling chaotic, you can downgrade that to a warning with -Wno-error=coverage-mismatch.

Heads up: doing that may result in poorly optimized code.

Also, by default, GCC will warn you if the feedback profiles don't exist at all (see -Wmissing-profile) ๐Ÿ‘€

If you give it a path, GCC goes digging there to find the profile feedback data files ๐Ÿฆ‹ See -fprofile-dir.

-fauto-profile, -fauto-profile=path

Okay so this turns on sampling-based feedback-directed optimizations, plus a whole crew of other optimizations that are mostly only worth it when profile feedback is around ๐Ÿ’…

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

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

Making an AutoFDO profile data file means running your program with the perf utility on a supported GNU/Linux target system. For more info, check out <https://perf.wiki.kernel.org/> โœจ

E.g. ๐Ÿ‘€

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

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

E.g.

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

Next up are the options that control compiler behavior around floating-point arithmetic. โš–๏ธ These options trade speed against correctness, so all of them must be specifically enabled. Choose wisely, besties ๐Ÿ’–

-ffloat-store

Basically, this tells the compiler not to keep your float variables chilling in registers, and to stop any other options from swapping whether a float comes from a register or from memory ๐Ÿ™…โ€โ™€๏ธ It prevents that undesirable excess precision on machines like the 68000, where the floating registers (of the 68881) keep more precision than a double is supposed to have. Same story on the x86 architecture. For most programs, the excess precision only does good, but a few programs rely on the precise definition of IEEE floating point. For those, use -ffloat-store after you've modified them to store all pertinent intermediate computations into variables.

-fexcess-precision=style

This one gives you more control over excess precision on machines where floating-point operations happen in a format with more precision or range than the IEEE standard and interchange floating-point types ๐Ÿงฎ By default, -fexcess-precision=fast is in effect, which means operations may run in a wider precision than the types in your source if that makes the code faster. It's unpredictable when the rounding to your source types actually happens, so, hmm, bestie, that's a vibe ๐ŸŒ€

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

-fexcess-precision=standard is not implemented for languages other than C. On the x86, it has no effect if -mfpmath=sse or -mfpmath=sse+387 is specified. In the former case, IEEE semantics apply without excess precision, and in the latter, rounding is unpredictable.

-ffast-math

This one 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 be defined.

It's not turned on by any -O option besides -Ofast, since it can result in incorrect output for programs that depend on an exact implementation of IEEE or ISO rules/specifications for math functions.

It may, however, yield faster code for programs that don't need the guarantees of those specifications. Use with care, bestie ๐Ÿ’€

-fno-math-errno

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

It's not turned on by any -O option, since it can result in incorrect output for programs that depend on an exact implementation of IEEE or ISO rules/specifications for math functions. It may, however, yield faster code for programs that don't need those guarantees.

The default is -fmath-errno.

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

-funsafe-math-optimizations

Allow optimizations for floating-point arithmetic that (a) assume arguments and results are valid and (b) may violate IEEE or ANSI standards. Lowkey dangerous energy ๐Ÿ˜ญ When used at link time, it may include libraries or startup files that change the default FPU control word or other similar optimizations.

It's not turned on by any -O option, since it can result in incorrect output for programs that depend on an exact implementation of IEEE or ISO rules/specifications for math functions. It may, however, yield faster code for programs that don't need 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 lets you re-associate operands in a series of floating-point operations ๐ŸŒ€ It violates the ISO C and C++ language standard by possibly changing the computation result. NOTE: re-ordering may change the sign of zero, ignore NaNs, and inhibit or create underflow or overflow. So it can't be used on code that relies on rounding behavior like (x + 2**52) - 2**52. It may also reorder floating-point comparisons, so it may not be used when ordered comparisons are required.

This option requires that both -fno-signed-zeros and -fno-trapping-math be in effect. Moreover, it doesn't make much sense with -frounding-math. For Fortran, the option is automatically enabled when both -fno-signed-zeros and -fno-trapping-math are in effect.

The default is -fno-associative-math.

-freciprocal-math

This allows the reciprocal of a value to be used instead of dividing by the value, if that enables optimizations โœจ For example, x / y can be replaced with x * (1/y), which is useful if (1/y) is subject to common subexpression elimination. Note 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 never NaNs or +-Infs ๐Ÿ™ˆ

It's not turned on by any -O option, since it can result in incorrect output for programs that depend on an exact implementation of IEEE or ISO rules/specifications for math functions. It may, however, yield faster code for programs that don't need 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 the behavior of distinct +0.0 and -0.0 values, which then prohibits simplification of expressions such as x+0.0 or 0.0*x (even with -ffinite-math-only). This option implies that 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 cannot generate user-visible traps ๐Ÿฆ‹ These traps include division by zero, overflow, underflow, inexact result and invalid operation. This option requires that -fno-signaling-nans be in effect. Setting it may 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 result in incorrect output for programs that depend on an exact implementation of IEEE or ISO rules/specifications for math functions.

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. Specify it for programs that change the FP rounding mode dynamically, or that may be executed with a non-default rounding mode. It also disables constant folding of floating-point expressions at compile time (which may be affected by rounding mode), plus arithmetic transformations that are unsafe in the presence of sign-dependent rounding modes.

The default is -fno-rounding-math.

This option is experimental and does not currently guarantee to disable all GCC optimizations that are affected by rounding mode. Future versions of GCC may provide finer control of 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 compile your code assuming IEEE signaling NaNs can cause user-visible traps during floating-point operations ๐Ÿ˜ญ. Turning it on disables optimizations that might change how many exceptions show up with signaling NaNs ๐Ÿšซ. It also implies -ftrapping-math, and it makes GCC define the preprocessor macro __SUPPORT_SNAN__ โœจ. The default is -fno-signaling-nans ๐ŸŒธ.
This option is experimental ๐Ÿงช, and it does not currently guarantee to disable all GCC optimizations that affect signaling NaN behavior ๐Ÿ’€.
  • -fno-fp-int-builtin-inexact โ€” bestie, this stops the built-in ceil, floor, round and trunc functions (plus their float and long double variants) from generating code that raises the "inexact" floating-point exception for noninteger arguments ๐Ÿ™…โ€โ™€๏ธ. ISO C99 and C11 let these functions raise that exception, but ISO/IEC TS 18661-1:2014, the C bindings to IEEE 754-2008 as integrated into ISO C2X, does not. The default is -ffp-int-builtin-inexact, which allows the exception to be raised, unless C2X or a later C standard is selected. This option does nothing unless -ftrapping-math is in effect ๐Ÿค“. Even if you use -fno-fp-int-builtin-inexact, if the functions generate a call to a library function, the "inexact" exception may still be raised if that library doesn't follow TS 18661 ๐Ÿซ .
  • -fsingle-precision-constant โ€” treats floating-point constants as single precision, instead of quietly converting them to double-precision constants ๐ŸŽ€.
  • -fcx-limited-range โ€” when this is on, GCC assumes complex division doesn't need a range reduction step โœ‚๏ธ. It also skips checking whether a complex multiplication or division result is "NaN + I*NaN" and trying to rescue it ๐Ÿ™ˆ. 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, but it applies to all languages anyway ๐ŸŒˆ.
  • -fcx-fortran-rules โ€” complex multiplication and division follow Fortran rules ๐Ÿงš. Range reduction gets done as part of complex division, but there's still no checking whether the result of a complex multiplication or division is "NaN + I*NaN", and no attempt to rescue it in that case ๐Ÿซถ. The default is -fno-cx-fortran-rules ๐Ÿ“.

Next up are the optimizations that can improve performance but aren't turned on by any -O options ๐Ÿš€. Heads up: this section also includes experimental options that might produce broken code โš ๏ธ๐Ÿ’€, so proceed with main character caution ๐Ÿ’….

  • -fbranch-probabilities โ€” after you run a program compiled with -fprofile-arcs, compile it a second time with -fbranch-probabilities to improve optimizations based on how many times each branch was taken ๐Ÿ“Š. When a program compiled with -fprofile-arcs exits, it saves arc execution counts to a file called sourcename.gcda for each source file ๐Ÿ’พ. The info in that data file is super dependent on the structure of the generated code, so you must use the same source code and the same optimization options for both compilations ๐Ÿ™. With -fbranch-probabilities, GCC puts a REG_BR_PROB note on each JUMP_INSN and CALL_INSN, and these can be used to improve optimization ๐Ÿ”. Right now they're only used in one place: in reorg.c. Instead of guessing which path a branch is most likely to take, the REG_BR_PROB values are used to exactly determine which path is taken more often ๐Ÿ‘‘. Enabled by -fprofile-use and -fauto-profile โœจ.
  • -fprofile-values โ€” if you combine this with -fprofile-arcs, it adds code to gather data about the values of expressions in your program ๐Ÿงฎ. With -fbranch-probabilities, it reads that data back and uses it for optimizations ๐Ÿซง. Enabled by -fprofile-generate, -fprofile-use, and -fauto-profile ๐Ÿ’–.
  • -fprofile-reorder-functions โ€” function reordering based on profile instrumentation records the first time each function executes, then orders those functions in ascending order ๐Ÿƒโ€โ™€๏ธ. Enabled with -fprofile-use ๐Ÿฆ‹.
  • -fvpt โ€” if you combine this with -fprofile-arcs, it tells the compiler to add code that gathers information about values of expressions ๐Ÿ•ต๏ธโ€โ™€๏ธ. With -fbranch-probabilities, it reads that data back and actually performs optimizations based on it. Right now those optimizations include specialization of division operations using knowledge about the value of the denominator โž—. Enabled with -fprofile-use and -fauto-profile ๐ŸŽ€.
  • -frename-registers โ€” tries to avoid false dependencies in scheduled code by using registers left over after register allocation ๐ŸŒˆ. This most benefits processors with lots of registers ๐Ÿ’ช. Depending on the debug information format the target uses, though, it can make debugging impossible, since variables no longer stay in a "home register" ๐Ÿ˜ญ. Enabled by default with -funroll-loops ๐Ÿ’….
  • -fschedule-fusion โ€” performs a target-dependent pass over the instruction stream to schedule instructions of the same type together ๐Ÿงฉ. The target machine can run them more efficiently if they're adjacent in the instruction flow โšก. Enabled at levels -O2, -O3, -Os ๐Ÿ’.
  • -ftracer โ€” performs tail duplication to enlarge superblock size ๐Ÿชž. This transformation simplifies the control flow of the function, which lets other optimizations do a better job ๐Ÿ‘‘. Enabled by -fprofile-use and -fauto-profile ๐Ÿซถ.
  • -funroll-loops โ€” unrolls loops whose number of iterations can be determined at compile time or upon entry to the loop ๐Ÿ”. -funroll-loops implies -frerun-cse-after-loop, -fweb and -frename-registers. It also turns on complete loop peeling, which means completely removing loops with a small constant number of iterations ๐Ÿฐ. This option makes code larger, and it may or may not make the code run faster ๐Ÿคทโ€โ™€๏ธ. Enabled by -fprofile-use and -fauto-profile ๐ŸŒธ.
  • -funroll-all-loops โ€” unrolls all loops, even if their number of iterations is uncertain when the loop is entered ๐Ÿ™ƒ. This usually makes programs run more slowly ๐Ÿข. -funroll-all-loops implies the same options as -funroll-loops ๐Ÿง.
  • -fpeel-loops โ€” peels loops for which there's enough information that they don't roll much, based on profile feedback or static analysis ๐ŸŒ. It also turns on complete loop peeling, which is complete removal of loops with a small constant number of iterations ๐Ÿงน. Enabled by -O3, -fprofile-use, and -fauto-profile ๐Ÿ’œ.
  • -fmove-loop-invariants โ€” enables the loop invariant motion pass in the RTL loop optimizer ๐Ÿšš. 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 out of the loop ๐Ÿ”€. There are duplicates of the loop on both branches, modified according to the result of the condition ๐Ÿช„. Enabled by -fprofile-use and -fauto-profile ๐ŸŒˆ.
  • -fversion-loops-for-strides โ€” if a loop iterates over an array with a variable stride, GCC creates another version of the loop that assumes the stride is always one ๐Ÿƒโ€โ™€๏ธ. For example, this:
for (int i = 0; i < n; ++i)
  x[i * stride] = ...;

becomes this:

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

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

  • -ffunction-sections, -fdata-sections โ€” places each function or data item into its own section in the output file, if the target supports arbitrary sections ๐Ÿง. The name of the function or the name of the data item determines the section's name in the output file ๐Ÿท๏ธ.
    • Use these on systems where the linker can perform optimizations to improve locality of reference in the instruction space ๐Ÿ“. Most systems using the ELF object format have linkers with such optimizations. On AIX, the linker rearranges sections (CSECTs) based on the call graph, and the performance impact varies ๐ŸŽข.
    • Together with a linker garbage collection (linker --gc-sections option), these options may lead to smaller statically-linked executables (after stripping) ๐Ÿชถ.
    • On ELF/DWARF systems, these options do not degenerate the quality of the debug information. There could be issues with other object files and debug info formats ๐Ÿ™ˆ.
    • Only use these options when there are significant benefits from doing so ๐Ÿง. When you specify them, the assembler and linker create larger object and executable files and are also slower ๐ŸŒ. These options affect code generation. They prevent optimizations by the compiler and assembler from using relative locations inside a translation unit, since those locations are unknown until link time ๐Ÿฅบ. An example of such an optimization is relaxing calls to short call instructions ๐Ÿ“ž.
  • -fstdarg-opt โ€” optimizes the prologue of variadic argument functions with respect to how those arguments are used ๐ŸŽญ.
NOTE: In Ubuntu 14.10 and later versions, -fstack-protector-strong is enabled by default for C, C++, ObjC, ObjC++, if none of -fno-stack-protector, -nostdlib, nor -ffreestanding are found ๐Ÿ›ก๏ธ.
  • -fsection-anchors โ€” tries to reduce the number of symbolic address calculations by using shared "anchor" symbols to address nearby objects ๐ŸŒธ. This transformation can help reduce the number of GOT entries and GOT accesses on some targets ๐Ÿฆ‹. For example, here's the implementation of the following function "foo" ๐Ÿ‘€:
static int a, b, c;
int foo (void) { return a + b + c; }

It usually 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 the following 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, so check that your target actually supports it before you get your hopes up ๐Ÿ’”

  • --param name=value โ€” okay, this one is lowkey iconic ๐Ÿ’…. GCC uses a bunch of little internal constants to decide how much optimization 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 constants from the command line with --param.

The names of specific parameters, and what their values mean, are tied to the compiler's internals. They can change without notice in future releases, so don't build your whole personality around them ๐Ÿฅฒ

If you want the minimal, maximal and default value of a parameter, you can use the --help=param -Q options ๐Ÿ”

Every value is an integer โœจ These names are recognized for all targets:

  • predictable-branch-outcome โ€” when a branch is predicted to be taken with a probability lower than this threshold (in percent), it's considered well predictable ๐Ÿ”ฎ
  • max-rtl-if-conversion-insns โ€” RTL if-conversion tries to remove conditional branches around a block and swap them for conditionally executed instructions. This is the maximum number of instructions in a block that should be considered for if-conversion. The compiler also uses other heuristics to decide whether if-conversion is likely to be profitable ๐Ÿง 
  • max-rtl-if-conversion-predictable-cost, max-rtl-if-conversion-unpredictable-cost โ€” same if-conversion vibe, but these set the maximum permissible cost for the sequence that if-conversion would generate. It depends on whether the branch is statically determined to be predictable or not. The units match the GCC internal seq_cost metric, and the compiler will try to pick a reasonable default for this using the BRANCH_COST target macro ๐Ÿ’ฐ
  • max-crossjump-edges โ€” the maximum number of incoming edges to consider for cross-jumping. The algorithm used by -fcrossjumping is O(N^2) in the number of edges incoming to each block. Higher values mean more aggressive optimization, so compile time goes up for a probably 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 maximum code size expansion factor when copying basic blocks instead of jumping. The expansion is relative to a jump instruction ๐Ÿ“
  • max-goto-duplication-insns โ€” the maximum number of instructions to duplicate into a block that jumps to a computed goto. To avoid O(N^2) behavior in a 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 maximum number of instructions to consider when looking for an instruction to fill a delay slot. If more than this arbitrary number gets searched, the time savings from filling the delay slot are minimal, so GCC stops searching. Higher values mean more aggressive optimization, with compile time going up for a probably small improvement in execution time ๐Ÿ•ฐ๏ธ
  • max-delay-slot-live-search โ€” when trying to fill delay slots, the maximum number of instructions to consider when searching for a block with valid live register information. Raising this arbitrarily chosen value means more aggressive optimization and longer compile time. This parameter should be removed once the delay slot code is rewritten to maintain the control-flow graph ๐Ÿ—‘๏ธ
  • max-gcse-memory โ€” the approximate maximum amount of memory that can be allocated for global common subexpression elimination. If more memory than specified is required, the optimization just doesn't happen ๐Ÿง 
  • max-gcse-insertion-ratio โ€” if the ratio of expression insertions to deletions is larger than this value for any expression, RTL PRE inserts or removes the expression. That leaves partially redundant computations in the instruction stream ๐Ÿซ 
  • max-pending-list-length โ€” the maximum number of pending dependencies scheduling allows before it flushes the current state and starts over. Large functions with few branches or calls can build up excessively large lists that needlessly eat memory and resources ๐Ÿฐ
  • max-modulo-backtrack-attempts โ€” the maximum number of backtrack attempts the scheduler should make when modulo scheduling a loop. Larger values can exponentially increase compilation time ๐Ÿ’€
  • max-inline-insns-single โ€” several parameters control the tree inliner. This one sets the maximum number of instructions (counted in GCC's internal representation) in a single function that the tree inliner considers for inlining. It only affects functions declared inline and methods implemented in a class declaration (C++) ๐Ÿ‘‘
  • max-inline-insns-auto โ€” when you use -finline-functions (included in -O3), a lot of functions that otherwise wouldn't be considered for inlining get investigated. For those, 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 that are considered relevant with -finline-small-functions ๐ŸŒฑ
  • max-inline-insns-size โ€” the bound applied to calls that are optimized for size. A small growth may be desirable to anticipate optimization opportunities exposed by inlining โœ‚๏ธ
  • uninlined-function-insns โ€” the number of instructions the inliner counts for function overhead, such as the function prologue and epilogue ๐Ÿงพ
  • uninlined-function-time โ€” the extra time the inliner counts for function overhead, such as 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 โ€” the 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 set by --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 after inlining, inlining is constrained by --param large-function-growth. This parameter is mainly useful for avoiding extreme compile times caused by the non-linear algorithms the back end uses ๐Ÿ˜
  • large-function-growth โ€” the maximal growth of a large function 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 is limited by --param inline-unit-growth. For small units that might be too tight. Consider a unit made 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 that inlining is totally sane. For very large units full of small inlineable functions, though, the overall unit growth limit is needed to prevent an exponential explosion of code size. So for smaller units, the size is increased to --param large-unit-insns before --param inline-unit-growth gets applied ๐Ÿงฉ
  • inline-unit-growth โ€” the maximal 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) aren't counted in the unit size ๐Ÿฅถ
  • ipa-cp-unit-growth โ€” the maximal 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 ๐ŸŒท
  • large-stack-frame โ€” the limit that defines large stack frames. While inlining, the algorithm tries not to grow past this limit too much ๐Ÿฅž
  • large-stack-frame-growth โ€” the maximal 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 maximum number of instructions an out-of-line copy of a self-recursive inline function can grow into by performing recursive inlining. --param max-inline-insns-recursive applies to functions declared inline. For functions not declared inline, recursive inlining only happens when -finline-functions (included in -O3) is enabled, and --param max-inline-insns-recursive-auto applies instead ๐Ÿ”
  • max-inline-recursive-depth, max-inline-recursive-depth-auto โ€” the maximum recursion depth used for recursive inlining ๐Ÿชž

--param max-inline-recursive-depth is the one for functions declared inline ๐Ÿ’–. For functions that aren't declared inline, recursive inlining only happens when -finline-functions is enabled (it's already included in -O3 โœจ), and then --param max-inline-recursive-depth-auto is the one that applies ๐Ÿฆ‹.

Here are the rest of the --param knobs, bestie ๐Ÿ‘‘

  • min-inline-recursive-probability โ€” recursive inlining is only worth it for functions that recurse deeply on average ๐ŸŒ€. For functions with shallow recursion it can backfire by making the prologue bigger or the function body more complicated for other optimizers ๐Ÿ˜ญ. With profile feedback (see -fprofile-generate), the real recursion depth can be guessed from how likely a function is to recurse through a given call expression ๐Ÿ”ฎ. This param only lets inlining touch call expressions whose probability goes over the threshold, measured in percents ๐Ÿ’œ.
  • early-inlining-insns โ€” how much growth the early inliner is allowed to make ๐Ÿ“ˆ. Basically it boosts the amount of inlining for code with a large abstraction penalty ๐Ÿงš.
  • max-early-inliner-iterations โ€” caps how many iterations the early inliner runs ๐Ÿ”. This bounds how many nested indirect calls it can resolve, and deeper chains get handled by late inlining instead ๐Ÿซถ.
  • comdat-sharing-probability โ€” the probability, in percent, that C++ inline functions with comdat visibility get shared across multiple compilation units ๐ŸŒธ.
  • profile-func-internal-id โ€” controls whether the function's internal id gets used in profile database lookups ๐Ÿชช. When the value is 0, the compiler uses an id based on the function's assembler name and filename, which keeps old profile data more forgiving when source changes happen, like function reordering ๐Ÿฆ‹.
  • min-vect-loop-bound โ€” the minimum number of iterations below which loops won'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 for figuring out the maximum distance an expression can be moved by GCSE optimizations ๐Ÿšš. It's only supported in the code hoisting pass right now ๐Ÿงน. The bigger the ratio, the more aggressively simple expressions get hoisted, meaning expressions that cost less than gcse-unrestricted-cost ๐Ÿ”ฅ. Setting it to 0 disables hoisting of simple expressions ๐Ÿ™ˆ.
  • gcse-unrestricted-cost โ€” the cost, roughly measured as a single typical machine instruction, at which GCSE optimizations stop constraining how far an expression can travel ๐Ÿƒโ€โ™€๏ธ. Also only supported in the code hoisting pass ๐Ÿ’…. The lower the cost, the more aggressive the hoisting is, and 0 lets every expression travel unrestricted distances ๐ŸŒˆ.
  • max-hoist-depth โ€” how deep the search goes in the dominator tree for expressions to hoist ๐ŸŒณ. This keeps the hoisting algorithm from going quadratic ๐Ÿ˜ค. A value of 0 means there's no limit on the search, but compiling huge functions might get slower ๐Ÿข.
  • max-tail-merge-comparisons โ€” the maximum number of similar bbs a bb gets compared against ๐Ÿง. This stops tree tail merging from going quadratic ๐Ÿ™ƒ.
  • max-tail-merge-iterations โ€” the maximum number of passes over a function โฑ๏ธ. It limits compilation time in tree tail merging ๐Ÿ’œ.
  • store-merging-allow-unaligned โ€” lets the store merging pass introduce unaligned stores, but only if that's legal ๐Ÿงฑ.
  • max-stores-to-merge โ€” the maximum number of stores the store merging pass will try to fold into wider stores ๐Ÿงƒ.
  • max-unrolled-insns โ€” the maximum number of instructions a loop can have and still get unrolled ๐Ÿ”„. If the loop does get unrolled, this same number also decides how many times the loop body gets unrolled ๐ŸŽ€.
  • max-average-unrolled-insns โ€” like the one above, but counts instructions biased by how probable their execution is ๐Ÿ“Š. If a loop gets unrolled, this value also sets how many times the loop code is unrolled ๐Ÿซง.
  • max-unroll-times โ€” the maximum number of unrollings for a single loop ๐Ÿ”‚.
  • max-peeled-insns โ€” the maximum number of instructions a loop can have and still get peeled ๐Ÿ‘. If it's peeled, this also decides how many times the loop code gets peeled ๐Ÿง….
  • max-peel-times โ€” the maximum number of peelings for a single loop ๐ŸŠ.
  • max-peel-branches โ€” the maximum number of branches on the hot path through the peeled sequence ๐Ÿ›ค๏ธ.
  • max-completely-peeled-insns โ€” the maximum number of insns a completely peeled loop can have ๐Ÿญ.
  • max-completely-peel-times โ€” the maximum number of loop iterations for a loop to qualify for complete peeling ๐ŸŽฏ.
  • max-completely-peel-loop-nest-depth โ€” the maximum depth of a loop nest that's suitable for complete peeling ๐Ÿช†.
  • max-unswitch-insns โ€” the maximum number of insns an unswitched loop can have ๐Ÿ”€.
  • max-unswitch-level โ€” the maximum number of branches unswitched in a single loop ๐ŸŽš๏ธ.
  • lim-expensive โ€” the minimum cost for an expression to count as expensive in loop invariant motion ๐Ÿ’ธ.
  • min-loop-cond-split-prob โ€” when FDO profile information is available, this sets the minimum probability a semi-invariant condition statement needs before it triggers 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, so the time complexity doesn't go quadratic ๐Ÿซ .
  • 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 whenever it adds a new one ๐Ÿงน.
  • avg-loop-niter โ€” the average number of iterations of a loop ๐Ÿ”ข.
  • dse-max-object-size โ€” the maximum size, in bytes, of objects tracked bytewise by dead store elimination ๐Ÿ“ฆ. Bigger values can mean longer compilation times ๐ŸŒ.
  • dse-max-alias-queries-per-store โ€” the maximum number of queries into the alias oracle per store ๐Ÿ”ฎ. Bigger values mean longer compilation times, but they might remove more dead stores ๐Ÿ—‘๏ธ.
  • scev-max-expr-size โ€” the bound on how big expressions can be in the scalar evolutions analyzer ๐Ÿ“. Large expressions slow the analyzer down ๐Ÿ˜ฉ.
  • scev-max-expr-complexity โ€” the bound on how complex expressions can be in the scalar evolutions analyzer ๐Ÿงฉ. Complex expressions slow it down too ๐Ÿ’€.
  • max-tree-if-conversion-phi-args โ€” the maximum number of arguments in a PHI supported by tree if conversion, unless the loop is marked with simd pragma ๐Ÿท๏ธ.
  • vect-max-version-for-alignment-checks โ€” the maximum number of run-time checks the vectorizer can perform when it does loop versioning for alignment ๐Ÿงญ.
  • vect-max-version-for-alias-checks โ€” the maximum number of run-time checks the vectorizer can perform when it does loop versioning for alias ๐Ÿ‘ฏ.
  • vect-max-peeling-for-alignment โ€” the maximum number of loop peels the vectorizer can use to improve access alignment ๐Ÿก. A value of -1 means no limit โ™พ๏ธ.
  • max-iterations-to-track โ€” the maximum number of loop iterations the brute-force algorithm for counting loop iterations will try to evaluate ๐Ÿ•ต๏ธโ€โ™€๏ธ.
  • hot-bb-count-fraction โ€” the denominator n of the fraction 1/n of the maximal execution count of a basic block in the entire program. A basic block needs at least this to count as hot ๐Ÿ”ฅ. The default is 10000, so a basic block is hot if its execution count is greater than 1/10000 of the maximal execution count ๐Ÿ’ฏ. 0 means it's never considered hot. This is used in non-LTO mode ๐Ÿซถ.
  • hot-bb-count-ws-permille โ€” the number of most-executed permilles, from 0 to 1000, of the profiled execution of the entire program that a basic block's execution count has to be part of to be considered hot ๐ŸŒก๏ธ. The default is 990, so a basic block is hot if its count contributes to the upper 990 permilles, or 99.0%, of the profiled execution ๐Ÿง. 0 means it's never considered hot. This is used in LTO mode ๐ŸŒ.
  • hot-bb-frequency-fraction โ€” the denominator n of the fraction 1/n of the execution frequency of a function's entry block that a basic block in that function needs to have to be considered hot ๐ŸŒž. The default is 1000, so a basic 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 considered hot ๐Ÿšซ.
  • unlikely-bb-count-fraction โ€” the denominator n of the fraction 1/n of the number of profiled runs of the entire program. If a basic block's execution count falls below that, the block is considered unlikely to execute ๐Ÿฅถ. The default is 20, so 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 to execute ๐ŸŒ™.
  • max-predicted-iterations โ€” the maximum number of loop iterations the compiler predicts statically ๐Ÿ”ฎ. This helps when a function has one loop with a known bound and another with an unknown bound ๐Ÿคทโ€โ™€๏ธ. The known count gets predicted correctly, but the unknown count averages to roughly 10, so the unbounded loop looks artificially cold next to the other one ๐Ÿฅถโœจ.
  • builtin-expect-probability โ€” ๐Ÿ’– Sets how likely the expression is to have the specified value. It takes a percentage (so 0 ... 100) as input.
  • builtin-string-cmp-inline-length โ€” โœจ The biggest a constant string can be in a builtin string cmp call and still be eligible for inlining, bestie.
  • align-threshold โ€” ๐ŸŽ€ Picks a fraction of the maximal frequency of executions of a basic block in a function, which decides whether that basic block gets aligned.
  • align-loop-iterations โ€” ๐Ÿฆ‹ A loop that's expected to iterate at least the selected number of iterations gets aligned. Main character loops, honestly.
  • tracer-dynamic-coverage, tracer-dynamic-coverage-feedback โ€” ๐ŸŒธ This value caps superblock formation once the given percentage of executed instructions is covered, so the code doesn't balloon for no reason. The tracer-dynamic-coverage-feedback one is only used when profile feedback is available. Real profiles aren't as balanced as statically estimated ones, so the threshold can be a larger value.
  • tracer-max-code-growth โ€” ๐Ÿงš Stops tail duplication once code growth has reached the given percentage. Ngl this is a pretty artificial limit, since most of the duplicates get eliminated later in cross jumping, so it can be set way higher than the code growth you actually want. ๐Ÿ’…
  • tracer-min-branch-ratio โ€” ๐Ÿ’œ Stops reverse growth when the reverse probability of the best edge is less than this threshold, measured in percent.
  • tracer-min-branch-probability, tracer-min-branch-probability-feedback โ€” ๐Ÿ“ Stops forward growth if the best edge has a probability lower than this threshold. Same deal as tracer-dynamic-coverage: there are two of them. 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 effective.
  • stack-clash-protection-guard-size โ€” ๐Ÿ›ก๏ธ Specifies the size of the operating system provided stack guard as 2 raised to num bytes. Higher values may reduce the number of explicit probes, but a value larger than the operating system provided guard will leave code vulnerable to stack clash style attacks. ๐Ÿ’€
  • stack-clash-protection-probe-interval โ€” ๐Ÿ”ฅ Stack clash protection involves probing stack space as it gets allocated. This param controls the maximum distance between probes into the stack as 2 raised to num bytes. Higher values may reduce the number of explicit probes, but a value larger than the operating system provided guard will leave code vulnerable to stack clash style attacks.
  • max-cse-path-length โ€” ๐ŸŒˆ The maximum number of basic blocks on a path that CSE considers.
  • max-cse-insns โ€” ๐Ÿ‘‘ The maximum number of instructions CSE processes before flushing.
  • ggc-min-expand โ€” ๐Ÿง GCC uses a garbage collector to manage its own memory allocation. This parameter sets the minimum percentage by which the garbage collector's heap is allowed to expand between collections. Tuning it may improve compilation speed, but it has no effect on code generation.

The default is 30% + 70% * (RAM/1GB) with an upper bound of 100% when RAM >= 1GB. If getrlimit is available, the notion of "RAM" is the smallest of actual RAM and RLIMIT_DATA or RLIMIT_AS. If GCC can't calculate RAM on a particular platform, the lower bound of 30% is used. Setting this parameter and ggc-min-heapsize to zero causes a full collection to occur at every opportunity.

This is extremely slow, but it can be useful for debugging. ๐Ÿ˜ญ
  • ggc-min-heapsize โ€” ๐Ÿซง The minimum size of the garbage collector's heap before it 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 smaller of RAM/8, RLIMIT_RSS, or a limit that tries to ensure RLIMIT_DATA or RLIMIT_AS aren't exceeded, but with a lower bound of 4096 (four megabytes) and an upper bound of 131072 (128 megabytes). If GCC can't calculate RAM on a particular platform, the lower bound is used. Setting this parameter very large effectively disables garbage collection. Setting this parameter and ggc-min-expand to zero causes a full collection to occur at every opportunity.

  • max-reload-search-insns โ€” ๐Ÿ” The maximum number of instructions reload should look backward through to find an equivalent register. Increasing this means more aggressive optimization, making compilation time go up with probably slightly better performance.
  • max-cselib-memory-locations โ€” ๐Ÿง  The maximum number of memory locations cselib should take into account. Increasing this means more aggressive optimization, making compilation time go up with probably slightly better performance.
  • max-sched-ready-insns โ€” ๐Ÿš€ The maximum number of instructions ready to be issued that the scheduler should consider at any given time during the first scheduling pass. Increasing this means more thorough searches, making compilation time go up with probably little benefit.
  • max-sched-region-blocks โ€” ๐Ÿงฉ The maximum number of blocks in a region to be considered for interblock scheduling.
  • max-pipeline-region-blocks โ€” ๐Ÿฅž The maximum number of blocks in a region to be considered for pipelining in the selective scheduler.
  • max-sched-region-insns โ€” ๐ŸŒท The maximum number of insns in a region to be considered for interblock scheduling.
  • max-pipeline-region-insns โ€” ๐Ÿญ The maximum number of insns in a region to be 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 maximum number of iterations through the CFG to extend regions. A value of 0 disables region extensions.
  • max-sched-insn-conflict-delay โ€” โณ The maximum conflict delay for an insn to be considered for speculative motion.
  • sched-spec-prob-cutoff โ€” โœ‚๏ธ The minimal probability of speculation success (in percents) so that speculative insns get scheduled.
  • sched-state-edge-prob-cutoff โ€” ๐Ÿช„ The minimum probability an edge must have for the scheduler to save its state across it.
  • sched-mem-true-dep-cost โ€” โฑ๏ธ The minimal distance (in CPU cycles) between a store and a load targeting the same memory locations.
  • selsched-max-lookahead โ€” ๐Ÿ‘€ The maximum size of the lookahead window of selective scheduling. It's a depth of search for available instructions.
  • selsched-max-sched-times โ€” ๐Ÿ” The maximum number of times an instruction is scheduled during selective scheduling. This is the limit on the number of iterations through which the instruction may be pipelined.
  • selsched-insns-to-rename โ€” โœ๏ธ The maximum number of best instructions in the ready list that are 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 maximum size, measured as the number of RTLs, that can be recorded in an expression in the combiner for a pseudo register as the last known value of that register.
  • max-combine-insns โ€” ๐Ÿงƒ The maximum number of instructions the RTL combiner tries to combine.
  • integer-share-limit โ€” ๐Ÿค Small integer constants can use a shared data structure, which reduces the compiler's memory usage and increases its speed. This sets the maximum value of a shared integer constant.
  • ssp-buffer-size โ€” ๐Ÿ›๏ธ The minimum size of buffers (i.e. arrays) that receive stack smashing protection when -fstack-protection is used.

The default before Ubuntu 10.10 was "8". Currently it is "4", to increase the number of functions protected by the stack protector. ๐ŸŒŸ

  • min-size-for-stack-sharing โ€” ๐Ÿ“ฆ The minimum size of variables taking part in stack slot sharing when not optimizing.
  • max-jump-thread-duplication-stmts โ€” ๐Ÿงต The maximum number of statements allowed in a block that needs to be duplicated when threading jumps.
  • max-fields-for-field-sensitive โ€” ๐Ÿ—‚๏ธ The maximum number of fields in a structure treated in a field-sensitive manner during pointer analysis.
  • prefetch-latency โ€” ๐Ÿƒ An estimate of the average number of instructions executed before a prefetch finishes. The distance prefetched ahead is proportional to this constant. Increasing this number may also lead to fewer streams being prefetched (see simultaneous-prefetches).
  • simultaneous-prefetches โ€” ๐Ÿšฆ The maximum number of prefetches that can run at the same time.
  • l1-cache-line-size โ€” ๐Ÿ“ The size of a cache line in the L1 data cache, in bytes.
  • l1-cache-size โ€” ๐Ÿ’พ The size of the L1 data cache, in kilobytes.
  • l2-cache-size โ€” ๐Ÿ—„๏ธ The size of the L2 data cache, in kilobytes.
  • prefetch-dynamic-strides โ€” ๐ŸŒŠ Whether the loop array prefetch pass should issue software prefetch hints for strides that are non-constant. In some cases this may be beneficial, though the fact that the stride is non-constant may make it hard to predict when there's a clear benefit to issuing these hints.

Set to 1 if the prefetch hints should be issued for non-constant strides. Set to 0 if prefetch hints should be issued only for strides that are known to be constant and below prefetch-minimum-stride.

  • prefetch-minimum-stride โ€” ๐ŸŽˆ The minimum constant stride, in bytes, to start using prefetch hints for. If the stride is less than this threshold, prefetch hints won't be issued.

This one is giving hardware prefetcher drama ๐Ÿ”ฅ Some processors have their own hardware prefetchers, and those can clash with the software prefetchers ๐Ÿ™ˆ If the hardware prefetchers have a maximum stride they can handle, that number belongs here so the software prefetchers can actually be useful โœจ

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

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


  • loop-interchange-max-num-stmts โ€” the max number of stmts a loop can have and still get interchanged ๐Ÿ”„
  • loop-interchange-stride-ratio โ€” the minimum ratio between the strides of two loops for interchange to be profitable ๐Ÿ’œ
  • min-insn-to-prefetch-ratio โ€” the minimum ratio of instructions to prefetches needed before prefetching gets switched on in a loop ๐ŸŒธ
  • prefetch-min-insn-to-mem-ratio โ€” same energy, but for memory references: the minimum ratio of instructions to memory references needed to enable prefetching in a loop ๐Ÿงš
  • use-canonical-types โ€” whether the compiler uses the "canonical" type system. It should always be 1, because that's the more efficient internal way to compare types in C++ and Objective-C++ ๐Ÿ‘‘ But if bugs in the canonical type system are causing compilation failures, set this to 0 to turn canonical types off ๐Ÿ’€
  • switch-conversion-max-branch-ratio โ€” switch initialization conversion won't create arrays bigger than switch-conversion-max-branch-ratio times the number of branches in the switch ๐Ÿ“
  • max-partial-antic-length โ€” the max length of the partial antic set computed during tree partial redundancy elimination (-ftree-pre) when optimizing at -O3 and above. Some source code can make this optimization run away and eat all the memory on the host machine ๐Ÿ˜ญ This param caps the set lengths so that doesn't happen. Setting it to 0 allows an unlimited set length ๐Ÿซถ
  • rpo-vn-max-loop-depth โ€” the max loop depth that gets value-numbered optimistically. When the limit hits, the innermost rpo-vn-max-loop-depth loops and the outermost loop in the loop nest are value-numbered optimistically, and the remaining ones are not ๐ŸŒˆ
  • sccvn-max-alias-queries-per-access โ€” the max number of alias-oracle queries performed when hunting for redundancies in loads and stores. If this limit is hit, the search is aborted and the load or store is not considered redundant. The number of queries is algorithmically limited to the number of stores on all paths from the load to the function entry ๐Ÿ”
  • ira-max-loops-num โ€” IRA uses regional register allocation by default. If a function has more loops than this number, only at most this many of the most frequently executed loops form regions for regional register allocation ๐Ÿ‘€
  • ira-max-conflict-table-size โ€” IRA has a super smart way to compress the conflict table, but huge functions can still need excessive memory. If a function's conflict table could be bigger than this many MB, the register allocator switches to a faster, simpler, lower-quality algorithm that doesn't build a pseudo-register conflict table ๐Ÿข
  • ira-loop-reserved-regs โ€” IRA can evaluate more accurate register pressure in loops when deciding whether to move loop invariants (see -O3). This is the number of available registers reserved for other purposes. The default is the best value found from numerous experiments ๐Ÿงช
  • lra-inheritance-ebb-probability-cutoff โ€” LRA tries to reuse values reloaded into registers in subsequent insns. That's called inheritance, and EBB is the region used for it. This parameter is the minimal fall-through edge probability, in percentage, used to add a BB to the inheritance EBB in LRA. The default was chosen from numerous runs of SPEC2000 on x86-64 ๐Ÿ“Š
  • loop-invariant-max-bbs-in-loop โ€” loop invariant motion can be very expensive in both compilation time and compile-time memory for very large loops. Loops with more basic blocks than this parameter won't have loop invariant motion performed on them ๐Ÿšซ
  • loop-max-datarefs-for-datadeps โ€” building data dependencies is expensive for very large loops. This limits the number of data references in loops considered for data dependence analysis. These large loops are not handled by optimizations that use loop data dependencies ๐Ÿ™…
  • max-vartrack-size โ€” the max number of hash table slots to use during variable tracking dataflow analysis of any function. If this limit is exceeded with variable tracking at assignments enabled, analysis for that function is retried without it, after removing all debug insns from the function. If the limit is still exceeded without debug insns, var tracking analysis is completely disabled for the function. Setting this to zero makes it unlimited โ™พ๏ธ
  • max-vartrack-expr-depth โ€” the max number of recursion levels when mapping variable names or debug temporaries to value expressions. This trades compilation time for more complete debug information. If it's set too low, value expressions that are available and could be represented in debug information may not get used. Setting it higher may let the compiler find more complex debug expressions, but compile time and memory use may grow ๐Ÿ›
  • max-debug-marker-count โ€” a threshold on the number of debug markers (e.g. begin stmt markers) to avoid complexity explosion at inlining or expanding to RTL. If a function has more such gimple stmts than the limit, those stmts get dropped from the inlined copy of the function and from its RTL expansion ๐Ÿงน
  • min-nondebug-insn-uid โ€” uids starting at this parameter are used for nondebug insns. The range below it is reserved exclusively for debug insns created by -fvar-tracking-assignments, but debug insns may get (non-overlapping) uids above it if the reserved range is exhausted ๐Ÿ†”
  • ipa-sra-ptr-growth-factor โ€” IPA-SRA only replaces a pointer to an aggregate with one or more new parameters when their cumulative size is less than or equal to ipa-sra-ptr-growth-factor times the size of the original pointer parameter ๐Ÿ“
  • ipa-sra-max-replacements โ€” the max number of pieces of an aggregate that IPA-SRA tracks. As a consequence, it's also the max number of replacements of a formal parameter ๐Ÿงฉ
  • sra-max-scalarization-size-Ospeed, sra-max-scalarization-size-Osize โ€” the two Scalar Reduction of Aggregates passes (SRA and IPA-SRA) aim to replace scalar parts of aggregates with uses of independent scalar variables. These control the max size, in storage units, of an aggregate considered for replacement when compiling for speed (sra-max-scalarization-size-Ospeed) or for size (sra-max-scalarization-size-Osize), respectively ๐ŸŽ๏ธ๐Ÿ“ฆ
  • sra-max-propagations โ€” the max number of artificial accesses that Scalar Replacement of Aggregates (SRA) will track per local variable, so it can facilitate copy propagation ๐Ÿ”
  • tm-max-aggregate-size โ€” when making copies of thread-local variables in a transaction, this is the size in bytes after which variables are saved with the logging functions instead of save/restore code sequence pairs. This option only applies when using -fgnu-tm ๐Ÿงต
  • graphite-max-nb-scop-params โ€” to avoid exponential effects in the Graphite loop transforms, the number of parameters in a Static Control Part (SCoP) is bounded. A value of 0 lifts the bound. A variable whose value is unknown at compile time and defined outside a SCoP counts as a parameter of the SCoP ๐Ÿ”’
  • loop-block-tile-size โ€” loop blocking or strip mining transforms, enabled with -floop-block or -floop-strip-mine, strip mine each loop in the loop nest by a given number of iterations. The strip length can be changed using this parameter ๐Ÿงฑ
  • ipa-cp-value-list-size โ€” IPA-CP tries to track all possible values and types passed to a function's parameter so it can propagate them and perform devirtualization. This is the max number of values and types it stores per formal parameter of a function ๐Ÿ“š
  • ipa-cp-eval-threshold โ€” IPA-CP calculates its own score for its cloning profitability heuristics and performs the cloning opportunities whose scores exceed ipa-cp-eval-threshold ๐ŸŽฏ
  • ipa-cp-max-recursive-depth โ€” the max depth of recursive cloning for a self-recursive function ๐Ÿ”„
  • ipa-cp-min-recursive-probability โ€” recursive cloning only happens when the probability of the call being executed exceeds this parameter ๐ŸŽฒ
  • ipa-cp-recursion-penalty โ€” the percentage penalty recursive functions receive when they're evaluated for cloning ๐Ÿ“‰
  • ipa-cp-single-call-penalty โ€” the percentage penalty functions containing a single call to another function receive when they're evaluated for cloning ๐Ÿ“‰
  • ipa-max-agg-items โ€” IPA-CP can also propagate a number of scalar values passed in an aggregate. This controls the max number of such values per parameter ๐Ÿ’–
  • ipa-cp-loop-hint-bonus โ€” okay so when IPA-CP realizes a cloning candidate would make a loop's number of iterations known, it gives that candidate a bonus of ipa-cp-loop-hint-bonus on top of its profitability score ๐Ÿ“ˆโœจ
  • ipa-max-aa-steps โ€” IPA-CP uses alias analysis to track the values that function parameters point to ๐Ÿ”. But it won't burn all its time on huge functions, so after checking ipa-max-aa-steps statements that modify memory, it gives up and treats all memory as clobbered ๐Ÿ’€
  • ipa-max-switch-predicate-bounds โ€” the max number of boundary endpoints in a switch statement's case ranges ๐ŸŽ€. If a switch goes over this limit, IPA-CP won't build the cloning cost predicate (the thing it uses to estimate cloning benefit) for that switch's default case ๐Ÿ™ˆ
  • ipa-max-param-expr-ops โ€” IPA-CP checks conditionals that reference a function parameter to see if cloning for a certain constant value is worth it ๐Ÿง . But if a parameter expression has more operations than ipa-max-param-expr-ops, it's considered too complicated and IPA analysis just skips it ๐Ÿšซ
  • lto-partitions โ€” the desired number of partitions during WHOPR compilation ๐Ÿงฉ. It should 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 keeps tiny programs from getting chopped 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, and it's only meant for use with balanced partitioning โš–๏ธ
  • lto-max-streaming-parallelism โ€” the max number of parallel processes used for LTO streaming ๐Ÿ’œ
  • cxx-max-namespaces-for-diagnostic-help โ€” when C++ name lookup fails for an identifier, this is how many namespaces GCC will check for suggestions ๐Ÿ”Ž
  • sink-frequency-threshold โ€” the max relative execution frequency (in percent) of the target block compared to a statement's original block, which decides whether that statement can get sunk ๐Ÿ›. Bigger numbers mean more aggressive sinking ๐Ÿ”ฅ. A small positive adjustment is applied to statements with memory operands, since sinking those is even more profitable ๐Ÿ’…
  • max-stores-to-sink โ€” the max number of conditional store pairs that can be sunk ๐Ÿชฃ. Set to 0 if either vectorization (-ftree-vectorize) or if-conversion (-ftree-loop-if-convert) is disabled ๐Ÿ™ƒ
  • case-values-threshold โ€” the smallest number of different values where a jump table is better than a tree of conditional branches ๐ŸŒณ. If it's 0, the machine's default is used ๐Ÿช„
  • jump-table-max-growth-ratio-for-size โ€” the max code size growth ratio (in percent) when expanding into a jump table ๐Ÿ“. This one is used when optimizing for size ๐Ÿค
  • jump-table-max-growth-ratio-for-speed โ€” the same max code size growth ratio (in percent) when expanding into a jump table โšก. This one is used when optimizing for speed ๐ŸŽ๏ธ
  • tree-reassoc-width โ€” sets the max number of instructions executed in parallel in a reassociated tree ๐ŸŒˆ. If it has a non-zero value, it overrides the target-dependent heuristics that would be used by default โœจ
  • sched-pressure-algorithm โ€” lets you pick between the two implementations of -fsched-pressure ๐ŸŽญ. Algorithm 1 is the original and is more likely to stop instructions from getting reordered ๐ŸงŠ. Algorithm 2 was designed as a compromise between the pretty conservative algorithm 1 and the rather aggressive default scheduler ๐Ÿค. It leans more heavily on having a regular register file and accurate register pressure classes ๐Ÿ“š. See 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 considered when looking 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 using -fsanitize=address ๐Ÿ’–. To turn off stack protection, use --param asan-stack=0 option ๐Ÿ™ˆ
  • asan-instrument-reads โ€” turns on buffer overflow detection for memory reads ๐Ÿ‘€. It's on by default when using -fsanitize=address ๐Ÿ’–. To turn off memory reads protection, use --param asan-instrument-reads=0 ๐Ÿšซ
  • asan-instrument-writes โ€” turns on buffer overflow detection for memory writes โœ๏ธ. It's on by default when using -fsanitize=address ๐Ÿ’–. To turn off memory writes protection, use --param asan-instrument-writes=0 option ๐Ÿ™…โ€โ™€๏ธ
  • asan-memintrin โ€” turns on detection for built-in functions ๐Ÿ› ๏ธ. It's on by default when using -fsanitize=address ๐Ÿ’–. To turn off built-in functions protection, use --param asan-memintrin=0 ๐Ÿšซ
  • asan-use-after-return โ€” turns on detection of use-after-return ๐Ÿ”™. 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 the function being instrumented has a number of memory accesses that's greater than or equal to this number, GCC uses callbacks instead of inline checks ๐Ÿ“ž. For example, to disable inline code, use --param asan-instrumentation-with-call-threshold=0 ๐Ÿ’…
  • use-after-scope-direct-emission-threshold โ€” if a local variable's size in bytes is smaller than or equal to this number, shadow memory is poisoned (or unpoisoned) directly ๐Ÿช„. That means no run-time callbacks are used ๐Ÿ™Œ
  • max-fsm-thread-path-insns โ€” the max number of instructions copied when duplicating blocks on a finite state automaton jump thread path ๐Ÿงต
  • max-fsm-thread-length โ€” the max number of basic blocks on a finite state automaton jump thread path ๐Ÿงถ
  • max-fsm-thread-paths โ€” the max number of new jump thread paths created for a finite state automaton ๐Ÿงญ
  • parloops-chunk-size โ€” the chunk size of the omp schedule for loops parallelized by parloops ๐Ÿฐ
  • parloops-schedule โ€” the schedule type of the omp schedule for loops parallelized by parloops ๐Ÿ“…. The options are static, dynamic, guided, auto, and runtime ๐ŸŽ€
  • parloops-min-per-thread โ€” the minimum number of iterations per thread of an innermost parallelized loop where the parallel version is preferred over the single-threaded one ๐Ÿงต. For a parallelized loop nest, the minimum number of iterations of the outermost loop per thread is two ๐Ÿ‘‘
  • max-ssa-name-query-depth โ€” the max recursion depth when querying properties of SSA names in things like fold routines ๐ŸŒ€. One level of recursion means following one use-def chain ๐Ÿ”—
  • hsa-gen-debug-stores โ€” enables special debug stores inside HSA kernels, which the libgomp plugin then reads and reports ๐Ÿ›ฐ๏ธ. These stores are disabled by default, so use --param hsa-gen-debug-stores=1 to turn them on โญ
  • max-speculative-devirt-maydefs โ€” the max number of may-defs analyzed while hunting for a must-def that shows the dynamic type of an object making a virtual call we might speculatively devirtualize ๐Ÿ•ต๏ธโ€โ™€๏ธ
  • max-vrp-switch-assertions โ€” the max number of assertions added along the default edge of a switch statement during VRP ๐Ÿงช
  • unroll-jam-min-percent โ€” the minimum percentage of memory references that have to get optimized away for unroll-and-jam to count as profitable ๐Ÿ’ธ
  • unroll-jam-max-unroll โ€” the max number of times the outer loop can be unrolled by the unroll-and-jam transformation ๐Ÿฅ
  • max-rtl-if-conversion-unpredictable-cost โ€” the max cost you'll accept for the sequence the RTL if-conversion pass generates for a branch that's considered unpredictable ๐ŸŽฒ
  • max-variable-expansions-in-unroller โ€” if -fvariable-expansion-in-unroller is used, this is the max number of times one variable gets expanded during loop unrolling ๐ŸŒท
  • tracer-min-branch-probability-feedback โ€” stop forward growth if the best edge's probability is below this threshold (in percent) ๐Ÿ›‘. It's used when profile feedback is available ๐Ÿ“Š
  • partial-inlining-entry-probability โ€” the max probability (in percent, relative to the function's entry BB) of the entry BB of a split region that still lets partial inlining happen ๐Ÿงฉ
  • max-tracked-strlens โ€” the max number of strings the strlen optimization pass will track string lengths for ๐Ÿงต
  • gcse-after-reload-partial-fraction โ€” the threshold ratio for performing partial redundancy elimination after reload ๐Ÿ”
  • gcse-after-reload-critical-fraction โ€” the threshold ratio of critical edges' execution count that allows redundancy elimination after reload ๐Ÿชž
  • max-loop-header-insns โ€” the max number of insns in a loop header that the copy loop headers pass is allowed to duplicate ๐Ÿ“‹
  • vect-epilogues-nomask โ€” enables loop epilogue vectorization using a smaller vector size ๐Ÿฆ‹
  • slp-max-insns-in-bb โ€” the max number of instructions in a basic block that can be considered for SLP vectorization ๐Ÿง
  • 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 it checks 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 โ€” whether codegen errors should count as ICEs when -fchecking is on ๐Ÿ™ˆ
  • sms-max-ii-factor โ€” a tuning factor for the upper bound the swing modulo scheduler uses when it schedules a loop โญ
  • lra-max-considered-reload-pseudos โ€” the max number of reload pseudos that get considered while spilling a non-reload pseudo ๐Ÿงš
  • max-pow-sqrt-depth โ€” the max depth of sqrt chains 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 allocas/VLAs protection ๐Ÿ›ก๏ธ
  • max-iterations-computation-cost โ€” a bound on how expensive an expression can be when computing the number of iterations ๐Ÿ’œ
  • max-isl-operations โ€” the max number of isl operations, where 0 means unlimited โ™พ๏ธ
  • graphite-max-arrays-per-scop โ€” the max number of arrays per scop ๐ŸŒธ
  • max-vartrack-reverse-op-size โ€” the max size of a loc list for which reverse ops should be added ๐Ÿฆ‹
  • tracer-dynamic-coverage-feedback โ€” the percentage of a function, weighted by execution frequency, that trace formation must cover. This is only 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 gives up on threading 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 peeks into, and at ' ' only the instruction sorting heuristic is turned on ๐ŸŽ€
  • loop-versioning-max-inner-insns โ€” the max number of instructions an inner loop can have before the loop versioning pass decides it's too big to copy ๐Ÿซถ
  • loop-versioning-max-outer-insns โ€” the max number of instructions an outer loop can have before the loop versioning pass decides it's too big to copy. Any instructions in inner loops that directly benefit from versioning don't count toward this ๐Ÿ‘‘
  • ssa-name-def-chain-limit โ€” the max number of SSA_NAME assignments to follow when figuring out a property of a variable, like its value. This caps the iterations or recursive calls GCC makes while optimizing certain statements or checking whether they're valid before it issues diagnostics ๐Ÿช„
  • store-merging-max-size โ€” the max size of a single store merging region, in bytes ๐Ÿ’พ
  • hash-table-verification-limit โ€” the number of elements that get hash table verification for each element searched ๐ŸŒท
  • max-find-base-term-values โ€” the max number of VALUEs handled during a single find_base_term call ๐Ÿ“
  • analyzer-max-enodes-per-program-point โ€” the max number of exploded nodes per program point in the analyzer. Once that's hit, analysis of that point wraps up โœจ
  • analyzer-min-snodes-for-call-summary โ€” the min number of supernodes a function needs before the analyzer will bother summarizing its effects at call sites ๐Ÿ“
  • analyzer-max-recursion-depth โ€” the max number of times a callsite can show up in a call stack within the analyzer. Once it's reached, analysis of any call that would recurse deeper gets terminated ๐ŸŒŠ
  • gimple-fe-computed-hot-bb-threshold โ€” the number of executions a basic block needs before it counts as hot. This one is only used in the GIMPLE FE ๐Ÿ”ฅ
  • analyzer-bb-explosion-factor โ€” the max number of 'after supernode' exploded nodes per supernode in the analyzer. Past that, analysis stops ๐Ÿ’ฅ

The following choices of name are available on AArch64 targets ๐ŸŒˆ

  • aarch64-sve-compare-costs โ€” when vectorizing for SVE, this considers using "unpacked" vectors for smaller elements and lets 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 the float type. The precision of division scales with this param when division approximation is enabled. The default value is 1 ๐ŸŽฏ
  • aarch64-double-recp-precision โ€” the number of Newton iterations used to calculate the reciprocal for the double type. The precision of division scales with this param when division approximation is enabled. The default value is 2 ๐Ÿ’ซ
  • aarch64-autovec-preference โ€” forces an ISA selection strategy for auto-vectorization. It accepts values from 0 to 4, inclusive ๐Ÿฆ„
    • 0 โ€” use the default heuristics
    • 1 โ€” use only Advanced SIMD for auto-vectorization
    • 2 โ€” use only SVE for auto-vectorization
    • 3 โ€” use both Advanced SIMD and SVE, preferring Advanced SIMD when the costs are deemed equal
    • 4 โ€” use both Advanced SIMD and SVE, preferring SVE when the costs are deemed equal

The default value is 0 ๐ŸŒธ


โœจ Program Instrumentation Options โœจ

GCC has a bunch of command-line options that bolt run-time instrumentation onto the code it normally spits out ๐Ÿ”. One reason to instrument is to collect profiling stats so you can hunt down program hot spots, do code coverage analysis, or set up profile-guided optimizations ๐Ÿ“Š. Another kind is run-time checking, which catches programming mistakes like invalid pointer dereferences or out-of-bounds array accesses, plus sneaky attacks like stack smashing or C++ vtable hijacking ๐Ÿ›ก๏ธ. There's also a general hook 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 have to use this option when compiling the source files you want data about, and you have to use it when linking too ๐Ÿซถ.

You can use the function attribute no_instrument_function to skip profiling for individual functions when compiling with these options ๐Ÿ™ˆ.

  • -fprofile-arcs โ€” adds code so program flow arcs get instrumented ๐Ÿน. While the program runs, it records how many times each branch and call gets executed, and how many times each one is taken or returns ๐Ÿ”. On targets that support constructors with priority support, profiling handles constructors, destructors, and C++ constructors (and destructors) of classes that are used as the type of a global variable properly ๐Ÿ‘‘.

When the compiled program exits, it saves this data to a file called auxname.gcda for each source file ๐Ÿ’พ. That data can feed profile-directed optimizations (-fbranch-probabilities) or test coverage analysis (-ftest-coverage) ๐ŸŒˆ. Each object file's auxname comes from the output file's name if you explicitly specified one and it's not the final executable. Otherwise it comes from the basename of the source file. Either way, any suffix gets removed. For example, you'd get foo.gcda for the input file dir/foo.c, or dir/foo.gcda for an output file specified as -o dir/foo.o ๐Ÿฆ‹.

  • --coverage โ€” this is the one to use when you want to compile and link 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 ๐Ÿ“š.
    • Compile the source files with -fprofile-arcs, plus your optimization and code generation options. For test coverage analysis, add the extra -ftest-coverage option. You don't need to profile every source file in a program ๐Ÿ’….
    • Compile the source files with -fprofile-abs-path too, so the .gcno files get absolute path names. That way gcov can find the right sources in projects where compilations happen from different working directories ๐Ÿ—บ๏ธ.
    • Link your object files with -lgcov or -fprofile-arcs. The latter implies the former ๐Ÿ”—.
    • Run the program on a representative workload to generate the arc profile information. You can repeat this as many times as you want ๐Ÿƒโ€โ™€๏ธ. You can run concurrent instances of your program, and as long as the file system supports locking, the data files will update correctly ๐Ÿ”’. Unless a strict ISO C dialect option is in effect, fork calls get detected and handled correctly without double counting ๐Ÿด.
    • For profile-directed optimizations, compile the source files again with the same optimization and code generation options, plus -fbranch-probabilities โšก.
    • For test coverage analysis, use gcov to produce human-readable information from the .gcno and .gcda files. Check the gcov documentation for more info ๐Ÿ“–.

Okay so with -fprofile-arcs, GCC builds a program flow graph for every function in your program, then finds a spanning tree for it ๐ŸŒณ. Only the arcs that are not on that tree need instrumenting, which is lowkey genius, because the compiler just sneaks in counting code for those arcs ๐Ÿ”ข. If an arc is the only exit or the only entrance to a block, the counter can go right inside that block ๐ŸŽ€. Otherwise GCC has to make a brand new basic block just to hold the instrumentation code ๐Ÿงฑ.

  • -ftest-coverage โ€” Produces a notes file that the gcov code-coverage utility can read to show program coverage ๐Ÿ“Š. Each source file's note file is named auxname.gcno. For what auxname means and how to generate test coverage data, look back at -fprofile-arcs above ๐Ÿ‘€. Coverage data matches your source more closely if you don't optimize ๐Ÿ’….
  • -fprofile-abs-path โ€” Automatically turns relative source file names into absolute path names inside the .gcno files ๐Ÿ—บ๏ธ. This helps gcov find the right sources in projects that compile from different working directories ๐Ÿซถ.
  • -fprofile-dir=path โ€” Sets the directory where profile data files get searched for, to path ๐Ÿ“. This only affects profile data made by -fprofile-generate, -ftest-coverage, and -fprofile-arcs, and used by -fprofile-use, -fbranch-probabilities, and their related options ๐Ÿ”—. Absolute and relative paths both work ๐ŸŒธ. By default GCC uses the current directory, so the profile data file lands in the same folder as the object file ๐Ÿ“‚. To stop file names from clashing, if the object file name isn't an absolute path, GCC mangles the absolute path of the sourcename.gcda file and uses that as the .gcda file name ๐ŸŒ€. See the similar option -fprofile-note โœจ.

When an executable runs in a massive parallel environment, it's recommended to save profiles into different folders ๐Ÿงš. You can do that with variables inside path that get exported at run-time:

  • %p โ€” process ID.
  • %q{VAR} โ€” value of the environment variable VAR ๐ŸŒˆ.
  • -fprofile-generate, -fprofile-generate=path โ€” Turns on the options you'd normally use to instrument an app, so it produces a profile you can use later to recompile with profile feedback based optimization ๐Ÿ”ฅ. You must use -fprofile-generate both when compiling and when linking, or it won't work right ๐Ÿ’€.

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 actually optimize using the profile you collected, use -fprofile-use ๐Ÿ‘‘.

  • -fprofile-note=path โ€” If path is specified, GCC saves the .gcno file into that location ๐Ÿ“. If you combine this with multiple source files, the .gcno file gets overwritten ๐Ÿ™ˆ.
  • -fprofile-prefix-path=path โ€” Use this with profile-generate=profile_dir and profile-use=profile_dir to tell GCC where the base directory of your built source tree is ๐ŸŒท. By default, profile_dir holds files with mangled absolute paths of every object file in the build ๐Ÿ˜ตโ€๐Ÿ’ซ. That's a problem when the directory you built the instrumented binary in is different from the one you used for the optimized build, because then the profile data won't be found during the optimized build ๐Ÿ˜ญ. In that situation, -fprofile-prefix-path=path with path pointing to the base build directory strips out the irrelevant part and keeps every file name relative to the main build directory ๐Ÿงธ.
  • -fprofile-update=method โ€” Changes how an instrumented app updates its profile data ๐Ÿ”„. method should be one of single, atomic, or prefer-atomic. single is great for single-threaded apps, while atomic stops profile corruption by emitting thread-safe code ๐Ÿงต.
Warning: If an app doesn't properly join all of its threads (or it creates a detached thread), the profile file can still get corrupted ๐Ÿšจ.

Using prefer-atomic becomes atomic when the target supports it, and falls back to single otherwise ๐Ÿฆ‹. The GCC driver picks prefer-atomic automatically when -pthread is on the command line ๐Ÿ’œ.

  • -fprofile-filter-files=regex โ€” Only instruments functions from files whose names match any of the regular expressions, separated by a semicolon ๐ŸŽฏ. For example, -fprofile-filter-files=main.c;module.*.c instruments only main.c and every C file starting with 'module' ๐Ÿ“.
  • -fprofile-exclude-files=regex โ€” Only instruments functions from files whose names do not match all of the regular expressions, separated by a semicolon ๐Ÿ™…โ€โ™€๏ธ. For example, -fprofile-exclude-files=/usr/* stops every file in the /usr/ folder from being instrumented ๐Ÿšซ.
  • -fprofile-reproducible=[multithreaded|parallel-runs|serial] โ€” Controls how reproducible the profile from -fprofile-generate is ๐Ÿ”. This lets you rebuild a program and get the same outcome, which is super useful for things like distribution packages ๐Ÿ“ฆ.

With -fprofile-reproducible=serial, the profile is reproducible as long as the trained program behaves the same on every invocation of the train run, isn't multi-threaded, and always streams profile data in the same order ๐ŸŽ€. Profile streaming happens at the end of the program run, but also before the fork function is invoked ๐Ÿด.

Heads up, though: it's pretty common for execution counts in parts of a program to depend on things like the length of temporary file names or memory space randomization, which can change hash-table collision rates ๐ŸŽฒ. That non-reproducible part can be marked with the no_instrument_function function attribute ๐Ÿท๏ธ. You can use gcov-dump with -l to dump the gathered data and check that it really is reproducible ๐Ÿ”.

With -fprofile-reproducible=parallel-runs, the collected profile stays reproducible no matter what order the data gets streamed into the gcda files ๐Ÿงฉ. This setting lets you run multiple instances of the instrumented program in parallel, like with make -j ๐Ÿƒโ€โ™€๏ธ. The tradeoff is that the quality of the gathered data drops, 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 โœจ. For more details, check <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 when the instrumented program starts up ๐Ÿ™Œ. For a list of supported options, see <https://github.com/google/sanitizers/wiki/AddressSanitizerFlags#run-time-flags> ๐Ÿฆ‹. This option cannot be combined with -fsanitize=thread ๐Ÿšซ.

  • -fsanitize=kernel-address โ€” Enables AddressSanitizer for the Linux kernel ๐Ÿง. For more details, see <https://github.com/google/kasan/wiki> ๐Ÿซถ.
  • -fsanitize=pointer-compare โ€” Instruments comparison operations (<, <=, >, >=) that have pointer operands ๐Ÿ‘€. This option has to be combined with either -fsanitize=kernel-address or -fsanitize=address ๐Ÿ’…. It cannot be combined with -fsanitize=thread ๐Ÿšซ.

Note: The check is disabled at run time by default ๐Ÿ˜ด. To turn it on, add detect_invalid_pointer_pairs=2 to the ASAN_OPTIONS environment variable โšก. Using detect_invalid_pointer_pairs=1 only detects invalid operations when both pointers are non-null ๐ŸŽฏ.

  • -fsanitize=pointer-subtract โ€” Instruments subtraction with pointer operands ๐Ÿงฎ. This option has to be combined with either -fsanitize=kernel-address or -fsanitize=address ๐Ÿ’œ. It cannot 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 ๐ŸŽ€.

Heads up: sanitized atomic builtins can't throw exceptions when they operate 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 when the executable is linked against a library that overrides malloc and other allocator functions ๐Ÿง . For more details, see <https://github.com/google/sanitizers/wiki/AddressSanitizerLeakSanitizer> ๐Ÿ“š. The run-time behavior can be influenced with the LSAN_OPTIONS environment variable ๐ŸŒฟ. This option cannot be combined with -fsanitize=thread ๐Ÿšซ.
  • -fsanitize=undefined โ€” Enables UndefinedBehaviorSanitizer, a fast undefined behavior detector ๐Ÿ”. Various computations get instrumented to detect undefined behavior at runtime โš™๏ธ. For more details, see <https://clang.llvm.org/docs/UndefinedBehaviorSanitizer.html> ๐Ÿฆ„. The run-time behavior can be influenced with the UBSAN_OPTIONS environment variable ๐ŸŒŸ. The current suboptions are:
    • -fsanitize=shift โ€” Enables checking that the result of a shift operation isn't undefined ๐Ÿซง. What counts as undefined differs slightly between C and C++, and also between ISO C90 and C99, and so on ๐Ÿค“. This option has two suboptions, -fsanitize=shift-base and -fsanitize=shift-exponent ๐Ÿงฉ.
    • -fsanitize=shift-exponent โ€” Enables checking that the second argument of a shift operation isn't negative and is smaller than the precision of the promoted first argument ๐Ÿ”ข.
  • -fsanitize=shift-base โ€” ๐Ÿ’– okay so if the second argument of a shift is within range, the compiler checks that the result of the shift isn't undefined. Heads up: what counts as undefined is slightly different between C and C++, and also between ISO C90 and C99, etc. โœจ
  • -fsanitize=integer-divide-by-zero โ€” ๐Ÿงฎ catches integer division by zero, plus the sneaky INT_MIN / -1 division.
  • -fsanitize=unreachable โ€” ๐Ÿ™ˆ with this on, the compiler turns the __builtin_unreachable call into a diagnostics message call instead. When you reach __builtin_unreachable, the behavior is undefined, so this is the warning you want.
  • -fsanitize=vla-bound โ€” ๐Ÿ“ checks that the size of a variable length array is positive.
  • -fsanitize=null โ€” ๐Ÿšซ pointer checking, bestie! Your app will throw an error if it tries to dereference a NULL pointer, if a reference (possibly an rvalue reference) gets bound to a NULL pointer, or if a method gets invoked on an object pointed to by a NULL pointer.
  • -fsanitize=return โ€” ๐Ÿ”™ return statement checking. Programs built with this on will throw an error message when the end of a non-void function is reached without actually returning a value. This 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 totally count here! For example, this is not an overflow:
signed char a = SCHAR_MAX;
a++;
  • -fsanitize=bounds โ€” ๐Ÿ“ฆ enables instrumentation of array bounds, so various out of bounds accesses get detected. Flexible array members, flexible array member-like arrays, and initializers of variables with static storage are not instrumented.
  • -fsanitize=bounds-strict โ€” ๐Ÿ“ the stricter version! Most out of bounds accesses get detected, including flexible array members and flexible array member-like arrays. Initializers of variables with static storage still aren't instrumented.
  • -fsanitize=alignment โ€” ๐Ÿงฑ checks pointer alignment when they're 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, so various out of bounds pointer accesses are detected.
  • -fsanitize=float-divide-by-zero โ€” โž— detects floating-point division by zero. Unlike other similar options, this one is NOT enabled by -fsanitize=undefined, since floating-point division by zero can be a legit way of getting infinities and NaNs. ๐ŸŒˆ
  • -fsanitize=float-cast-overflow โ€” ๐Ÿ”„ enables floating-point type to integer conversion checking. It checks that the result of the conversion doesn't overflow. Unlike other similar options, this one is NOT enabled by -fsanitize=undefined. โš ๏ธ This option does not work well with FE_INVALID exceptions enabled.
  • -fsanitize=nonnull-attribute โ€” ๐Ÿ™… instruments calls and checks whether null values are 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 returning null values from those functions gets detected.
  • -fsanitize=bool โ€” ๐Ÿ”˜ instruments loads from bool. If a value other than 0/1 gets loaded, a run-time error is issued.
  • -fsanitize=enum โ€” ๐Ÿ—‚๏ธ instruments loads from an enum type. If a value outside the range of values for that enum type gets loaded, a run-time error is issued.
  • -fsanitize=vptr โ€” ๐Ÿงฌ C++ only, bestie! It instruments 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, a run-time error is issued.
  • -fsanitize=builtin โ€” ๐Ÿ› ๏ธ instruments arguments to selected builtin functions. If an invalid value gets passed to those arguments, a run-time error is issued. E.g. passing 0 as the argument to __builtin_ctz or __builtin_clz invokes undefined behavior and is diagnosed by this option.

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, so don't even try it ๐Ÿ˜ญ
  • -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 of opts. Turning this on for a sanitizer makes it try to keep the program running as if no error happened. That means multiple runtime errors can get reported in one run, and the exit code might say success even when errors were reported. The -fno-sanitize-recover= option can alter this: only the first detected error gets reported, and then the program exits with a non-zero exit code. ๐Ÿ˜ค

Currently this feature 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 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 the compiler side, it also needs to be enabled on the runtime library side, otherwise the failures are still fatal. โ˜ ๏ธ The runtime library defaults to halt_on_error=0 for ThreadSanitizer and UndefinedBehaviorSanitizer, while the default value for AddressSanitizer is halt_on_error=1. 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 equivalent to 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 detect use-after-scope bugs. This option sets -fstack-reuse to none.
  • -fsanitize-undefined-trap-on-error โ€” ๐Ÿชค instructs the compiler to report undefined behavior using __builtin_trap rather than a libubsan library routine. The advantage? 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. It inserts a call to __sanitizer_cov_trace_pc into every basic block.
  • -fsanitize-coverage=trace-cmp โ€” ๐Ÿงฒ enables dataflow guided fuzzing code instrumentation. It inserts a call to:
    • __sanitizer_cov_trace_cmp1, __sanitizer_cov_trace_cmp2, __sanitizer_cov_trace_cmp4 or __sanitizer_cov_trace_cmp8 for integral comparisons 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 call, function return, indirect jump) are valid. This stops control from being diverted to an unexpected target, and it's meant to protect against threats like Return-oriented Programming (ROP), and similarly call/jmp-oriented programming (COP/JOP). ๐Ÿ‘‘
    • branch โ€” checks validity of control-flow transfer 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. The check 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. ๐ŸŽ€

Bestie, the nocf_check attribute is your escape hatch ๐Ÿฆ‹ Use it to mark which functions and calls should get skipped from instrumentation, no cap.

Right now the x86 GNU/Linux target has its own version built on Intel Control-flow Enforcement Technology (CET), and it works on i686 processors or newer ๐Ÿ’…

NOTE: In Ubuntu 19.10 and later versions, -fcf-protection is turned on by default for C, C++, ObjC, ObjC++, if none of -fno-cf-protection nor -fcf-protection=* are found. ๐Ÿ™ˆ

-fstack-protector

Okay so this one adds extra code to check for buffer overflows, like stack smashing attacks ๐Ÿ›ก๏ธ It works by slipping a guard variable into any function with vulnerable objects. That includes functions that call alloca, and functions with buffers larger than or equal to 8 bytes. The guards get set up when a function is entered and then checked when it exits. If a guard check fails, an error message gets printed and the program exits. Only variables that are actually allocated on the stack count here, so optimized away variables or variables allocated in registers don't count. ๐Ÿ’–

-fstack-protector-all

Same energy as -fstack-protector, except now EVERY function gets protected ๐Ÿ‘‘

-fstack-protector-strong

This is -fstack-protector but with extra functions added to the protected list: the ones that have local array definitions, or that have references to local frame addresses. Same rule as before though, only variables that are actually allocated on the stack are considered, and optimized away variables or variables allocated in registers don't count. โœจ

-fstack-protector-explicit

Like -fstack-protector, but it only protects the functions that have the stack_protect attribute. ๐ŸŽ€

-fstack-check

Generate code to verify that you don't go past the boundary of the stack ๐Ÿงš You should turn this on if you're running in an environment with multiple threads. In a single-threaded environment you only rarely need it, because stack overflow is automatically detected on nearly all systems if there's only one stack.

Note that this switch doesn't actually do the checking itself. The operating system or the language runtime has to do that. What the switch does is generate code so they can see the stack being extended.

You can also tack on a string parameter, and the options are:

  • no means no checking
  • generic means force the use of old-style checking
  • specific means use the best checking method, and it's equivalent to bare -fstack-check

Old-style checking is a generic mechanism that needs no specific target support in the compiler, but it comes with these drawbacks:

  1. Modified allocation strategy for large objects: they are always allocated dynamically if their size exceeds a fixed threshold. Note this may change the semantics of some code.
  2. Fixed limit on the size of the static frame of functions: when it is topped by a particular function, stack checking is not reliable and a warning is issued by the compiler.
  3. Inefficiency: because of both the modified allocation strategy and the generic implementation, code performance is hampered.

Also, old-style stack checking is the fallback method for specific if no target support has been added in the compiler. ๐Ÿ™ˆ

-fstack-check= is designed for Ada's needs to detect infinite recursion and stack overflows, and specific is an excellent choice when compiling Ada code. It's not generally sufficient to protect against stack-clash attacks though. For those, you want -fstack-clash-protection. ๐Ÿฆ‹

-fstack-clash-protection

Generate code to prevent stack clash style attacks. When this is enabled, the compiler only allocates one page of stack space at a time, and each page gets accessed right after allocation. That means allocations can't jump over any stack guard page the operating system provides. ๐Ÿ’…

Most targets don't fully support stack clash protection. On those targets, though, -fstack-clash-protection will protect dynamic stack allocations. It may also 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

Generate code to make sure the stack doesn't grow beyond a certain value, either the value of a register or the address of a symbol. If a larger stack is needed, a signal gets raised at run time. On most targets the signal is raised before the stack overruns the boundary, so you can catch it without taking special precautions. ๐ŸŒธ

For instance, if the stack starts at absolute address 0x80000000 and grows downwards, you can use the flags -fstack-limit-symbol=__stack_limit and -Wl,--defsym,__stack_limit=0x7ffe0000 to enforce a stack limit of 128KB. Note that this may only work with the GNU linker.

You can locally override stack limit checking by using the no_stack_limit function attribute.

-fsplit-stack

Generate code to automatically split the stack before it overflows. The result is a discontiguous stack that can only overflow if the program can't allocate any more memory. This is most useful with threaded programs, since you no longer have to figure out a good stack size to use for each thread ๐Ÿงš This is currently only implemented for the x86 targets running GNU/Linux.

When code compiled with -fsplit-stack calls code compiled without -fsplit-stack, there may not be much stack space left for that latter code to run in. If compiling all code, including library code, with -fsplit-stack isn't an option, the linker can fix up those calls so the code compiled without -fsplit-stack always gets a large stack. Support for this is implemented in the gold linker in GNU binutils release 2.21 and later.

-fvtable-verify=[std|preinit|none]

Only available when compiling C++ code, this one turns on 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. Using -fvtable-verify=none turns it off instead ๐Ÿ”ฅ If an invalid vtable pointer is detected at run time, an error is reported and the program's execution is immediately halted.

This option builds run-time data structures at program startup, and those are what get used to verify the vtable pointers. The std and preinit options control the timing of when they're built. In both cases the data structures are built before execution reaches main. With -fvtable-verify=std they're built after shared libraries have been loaded and initialized. With -fvtable-verify=preinit they're built before shared libraries have been loaded and initialized. ๐Ÿ’œ

If this option shows up multiple times on the command line with different values, none takes highest priority over both std and preinit, and preinit takes priority over std. ๐Ÿ‘‘

-fvtv-debug

Used together with -fvtable-verify=std or -fvtable-verify=preinit, this makes the debug versions of the 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 gets written to a file named vtv_set_ptr_data.log in the directory named by the environment variable VTV_LOGS_DIR if it's defined, or in the current working directory otherwise. ๐Ÿฆ‹

Note: This feature appends data to the log file. If you want a fresh log file, be sure to delete any existing one.

-fvtv-counts

This is a debugging flag, bestie ๐Ÿ” Used with -fvtable-verify=std or -fvtable-verify=preinit, the compiler keeps track of the total number of virtual calls it encounters and the number of verifications it inserts. It also counts the calls to certain run-time library functions that it inserts, and logs all of this for each compilation unit. The info is written to a file named vtv_count_data.log in the directory named by the environment variable VTV_LOGS_DIR if that's defined, or the current working directory otherwise. It also counts the size of the vtable pointer sets for each class and writes that to vtv_class_set_sizes.log in the same directory. ๐ŸŒˆ

Note: This feature appends data to the log files. To get fresh log files, be sure to delete any existing ones.

-finstrument-functions

Generate instrumentation calls for entry and exit to functions. 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 information may not be available to the profiling functions otherwise.) โญ

void __cyg_profile_func_enter (void *this_fn,
                               void *call_site);
void __cyg_profile_func_exit  (void *this_fn,
                               void *call_site);

The first argument is the address of the start of the current function, which can be looked up exactly in the symbol table. ๐Ÿงš

This instrumentation also happens 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 those functions have to be available. If all your uses of a function get expanded inline, this may mean an extra 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.) ๐Ÿ’…

Okay so a function can wear the attribute "no_instrument_function" ๐ŸŽ€, and when it does, GCC just skips instrumenting it. Bestie, that's a VIP pass ๐Ÿงš It's super useful for the profiling functions listed above, high-priority interrupt routines, and any functions that can't safely call the profiling functions (like signal handlers, if the profiling routines generate output or allocate memory). Those functions get to stay off the radar, no cap ๐Ÿฆ‹

  • -finstrument-functions-exclude-file-list=file,file,... โ€” This is the bouncer list for files ๐Ÿซถ Give it a list, and any function defined in a file that matches one of those entries gets left out of instrumentation (same deal as -finstrument-functions, see above). Matching is done on substrings, so if the file parameter is a substring of the file name, it counts as a match. โœจ

Here's a lil example ๐Ÿ’–

-finstrument-functions-exclude-file-list=/bits/stl,include/sys

That one excludes any inline function defined in files whose pathnames contain /bits/stl or include/sys. Bestie, that's a whole lot of stuff gone in one line ๐Ÿ˜ญ

Okay, now the tricky part ๐Ÿ™ˆ If, for some reason, you want to include a literal comma in one of the sym entries, you write two commas, ,,. For example, -finstrument-functions-exclude-file-list=',,tmp' (note the single quote surrounding the option).

  • -finstrument-functions-exclude-function-list=sym,sym,... โ€” This is the sibling of the file list, but it goes by function names instead ๐Ÿ’… The name it matches is the user-visible name, like "vector<int> blah(const vector<int> &)", not the internal mangled name (e.g., "_Z4blahRSt6vectorIiSaIiEE"). Same vibe as before: substring matching, so if the sym parameter is a substring of the function name, it's a match. For C99 and C++ extended identifiers, the function name has to be given in UTF-8, not using universal character names. ๐ŸŒˆ
  • -fpatchable-function-entry=N[,M] โ€” Generate N NOPs right at the beginning of each function, with the function entry point before the Mth NOP. If M is omitted, it defaults to 0, so the function entry points to the address just at the first NOP. These NOP instructions reserve extra space that can be used to patch in any desired instrumentation at run time, provided that the code segment is writable ๐Ÿ”ฅ The amount of space is controllable indirectly via the number of NOPs. The NOP instruction used corresponds to the instruction emitted by the internal GCC back-end interface "gen_nop". This behavior is target-specific and may also depend on the architecture variant and/or other compilation options.

For run-time identification, the starting addresses of these areas, which correspond to their respective function entries minus M, are additionally collected in the "__patchable_function_entries" section of the resulting binary ๐Ÿงš

Note that the value of "__attribute__ ((patchable_function_entry (N,M)))" takes precedence over command-line option -fpatchable-function-entry=N,M. This can be used to increase the area size or to remove it completely on a single function. If "N=0", no pad location is recorded. ๐Ÿ’œ

The NOP instructions are inserted at---and maybe before, depending on M---the function entry address, even before the prologue.


๐ŸŽ€ Options Controlling the Preprocessor ๐ŸŽ€

These options control the C preprocessor, which is run on each C source file before actual compilation.

If you use the -E option, nothing is done except preprocessing. Some of these options make sense only together with -E, because they cause the preprocessor output to be unsuitable for actual compilation.

In addition to the options listed here, there are a number of options to control search paths for include files documented in Directory Options. Options to control preprocessor diagnostics are listed in Warning Options. ๐ŸŒธ

  • -D name โ€” Predefine name as a macro, with the definition 1 โœจ
  • -D name=definition โ€” The contents of definition get tokenized and processed as if they appeared during translation phase three in a #define directive. Basically, the definition gets truncated by any embedded newline characters ๐Ÿ™ˆ

If you're invoking the preprocessor from a shell or shell-like program, you may need to use the shell's quoting syntax to protect characters like spaces that have a meaning in the shell syntax. ๐Ÿš

If you wanna define a function-like macro on the command line, write its argument list with surrounding parentheses before the equals sign (if any). Parentheses mean something to most shells, so you should quote the option. With sh and csh, -D'name(args...)=definition' works ๐Ÿ’…

-D and -U options are processed in the order they're given on the command line. All -imacros file and -include file options are 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. However, the first directory searched for file is the preprocessor's working directory, instead of 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. Macros it defines remain 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 remain defined ๐ŸŒˆ
  • -pthread โ€” Define additional macros required for using the POSIX threads library. You should use this option consistently for both compilation and linking ๐Ÿงต This option is 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, output 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 specified explicitly (with -MT or -MQ), the object file name consists of the name of the source file with any suffix replaced with the object file suffix, and with any leading directory parts removed. If there are many included files, the rule is 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, you should 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. ๐Ÿ™ˆ

  • -MM โ€” Like -M, but do not 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 in itself determine whether that header appears in -MM dependency output.

  • -MF file โ€” When used with -M or -MM, 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 renders that useless. This feature is used in automatic updating of makefiles ๐Ÿ› ๏ธ

  • -MP โ€” This option 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 โ€” Change 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. The 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 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 mention only user header files, not system header files ๐ŸŒธ
  • -fpreprocessed โ€” ๐Ÿงš This tells the preprocessor the input file is already preprocessed, so it skips macro expansion, trigraph conversion, escaped newline splicing, and most directives. It still spots and removes comments, so a file made with -C won't cause drama when you hand it to the compiler. In this mode the integrated preprocessor is basically just a tokenizer for the front ends ๐Ÿ’…. It's switched on automatically for input files ending in .i, .ii or .mi, which are the extensions GCC uses for preprocessed files made by -save-temps โœจ.
  • -fdirectives-only โ€” ๐Ÿฆ‹ When preprocessing, this handles directives but leaves macros alone. How it acts depends on -E and -fpreprocessed, so pay attention:
    • With -E, it only handles directives like "#define", "#ifdef", and "#error". Macro expansion and trigraph conversion are skipped, and -dD gets turned on automatically ๐ŸŒธ.
    • With -fpreprocessed, predefining command-line macros and most builtin macros is turned off. Contextual macros like __LINE__ still get handled normally. This is how you compile files that were previously run through -E -fdirectives-only ๐ŸŽ€.
    • With both -E and -fpreprocessed, the -fpreprocessed rules win. That lets you fully preprocess files that were earlier run through -E -fdirectives-only ๐Ÿ‘‘.
  • -fdollars-in-identifiers โ€” ๐Ÿ’– Lets $ show up inside identifiers.
  • -fextended-identifiers โ€” ๐ŸŒˆ Lets identifiers use universal character names and extended characters. It's on by default for C99 (and later C standards) and for C++, so you're probably already getting it ๐Ÿ’….
  • -fno-canonical-system-headers โ€” ๐Ÿ“ When preprocessing, this stops system header paths from being shortened through canonicalization.
  • -fmax-include-depth=depth โ€” ๐Ÿซถ Sets how deep nested #includes can go. The default is 200 โœจ.
  • -ftabstop=width โ€” ๐Ÿ“ Sets the distance between tab stops. This helps the preprocessor report the right column numbers in warnings and errors even when tabs are on the line ๐ŸŒธ. If the value is less than 1 or greater than 100, the option gets ignored ๐Ÿ™ˆ. The default is 8.
  • -ftrack-macro-expansion[=level] โ€” ๐Ÿ” This tracks where tokens come from across macro expansions. When an error happens inside a macro, the compiler can then show you the current macro expansion stack, which is so helpful ๐Ÿ˜ญ. The catch is that it makes the preprocessor and compiler use more memory. The level parameter lets you pick how precisely tokens get tracked, so you can cut memory use if you need to:
    • Level 0 turns this option off ๐Ÿ’€.
    • Level 1 tracks in a degraded mode for minimal memory overhead. In this mode, every token that comes from expanding an argument of a function-like macro has the same location.
    • Level 2 tracks token locations completely. It's the most memory hungry option ๐Ÿ”ฅ.
    • If you give the option with no argument, the level defaults to 2.

Also, -ftrack-macro-expansion=2 is on by default, so it's already doing its thing ๐Ÿ’œ.

  • -fmacro-prefix-map=old=new โ€” ๐Ÿ—บ๏ธ When preprocessing files living in directory old, __FILE__ and __BASE_FILE__ expand as if those files lived in directory new instead. You can use . for new to flip an absolute path into a relative one, which can lead to more reproducible, location-independent builds ๐Ÿฆ‹. This also changes __builtin_FILE() during compilation. See also -ffile-prefix-map.
  • -fexec-charset=charset โ€” ๐Ÿ’ฌ Sets the execution character set, which covers string and character constants. The default is UTF-8. charset can be any encoding your system's iconv library routine supports โœจ.
  • -fwide-exec-charset=charset โ€” ๐ŸŒ Sets the wide execution character set, used for wide string and character constants. The default is whichever of UTF-32BE, UTF-32LE, UTF-16BE, or UTF-16LE matches the width of wchar_t and the byte order (big-endian or little-endian) being used for code generation ๐Ÿง . Just like -fexec-charset, charset can be any encoding iconv supports, but be warned: you'll have problems with encodings that don't fit exactly in wchar_t ๐Ÿ˜ฌ.
  • -finput-charset=charset โ€” ๐Ÿ“ฅ Sets the input character set, which translates the input file's characters into the source character set GCC uses. If the locale doesn't say anything, or GCC can't get that info from the locale, the default is UTF-8. The locale or this command-line option can override it, and if they conflict, the command-line option wins right now ๐Ÿ’…. charset can be any encoding iconv supports.
  • -fpch-deps โ€” ๐Ÿ—‚๏ธ When you're using precompiled headers, this makes the dependency-output flags also list files from the precompiled header's own dependencies. Without it, only the precompiled header gets listed, not the files that were used to make it, because those files aren't consulted when a precompiled header is in use ๐Ÿ™ˆ.
  • -fpch-preprocess โ€” ๐Ÿงฉ This lets you use a precompiled header together with -E. It drops a special #pragma, #pragma GCC pch_preprocess "filename", into the output to mark where the precompiled header was found and what its filename is. When -fpreprocessed is in play, GCC recognizes that #pragma and loads the PCH ๐Ÿ’œ. It's off by default, since the preprocessed output is really only good as input to GCC. -save-temps switches it on.
You should not write this #pragma in your own code. It is safe to edit the filename, though, if the PCH file lives in a different spot. The filename can be absolute, or relative to GCC's current directory โš ๏ธ.
  • -fworking-directory โ€” ๐Ÿ“‚ Turns on linemarkers in the preprocessor output so the compiler knows the working directory at the time of preprocessing. With this on, after the initial linemarker, the preprocessor emits a second linemarker with the current working directory followed by two slashes. When that directory shows up in the preprocessed input, GCC uses it as the working directory in some debugging information formats ๐Ÿ”. This is implicitly enabled when debugging info is on, but you can block it with the negated form -fno-working-directory. If -P is on the command line, this option does nothing, because no #line directives get emitted whatsoever ๐Ÿšซ.
  • -A predicate=answer โ€” ๐ŸŽฏ Makes an assertion with the predicate predicate and the answer answer. This form is the preferred one over the older -A predicate(answer) form. The older form still works, but the new one is better because it doesn't use shell special characters ๐Ÿ’….
  • -A -predicate=answer โ€” โŒ Cancels an assertion with the predicate predicate and the answer answer ๐Ÿฅ€.
  • -C โ€” ๐Ÿ’ฌ Keeps comments, so they don't get discarded. All comments pass through to the output file, except the ones inside 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, a comment at the start of what would be a directive line turns that line into an ordinary source line, since the first token on the line is no longer a # ๐Ÿ˜ญ.
  • -CC โ€” ๐Ÿง Keeps comments even during macro expansion. It's like -C, except comments inside macros also get passed through to the output wherever the macro is expanded ๐ŸŒˆ. On top of everything -C does, -CC converts all C++-style comments inside a macro into C-style comments. That stops a later use of the macro from accidentally commenting out the rest of the source line ๐Ÿ™…โ€โ™€๏ธ. -CC is generally used to support lint comments ๐Ÿซง.
  • -P โ€” ๐Ÿค Stops linemarkers from showing up in the preprocessor output. This could be handy when you're running the preprocessor on something that isn't C code and sending it to a program that might get confused by linemarkers ๐ŸŒธ.
  • -traditional, -traditional-cpp โ€” ๐Ÿ•ฐ๏ธ These try to copy the behavior of pre-standard C preprocessors, instead of the ISO C ones. Check the GNU CPP manual for the details ๐Ÿ“–.
GCC doesn't try to emulate a pre-standard C compiler in any other way. These options only work with the -E switch, or when you invoke CPP explicitly ๐Ÿ™ƒ.
  • -trigraphs โ€” ๐Ÿ”บ Supports ISO C trigraphs. These are three-character sequences that all start with ??, and ISO C defines them 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 โ€” ๐Ÿ—ƒ๏ธ Turns on special code to work around file systems that only allow super short file names, like MS-DOS ๐Ÿ’พ.
  • -H โ€” ๐ŸŒณ Prints the name of each header file used, along with all the other normal activities ๐Ÿƒ. Each name gets indented to show how deep it sits in the #include stack. Precompiled header files get printed too, even when they turn out to be invalid. An invalid precompiled header shows up with ...x, and a valid one shows up with ...! ๐Ÿ”ฅ.
  • -dletters โ€” ๐Ÿ› ๏ธ Asks GCC to make 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 get silently ignored ๐Ÿคซ. If you specify letters whose behaviors conflict, the result is undefined ๐Ÿ’€.
    • -dM โ€” โœจ Instead of the normal output, this generates a list of #define directives for all the macros defined while the preprocessor runs, including the predefined ones. It's a great way to find out what's predefined in your version of the preprocessor ๐Ÿ”ฎ. Assuming you have no file foo.h, the command
touch foo.h; cpp -dM foo.h

Okay so touch foo.h; cpp -dM foo.h shows all the predefined macros ๐Ÿ’–โœจ (the whole list just pops up, it's giving everything).

๐Ÿ™ˆ If you use -dM without the -E option, -dM gets interpreted as a synonym for -fdump-rtl-mach. Bestie, read that twice.
  • -dD โ€” Basically -dM, but with two differences ๐Ÿฆ‹. It does not include the predefined macros, and it outputs both the #define directives and the result of preprocessing. Both kinds of output go to the standard output file.
  • -dN โ€” Same energy as -dD, but it only spits out the macro names ๐ŸŒธ, not their expansions.
  • -dI โ€” Outputs #include directives on top of the preprocessing result ๐Ÿ“š.
  • -dU โ€” Like -dD, but way more selective ๐Ÿ’…. Only macros that are expanded, or whose definedness is tested in preprocessor directives, get output. The output is delayed until the macro is used or tested, and #undef directives are also output for macros that were tested but were undefined at the time.
  • -fdebug-cpp โ€” Only useful if you're debugging GCC itself ๐Ÿงš. When used from CPP or with -E, it dumps debugging info about location maps. Every token in the output is preceded by the dump of the map its location belongs to.

When used from GCC without -E, this option has no effect.

  • -Wp,option โ€” You can use this to bypass the compiler driver and pass option straight through to the preprocessor ๐Ÿš€. If option contains commas, it gets split into multiple options at the commas.
โš ๏ธ Many options get modified, translated, or interpreted by the compiler driver before they reach the preprocessor, and -Wp forcibly skips that phase. The preprocessor's direct interface is undocumented and subject to change, so whenever possible, avoid -Wp and let the driver handle the options instead ๐Ÿฅบ.
  • -Xpreprocessor option โ€” Passes option along to the preprocessor ๐ŸŽ€. Use this for system-specific preprocessor options that GCC doesn't recognize.

If you want to pass an option that takes an argument, you must use -Xpreprocessor twice, once for the option and once for the argument ๐Ÿ’€.

  • -no-integrated-cpp โ€” Preprocessing happens as a separate pass before compilation ๐Ÿ“. By default, GCC preprocesses as an integrated part of input tokenization and parsing. If this option is provided, the appropriate language front end (cc1, cc1plus, or cc1obj for C, C++, and Objective-C, respectively) gets invoked twice: once for preprocessing only, and once for actual compilation of the preprocessed input. This can be useful together with the -B or -wrapper options to specify an alternate preprocessor or to do extra processing of the program source between normal preprocessing and compilation ๐ŸŒˆ.

โœจ Passing Options to the Assembler โœจ

You can pass options to the assembler ๐Ÿซถ.

  • -Wa,option โ€” Passes option to the assembler ๐Ÿฆ‹. If option contains commas, it gets split into multiple options at the commas.
  • -Xassembler option โ€” Passes option to the assembler too ๐Ÿ’œ. You can use this to supply system-specific assembler options that GCC doesn't recognize.

If you want to pass an option that takes an argument, you must use -Xassembler twice, once for the option and once for the argument ๐Ÿ˜ญ.


โœจ Options for Linking โœจ

These options come into play when the compiler links object files into an executable output file ๐Ÿ”—. They're meaningless if the compiler isn't doing a link step, so don't bother.

  • object-file-name โ€” A file name that doesn't end in a special recognized suffix is considered to name an object file or library ๐Ÿ“ฆ. (The linker tells object files apart from libraries by looking at the file contents.) If linking is done, these object files are used as input to the linker.
  • -c, -S, -E โ€” If any of these options is used, the linker is not run, and object file names should not be used as arguments ๐Ÿ™…โ€โ™€๏ธ.
  • -flinker-output=type โ€” This option 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 may be useful to control the type manually ๐Ÿง .
    • exec โ€” Code generation produces a static binary ๐Ÿชจ. In this case, -fpic and -fpie are both disabled.
    • dyn โ€” Code generation produces a shared library ๐ŸŒธ. In this case, -fpic or -fPIC is preserved, but not enabled automatically. This allows building shared libraries without position-independent code on architectures where that's possible, i.e. on x86.
    • pie โ€” Code generation produces an -fpie executable ๐Ÿ‘‘. This results in similar optimizations as exec, except that -fpie is not disabled if it was specified at compilation time.
    • rel โ€” The compiler assumes incremental linking is happening ๐Ÿงฉ. The sections containing intermediate code for link-time optimization are merged, pre-optimized, and output to the resulting object file. In addition, if -ffat-lto-objects is specified, binary code is produced for future non-LTO linking. The object file produced by incremental linking is smaller than a static library produced from the same object files. At link time, the result of incremental linking also loads faster than a static library, assuming that the majority of objects in the library are used.
    • nolto-rel โ€” Configures the compiler for incremental linking where code generation is forced, a final binary is produced, and the intermediate code for later link-time optimization is stripped ๐Ÿช„. When multiple object files are linked together, the resulting code is better optimized than with link-time optimizations disabled (for example, cross-module inlining happens), but most of the benefits of whole program optimizations are lost.

During the incremental link (by -r), the linker plugin defaults to rel. With current interfaces to GNU Binutils, it is however not possible to incrementally link LTO objects and non-LTO objects into a single mixed object file ๐Ÿ˜ตโ€๐Ÿ’ซ. If any of the object files in an incremental link cannot be used for link-time optimization, the linker plugin issues a warning and uses nolto-rel. To maintain whole program optimization, it's recommended to link such objects into a static library instead. Alternatively, it is possible to use H.J. Lu's binutils with support for mixed objects ๐Ÿ”ฅ.

  • -fuse-ld=bfd โ€” Use the bfd linker instead of the default linker ๐Ÿ› ๏ธ.
  • -fuse-ld=gold โ€” Use the gold linker instead of the default linker ๐Ÿฅ‡.
  • -fuse-ld=lld โ€” Use the LLVM lld linker instead of the default linker ๐Ÿ’ซ.
  • -fuse-ld=mold โ€” Use the Modern Linker (mold) instead of the default linker โšก.
  • -llibrary, -l library โ€” Searches the library named library when linking ๐Ÿ”. (The second alternative, with the library as a separate argument, is only there for POSIX compliance and isn't recommended, ngl.)

The -l option is passed directly to the linker by GCC ๐Ÿซ . Refer to your linker documentation for the exact details. The general description below applies to the GNU linker.

The linker searches a standard list of directories for the library. The directories searched include several standard system directories, plus any that 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 gives preference to linking with the shared library unless the -static option is used ๐ŸŽฏ.

It makes a difference where in the command you write this option ๐Ÿ™ƒ. The linker searches and processes libraries and object files in the order they'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 โ€” Don't use the standard system startup files when linking ๐Ÿšซ. The standard system libraries are still used normally, unless -nostdlib, -nolibc, or -nodefaultlibs is used.
  • -nodefaultlibs โ€” Don't use the standard system libraries when linking ๐Ÿ™…. Only the libraries you specify are passed to the linker, and options specifying linkage of the system libraries, such as -static-libgcc or -shared-libgcc, are ignored. The standard startup files are 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. These entry points should be supplied through some other mechanism when this option is specified ๐Ÿงฏ.

  • -nolibc โ€” Don't use the C library, or the system libraries tightly coupled with it, when linking ๐ŸงŠ. You still link with the startup files, libgcc, or toolchain-provided language support libraries such as libgnat, libgfortran, or libstdc++, unless options preventing their inclusion are used as well. This typically removes -lc from the link command line, along with system libraries that normally go with it and become meaningless when the absence of a C library is assumed, for example -lpthread or -lm in some configurations. This is intended for bare-board targets where there really is no C library available ๐Ÿค–.
  • -nostdlib โ€” Don't use the standard system startup files or libraries when linking ๐ŸŒ‘. No startup files are used, and only the libraries you specify are passed to the linker. Options specifying linkage of the system libraries, such as -static-libgcc or -shared-libgcc, are ignored.

The compiler may generate calls to "memcmp", "memset", "memcpy" and "memmove". These entries are usually resolved by entries in libc. These entry points should be supplied through some other mechanism when this option is specified ๐Ÿซฃ.

๐Ÿ’€ One of the standard libraries bypassed by -nostdlib and -nodefaultlibs is libgcc.a, a library of internal subroutines which GCC uses to overcome shortcomings of particular machines, or special needs for some languages.

In most cases, you still need libgcc.a even when you're trying to dodge the other standard libraries ๐Ÿซถ so when you go with -nostdlib or -nodefaultlibs, you should usually add -lgcc too. That way you won't end up with unresolved references to GCC's internal library subroutines โœจ (an example is __main, which makes sure C++ constructors get called ๐Ÿ’…)

  • -e entry, --entry=entry โ€” okay so this sets the program entry point to entry. The linker is the one who reads it, and the GNU linker takes either a symbol name or an address ๐Ÿฆ‹
  • -pie โ€” makes a dynamically linked position independent executable on targets that support it ๐Ÿ’–
For predictable results, you must also specify the same set of options used for compilation (-fpie, -fPIE, or model suboptions) when you use this linker option. Don't skip this, bestie ๐Ÿ˜ญ
  • -no-pie โ€” the opposite energy: no dynamically linked position independent executable for you ๐Ÿ™…โ€โ™€๏ธ
  • -static-pie โ€” a static position independent executable on targets that support it ๐ŸŒธ It's similar to a static executable, but it can be loaded at any address without a dynamic linker, which is so iconic ๐Ÿ‘‘
Same rule applies: for predictable results, you must also specify the same set of options used for compilation (-fpie, -fPIE, or model suboptions) when you use this linker option.
  • -pthread โ€” links with the POSIX threads library ๐Ÿงต This one is supported on GNU/Linux targets, most other Unix derivatives, and also on x86 Cygwin and MinGW targets. On some targets it also sets flags for the preprocessor, so use it consistently for both compilation and linking, periodt โœจ
  • -r โ€” produces a relocatable object as output. This is also known as partial linking ๐Ÿงฉ
  • -rdynamic โ€” passes the flag -export-dynamic to the ELF linker on targets that support it. This tells the linker to add all symbols, not just the used ones, to the dynamic symbol table ๐ŸŒˆ It's needed for some uses of dlopen or to get backtraces from inside a program, so it's giving very necessary energy ๐Ÿ’…
  • -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 has no effect, so don't stress ๐Ÿ’€
  • -shared โ€” produces a shared object that can then be linked with other objects to form an executable ๐Ÿฆ‹ Not all systems support this one.
For predictable results, you must also specify the same set of options used for compilation (-fpic, -fPIC, or model suboptions) when you use this linker option.[1]
  • -shared-libgcc, -static-libgcc โ€” on systems that provide libgcc as a shared library, these force the use of either the shared or the static version, respectively. If no shared version of libgcc was built when the compiler was configured, these do nothing ๐Ÿ™ƒ

Okay, so there are a few situations where an app should use the shared libgcc instead of the static one. The biggest one is when the app wants to throw and catch exceptions across different shared libraries. In that case, each of the libraries and the app itself should use the shared libgcc ๐Ÿซถ

That's why the G++ driver automatically adds -shared-libgcc whenever you build a shared library or a main executable. C++ programs typically use exceptions, so this is the right move, fr fr โœจ

If you use the GCC driver to make shared libraries instead, 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 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, linking with the static version of libgcc by default instead. This lets exceptions propagate through those shared libraries without incurring relocation costs at library load time ๐ŸŒธ

But if a library or main executable is supposed to throw or catch exceptions, you must link it using the G++ driver, or use the option -shared-libgcc, so it gets linked with the shared libgcc. No skipping this one, bestie ๐Ÿ˜ญ

  • -static-libasan โ€” when -fsanitize=address is used to link a program, the GCC driver automatically links against libasan. If libasan is available as a shared library and -static isn't used, it links against the shared version. This option tells the GCC driver to link libasan statically, without necessarily linking other libraries statically ๐Ÿ”
  • -static-libtsan โ€” when -fsanitize=thread is used to link a program, the GCC driver automatically links against libtsan. If libtsan is available as a shared library and -static isn't used, it links against the shared version. This option tells the GCC driver to link libtsan statically, without necessarily linking other libraries statically ๐Ÿงต
  • -static-liblsan โ€” when -fsanitize=leak is used to link a program, the GCC driver automatically links against liblsan. If liblsan is available as a shared library and -static isn't used, it links against the shared version. This option tells the GCC driver to link liblsan statically, without necessarily linking other libraries statically ๐Ÿซง
  • -static-libubsan โ€” when -fsanitize=undefined is used to link a program, the GCC driver automatically links against libubsan. If libubsan is available as a shared library and -static isn't used, it links against the shared version. This option tells the GCC driver to link libubsan statically, without necessarily linking other libraries statically ๐Ÿ“
  • -static-libstdc++ โ€” when the g++ program links a C++ program, it normally links against libstdc++ automatically. If libstdc++ is available as a shared library and -static isn't used, it links against the shared version, which is normally fine ๐Ÿ’œ Sometimes, though, you want to freeze the version of libstdc++ your program uses without going all the way to a fully static link. This option 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 as an option ๐Ÿ› ๏ธ Use this to supply system-specific linker options that GCC doesn't recognize, lowkey a lifesaver ๐Ÿ™Œ

If you want to pass an option that takes a separate argument, you have to use -Xlinker twice: once for the option and once for the argument. For example, to pass -assert definitions, you must write -Xlinker -assert -Xlinker definitions. Writing -Xlinker "-assert definitions" does not work, because that passes the entire string as one single argument, which is not what the linker expects ๐Ÿ’€

With the GNU linker, it's usually more convenient to pass arguments using the option=value syntax instead of separate arguments. For example, you can write -Xlinker -Map=output.map rather than -Xlinker -Map -Xlinker output.map. Other linkers may not support this syntax for command-line options โœจ

  • -Wl,option โ€” passes option to the linker too ๐ŸŽ€ If option contains commas, it gets split into multiple options at the commas. You can use this syntax to pass an argument to the option. For example, -Wl,-Map,output.map passes -Map output.map to the linker. With the GNU linker, you can also get the same effect with -Wl,-Map=output.map ๐Ÿงš
NOTE: In Ubuntu 8.10 and later versions, for LDFLAGS, the option -Wl,-z,relro is used. To disable it, use -Wl,-z,norelro.
  • -u symbol โ€” pretends the symbol symbol is undefined, to force linking of library modules that define it ๐ŸŽฏ You can use -u multiple times with different symbols to force loading of additional library modules.
  • -z keyword โ€” -z gets passed straight on to the linker along with the keyword keyword. Check the section in your linker's documentation for permitted values and what they mean ๐Ÿ“–

These options specify directories to search for header files, for libraries, and for parts of the compiler ๐Ÿ—‚๏ธ

  • -I dir, -iquote dir, -isystem dir, -idirafter dir โ€” adds the directory dir to the list of directories searched for header files during preprocessing ๐Ÿ’… If dir begins with = or $SYSROOT, then the = or $SYSROOT is replaced by the sysroot prefix. See --sysroot and -isysroot.

Directories 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 the #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. For the quote form of the include directive, the directories specified by -iquote options are searched in left-to-right order, as they appear on the command line.
  3. Directories specified with -I options are scanned in left-to-right order.
  4. Directories specified with -isystem options are scanned in left-to-right order.
  5. Standard system directories are scanned.
  6. Directories specified with -idirafter options are scanned in left-to-right order.

Okay bestie, so you can totally use -I to override a system header file ๐ŸŽ€ by swapping in your own version, because these directories get searched before the standard system header directories โœจ. BUT (big but) don't use this option to add directories full of vendor-supplied system headers ๐Ÿ™ˆ. Use -isystem for that ๐Ÿ’….

The -isystem and -idirafter options also mark the directory as a system directory ๐Ÿฆ‹, so it gets the same VIP 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 gets ignored ๐Ÿ’€. The directory is still searched, just 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 messed up by accident ๐Ÿซถ. If you really need to change the search order for system directories, go with the -nostdinc and/or -isystem options ๐Ÿ”ฅ.

  • -I- โ€” Split the include path ๐ŸŒธ. This one is deprecated, so please use -iquote instead for the -I directories that come before the -I-, and then remove the -I- option.
    • Any directories given with -I options before -I- only get searched for headers requested with "#include "file"". They don't get searched for "#include <file>".
    • If more directories are given with -I options after the -I-, those get searched for all #include directives.
    • -I- also stops the directory of the current file from being used as the first search directory for "#include "file"". There's no way to override this effect of -I- ๐Ÿ™ƒ.
  • -iprefix prefix โ€” Pick prefix as the prefix for the later -iwithprefix options ๐Ÿง. If the prefix represents a directory, make sure you include the final / ๐Ÿ“.
  • -iwithprefix dir, -iwithprefixbefore dir โ€” Tack dir onto the prefix you set earlier with -iprefix, and add the result to the include search path ๐Ÿ›ฃ๏ธ. -iwithprefixbefore puts it in the same spot -I would, while -iwithprefix puts it where -idirafter would ๐Ÿ’–.
  • -isysroot dir โ€” This is basically the --sysroot option, but it only applies to header files ๐ŸŽ€. The exception is Darwin targets, where it applies to both header files and libraries. Check out --sysroot for more info ๐Ÿ’….
  • -imultilib dir โ€” Use dir as a subdirectory of the directory that holds the target-specific C++ headers ๐ŸŒˆ.
  • -nostdinc โ€” Don't search the standard system directories for header files ๐Ÿ™…. Only the directories given with -I, -iquote, -isystem, and/or -idirafter (plus the current file's directory, if that's appropriate) get searched โœจ.
  • -nostdinc++ โ€” Skip the C++-specific standard directories when searching for headers, but keep searching the other standard directories ๐Ÿ’œ. (This one gets used when building the C++ library ๐Ÿ“š.)
  • -iplugindir=dir โ€” Set the directory to search for plugins that get passed with -fplugin=name instead of -fplugin=path/name.so ๐Ÿ”Œ. This isn't really meant for you to use ๐Ÿ™ˆ. Only the driver passes it along ๐Ÿš—.
  • -Ldir โ€” Add directory dir to the list of directories searched for -l ๐Ÿ“.
  • -Bprefix โ€” This tells the compiler where to find its own executables, libraries, include files, and data files ๐Ÿงš.
    • The compiler driver runs one or more of the subprograms cpp, cc1, as, and ld ๐Ÿƒ. It tries prefix as a prefix for each program it runs, both with and without machine/version/ for the corresponding target machine and compiler version.
    • For each subprogram, the driver first tries the -B prefix, if there is one. If that name isn't found, or if -B isn't specified, the driver tries two standard prefixes, /usr/lib/gcc/ and /usr/local/lib/gcc/. If neither of those turns up a file that's found, the unmodified program name gets searched for using the directories in your PATH environment variable ๐Ÿ—บ๏ธ.
    • The compiler checks whether the path given by -B refers to a directory, and if needed it adds a directory separator character to the end of the path ๐Ÿซถ.
    • -B prefixes that effectively specify directory names also apply to libraries in the linker ๐Ÿ”—, because the compiler translates these options into -L options for the linker. They also apply to include files in the preprocessor ๐Ÿงฉ, because the compiler translates these options into -isystem options for the preprocessor. In this case, the compiler appends include to the prefix.
    • The runtime support file libgcc.a can also be searched for using the -B prefix, if needed. If it isn't found there, the two standard prefixes above are tried, and that's 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 given by -B is [dir/]stageN/, where N is a number in the range 0 to 9, then it gets replaced by [dir/]include. This is to help with boot-strapping the compiler ๐Ÿฅพ.
  • -no-canonical-prefixes โ€” Don't expand any symbolic links ๐Ÿ”—, don't resolve references to /../ or /./, and don't make the path absolute when generating a relative prefix ๐Ÿ™….
  • --sysroot=dir โ€” Use dir as the logical root directory for headers and libraries ๐Ÿ‘‘. For example, if the compiler normally searches for headers in /usr/include and libraries in /usr/lib, it searches dir/usr/include and dir/usr/lib instead.
    • If you use both this option and -isysroot, then --sysroot applies to libraries, but -isysroot applies to header files.
    • The GNU linker (beginning with version 2.16) has the necessary support for this option ๐Ÿ’–. If your linker doesn't support it, the header file aspect of --sysroot still works, but the library aspect doesn't ๐Ÿ˜ญ.
  • --no-sysroot-suffix โ€” For some targets, a suffix gets added to the root directory given with --sysroot, depending on the other options you used ๐Ÿง. So headers might be found in dir/suffix/usr/include instead of dir/usr/include. This option turns off adding that suffix ๐Ÿšซ.

๐ŸŽ€ Options for Code Generation Conventions ๐ŸŽ€

These machine-independent options control the interface conventions used in code generation ๐Ÿง .

Most of them have both positive and negative forms, and the negative form of -ffoo is -fno-foo ๐Ÿ”„. In the list below, only one of the forms is listed, the one that is not the default. You can figure out the other form by either removing no- or adding it ๐Ÿงฉ.

  • -fstack-reuse=reuse-level โ€” This option 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. The option is needed when the program extends the lifetime of a scoped local variable or a compiler generated temporary beyond the end point defined by the language ๐Ÿซฃ. When a 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 a 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, and the aggressive stack reuse can lead to runtime errors ๐Ÿ’€. This option is used to control the temporary stack reuse optimization โœจ.

  • -ftrapv โ€” This option generates traps for signed overflow on addition, subtraction, and multiplication operations ๐Ÿšจ. The options -ftrapv and -fwrapv override each other, so using -ftrapv -fwrapv on the command-line results in -fwrapv being effective. Note that only active options override, so using -ftrapv -fwrapv -fno-wrapv on the command-line results in -ftrapv being effective.
  • -fwrapv โ€” This option tells the compiler to assume that signed arithmetic overflow of addition, subtraction, and multiplication wraps around using twos-complement representation ๐ŸŒ€. This flag enables some optimizations and disables others ๐ŸŽ›๏ธ. The options -ftrapv and -fwrapv override each other, so using -ftrapv -fwrapv on the command-line results in -fwrapv being effective. Note that only active options override, so using -ftrapv -fwrapv -fno-wrapv on the command-line results in -ftrapv being effective.
  • -fwrapv-pointer: okay bestie, this one tells the compiler to assume pointer arithmetic overflow on addition and subtraction just wraps around using twos-complement representation ๐Ÿ”„โœจ It also turns off some optimizations that would otherwise assume pointer overflow is invalid ๐Ÿ™ˆ
  • -fstrict-overflow: lowkey the opposite energy ๐Ÿ’… It implies -fno-wrapv -fno-wrapv-pointer. When you negate it (-fno-strict-overflow), it implies -fwrapv -fwrapv-pointer instead ๐Ÿฆ‹
  • -fexceptions: enables exception handling ๐Ÿ’– It generates the extra code needed to propagate exceptions. On some targets it also means GCC generates frame unwind information for every function, which can add significant data size overhead (it doesn't touch execution, though ๐Ÿ“ฆ).

If you don't specify it, 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 usually need it. You might still need to enable it when compiling C code that has to interoperate with exception handlers written in C++ ๐Ÿซถ And you might wanna disable it if you're compiling older C++ programs that don't use exception handling ๐Ÿ’€

  • -fnon-call-exceptions: makes trapping instructions able to throw exceptions ๐Ÿงจ Heads up, this needs platform-specific runtime support that doesn't exist everywhere. It only lets trapping instructions throw exceptions (so memory references or floating-point instructions). It can't throw exceptions out of arbitrary signal handlers like "SIGALRM", so don't even try ๐Ÿ™…โ€โ™€๏ธ
  • -fdelete-dead-exceptions: instructions that might throw exceptions but don't otherwise contribute to the program's execution can get optimized away ๐Ÿ—‘๏ธ This is on by default for the Ada front end, which the Ada language specification permits. The optimization passes that remove dead exceptions are enabled independently at different optimization levels.
  • -funwind-tables: basically -fexceptions, except it only generates any needed static data and doesn't change the generated code in any other way ๐Ÿ“š You usually don't need to turn this on yourself, because a language processor that needs this handling enables it for you ๐Ÿงš
  • -fasynchronous-unwind-tables: generates an unwind table in DWARF format, if the target machine supports it ๐Ÿ—บ๏ธ The table is exact at every instruction boundary, so it can be used for stack unwinding from asynchronous events, like a debugger or a garbage collector ๐Ÿซง
  • -fno-gnu-unique: okay this one is a little messy ๐Ÿฅด With a recent GNU assembler and C library, the C++ compiler uses the "STB_GNU_UNIQUE" binding so template static data members and static local variables in inline functions stay unique even with "RTLD_LOCAL". That's needed so a library used by two different "RTLD_LOCAL" plugins doesn't end up disagreeing about the symbol's binding.

The catch? This makes dlclose get ignored for affected DSOs. If your program relies on reinitializing a DSO through dlclose and dlopen, you can use -fno-gnu-unique ๐Ÿ”

  • -fpcc-struct-return: returns short struct and union values in memory, like the longer ones, instead of in registers ๐Ÿงฑ It's less efficient, but it lets GCC-compiled files play nicely with files built by other compilers, especially the Portable C Compiler (pcc) ๐Ÿค

The exact convention for returning structures in memory depends on the target configuration macros. Short structures and unions are the ones whose size and alignment match some integer type.

Warning: code compiled with -fpcc-struct-return is not binary compatible with code compiled with -freg-struct-return. Only use it to conform to a non-default application binary interface โš ๏ธ
  • -freg-struct-return: returns struct and union values in registers whenever possible ๐ŸŽ๏ธ It's more efficient for small structures than -fpcc-struct-return.

If you specify neither flag, GCC goes with whatever convention is standard for the target. If there's no standard convention, it 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 to conform to a non-default application binary interface โš ๏ธ
  • -fshort-enums: an enum type only gets as many bytes as it needs for its declared range of values ๐Ÿ”ข Specifically, the enum type ends up equivalent to the smallest integer type that has enough room.
Warning: -fshort-enums makes GCC generate code that is not binary compatible with code generated without it. Only use it to conform to a non-default application binary interface โš ๏ธ
  • -fshort-wchar: overrides the underlying type of wchar_t to be short unsigned int instead of the target's default ๐ŸŒธ This is handy for building programs that run under WINE.
Warning: -fshort-wchar makes GCC generate code that is not binary compatible with code generated without it. 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 using the extern keyword, which don't allocate any storage.

The default is -fno-common, which puts uninitialized global variables in the BSS section of the object file. That stops the linker from merging tentative definitions, so if the same variable is accidentally defined in more than one compilation unit, you get a multiple-definition error. Good for catching mistakes ๐Ÿ™Œ

-fcommon puts uninitialized global variables in a common block instead. That lets the linker resolve all the tentative definitions of the same variable across different compilation units to the same object, or to a non-tentative definition. This behavior is inconsistent with C++, and on many targets it costs a speed and code size penalty on global variable references. It's mainly useful for getting legacy code to link without errors ๐Ÿฆ•

  • -fno-ident: ignores the #ident directive ๐Ÿ™ˆ
  • -finhibit-size-directive: don't output a .size assembler directive, or anything else that would cause trouble if the function gets split in the middle with the two halves placed far apart in memory ๐Ÿงฉ This one is used when compiling crtstuff.c, so you probably won't need it for anything else.
  • -fverbose-asm: adds extra commentary to the generated assembly so it's easier to read ๐Ÿ“ This is mostly for people who actually need to read generated assembly, like when debugging the compiler itself ๐Ÿง‘โ€๐Ÿ’ป

-fno-verbose-asm, the default, leaves that extra info out, which is useful when you're comparing two assembler files โš–๏ธ

The added comments include:

  • information on the compiler version and command-line options,
  • the source code lines associated with the assembly instructions, in the form FILENAME:LINENUMBER:CONTENT OF LINE,
  • hints on which high-level expressions correspond to the various assembly instruction operands.

For example, given this C source file:

        int test (int n)
        {
          int i;
          int total = 0;

          for (i = 0; i < n; i++)
            total += i * i;

          return total;
        }

Compiling it to (x86_64) assembly with -S and sending the result straight to stdout with -o - looks like this:

gcc -S test.c -fverbose-asm -Os -o -

That gives output similar to this ๐Ÿ‘€

        .file   "test.c"
# GNU C11 (GCC) version 7.0.0 20160809 (experimental) (x86_64-pc-linux-gnu)
  [...snip...]
# options passed:
  [...snip...]

        .text
        .globl  test
        .type   test, @function
test:
.LFB0:
        .cfi_startproc
# test.c:4:   int total = 0;
        xorl    %eax, %eax      # <retval>
# test.c:6:   for (i = 0; i < n; i++)
        xorl    %edx, %edx      # i
.L2:
# test.c:6:   for (i = 0; i < n; i++)
        cmpl    %edi, %edx      # n, i
        jge     .L5     #,
# test.c:7:     total += i * i;
        movl    %edx, %ecx      # i, tmp92
        imull   %edx, %ecx      # i, tmp92
# test.c:6:   for (i = 0; i < n; i++)
        incl    %edx    # i
# test.c:7:     total += i * i;
        addl    %ecx, %eax      # tmp92, <retval>
        jmp     .L2     #
.L5:
# test.c:10: }
        ret
        .cfi_endproc
.LFE0:
        .size   test, .-test
        .ident  "GCC: (GNU) 7.0.0 20160809 (experimental)"
        .section        .note.GNU-stack,"",@progbits

The comments are meant for humans rather than machines, so the precise format of them is subject to change ๐Ÿ’œ

  • -frecord-gcc-switches: records the command line used to invoke the compiler into the object file being created ๐Ÿ—‚๏ธ This is only implemented on some targets, and the exact format depends on the target and binary file format, but it usually takes the form of a section containing ASCII text. It's related to -fverbose-asm, but that one only records info as comments in the assembler output file, so it never reaches the object file. See also -grecord-gcc-switches for another way of storing compiler options in the object file โœจ
  • -fpic โ€” okay bestie, this one spits out position-independent code (PIC) that's ready to live in a shared library ๐Ÿ’œ, if your target machine supports it โœจ. Every constant address gets accessed through a global offset table (GOT). The dynamic loader fills in the GOT entries when the program starts (the dynamic loader is not part of GCC, it's part of the operating system ๐Ÿ™ˆ). If the GOT size for the linked executable goes over a machine-specific maximum, the linker throws an error saying -fpic does not work, and then you just recompile with -fPIC instead ๐Ÿ’…. (These maximums are 8k on the SPARC, 28k on AArch64 and 32k on the m68k and RS/6000. The x86 has no such limit ๐Ÿซถ.)
    • Position-independent code needs special support, so it only works on certain machines ๐Ÿฆ‹. For the x86, GCC supports PIC for System V but not for the Sun 386i ๐Ÿ’€. Code generated for the IBM RS/6000 is always position-independent ๐Ÿ‘‘.
    • When this flag is set, the macros __pic__ and __PIC__ are defined to 1 โœจ.
  • -fPIC โ€” if the target machine supports it, this emits position-independent code that's suitable for dynamic linking and has no limit on the size of the global offset table ๐ŸŒˆ. This one actually makes a difference on AArch64, m68k, PowerPC and SPARC ๐Ÿ’–.
    • Position-independent code needs special support, so it only works on certain machines.
    • When this flag is set, the macros __pic__ and __PIC__ are defined to 2.
  • -fpie, -fPIE โ€” these are giving the same energy as -fpic and -fPIC, BUT the PIC they generate can only be linked into executables ๐Ÿงš. Usually you'd use these to compile code that's getting linked with the -pie GCC option.
    • -fpie and -fPIE both define the macros __pie__ and __PIE__. The macros have the value 1 for -fpie and 2 for -fPIE.
  • -fno-plt โ€” don't use the PLT for external function calls in position-independent code ๐Ÿ™…. Instead, load the callee address at call sites from the GOT and branch to it. This is more efficient because it kills the PLT stubs and exposes GOT loads to optimizations ๐Ÿ”ฅ. On architectures like 32-bit x86, where PLT stubs expect the GOT pointer in a specific register, this gives the compiler more register allocation freedom ๐Ÿ’…. Lazy binding needs the PLT, so with -fno-plt all external symbols get resolved at load time โฐ.
    • Alternatively, the function attribute noplt can be used to avoid calls through the PLT for specific external functions ๐ŸŽ€.
    • In position-dependent code, a few targets also convert calls to functions that are marked to not use the PLT so they use the GOT instead โœจ.
  • -fno-jump-tables โ€” don't use jump tables for switch statements, even where they'd be more efficient than other code generation strategies ๐Ÿ™ˆ. This 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 ๐Ÿ“.

  • -ffixed-reg โ€” treat the register named reg as a fixed register ๐Ÿ”’. Generated code should never refer to it (except maybe as a stack pointer, frame pointer or in some other fixed role).
    • reg must be the name of a register. The accepted register names are machine-specific and are defined in the REGISTER_NAMES macro in the machine description macro file.
    • This flag 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 it for other registers that have fixed pervasive roles in the machine's execution model produces disastrous results ๐Ÿ’€.
    • This flag doesn't have a negative form, because it specifies a three-way choice.
  • -fcall-saved-reg โ€” treat the register named reg as an allocable register that's saved by functions ๐Ÿ›Ÿ. It may be allocated even for temporaries or variables that live across a call. Functions compiled this way save and restore reg if they use it.
    • It is an error to use this flag with the frame pointer or stack pointer. Using it for other registers that have fixed pervasive roles in the machine's execution model produces disastrous results ๐Ÿ’€.
    • A different sort of disaster results from using this flag for a register where function values may be returned ๐Ÿ˜ญ.
    • This flag doesn't have a negative form, because it specifies a three-way choice.
  • -fpack-struct[=n] โ€” without a value, pack all structure members together without holes ๐Ÿ“ฆ. When you give a value (which must be a small power of two), members get packed according to that value, which is the maximum alignment (that is, objects with default alignment requirements larger than this are output potentially unaligned at the next fitting location.
Warning: the -fpack-struct switch causes GCC to generate code that is not binary compatible with code generated without that switch. Additionally, it makes the code suboptimal. Use it to conform to a non-default application binary interface. ๐Ÿšจ
  • -fleading-underscore โ€” this one and its counterpart, -fno-leading-underscore, forcibly change the way C symbols are represented in the object file ๐Ÿ”. One use is to help link with legacy assembly code.
Warning: the -fleading-underscore switch causes GCC to generate code that is not binary compatible with code generated without that switch. Use it to conform to a non-default application binary interface. Not all targets provide complete support for this switch. โš ๏ธ
  • -ftls-model=model โ€” alter the thread-local storage model that gets used ๐Ÿงต. The model argument should be one of global-dynamic, local-dynamic, initial-exec or local-exec. The choice is subject to optimization: the compiler may use a more efficient model for symbols not visible outside of the translation unit, or if -fpic is not given on the command line.
    • The default without -fpic is initial-exec; with -fpic the default is global-dynamic.
  • -ftrampolines โ€” for targets that normally need trampolines for nested functions, always generate them instead of using descriptors ๐Ÿงฉ. Otherwise, for targets that don't need them, like HP-PA or IA-64, it does nothing.
    • A trampoline is a small piece of code that's created at run time on the stack when the address of a nested function is taken, and it's used to call the nested function indirectly. Therefore, it requires the stack to be made executable in order for the program to work properly ๐Ÿ˜ฑ.
    • -fno-trampolines is enabled by default on a language-by-language basis to let the compiler avoid generating them, if it computes that this is safe, and replace them with descriptors. Descriptors are made up of data only, but the generated code must be prepared to deal with them. As of this writing, -fno-trampolines is enabled by default only for Ada.
    • Code compiled with -ftrampolines and code compiled with -fno-trampolines are not binary compatible if nested functions are present. This option must therefore be used on a program-wide basis and be manipulated with extreme care ๐Ÿซฃ.
  • -fvisibility=[default|internal|hidden|protected] โ€” set the default ELF image symbol visibility to the specified option. All symbols are marked with this unless overridden within the code ๐Ÿ‘€. Using this feature can 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. The default if -fvisibility isn't specified is default, i.e., make every symbol public.
    • A good explanation of the benefits offered by 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/). However, 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. This is the norm with DLLs on Windows, and with -fvisibility=hidden and __attribute__ ((visibility("default"))) instead of __declspec(dllexport) you get almost identical semantics with identical syntax. This is a great boon to those working with cross-platform projects ๐ŸŒธ.
    • For those adding visibility support to existing code, you may find #pragma GCC visibility of use. This works by enclosing the declarations you wish to set visibility for with (for example) #pragma GCC visibility push(hidden) and #pragma GCC visibility pop. Bear in mind that symbol visibility should be viewed as part of the API interface contract, and thus all new code should always specify visibility when it is not the default; i.e., declarations only for use within the local DSO should always be marked explicitly as hidden so as to avoid PLT indirection overheads. Making this abundantly clear also aids readability and self-documentation of the code. Note that due to ISO C++ specification requirements, operator new and operator delete must always be of default visibility.
    • Be aware that headers from outside your project, in particular system headers and headers from any other library you use, may not be expecting to be compiled with visibility other than the default. You may need to explicitly say #pragma GCC visibility push(default) before including any such headers.

๐ŸŽ€ Continuing the -fvisibility tea โ˜•

Okay, bestie, extern declarations are not affected by -fvisibility ๐Ÿ™ˆ So a lot of code can be recompiled with -fvisibility=hidden with zero modifications โœจ BUT, and this is a big but, 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 ๐Ÿงš That means an exception class that gets thrown between DSOs must be explicitly marked with default visibility, so the type_info nodes get unified between the DSOs. Main character energy for real ๐Ÿ‘‘

An overview of all these techniques, what they're good for, and how to use them lives at http://gcc.gnu.org/wiki/Visibility ๐ŸŒˆ

๐Ÿฆ‹ -fstrict-volatile-bitfields

Use this one if you want accesses to volatile bit-fields (or other structure fields, though the compiler usually respects those types anyway) to be a single access of the field's type width, aligned to a natural alignment when possible ๐Ÿ“ Like, 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) and force GCC to use 16-bit accesses instead of a more efficient 32-bit one ๐Ÿ’œ

If this option is disabled, the compiler picks the most efficient instruction ๐Ÿซถ In that example, that might be a 32-bit load, even though it touches bytes that have no part of the bit-field in them, or memory-mapped registers that have nothing to do with the one being updated. Yikes ๐Ÿ’€

In some cases, like when the packed attribute is applied to a structure field, it might not be possible to access the field with one read or write that's correctly aligned for the target machine. When that happens, GCC falls back to generating multiple accesses, instead of code that would fault or truncate the result at run time ๐Ÿ›ก๏ธ

Note: Due to restrictions of the C/C++11 memory model, write accesses are not allowed to touch non bit-field members. So it's recommended to define all the bits of the field's type as bit-field members ๐Ÿ™

The default value of this option is determined by the application binary interface for the target processor ๐ŸŒธ

โœจ -fsync-libcalls

This option controls whether any out-of-line instance of the __sync family of functions can be used to implement the C++11 __atomic family of functions ๐Ÿ’–

The default is enabled, so the only useful form of this option is -fno-sync-libcalls ๐Ÿ”ฅ It's used in the implementation of the libatomic runtime library, so you know it's serious business ๐Ÿ’…


๐Ÿ’– GCC Developer Options ๐Ÿ’–

Okay so this section is all about command-line options that are mostly for GCC developers ๐Ÿงš That includes options for compiler testing, digging into compiler bugs, and checking compile-time performance problems. You'll find options that produce debug dumps at various points in compilation, options that print stats like memory use and execution time, and options that print info about GCC's configuration, like where it searches for libraries ๐Ÿ” Real talk: you should rarely need any of these for ordinary compiling and linking tasks, so don't stress ๐Ÿซถ

Many developer options that make GCC dump output to a file take an optional =filename suffix. You can specify stdout or - to dump to standard output, and stderr for standard error ๐Ÿฆ‹

If =filename is left out, GCC builds a default dump file name by concatenating the base dump file name, a pass number, a phase letter, and a pass name ๐ŸŒˆ The base dump file name is the name of the output file if you explicitly specified one and it's not an executable. Otherwise it's the source file name. The pass number is determined by the order passes get registered with the compiler's pass manager. That's usually the same as execution order, BUT passes registered by plugins, target-specific passes, or passes that are otherwise registered late get numbered higher than the pass named final, even if they actually run earlier ๐Ÿ˜ญ The phase letter is one of i (inter-procedural analysis), l (language-specific), r (RTL), or t (tree). The files get created in the directory of the output file ๐Ÿ“

๐ŸŒธ -fcallgraph-info, -fcallgraph-info=MARKERS

These make the compiler output callgraph information for your program, on a per-object-file basis ๐Ÿ•ธ๏ธ The info is generated in the common VCG format. You can decorate it with extra per-node and/or per-edge information by passing a comma-separated list of markers. When the su marker is specified, the callgraph gets decorated with stack usage information, which is equivalent to -fstack-usage ๐Ÿ“š When the da marker is specified, the callgraph gets decorated with info about dynamically allocated objects ๐Ÿ“

When you compile with -flto, no callgraph information is output along with the object file ๐Ÿ™ˆ At LTO link time, -fcallgraph-info may generate multiple callgraph information files next to the intermediate LTO output files.

๐Ÿ”ฎ -dletters, -fdump-rtl-pass, -fdump-rtl-pass=filename

These say to make debugging dumps during compilation at the times specified by letters ๐Ÿงช This is used for debugging the RTL-based passes of the compiler, so it's giving nerdy and iconic ๐Ÿค“

Some -dletters switches mean something different when -E is used for preprocessing ๐Ÿซถ

You can enable debug dumps with a -fdump-rtl switch or with some -d option letters. Here are the possible letters you can use in pass and letters, and what they mean ๐Ÿ‘‘

  • -fdump-rtl-alignments โ€” Dump after branch alignments have been computed. ๐ŸŽ€
  • -fdump-rtl-asmcons โ€” Dump after fixing RTL statements that have unsatisfied in/out constraints. ๐Ÿ’…
  • -fdump-rtl-auto_inc_dec โ€” Dump after auto-inc-dec discovery. This pass only runs on architectures that have auto inc or auto dec instructions. โœจ
  • -fdump-rtl-barriers โ€” Dump after cleaning up the barrier instructions. ๐Ÿงน
  • -fdump-rtl-bbpart โ€” Dump after partitioning hot and cold basic blocks. ๐Ÿ”ฅ
  • -fdump-rtl-bbro โ€” Dump after block reordering. ๐Ÿ”
  • -fdump-rtl-btl1, -fdump-rtl-btl2 โ€” These enable dumping after the two branch target load optimization passes. ๐ŸŽฏ
  • -fdump-rtl-bypass โ€” Dump after jump bypassing and control flow optimizations. ๐Ÿฆ‹
  • -fdump-rtl-combine โ€” Dump after the RTL instruction combination pass. ๐Ÿงฉ
  • -fdump-rtl-compgotos โ€” Dump after duplicating the computed gotos. ๐ŸŒˆ
  • -fdump-rtl-ce1, -fdump-rtl-ce2, -fdump-rtl-ce3 โ€” These enable dumping after the three if conversion passes. ๐Ÿ“
  • -fdump-rtl-cprop_hardreg โ€” Dump after hard register copy propagation. ๐Ÿ’œ
  • -fdump-rtl-csa โ€” Dump after combining stack adjustments. ๐Ÿฅž
  • -fdump-rtl-cse1, -fdump-rtl-cse2 โ€” These enable dumping after the two common subexpression elimination passes. ๐ŸŒธ
  • -fdump-rtl-dce โ€” Dump after the standalone dead code elimination passes. ๐Ÿ—‘๏ธ
  • -fdump-rtl-dbr โ€” Dump after delayed branch scheduling. โณ
  • -fdump-rtl-dce1, -fdump-rtl-dce2 โ€” These enable dumping after the two dead store elimination passes. ๐Ÿ’€
  • -fdump-rtl-eh โ€” Dump after finalization of EH handling code. ๐Ÿ›Ÿ
  • -fdump-rtl-eh_ranges โ€” Dump after conversion of EH handling range regions. ๐Ÿ“
  • -fdump-rtl-expand โ€” Dump after RTL generation. ๐ŸŒฑ
  • -fdump-rtl-fwprop1, -fdump-rtl-fwprop2 โ€” These enable dumping after the two forward propagation passes. โžก๏ธ
  • -fdump-rtl-gcse1, -fdump-rtl-gcse2 โ€” These enable dumping after global common subexpression elimination. ๐ŸŒ
  • -fdump-rtl-init-regs โ€” Dump after the initialization of the registers. ๐Ÿ
  • -fdump-rtl-initvals โ€” Dump after the computation of the initial value sets. ๐Ÿงฎ
  • -fdump-rtl-into_cfglayout โ€” Dump after converting to cfglayout mode. ๐Ÿ—บ๏ธ
  • -fdump-rtl-ira โ€” Dump after iterated register allocation. ๐ŸŽจ
  • -fdump-rtl-jump โ€” Dump after the second jump optimization. ๐Ÿฆ˜
  • -fdump-rtl-loop2 โ€” This enables dumping after the RTL loop optimization passes. ๐Ÿ”„
  • -fdump-rtl-mach โ€” Dump after performing the machine dependent reorganization pass, if that pass exists. ๐Ÿ› ๏ธ
  • -fdump-rtl-mode_sw โ€” Dump after removing redundant mode switches. โœ‚๏ธ
  • -fdump-rtl-rnreg โ€” Dump after register renumbering. ๐Ÿ”ข
  • -fdump-rtl-outof_cfglayout โ€” Dump after converting from cfglayout mode. ๐Ÿ”™
  • -fdump-rtl-peephole2 โ€” Dump after the peephole pass. ๐Ÿ”
  • -fdump-rtl-postreload โ€” Dump after post-reload optimizations. ๐Ÿš€
  • -fdump-rtl-pro_and_epilogue โ€” Dump after generating the function prologues and epilogues. ๐ŸŽฌ
  • -fdump-rtl-sched1, -fdump-rtl-sched2 โ€” These enable dumping after the basic block scheduling passes. ๐Ÿ—“๏ธ
  • -fdump-rtl-ree โ€” Dump after sign/zero extension elimination. ๐Ÿ”ข
  • -fdump-rtl-seqabstr โ€” Dump after common sequence discovery. ๐Ÿงฌ
  • -fdump-rtl-shorten โ€” Dump after shortening branches. ๐Ÿ“
  • -fdump-rtl-sibling โ€” Dump after sibling call optimizations. ๐Ÿ‘ฏ
  • -fdump-rtl-split1, -fdump-rtl-split2, -fdump-rtl-split3, -fdump-rtl-split4, -fdump-rtl-split5 โ€” These options enable dumping after five rounds of instruction splitting. โœ‚๏ธ
  • -fdump-rtl-sms โ€” Dump after modulo scheduling. This pass only runs on some architectures. ๐ŸŽถ
  • -fdump-rtl-stack โ€” Dump after converting GCC's "flat register file" registers to the x87's stack-like registers. This pass only runs on x86 variants. ๐Ÿฅž
  • -fdump-rtl-subreg1, -fdump-rtl-subreg2 โ€” These enable dumping after the two subreg expansion passes. ๐Ÿงฉ
  • -fdump-rtl-unshare โ€” Dump after all RTL has been unshared. ๐Ÿซง
  • -fdump-rtl-vartrack โ€” Dump after variable tracking. ๐Ÿ•ต๏ธโ€โ™€๏ธ
  • -fdump-rtl-vregs โ€” okay so this one drops a dump right after the virtual registers get swapped out for 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 โ€” ngl these are defined, but they always produce empty files ๐Ÿ’€ literally nothing in them, bestie ๐Ÿ˜ญ
  • -da, -fdump-rtl-all โ€” produces all the dumps listed above ๐Ÿ‘‘ the full buffet ๐Ÿ“
  • -dA โ€” annotates the assembler output with miscellaneous debugging info ๐ŸŒธ
  • -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 behaviour, no notes
  • -dp โ€” annotates the assembler output with a comment showing which pattern and alternative got used ๐Ÿ’… it also prints the length and cost of each instruction, so it's giving detail ๐Ÿ”ฅ
  • -dP โ€” dumps the RTL in the assembler output as a comment before each instruction ๐ŸŽ€ it also turns on -dp annotation, so you get both
  • -dx โ€” just generates RTL for a function instead of compiling it ๐Ÿงš usually used with -fdump-rtl-expand
  • -fdump-debug โ€” dumps the debugging info generated during the debug generation phase ๐Ÿ›โœจ
  • -fdump-earlydebug โ€” dumps the debugging info generated during the early debug generation phase ๐ŸŒˆ
  • -fdump-noaddr โ€” when doing debugging dumps, suppresses the address output ๐Ÿซถ this makes it way easier to diff your dumps when you're comparing compiler invocations with different compiler binaries and/or different text / bss / data / heap / stack / dso start locations
  • -freport-bug โ€” collects and dumps debug info into a temporary file if an internal compiler error (ICE) happens ๐Ÿ˜ญ so you have receipts
  • -fdump-unnumbered โ€” when doing debugging dumps, suppresses instruction numbers and address output ๐Ÿ™ˆ this makes diff way more feasible for dumps from different options, especially with and without -g
  • -fdump-unnumbered-links โ€” when doing debugging dumps (see the -d option above), suppresses the 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, so the language tree lands in a file ๐Ÿ“‚ the file name is your source file name with a switch-specific suffix appended, and it gets created in the same directory as the output file. the dumps you can ask for are:
    • all โ€” enables all inter-procedural analysis dumps ๐Ÿ‘‘
    • cgraph โ€” dumps info about call-graph optimization, unused function removal, and inlining decisions ๐Ÿ•ธ๏ธ
    • inline โ€” dumps after function inlining ๐ŸŒธ

on top of that, you can add -optimized, -missed, -note, and -all, which mean the same thing as they do for -fopt-info, and they default to -optimized if you don't pick one ๐Ÿ’… for example, -fdump-ipa-inline-optimized-missed will emit info on the callsites that got inlined, along with the callsites that didn't. by default the dump has messages about successful optimizations (same as -optimized) plus the low-level details about the analysis ๐Ÿง โœจ

  • -fdump-lang-all, -fdump-lang-switch, -fdump-lang-switch-options, -fdump-lang-switch-options=filename โ€” these control the dumping of language-specific info ๐ŸŽ€ the options and filename parts work exactly like they do in the -fdump-tree option. the switch values you can use are:
    • all โ€” enables all language-specific dumps ๐Ÿ‘‘
    • class โ€” dumps class hierarchy info ๐Ÿฆ‹ virtual table info gets emitted unless you specify slim. this one is C++ only
    • raw โ€” dumps the raw internal tree data ๐Ÿงš this one is C++ only too
  • -fdump-passes โ€” prints on stderr the list of optimization passes that get turned on and off by your current command-line options ๐Ÿ“œ
  • -fdump-statistics-option โ€” enables and controls dumping of pass statistics into a separate file ๐Ÿ“Š the file name is made by appending a suffix ending in .statistics to the source file name, and it'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 them. with no option, the default is to sum the 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, straight to a file ๐ŸŒณ if you use the -options form, options is a list of - separated options that control the details of the dump. not every option works with every dump, and the ones that don't make sense just get ignored ๐Ÿ™ˆ here's the lineup:
    • address โ€” prints the address of each node ๐Ÿ  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 making it easier to work backwards from mangled names in the assembly file
    • slim โ€” when dumping front-end intermediate representations, stops members of a scope or a function body from getting dumped just because that scope was reached ๐Ÿงน only items directly reachable by some other path get dumped. when dumping pretty-printed trees, this inhibits dumping the bodies of control structures. when dumping RTL, it prints 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 honours this) and also includes info from the optimization passes ๐Ÿ”ฌ
    • stats โ€” enables dumping various statistics about the pass (again, not every dump option honours 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 one plot. this option only works for RTL dumps, and the RTL is always dumped in slim form
    • vops โ€” enables showing virtual operands for every statement ๐Ÿงฉ
    • lineno โ€” enables showing line numbers for statements ๐Ÿ“
    • uid โ€” enables showing the unique ID (DECL_UID) for each variable ๐Ÿ†”
    • verbose โ€” enables showing the tree dump for each statement ๐Ÿ“
    • eh โ€” enables showing the EH region number holding each statement ๐Ÿ›Ÿ
    • scev โ€” enables showing scalar evolution analysis details ๐Ÿ“ˆ
    • optimized โ€” enables showing optimization info (only available in certain passes) โœ…
    • missed โ€” enables showing missed optimization info (only available in certain passes) โŒ
    • note โ€” enables other detailed optimization info (only available in certain passes) ๐Ÿ—’๏ธ
    • all โ€” turns on all options, except raw, slim, verbose, and lineno ๐Ÿ‘‘
    • optall โ€” turns on all optimization options, i.e., optimized, missed, and note ๐Ÿ’…

now, if you want to figure out which tree dumps are available, or 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 want. for example, the codes tree-evrp, tree-vrp1, and tree-vrp2 correspond to the three Value Range Propagation passes. the number at the end tells apart distinct invocations of the same pass ๐Ÿ”ข
  2. To enable the creation of the dump file, append the pass code to the -fdump- option prefix and invoke GCC with it. for example, to enable the dump from the Early Value Range Propagation pass, invoke GCC with the -fdump-tree-evrp option. optionally, you can specify the name of the dump file. if you don't, GCC creates one as described below ๐Ÿ“
  3. Find the pass dump in a file whose name is made of three components separated by a period: the name of the source file GCC was invoked to compile, a numeric suffix indicating the pass number followed by the letter t for tree passes (and the letter r for RTL passes), and finally the pass code. for example, the Early VRP pass dump might be in a file named myfile.c.038t.evrp in the current working directory ๐ŸŽฏ
โš ๏ธ bestie, the numeric codes are not stable, so they may change from one version of GCC to another. don't hardcode them ๐Ÿ™…โ€โ™€๏ธ

  • -fopt-info, -fopt-info-options, -fopt-info-options=filename โ€” this controls optimization dumps from the various optimization passes โœจ if you use the -options form, options is a list of - separated option keywords that select the dump details and optimizations ๐ŸŽ€

the options split into three groups:

  1. options describing what kinds of messages should be emitted ๐Ÿ’ฌ
  2. options describing the verbosity of the dump ๐Ÿ”Š
  3. options describing which optimizations should be included ๐Ÿ› ๏ธ

you can freely mix options from each group, since they don't overlap ๐Ÿซถ but if there's ever a conflict, the later options on the command line override the earlier ones, so the last one wins ๐Ÿ‘‘

the following options control which kinds of messages get emitted:

  • optimized โ€” prints info when an optimization is successfully applied โœ… it's up to each pass to decide what info is relevant. for example, the vectorizer passes print the source location of loops that were successfully vectorized ๐Ÿš€
  • missed โ€” prints info about missed optimizations โŒ individual passes control which information gets included in the output
  • note โ€” okay so this one is the chatty mode ๐Ÿ—ฃ๏ธ It prints verbose info about optimizations, like certain transformations and more detailed messages about the decisions the compiler makes โœจ
  • all โ€” the full send ๐Ÿ’… It dumps detailed optimization info, which covers optimized, missed, and note all in one go ๐ŸŒˆ

Next up is the option that controls how much detail the dump spills ๐Ÿซ–

  • internals โ€” by default you only get the "high-level" messages ๐Ÿ™ˆ Turn this on and you'll get extra, more detailed messages that are mostly only of interest to GCC developers ๐Ÿง‘โ€๐Ÿ’ป

Now for the keyword squad ๐Ÿ‘ฏโ€โ™€๏ธ You can grab dumps for a whole group of optimizations at once by using one or more of these:

  • ipa โ€” dumps from all interprocedural optimizations ๐Ÿ”—
  • loop โ€” dumps from all loop optimizations ๐Ÿ”
  • inline โ€” dumps from all inlining optimizations ๐Ÿ“ฆ
  • omp โ€” dumps from all OMP (Offloading and Multi Processing) optimizations ๐Ÿงš
  • vec โ€” dumps from all vectorization optimizations ๐Ÿฆ‹
  • optall โ€” the everything bagel ๐Ÿฅฏ Dumps from every optimization, and it's a superset of all the groups above ๐Ÿ‘‘

If you leave options out, it defaults to optimized-optall. That means you get messages about successful optimizations from all the passes, minus anything treated as "internals" ๐Ÿซถ

If you give it a filename, the dumps from every applicable optimization get concatenated into that file. If you don't, the dump goes to stderr ๐Ÿ“œ You can use multiple -fopt-info options, but only one of them can include a filename. If you pass other filenames, all but the first such option get ignored ๐Ÿ™…โ€โ™€๏ธ

Heads up, bestie: the output filename gets overwritten when you have multiple translation units. If you want a combined output from several translation units, use stderr instead ๐Ÿšจ

Here's the first example, where the optimization info goes to stderr ๐Ÿ’–

gcc -O3 -fopt-info

This one outputs a missed optimization report from all the passes into missed.all ๐ŸŽ€

gcc -O3 -fopt-info-missed=missed.all

And this one prints info about missed optimization opportunities from the vectorization passes on stderr ๐ŸŒธ Fun fact: -fopt-info-vec-missed is equivalent to -fopt-info-missed-vec, and the order of the group names and message types after -fopt-info doesn't matter ๐ŸคŒ

gcc -O2 -ftree-vectorize -fopt-info-vec-missed

Another one, outputting missed optimizations plus optimized locations from all the inlining passes into inline.txt ๐Ÿ“

gcc -O3 -fopt-info-inline-optimized-missed=inline.txt

Finally, the plot twist ๐Ÿ˜ญ Here the two output filenames, vec.miss and loop.opt, are in conflict, since only one output file is allowed. So only the first option takes effect and the rest get ignored. That means only vec.miss gets produced, and it holds the vectorizer's dumps about missed opportunities ๐Ÿ’€

gcc -fopt-info-vec-missed=vec.miss -fopt-info-loop-optimized=loop.opt

  • -fsave-optimization-record โ€” this one writes a SRCFILE.opt-record.json.gz file ๐Ÿ“‚ It details what optimizations were performed, for the ones that support -fopt-info
This option is experimental, and the format of the data inside the compressed JSON file is subject to change ๐Ÿงช

It's roughly a machine-readable version of -fopt-info-all, organized as a collection of messages with source file, line number, and column number. Each message also carries these extra goodies โœจ

  • the execution count of the code being optimized, plus metadata about whether it 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 those categories they are, and, when available, their source code location ๐Ÿ—บ๏ธ
  • the GCC pass that emitted the message ๐Ÿงฉ
  • the location in GCC's own code from which the message was emitted ๐Ÿซฃ

Also, some messages are logically nested within other messages, reflecting implementation details of the optimization passes ๐Ÿช†

  • -fsched-verbose=n โ€” for targets that use instruction scheduling, this controls how much debugging output the scheduler dumps into 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 information, and unit/insn info.
    • For n greater than two, it includes the RTL at the abort point, plus control-flow and regions info.
    • For n over four, -fsched-verbose also includes dependence info ๐Ÿฅต

  • -fenable-kind-pass and -fdisable-kind-pass=range-list โ€” this is a whole set of options for explicitly disabling or enabling optimization passes ๐ŸŽ›๏ธ They're meant for debugging GCC itself, so regular compiler users should stick with the normal options for enabling and disabling passes instead ๐Ÿ™
    • -fdisable-ipa-pass โ€” disables the IPA pass called pass, where pass is the pass name. If the same pass is statically invoked in the compiler multiple times, append a sequential number to the pass name, starting from 1.
    • -fdisable-rtl-pass / -fdisable-rtl-pass=range-list โ€” disables the RTL pass called pass. Same deal with the sequential numbering for repeated passes. range-list is a comma-separated list of function ranges or assembler names. Each range is a number pair separated by a colon, and it's inclusive at both ends. If the range is trivial, the number pair can be simplified to a single number. If the function's call graph node uid falls within one of the specified ranges, the pass is disabled for that function. You can find the uid in the function header of a dump file, and you can dump the pass names with -fdump-passes ๐Ÿ”
    • -fdisable-tree-pass / -fdisable-tree-pass=range-list โ€” disables the tree pass called pass. See -fdisable-rtl for how the option arguments work ๐ŸŒณ
    • -fenable-ipa-pass โ€” enables the IPA pass called pass. Same sequential numbering for repeated passes ๐Ÿ’ซ
    • -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 these options get used ๐Ÿง

# disable ccp1 for all functions
   -fdisable-tree-ccp1
# disable complete unroll for function whose cgraph node uid is 1
   -fenable-tree-cunroll=1
# disable gcse2 for functions at the following ranges [1,1],
# [300,400], and [400,1000]
# disable gcse2 for functions foo and foo2
   -fdisable-rtl-gcse2=foo,foo2
# disable early inlining
   -fdisable-tree-einline
# disable ipa inlining
   -fdisable-ipa-inline
# enable tree full unroll
   -fenable-tree-unroll

  • -fchecking and -fchecking=n โ€” turns on internal consistency checking ๐Ÿ›ก๏ธ The default depends on how the compiler was configured. -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 it generates certain symbol names that have to be different in every compiled file ๐ŸŽฒ It's also used to place unique stamps in coverage data files and in the object files that produce them. Use -frandom-seed if you want 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 ๐Ÿ”ข

The string should be different for every file you compile ๐Ÿซต
  • -save-temps and -save-temps=cwd โ€” store the usual "temporary" intermediate files permanently ๐Ÿ’พ They go in the current directory and get named after the source file. So compiling foo.c with -c -save-temps produces foo.i and foo.s, as well as foo.o. That creates a preprocessed foo.i output file even though the compiler now normally uses an integrated preprocessor ๐Ÿงผ

When you combine it with the -x command-line option, -save-temps is smart 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 ๐Ÿง 

Be careful if you invoke GCC in parallel ๐Ÿšจ Compiling several different source files that share a common base name in different subdirectories, or the same source file compiled for multiple output destinations, means the parallel compilers will likely interfere with each other and overwrite the temporary files. For instance:
gcc -save-temps -o outdir1/foo.o indir1/foo.c&
gcc -save-temps -o outdir2/foo.o indir2/foo.c&

That might result in foo.i and foo.o being written to simultaneously by both compilers ๐Ÿ˜ฑ

  • -save-temps=obj โ€” stores the usual "temporary" intermediate files permanently too ๐Ÿ“ฆ If the -o option is used, the temporary files are based on the object file. If -o isn't used, -save-temps=obj behaves just like -save-temps ๐Ÿซถ

For example:

gcc -save-temps=obj -c foo.c
gcc -save-temps=obj -c bar.c -o dir/xbar.o
gcc -save-temps=obj foobar.c -o dir2/yfoobar
  • -time[=file] โ€” okay bestie, this one tells you how much CPU time each subprocess in the compile chain ate ๐Ÿ• For C source files that's the compiler proper and the assembler (plus the linker if linking happens) โœจ

Without an output file, you get output that 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 time spent running the program itself. The second is "system time", which is time spent in operating system routines on the program's behalf. Both are in seconds โฑ๏ธ

With an output file, the info gets appended to that file instead, and it looks like this:

0.12 0.01 cc1 <options>
0.00 0.01 as <options>

Now the "user time" and "system time" get moved in front of the program name, and the options passed to each program get shown too, so you can later figure out which file was compiled and with what options ๐Ÿ”๐Ÿ’…

  • -fdump-final-insns[=file] โ€” dumps the final internal representation (RTL) into file ๐Ÿ—‚๏ธ If you leave off the optional argument (or file is .), the dump file name is made by tacking .gkd onto the compilation output file name.
  • -fcompare-debug[=opts] โ€” this one is lowkey a whole vibe ๐Ÿงช If nothing errors during compilation, GCC runs the compiler a second time, adding opts and -fcompare-debug-second to the arguments for that second go. It dumps the final internal representation in both compilations and prints an error if they don't match.

If the equal sign is left out, the default -gtoggle is used.

The environment variable GCC_COMPARE_DEBUG, if it's defined, non-empty and nonzero, implicitly enables -fcompare-debug. If GCC_COMPARE_DEBUG is 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 ๐Ÿ™…โ€โ™€๏ธ

Want full coverage during -fcompare-debug testing? Set GCC_COMPARE_DEBUG to -fcompare-debug-not-overridden. GCC rejects that as an invalid option in any actual compilation (rather than preprocessing, assembly or linking). If you only want a warning, setting GCC_COMPARE_DEBUG to -w%n-fcompare-debug not overridden will do the trick ๐ŸŽฏ

  • -fcompare-debug-second โ€” this gets passed to the compiler implicitly for the second compilation requested by -fcompare-debug ๐Ÿซถ It comes along with options to silence warnings, and it leaves out any other options that would make the compiler write output to files or to standard output as a side effect. During that second compilation, dump files and preserved temporary files get renamed to include the additional .gk extension, so they don't overwrite the ones from the first run.

When you pass this option to the compiler driver, it makes the first compilation get skipped ๐Ÿ’€ That makes it pretty much only useful for debugging the compiler proper.

  • -gtoggle โ€” turns off debug info generation if leaving out this option would generate it, or turns it on at level 2 otherwise ๐Ÿ”„ Where it sits on the command line doesn't matter. It takes effect after all other options are processed, and it only does its thing once, no matter how many times you give it. This one is 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 stats about the time each pass consumed when it's done โฐ
  • -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 than 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 they're processing object files in LTO mode (via -flto).

Disabled by default.

  • -flto-report-wpa โ€” same as -flto-report, but it only prints for the WPA phase of link-time optimization ๐ŸŽ€
  • -fmem-report โ€” makes the compiler print some statistics about permanent memory allocation when it finishes ๐Ÿง 
  • -fmem-report-wpa โ€” makes the compiler print some statistics about permanent memory allocation for the WPA phase only ๐Ÿง 
  • -fpre-ipa-mem-report, -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 how consistent the (estimated) profile is, and what effect each individual pass has ๐Ÿ“ˆ
  • -fstack-usage โ€” makes the compiler output stack usage info for your 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 one is 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 it's not 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 option is only supported by the C++ front end, and the info is generally only useful to the G++ development team ๐Ÿ™ˆ
  • -fdbg-cnt-list โ€” prints the name and the counter upper bound for all debug counters ๐Ÿ”ข
  • -fdbg-cnt=counter-value-list โ€” sets the internal debug counter lower and upper bounds ๐ŸŽš๏ธ counter-value-list is a comma-separated list of name:lower_bound1-upper_bound1 [:lower_bound2-upper_bound2...] tuples, which set the name of the counter and a list of closed intervals. The lower_bound is optional, and it's zero initialized if it isn't set. For example, with -fdbg-cnt=dce:2-4:10-11,tail_call:10, dbg_cnt(dce) returns true only for the second, third, fourth, tenth and eleventh invocation. For dbg_cnt(tail_call), true is returned for the first 10 invocations ๐Ÿ’œ
  • -print-file-name=library โ€” prints the full absolute name of the library file library that would be used when linking, and then stops there ๐Ÿ›‘ 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 an @ instead of the -, with no spaces between multiple switches. This is supposed to make shell processing easier.
  • -print-multi-os-directory โ€” prints the path to OS libraries for the selected multilib, relative to some lib subdirectory ๐Ÿ  If OS libraries are present in the lib subdirectory and no multilibs are used, this is usually just .. If OS libraries are present in libsuffix sibling directories, it prints something like ../lib64, ../lib or ../lib32. If OS libraries are present in lib/subdir subdirectories, it prints something like amd64, sparcv9 or ev6.
  • -print-multiarch โ€” prints the path to OS libraries for the selected multiarch, relative to some lib subdirectory ๐Ÿน
  • -print-prog-name=program โ€” like -print-file-name, but it searches for a program such as cpp ๐Ÿ”Ž
  • -print-libgcc-file-name โ€” same as -print-file-name=libgcc.a ๐Ÿงƒ

This is handy when you use -nostdlib or -nodefaultlibs but still want to link with libgcc.a. You can do:

gcc -nostdlib <files>... `gcc -print-libgcc-file-name`
  • -print-search-dirs โ€” prints the name of the configured installation directory, plus a list of the program and library directories gcc searches, and then stops ๐Ÿ—ƒ๏ธ

This is useful when gcc prints the error message installation problem, cannot exec cpp0: No such file or directory. To fix that, you either need to put cpp0 and the other compiler components where gcc expects to find them, or you can set the environment variable GCC_EXEC_PREFIX to the directory where you installed them. Don't forget the trailing / ๐Ÿšจ

  • -print-sysroot โ€” prints the target sysroot directory that gets used during compilation ๐ŸŒ This is the target sysroot specified either at configure time or with the --sysroot option, possibly with an extra suffix that depends on compilation options. If no target sysroot is specified, the option prints nothing.
  • -print-sysroot-headers-suffix โ€” prints the suffix added to the target sysroot when searching for headers, or gives an error if the compiler isn't configured with such a suffix, and then stops ๐Ÿงš
  • -dumpmachine โ€” okay bestie, this one just spills the compiler's target machine (like i686-pc-linux-gnu) and then immediately bounces. Nothing else happens ๐Ÿ’…
  • -dumpversion โ€” prints the compiler version (like 3.0, 6.3.0 or 7) and then dips, no extra steps ๐Ÿซถ This is the version that shows up in filesystem paths and specs, and depending on how the compiler was configured, it can be one number (major version), two numbers with a dot (major and minor), or three numbers with dots (major, minor and patchlevel) โœจ
  • -dumpfullversion โ€” prints the full compiler version and then leaves, no cap ๐Ÿ”ฅ The output is always three numbers separated by dots: major, minor and patchlevel version ๐ŸŒธ
  • -dumpspecs โ€” prints the compiler's built-in specs and then stops, nothing else ๐Ÿงš (This one is mostly used when GCC itself is being built, so it's giving behind-the-scenes energy ๐Ÿ™ˆ)

๐Ÿฆ‹ Machine-Dependent Options ๐Ÿฆ‹

okay so every target machine that GCC supports can have its own options ๐Ÿ’– Like, you might want to compile for a specific processor variant or ABI, or tweak optimizations that are specific to that machine. By convention, machine-specific option names start with -m ๐ŸŽ€

Some configurations also have extra target-specific options, usually so they can play nice with other compilers on the same platform ๐ŸŒˆ

โœจ AArch64 Options โœจ

These options are defined for AArch64 implementations ๐Ÿ‘‘

  • -mabi=name โ€” generates code for the data model you pick ๐Ÿ’… The valid values are ilp32, which is the SysV-like model where int, long int and pointers are 32 bits, and lp64, which is also SysV-like but int stays 32 bits while long int and pointers go up to 64 bits ๐Ÿฆ‹

The default depends on your specific target configuration ๐Ÿซถ

โš ๏ธ Heads up: the LP64 and ILP32 ABIs are not link-compatible. You have to compile your entire program with the same ABI and link it against a compatible set of libraries, or things get messy fr fr ๐Ÿ’€
  • -mbig-endian โ€” generates big-endian code ๐ŸŒธ This is the default when GCC is configured for an aarch64_be-*-* target โœจ
  • -mgeneral-regs-only โ€” generates code that only uses the general-purpose registers ๐Ÿ’œ This stops the compiler from 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-*-* target ๐Ÿงš
  • -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. This is the default code model ๐Ÿ‘‘
  • -mcmodel=large โ€” generates code for the large code model ๐ŸŒŒ It makes no assumptions about the addresses and sizes of sections. Programs can only be statically linked. The -mcmodel=large option is incompatible with -mabi=ilp32, -fpic and -fPIC ๐Ÿ’€
  • -mstrict-align, -mno-strict-align โ€” lets you avoid (or allow) memory accesses that might not be aligned on a natural object boundary, as described in the architecture specification ๐Ÿ™ˆ
  • -momit-leaf-frame-pointer, -mno-omit-leaf-frame-pointer โ€” omits or keeps the frame pointer in leaf functions ๐Ÿฆ‹ The former behavior is the default ๐Ÿ’…
  • -mstack-protector-guard=guard, -mstack-protector-guard-reg=reg, -mstack-protector-guard-offset=offset โ€” generates stack protection code using a canary at guard ๐Ÿ›ก๏ธ The supported locations are global for a global canary, or sysreg for a canary in an appropriate system register ๐Ÿ”

With the latter choice, the options -mstack-protector-guard-reg=reg and -mstack-protector-guard-offset=offset also tell it which system 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 ๐Ÿง

  • -mstack-protector-guard=guard, -mstack-protector-guard-reg=reg, -mstack-protector-guard-offset=offset โ€” okay this exact block shows up twice in the original page, so I'm keeping it twice ๐Ÿ’… It does the same thing: it generates stack protection code using a canary at guard. Supported locations are global for a global canary or sysreg for a canary in an appropriate system register ๐Ÿ”

With the latter choice, the options -mstack-protector-guard-reg=reg and -mstack-protector-guard-offset=offset furthermore specify which system register to use as base register for reading the canary, and from what offset from that base register. There is no default register or offset as this is entirely for use within the Linux kernel ๐Ÿง

  • -mtls-dialect=desc โ€” uses TLS descriptors as the thread-local storage mechanism for dynamic accesses of TLS variables ๐Ÿ’– This is the default โœจ
  • -mtls-dialect=traditional โ€” uses traditional TLS as the thread-local storage mechanism for dynamic accesses of TLS variables ๐Ÿฆ‹
  • -mtls-size=size โ€” specifies the bit size of immediate TLS offsets. Valid values are 12, 24, 32, 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 ๐Ÿฉน It works by inserting a NOP instruction between memory instructions and 64-bit integer multiply-accumulate instructions ๐ŸŒˆ
  • -mfix-cortex-a53-843419, -mno-fix-cortex-a53-843419 โ€” enables or disables the workaround for ARM Cortex-A53 erratum number 843419 ๐Ÿฉน This erratum workaround is made at link time, and this option will only pass the corresponding flag to the linker ๐Ÿ”—
  • -mlow-precision-recip-sqrt, -mno-low-precision-recip-sqrt โ€” enables or disables the reciprocal square root approximation โœจ This option only has an effect if -ffast-math or -funsafe-math-optimizations is used as well. Enabling it reduces the precision of reciprocal square root results to about 16 bits for single precision and to 32 bits for double precision ๐Ÿซ 
  • -mlow-precision-sqrt, -mno-low-precision-sqrt โ€” enables or disables the square root approximation ๐ŸŒŸ This option only has an effect if -ffast-math or -funsafe-math-optimizations is used as well. Enabling it reduces the precision of square root results to about 16 bits for single precision and to 32 bits for double precision. If enabled, it implies -mlow-precision-recip-sqrt ๐Ÿ’…
  • -mlow-precision-div, -mno-low-precision-div โ€” enables or disables the division approximation โž— This option only has an effect if -ffast-math or -funsafe-math-optimizations is used as well. Enabling it reduces the precision of division results to about 16 bits for single precision and to 32 bits for double precision ๐Ÿ“
  • -mtrack-speculation, -mno-track-speculation โ€” enables or disables generating additional code to track speculative execution through conditional branches ๐Ÿ•ต๏ธ The tracking state can then be used by the compiler when expanding calls to "__builtin_speculation_safe_copy", so it can generate a more efficient code sequence ๐Ÿง 
  • -moutline-atomics, -mno-outline-atomics โ€” enables or disables calls to out-of-line helpers that implement atomic operations ๐Ÿงฉ These helpers figure out at runtime whether the LSE instructions from ARMv8.1-A can be used. If they can't, they use 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 sums up the valid values for arch, plus the features each one turns on by default ๐Ÿ“‹

arch value : Architecture : Includes by default
armv8-a : Armv8-A : +fp, +simd
armv8.1-a : Armv8.1-A : armv8-a, +crc, +lse, +rdma
armv8.2-a : Armv8.2-A : armv8.1-a
armv8.3-a : Armv8.3-A : armv8.2-a
armv8.4-a : Armv8.4-A : armv8.3-a, +fp16fml, +dotprod
armv8.5-a : Armv8.5-A : armv8.4-a, +sb, +ssbs, +predres
armv8.6-a : Armv8.6-A : armv8.5-a, +bf16, +i8mm

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 valid 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 the one that gets used ๐Ÿ‘‰

GCC uses name to figure out what kind of instructions it's allowed to emit when generating assembly code ๐Ÿงพ If -march is specified without either -mtune or -mcpu also being specified, the code is tuned to perform well across a range of target processors 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, ares, exynos-m1,
emag, falkor, neoverse-e1, neoverse-n1, neoverse-n2, neoverse-v1,
neoverse-v2, neoverse-512tvb, qdf24xx, saphira, phecda, xgene1,
vulcan, octeontx, octeontx81,  octeontx83, octeontx2, octeontx2t98,
octeontx2t96 octeontx2t93, octeontx2f95, octeontx2f95n,
octeontx2f95mm, a64fx, thunderx, thunderxt88, thunderxt88p1,
thunderxt81, tsv110, thunderxt83, thunderx2t99, thunderx3t110, zeus,
cortex-a57.cortex-a53, cortex-a72.cortex-a53, cortex-a73.cortex-a35,
cortex-a73.cortex-a53, cortex-a75.cortex-a55, cortex-a76.cortex-a55,
ampere1, ampere1a, native.

The values cortex-a57.cortex-a53, cortex-a72.cortex-a53, cortex-a73.cortex-a35, cortex-a73.cortex-a53, cortex-a75.cortex-a55, cortex-a76.cortex-a55 tell GCC to tune for a big.LITTLE system ๐Ÿพ

The value neoverse-512tvb tells GCC to tune for Neoverse cores that (a) implement SVE and (b) have a total vector bandwidth of 512 bits per cycle ๐Ÿฆ‹. So bestie, these cores 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 below ๐ŸŽ€.

Also, 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 recognize the processor of the host system ๐Ÿ™ˆ.

If none of -mtune=, -mcpu= or -march= are specified, the code is tuned to perform well across a range of target processors ๐ŸŒˆ.

This option 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 allowed values for cpu are the same as for -mtune. The allowed values for feature are documented in the sub-section on aarch64-feature-modifiers,,-march and -mcpu Feature Modifiers. If you specify conflicting feature modifiers, the right-most one wins ๐Ÿซถ.

GCC uses name to figure out what kinds of instructions it's allowed to emit when generating assembly (as if by -march), and which processor to tune performance for (as if by -mtune) ๐Ÿ”ฅ. If you use this option together with -march or -mtune, those options take precedence over the matching part of this option ๐Ÿ‘‘.

-mcpu=neoverse-512tvb is special, because it doesn't point at one specific core. Instead it covers all Neoverse cores that (a) implement SVE and (b) have a total vector bandwidth of 512 bits a cycle ๐Ÿงš. Unless 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 does ๐Ÿ’….

  • -moverride=string โ€” Overrides the tuning decisions the back-end makes in response to a -mtune= switch ๐Ÿ’€.
The syntax, semantics, and accepted values for string are not guaranteed to stay consistent across releases โš ๏ธ.

This option is only meant to be useful when developing GCC ๐Ÿ™ˆ.

  • -mverbose-cost-dump โ€” Turns on verbose cost model dumping in the debug dump files ๐Ÿ”. This one exists for debugging the compiler itself ๐Ÿงช.
  • -mpc-relative-literal-loads, -mno-pc-relative-literal-loads โ€” Turn PC-relative literal loads on or off ๐Ÿฆ‹. With this option on, literal pools are accessed using a single instruction and emitted after each function ๐ŸŒธ. The catch is that it 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 allowed values are none, which disables return address signing; non-leaf, which enables pointer signing for functions that aren't leaf functions; and all, which enables pointer signing for all functions ๐Ÿ’œ. The default is none ๐Ÿ“.
This option has been deprecated by -mbranch-protection ๐Ÿฅ€.
  • -mbranch-protection=none|standard|pac-ret[+leaf+b-key]|bti โ€” Picks the branch protection features to use ๐Ÿ›ก๏ธ. none is the default and turns off all types of branch protection ๐Ÿ™…. standard turns on all types of branch protection features, and if a feature has extra tuning options, standard sets it to its standard level ๐ŸŒˆ. pac-ret[+leaf] turns on return address signing to its standard level, signing functions that save the return address to memory (non-leaf functions will practically always do this) using the a-key ๐Ÿ—๏ธ. The optional leaf argument extends the signing to include leaf functions ๐ŸŒฟ. The optional b-key argument signs the functions with the B-key instead of the A-key ๐Ÿ”‘. bti turns on the branch target identification mechanism ๐ŸŽฏ.
  • -mharden-sls=opts โ€” Enables compiler hardening against straight line speculation (SLS) ๐Ÿงฑ. opts is a comma-separated list of the following options:
    • retbr
    • blr

On top of that, -mharden-sls=all enables all SLS hardening, while -mharden-sls=none disables all of it ๐Ÿ™Œ.

  • -msve-vector-bits=bits โ€” Sets the number of bits in an SVE vector register ๐ŸŒŸ. This only does anything when SVE is enabled ๐Ÿ’–.

GCC supports two forms of SVE code generation. There's "vector-length agnostic" output, which works with any size of vector register, and "vector-length specific" output, which lets GCC make assumptions about the vector length when that helps optimization ๐Ÿง . The possible values of bits are: scalable, 128, 256, 512, 1024 and 2048 ๐ŸŽ€. Specifying scalable selects vector-length agnostic output ๐Ÿฆ„. At present, -msve-vector-bits=128 also generates vector-length agnostic output for big-endian targets ๐Ÿค“. Every other value generates vector-length specific code ๐Ÿ”ง.

The behavior 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 enables Advanced SIMD and floating-point instructions ๐Ÿ”.
  • fp โ€” Enables floating-point instructions. This is on by default for all possible values for options -march and -mcpu ๐Ÿ”ฅ.
  • simd โ€” Enables Advanced SIMD instructions. This also enables floating-point instructions. This is on by default for all possible values for options -march and -mcpu ๐ŸŽถ.
  • sve โ€” Enables Scalable Vector Extension instructions. This also enables Advanced SIMD and floating-point instructions ๐ŸŒŠ.
  • lse โ€” Enables Large System Extension instructions. This is on by default for -march=armv8.1-a ๐Ÿงฉ.
  • rdma โ€” Enables Round Double Multiply Accumulate instructions. This is on by default for -march=armv8.1-a โœ–๏ธ.
  • fp16 โ€” Enables the FP16 extension. This also enables floating-point instructions ๐ŸŒท.
  • fp16fml โ€” Enables the FP16 fmla extension. This also enables FP16 extensions and floating-point instructions. This option is 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 gets passed on to the assembler, so inline asm statements can use instructions from the RcPc extension ๐Ÿงต.
  • dotprod โ€” Enables the Dot Product extension. This also enables Advanced SIMD instructions ๐ŸŽฒ.
  • aes โ€” Enables the Armv8-a aes and pmull crypto extension. This also enables Advanced SIMD instructions ๐Ÿ”’.
  • sha2 โ€” Enables the Armv8-a sha2 crypto extension. This also enables Advanced SIMD instructions ๐Ÿง‚.
  • sha3 โ€” Enables the sha512 and sha3 crypto extension. This also enables Advanced SIMD instructions. Using this option with architectures prior to Armv8.2-A is not supported ๐Ÿ™ƒ.
  • sm4 โ€” Enables the sm3 and sm4 crypto extension. This also enables Advanced SIMD instructions. Using this 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 doesn't affect code generation ๐Ÿ“Š.
  • rng โ€” Enables the Armv8.5-a Random Number instructions. This option only enables the extension at the assembler level and doesn't 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 doesn't affect code generation. It's enabled by default for -march=armv8.5-a ๐Ÿšง.
  • ssbs โ€” Enables the Armv8-a Speculative Store Bypass Safe instruction. This option only enables the extension at the assembler level and doesn't affect code generation. It's enabled by default for -march=armv8.5-a ๐Ÿ›‘.
  • predres โ€” Enables the Armv8-a Execution and Data Prediction Restriction instructions. This option only enables the extension at the assembler level and doesn't affect code generation. It's enabled by default for -march=armv8.5-a ๐Ÿ”ฎ.
  • sve2 โ€” Enables the Armv8-a Scalable Vector Extension 2. This also enables SVE instructions ๐ŸŒ€.
  • sve2-bitperm โ€” Enables SVE2 bitperm instructions. This also enables SVE2 instructions ๐Ÿช„.
  • sve2-sm4 โ€” Enables SVE2 sm4 instructions. This also enables SVE2 instructions ๐Ÿฒ.
  • sve2-aes โ€” Enables SVE2 aes instructions. This also enables SVE2 instructions ๐Ÿ—๏ธ.
  • sve2-sha3 โ€” Enables SVE2 sha3 instructions. This also enables SVE2 instructions ๐ŸŒบ.
  • tme โ€” Enables the Transactional Memory Extension ๐Ÿง .
  • i8mm โ€” Enables 8-bit Integer Matrix Multiply instructions. This also enables Advanced SIMD and floating-point instructions. This option is 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 โ€” Enables brain half-precision floating-point instructions. This also enables Advanced SIMD and floating-point instructions. This option is enabled by default for -march=armv8.6-a. Using this option with architectures prior to Armv8.2-A is not supported ๐Ÿง ๐Ÿ’•.

Okay so crypto pulls in aes, sha2, and simd, and simd pulls in fp ๐Ÿ”ฅ. Going the other way, nofp drags along nosimd, which drags along nocrypto, noaes, and nosha2 ๐Ÿ’€. It's a whole domino situation, bestie ๐Ÿงš

โœจ Adapteva Epiphany Options โœจ

These -m options are specific to the Adapteva Epiphany ๐Ÿฆ‹

  • -mhalf-reg-file โ€” Don't hand out any register from r32...r63 ๐ŸŒธ. That way your code can run on chips that don't have those registers at all.
  • -mprefer-short-insn-regs โ€” Prefers registers that let the compiler emit short instructions โœจ. Heads up, 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. It's only a heuristic, so don't expect the same results across releases ๐Ÿ’œ.
  • -mcmove โ€” Turns on conditional moves ๐ŸŽ€.
  • -mnops=num โ€” Emits num NOPs before every other generated instruction ๐Ÿ˜ญ.
  • -mno-soft-cmpsf โ€” For single-precision float comparisons, this emits an fsub and checks the flags. It's faster than a software comparison, but it can give wrong answers with NaNs, or when two different small numbers subtract to zero. The default is -msoft-cmpsf, which is slower but IEEE-compliant software comparison ๐Ÿ’….
  • -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 ๐Ÿ’€.
This option changes the ABI, so compiling with a different stack offset than the libraries were built with generally doesn't work ๐Ÿ™…โ€โ™€๏ธ. It's handy for checking whether a different offset gives you better code, but if you want to actually build working programs with a different offset, configure the toolchain with the right --with-stack-offset=num option instead.
  • -mno-round-nearest โ€” Makes the scheduler assume the rounding mode is set to truncating. The default is -mround-nearest ๐Ÿ“.
  • -mlong-calls โ€” Unless an attribute says otherwise, this assumes every call might be out of range of the b / bl instructions. So it loads the function address into a register before making the (otherwise direct) call. This is the default ๐Ÿ‘‘.
  • -mshort-calls โ€” Unless an attribute says otherwise, this assumes direct calls are within range of the b / bl instructions, so those get used for direct calls. The default is -mlong-calls โœจ.
  • -msmall16 โ€” Assumes addresses can be loaded as 16-bit unsigned values. This doesn't apply to function addresses where -mlong-calls semantics are in effect ๐Ÿงš.
  • -mfp-mode=mode โ€” Sets the prevailing mode of the floating-point unit, which decides the FP 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 skipping unnecessary mode switches ๐Ÿ”ฅ. mode can be one of the following values:
    • caller โ€” Any mode at function entry is valid, and it gets retained or restored when the function returns and when it calls other functions. This is great for libraries or other compilation units you want to drop into programs with different FPU modes. Being able to use one object file is worth the extra switching overhead ๐Ÿซถ.
    • truncate โ€” The mode used for FP calculations with truncating rounding (round towards zero). That includes converting from floating point to integer.
    • round-nearest โ€” The mode used for FP calculations with round-to-nearest-or-even rounding.
    • int โ€” The mode used to do integer calculations in the FPU, like integer multiply or integer multiply-and-accumulate.

The default is -mfp-mode=caller ๐Ÿ’–.

  • -mno-split-lohi, -mno-postinc, -mno-postmodify โ€” Code generation tweaks 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 โ€” Switches 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, though plenty of library function interfaces are unaffected if they don't use SIMD vector modes in places that affect the size or alignment of relevant types ๐Ÿ‘€.
  • -msplit-vecmove-early โ€” Splits vector moves into single-word moves before reload. In theory this can give better register allocation, but so far the reverse seems to be the case ๐Ÿ˜ญ.
  • -m1reg-reg โ€” Picks a register to hold the constant -1, which makes loading small negative constants and certain bitmasks faster โญ. Allowable values for reg are r43 and r63, which use that register as a fixed register, and none, which means no register is used for this purpose. The default is -m1reg-none ๐Ÿ’œ.

๐ŸŒˆ AMD GCN Options ๐ŸŒˆ

These options are defined specifically for the AMD GCN port ๐Ÿ’–

  • -march=gpu, -mtune=gpu โ€” Sets the architecture type or tuning for gpu. The supported values for gpu are:
    • fiji โ€” Compile for GCN3 Fiji devices (gfx803) ๐ŸŽ€.
    • gfx900 โ€” Compile for GCN5 Vega 10 devices (gfx900) โœจ.
    • gfx906 โ€” Compile for GCN5 Vega 20 devices (gfx906) ๐Ÿ”ฅ.
  • -mstack-size=bytes โ€” Specifies how many bytes of stack space get requested for each GPU thread (wave-front). Beware, there may be a lot of threads and limited memory available ๐Ÿ’€. The size of the stack allocation can also affect run-time performance. The default is 32KB when using OpenACC or OpenMP, and 1MB otherwise ๐Ÿงš.

๐ŸŒธ ARC Options ๐ŸŒธ

These options control which architecture variant your code gets 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. Shortcut alias options also exist for backward compatibility and convenience. The supported values for cpu are:
    • arc600 โ€” Compile for ARC600. Aliases: -mA6, -mARC600.
    • arc601 โ€” Compile for ARC601. Alias: -mARC601.
    • arc700 โ€” Compile for ARC700. Aliases: -mA7, -mARC700. This is the default when configured with --with-cpu=arc700 ๐Ÿ‘‘.
    • arcem โ€” Compile for ARC EM.
    • archs โ€” Compile for ARC HS.
    • em โ€” Compile for ARC EM CPU with no hardware extensions.
    • em4 โ€” Compile for ARC EM4 CPU.
    • em4_dmips โ€” Compile for ARC EM4 DMIPS CPU.
    • em4_fpus โ€” Compile for ARC EM4 DMIPS CPU with the single-precision floating-point extension.
    • em4_fpuda โ€” Compile for ARC EM4 DMIPS CPU with single-precision floating-point and double assist instructions.
    • hs โ€” Compile for ARC HS CPU with no hardware extensions except the atomic instructions.
    • hs34 โ€” Compile for ARC HS34 CPU.
    • hs38 โ€” Compile for ARC HS38 CPU.
    • hs38_linux โ€” Compile for ARC HS38 CPU with all hardware extensions on.
    • arc600_norm โ€” Compile for ARC 600 CPU with norm instructions enabled.
    • arc600_mul32x16 โ€” Compile for ARC 600 CPU with norm and 32x16-bit multiply instructions enabled.
    • arc600_mul64 โ€” Compile for ARC 600 CPU with norm and mul64-family instructions enabled.
    • arc601_norm โ€” Compile for ARC 601 CPU with norm instructions enabled.
    • arc601_mul32x16 โ€” Compile for ARC 601 CPU with norm and 32x16-bit multiply instructions enabled.
    • arc601_mul64 โ€” Compile for ARC 601 CPU with norm and mul64-family instructions enabled.
    • nps400 โ€” Compile for ARC 700 on the NPS400 chip.
    • em_mini โ€” Compile for the ARC EM minimalist configuration, which features 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 โ€” Stops lr and sr instructions from using FPX extension aux registers ๐Ÿ™ˆ.
  • -mea โ€” Generates extended arithmetic instructions. Right now only divaw, adds, subs, and sat16 are supported. This is only valid for -mcpu=ARC700 ๐Ÿ”ฅ.
  • -mno-mpy โ€” Doesn't generate mpy-family instructions for ARC700. This option is deprecated ๐Ÿ’€.
  • -mmul32x16 โ€” Generates 32x16-bit multiply and multiply-accumulate instructions ๐Ÿฆ‹.
  • -mmul64 โ€” Generates mul64 and mulu64 instructions. This is only valid for -mcpu=ARC600 ๐ŸŒˆ.
  • -mnorm โ€” Generates norm instructions. This is the default if -mcpu=ARC700 is in effect ๐Ÿ“.
  • -mspfp, -mspfp-compact โ€” Generates single-precision FPX instructions, tuned for the compact implementation ๐ŸŽ€.
  • -mspfp-fast โ€” Generates single-precision FPX instructions, tuned for the fast implementation โœจ.
  • -msimd โ€” Enables ARC SIMD instructions through target-specific builtins. This is only valid for -mcpu=ARC700 ๐Ÿงš.
  • -msoft-float โ€” This option is ignored. It's only here for compatibility. Software floating-point code is emitted by default, and you can override that default with FPX options: -mspfp, -mspfp-compact, or -mspfp-fast for single precision, and -mdpfp, -mdpfp-compact, or -mdpfp-fast for double precision ๐Ÿซถ.
  • -mswap โ€” okay bestie, this one tells the compiler to generate swap instructions ๐Ÿ”„โœจ
  • -matomic โ€” this unlocks the locked load/store conditional extension so the atomic memory built-in functions can actually work ๐Ÿ”’๐Ÿ’– Not available for ARC 6xx or ARC EM cores, so don't even try it there ๐Ÿ™…โ€โ™€๏ธ
  • -mdiv-rem โ€” enables the 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 you're already set if that's your chip ๐Ÿ’…
  • -mll64 โ€” enables double load/store operations for ARC HS cores ๐Ÿ”ฅ
  • -mtp-regno=regno โ€” lets you specify the thread pointer register number ๐Ÿงต
  • -mmpy-option=multo โ€” compiles ARCv2 code with a multiplier design option ๐Ÿ”ข You can pick the option with either a string or a numeric value for multo, and wlh1 is the default ๐Ÿ‘‘ Here's the menu:
    • 0 or none โ€” no multiplier available ๐Ÿซฅ
    • 1 or w โ€” 16x16 multiplier, fully pipelined. This enables mpyw and mpyuw โœจ
    • 2 or wlh1 โ€” 32x32 multiplier, fully pipelined (1 stage). On top of the above, this adds mpy, mpyu, mpym, mpymu, and mpy_s ๐Ÿš€ This is the default!
    • 3 or wlh2 โ€” 32x32 multiplier, fully pipelined (2 stages). Also adds mpy, mpyu, mpym, mpymu, and mpy_s ๐Ÿ’œ
    • 4 or wlh3 โ€” two 16x16 multipliers, blocking, sequential. Also adds mpy, mpyu, mpym, mpymu, and mpy_s ๐Ÿงฉ
    • 5 or wlh4 โ€” one 16x16 multiplier, blocking, sequential. Also adds mpy, mpyu, mpym, mpymu, and mpy_s ๐Ÿข
    • 6 or wlh5 โ€” one 32x4 multiplier, blocking, sequential. Also adds 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, so keep that in mind ๐Ÿซถ

  • -mfpu=fpu โ€” turns on support for specific floating-point hardware extensions on ARCv2 cores ๐Ÿฆ„ These are the valid fpu values:
    • fpus โ€” single-precision floating-point hardware extensions ๐Ÿ’ซ
    • fpud โ€” double-precision floating-point hardware extensions. The single-precision extension comes along for the ride too. Not available for ARC EM ๐Ÿ™…โ€โ™€๏ธ
    • fpuda โ€” double-precision extensions using double-precision assist instructions, plus the single-precision extension. This is only available for ARC EM ๐ŸŒท
    • fpuda_div โ€” double-precision extensions using double-precision assist instructions, plus the single-precision, square-root, and divide extensions. Only for ARC EM โž—
    • fpuda_fma โ€” double-precision extensions using double-precision assist instructions, plus the single-precision and fused multiply and add extensions. Only for ARC EM โœ–๏ธโž•
    • fpuda_all โ€” double-precision extensions using double-precision assist instructions, and all the single-precision extensions too. Only for ARC EM ๐Ÿ‘‘
    • fpus_div โ€” single-precision floating-point, square-root, and divide extensions โž—โœจ
    • fpud_div โ€” double-precision floating-point, square-root, and divide extensions. This one includes fpus_div. Not available for ARC EM ๐Ÿ’…
    • fpus_fma โ€” single-precision floating-point and fused multiply and add extensions ๐ŸŽฏ
    • fpud_fma โ€” double-precision floating-point and fused multiply and add extensions. This one includes fpus_fma. Not available for ARC EM ๐Ÿง
    • fpus_all โ€” every single-precision floating-point extension ๐ŸŒŸ
    • fpud_all โ€” every single- and double-precision floating-point extension. Not available for ARC EM ๐Ÿ†
  • -mirq-ctrl-saved=register-range, blink, lp_count โ€” specifies the general-purpose registers the processor automatically saves and restores on interrupt entry and exit ๐Ÿ›Ÿ The register-range is two registers separated by a dash. It always starts with r0, and the upper limit is the fp register. blink and lp_count are optional ๐Ÿซง This option is only valid for ARC EM and ARC HS cores.
  • -mrgf-banked-regs=number โ€” specifies how many registers get replicated in the second register bank when entering a fast interrupt โšก Fast interrupts are the ones with the highest priority level, P0. They only save the PC and STATUS32 registers so there are no memory transactions during entry and exit ๐Ÿƒโ€โ™€๏ธ Use this when you're using fast interrupts on an ARC V2 family processor. Permitted values are 4, 8, 16, and 32.
  • -mlpc-width=width โ€” sets the width of the lp_count register ๐Ÿ“ Valid values are 8, 16, 20, 24, 28, and 32 bits, and the default is fixed at 32 bits. If the width is less than 32, the compiler won't try to transform your loops into the zero-delay loop mechanism unless it knows lp_count can 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 they also define preprocessor macro symbols ๐Ÿ“จ

  • -mdsp-packa โ€” passed down to the assembler to enable the DSP Pack A extensions. It also sets the preprocessor symbol __Xdsp_packa. This option is deprecated, so it's on its way out ๐Ÿ’€
  • -mdvbf โ€” passed down to the assembler to enable the dual Viterbi butterfly extension. It also sets the preprocessor symbol __Xdvbf. This option is deprecated ๐Ÿฅ€
  • -mlock โ€” passed down to the assembler to enable the locked load/store conditional extension. It also sets the preprocessor symbol __Xlock ๐Ÿ”
  • -mmac-d16 โ€” passed down to the assembler, and sets the preprocessor symbol __Xxmac_d16. This option is deprecated ๐Ÿซ 
  • -mmac-24 โ€” passed down to the assembler, and 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. It also sets the preprocessor symbol __Xrtsc. This option is deprecated โฐ
  • -mswape โ€” passed down to the assembler to enable the swap byte ordering extension instruction. It also sets the preprocessor symbol __Xswape ๐Ÿ”€
  • -mtelephony โ€” passed down to the assembler to enable dual- and single-operand instructions for telephony. It also sets the preprocessor symbol __Xtelephony. This option is deprecated ๐Ÿ“ž
  • -mxy โ€” passed down to the assembler to enable the XY memory extension. It 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 deciding whether an instruction is 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, which gives access to the full 32-bit address range ๐ŸŒ
  • -mmedium-calls โ€” doesn't use less than a 25-bit addressing range for calls, which is the offset available for an unconditional branch-and-link instruction. Conditional execution of function calls is suppressed so the 25-bit range can be used, instead of the 21-bit range you get with conditional branch-and-link. This is the default for tool chains built for arc-linux-uclibc and arceb-linux-uclibc targets ๐Ÿฆ‹
  • -G num โ€” puts definitions of externally-visible data in a small data section if that data is no bigger than num bytes ๐ŸŒฑ The default value of num is 4 for any ARC configuration, or 8 when you have double load/store operations ๐Ÿ“
  • -mno-sdata โ€” doesn't generate sdata references. This is the default for tool chains built for arc-linux-uclibc and arceb-linux-uclibc targets ๐Ÿšซ
  • -mvolatile-cache โ€” uses ordinarily cached memory accesses for volatile references. This is the default ๐Ÿ’พ
  • -mno-volatile-cache โ€” enables cache bypass for volatile references ๐Ÿƒโ€โ™€๏ธ

The following options fine tune code generation ๐ŸŽ€

  • -malign-call โ€” does alignment optimizations for call instructions ๐Ÿ“
  • -mauto-modify-reg โ€” enables the use of pre/post modify with register displacement ๐Ÿ”
  • -mbbit-peephole โ€” enables bbit peephole2 ๐Ÿช„
  • -mno-brcc โ€” disables a target-specific pass in arc_reorg that generates compare-and-branch (brcc) instructions. It has no effect on generation of these instructions driven by the combiner pass ๐Ÿ™…โ€โ™€๏ธโœจ
  • -mcase-vector-pcrel: okay bestie, this one uses PC-relative switch case tables to turn on case table shortening ๐Ÿ’… It's the default for -Os โœจ
  • -mcompact-casesi: turns on the compact casesi pattern ๐Ÿฆ‹ It's the default for -Os, but it's only available for ARCv1 cores, and it's deprecated ๐Ÿ’€
  • -mno-cond-exec: this one turns OFF the ARCompact-specific pass that generates conditional execution instructions ๐Ÿ™ˆ The target-independent pass is often lacking because of delay slot scheduling and interactions between operand numbers, literal sizes, instruction lengths, and the support for conditional execution. So the ARC port keeps a special pass that hunts for more conditional execution chances after register allocation, branch shortening, and delay slot scheduling are done. It generally (not always!) improves performance and code size, but it costs extra compilation time, which is why there's a switch to turn it off ๐Ÿซถ

If you're having problems with call instructions going 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. ๐Ÿงš This one is deprecated.
  • -mindexed-loads: enables indexed loads ๐Ÿ“ This can be problematic, because some optimizers then assume indexed stores exist, which is not the case ๐Ÿ’€
  • -mlra: enables Local Register Allocation ๐Ÿงช It's still experimental for ARC, so by default the compiler uses standard reload (i.e. -mno-lra) ๐ŸŒˆ
  • -mlra-priority-none: no priority gets indicated 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 big pile of registers often get shortened by calling a special function in libgcc. That's called a millicode call โœจ These calls can cause performance issues, and/or linking issues when you link in a nonstandard way, so this option lets you turn millicode call generation on or off ๐Ÿ”ฅ
  • -mcode-density-frame: lets the compiler emit enter and leave instructions ๐Ÿงš These are only valid for CPUs with the code-density feature ๐Ÿ’…
  • -mmixed-code: tweaks register allocation to help 16-bit instruction generation ๐Ÿฆ‹ This usually brings the average instruction size down, while bumping up the instruction count ๐Ÿซถ
  • -mq-class: deprecated ๐Ÿ’€ Enables q instruction alternatives. This is the default for -Os โœจ
  • -mRcq: enables Rcq constraint handling ๐Ÿ’– Most short code generation depends on this, and it's the default ๐Ÿ‘‘
  • -mRcw: enables Rcw constraint handling ๐Ÿ’œ Most ccfsm condexec mostly depends on this, and it's the default ๐Ÿ‘‘
  • -msize-level=level: fine-tunes size optimization with regards to instruction lengths and alignment ๐Ÿ“ The recognized values for level are:
    • 0: no size optimization. This level is deprecated and treated like 1 ๐Ÿ™ˆ
    • 1: short instructions get used opportunistically ๐ŸŒธ
    • 2: in addition, alignment of loops and of code after barriers gets dropped ๐Ÿ“
    • 3: in addition, optional data alignment gets dropped, and the option Os is enabled ๐Ÿ”ฅ

This defaults to 3 when -Os is in effect. Otherwise, when it's not set, the behavior is equivalent to level 1 โœจ

  • -mtune=cpu: sets instruction scheduling parameters for cpu, overriding anything implied by -mcpu= ๐ŸŽ€ Supported values for cpu are:
    • ARC600: tunes for the ARC600 CPU ๐Ÿงธ
    • ARC601: tunes for the ARC601 CPU ๐Ÿงธ
    • ARC700: tunes for the ARC700 CPU with standard multiplier block ๐Ÿ’ช
    • ARC700-xmac: tunes for the ARC700 CPU with XMAC block ๐Ÿ’ช
    • ARC725D: tunes for the ARC725D CPU ๐ŸŒท
    • ARC750D: tunes for the ARC750D CPU ๐ŸŒท
  • -mmultcost=num: the cost to assume for a multiply instruction, with 4 being equal to a normal instruction ๐Ÿงฎ
  • -munalign-prob-threshold=probability: sets the probability threshold for unaligning branches ๐Ÿง  When tuning for ARC700 and optimizing for speed, branches without a filled delay slot are preferably emitted unaligned and long, unless profiling shows the probability for the branch to be taken is below probability. The default is (REG_BR_PROB_BASE/2), i.e. 5000 ๐ŸŒˆ

The following options are maintained for backward compatibility, but they're now deprecated and will be removed in a future release ๐Ÿฅ€

  • -margonaut: obsolete FPX ๐Ÿชฆ
  • -mbig-endian, -EB: compiles code for big-endian targets. Using these is now deprecated ๐ŸŒŠ Big-endian code is supported by configuring GCC to build arceb-elf32 and arceb-linux-uclibc targets, where big endian is the default โœจ
  • -mlittle-endian, -EL: compiles code for little-endian targets. Using these is now deprecated ๐ŸŒŠ Little-endian code is supported by configuring GCC to build arc-elf32 and arc-linux-uclibc targets, where little endian is the default โœจ
  • -mbarrel_shifter: got a glow-up, it's now -mbarrel-shifter ๐Ÿ’…
  • -mdpfp_compact: got a glow-up, it's now -mdpfp-compact ๐Ÿ’…
  • -mdpfp_fast: got a glow-up, it's now -mdpfp-fast ๐Ÿ’…
  • -mdsp_packa: got a glow-up, it's now -mdsp-packa ๐Ÿ’…
  • -mEA: got a glow-up, it's now -mea ๐Ÿ’…
  • -mmac_24: got a glow-up, it's now -mmac-24 ๐Ÿ’…
  • -mmac_d16: got a glow-up, it's now -mmac-d16 ๐Ÿ’…
  • -mspfp_compact: got a glow-up, it's now -mspfp-compact ๐Ÿ’…
  • -mspfp_fast: got a glow-up, it's now -mspfp-fast ๐Ÿ’…
  • -mtune=cpu: the values arc600, arc601, arc700 and arc700-xmac for cpu are now ARC600, ARC601, ARC700 and ARC700-xmac respectively ๐Ÿ”ค
  • -multcost=num: got a glow-up, it's now -mmultcost ๐Ÿ’…

๐Ÿฆ‹ ARM Options ๐Ÿฆ‹

These -m options are defined for the ARM port ๐Ÿ’œ

  • -mabi=name: generates code for the specified ABI. Permissible values are: apcs-gnu, atpcs, aapcs, aapcs-linux and iwmmxt ๐Ÿงพ
  • -mapcs-frame: generates a stack frame that's compliant with the ARM Procedure Call Standard for all functions, even if it's not strictly necessary for the code to run correctly ๐Ÿ—๏ธ Specifying -fomit-frame-pointer with this option means stack frames don't get generated for leaf functions. The default is -mno-apcs-frame. This option is deprecated ๐Ÿ’€
  • -mapcs: a synonym for -mapcs-frame, and it's deprecated too ๐Ÿ’€
  • -mthumb-interwork: generates code that supports calling between the ARM and Thumb instruction sets ๐Ÿค Without this option, on pre-v5 architectures, the two instruction sets can't be reliably used inside one program. The default is -mno-thumb-interwork, since slightly larger code is generated when -mthumb-interwork is specified. In AAPCS configurations this option is meaningless ๐Ÿซ 
  • -mno-sched-prolog: stops the reordering of instructions in the function prologue, and stops them from being merged with the instructions in the function's body ๐Ÿ”’ This means all functions start with a recognizable set of instructions (or one of a small set of different function prologues), so that info can be used to locate where functions start inside an executable piece of code ๐Ÿ”Ž The default is -msched-prolog โœจ
  • -mfloat-abi=name: specifies which floating-point ABI to use ๐Ÿงฎ Permissible values are soft, softfp and hard. soft makes GCC generate output containing library calls for floating-point operations. softfp allows code using hardware floating-point instructions, but still uses the soft-float calling conventions. hard allows floating-point instructions and uses FPU-specific calling conventions ๐Ÿ”ฅ The default depends on the specific target configuration. Heads up: the hard-float and soft-float ABIs are not link-compatible ๐Ÿšซ You have to compile your entire program with the same ABI, and link with a compatible set of libraries ๐Ÿซถ
  • -mgeneral-regs-only: generates code that only uses the general-purpose registers ๐ŸŽฏ This stops the compiler from using floating-point and Advanced SIMD registers, but it won't put any restrictions on the assembler ๐Ÿง˜
  • -mlittle-endian: generates code for a processor running in little-endian mode ๐ŸŒ™ This is the default for all standard configurations โœจ
  • -mbig-endian: generates code for a processor running in big-endian mode ๐ŸŒž The default is to compile for a little-endian processor ๐ŸŒ™
  • -mbe8, -mbe32: when linking a big-endian image, selects between BE8 and BE32 formats ๐Ÿงฉ This has no effect on little-endian images, which it ignores. The default depends on the selected target architecture: for ARMv6 and later architectures it's BE8, and for older architectures it's BE32. BE32 format has been deprecated by ARM ๐Ÿ’€
  • -march=name[+extension...]: specifies the name of the target ARM architecture ๐Ÿ›๏ธ GCC uses this name to figure out what kinds of instructions it can emit when generating assembly code. This option can be used in conjunction with, or instead of, the -mcpu= option ๐Ÿค

Permissible names are: armv4t, armv5t, armv5te, armv6, armv6j, armv6k, armv6kz, armv6t2, armv6z, armv6zk, armv7, armv7-a, armv7ve, armv8-a, armv8.1-a, armv8.2-a, armv8.3-a, armv8.4-a, armv8.5-a, armv8.6-a, 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 ๐Ÿฅ€

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. An extension will also enable any necessary base extensions it depends on. For example, the +crypto extension will always enable the +simd extension ๐Ÿ”— The exception to the additive construction is for extensions prefixed with +no...: these extensions disable the specified option, and any other extensions that may depend on the presence of that extension ๐Ÿ™…โ€โ™€๏ธ

For example, -march=armv7-a+simd+nofp+vfpv4 is literally the same as -march=armv7-a+vfpv4 ๐Ÿ’… because the +nofp that comes after +simd wipes +simd out completely. Order matters, bestie ๐Ÿซถ

Most extension names sound generic, but what they actually do depends on which architecture you stick them on ๐Ÿฆ‹ For example, +simd works on both armv7-a and armv8-a, but on armv7-a it turns on the original ARMv7-A Advanced SIMD (Neon) stuff, while on armv8-a you get the ARMv8-A version ๐Ÿคฏ

Here's the full menu of what each architecture supports ๐Ÿ“œ If an architecture isn't mentioned below, it doesn't support any extensions at all, so don't even try ๐Ÿ’€

armv5te, armv6, armv6j, armv6k, armv6kz, armv6t2, armv6z, armv6zk

  • +fp โ€” The VFPv2 floating-point instructions ๐ŸŒธ +vfpv2 works as an alias for this one.
  • +nofp โ€” Turns off the floating-point instructions ๐Ÿšซ

armv7

The common subset of the ARMv7-A, ARMv7-R and ARMv7-M architectures โœจ

  • +fp โ€” The VFPv3 floating-point instructions, with 16 double-precision registers. +vfpv3-d16 is an alias for this one. Heads up: floating-point isn't supported by the base ARMv7-M architecture, but it's compatible with both ARMv7-A and ARMv7-R ๐Ÿ’œ
  • +nofp โ€” 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. +vfpv3-d16 is an alias for this one.
  • +simd โ€” The Advanced SIMD (Neon) v1 and VFPv3 floating-point instructions. +neon and +neon-vfpv3 are both aliases for this one ๐Ÿ”ฅ
  • +vfpv3 โ€” The VFPv3 floating-point instructions, with 32 double-precision registers
  • +vfpv3-d16-fp16 โ€” The VFPv3 floating-point instructions, with 16 double-precision registers and the half-precision floating-point conversion operations
  • +vfpv3-fp16 โ€” The VFPv3 floating-point instructions, with 32 double-precision registers and the half-precision floating-point conversion operations
  • +vfpv4-d16 โ€” The VFPv4 floating-point instructions, with 16 double-precision registers
  • +vfpv4 โ€” The VFPv4 floating-point instructions, with 32 double-precision registers
  • +neon-fp16 โ€” The Advanced SIMD (Neon) v1 and VFPv3 floating-point instructions, with the half-precision floating-point conversion operations
  • +neon-vfpv4 โ€” The Advanced SIMD (Neon) v2 and VFPv4 floating-point instructions
  • +nosimd โ€” Disable the Advanced SIMD instructions (this 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 ๐ŸŒˆ

  • +fp โ€” The VFPv4 floating-point instructions, with 16 double-precision registers. +vfpv4-d16 is an alias for this one.
  • +simd โ€” The Advanced SIMD (Neon) v2 and VFPv4 floating-point instructions. +neon-vfpv4 is an alias for this one.
  • +vfpv3-d16 โ€” The VFPv3 floating-point instructions, with 16 double-precision registers
  • +vfpv3 โ€” The VFPv3 floating-point instructions, with 32 double-precision registers
  • +vfpv3-d16-fp16 โ€” The VFPv3 floating-point instructions, with 16 double-precision registers 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 VFPv3 floating-point instructions. +neon-vfpv3 is an alias for this one.
  • +neon-fp16 โ€” The Advanced SIMD (Neon) v1 and VFPv3 floating-point instructions, with the half-precision floating-point conversion operations
  • +nosimd โ€” Disable the Advanced SIMD instructions (this 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 โ€” The Speculation Barrier Instruction ๐Ÿ›ก๏ธ
  • +predres โ€” The Execution and Data Prediction Restriction Instructions

armv8.1-a

  • +simd โ€” The ARMv8.1-A Advanced SIMD and floating-point instructions
  • +crypto โ€” The cryptographic instructions. This also enables the Advanced SIMD and floating-point instructions too ๐Ÿ”
  • +nocrypto โ€” Disable the cryptographic instructions
  • +nofp โ€” Disable the floating-point, Advanced SIMD and cryptographic instructions
  • +sb โ€” The Speculation Barrier Instruction ๐Ÿ›ก๏ธ
  • +predres โ€” The Execution and Data Prediction Restriction Instructions

armv8.2-a, armv8.3-a

  • +fp16 โ€” The half-precision floating-point data processing instructions. This also enables the Advanced SIMD and floating-point instructions ๐ŸŒŸ
  • +fp16fml โ€” The half-precision floating-point fmla extension. This also enables the half-precision floating-point extension, plus the Advanced SIMD and floating-point instructions ๐Ÿ’ซ
  • +simd โ€” The ARMv8.1-A Advanced SIMD and floating-point instructions
  • +crypto โ€” The cryptographic instructions. This also enables the Advanced SIMD and floating-point instructions
  • +dotprod โ€” 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 โ€” The Speculation Barrier Instruction ๐Ÿ›ก๏ธ
  • +predres โ€” The Execution and Data Prediction Restriction Instructions
  • +i8mm โ€” The 8-bit Integer Matrix Multiply instructions. This also enables Advanced SIMD and floating-point instructions ๐Ÿงฑ
  • +bf16 โ€” The Brain half-precision floating-point instructions. This also enables Advanced SIMD and floating-point instructions ๐Ÿง 

armv8.4-a

  • +fp16 โ€” The half-precision floating-point data processing instructions. This also enables the Advanced SIMD and floating-point instructions, 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 โ€” The Speculation Barrier Instruction ๐Ÿ›ก๏ธ
  • +predres โ€” The Execution and Data Prediction Restriction Instructions
  • +i8mm โ€” The 8-bit Integer Matrix Multiply instructions. This also enables Advanced SIMD and floating-point instructions ๐Ÿงฑ
  • +bf16 โ€” The Brain half-precision floating-point instructions. This also enables Advanced SIMD and floating-point instructions ๐Ÿง 

armv8.5-a

  • +fp16 โ€” The half-precision floating-point data processing instructions. This also enables the Advanced SIMD and floating-point instructions, 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
  • +i8mm โ€” The 8-bit Integer Matrix Multiply instructions. This also enables Advanced SIMD and floating-point instructions ๐Ÿงฑ
  • +bf16 โ€” The Brain half-precision floating-point instructions. This also enables Advanced SIMD and floating-point instructions ๐Ÿง 

๐Ÿ’– armv8.6-a

  • +fp16 โ€” okay so this one unlocks the half-precision floating-point data processing instructions ๐Ÿ”ฅ It also turns on the Advanced SIMD and floating-point instructions, plus the Dot Product extension and the half-precision floating-point fmla extension โœจ
  • +simd โ€” the ARMv8.3-A Advanced SIMD and floating-point instructions, plus the Dot Product extension ๐Ÿ’…
  • +crypto โ€” the cryptographic instructions ๐Ÿ” This one also gives you the Advanced SIMD and floating-point instructions and the Dot Product extension ๐Ÿฆ‹
  • +nocrypto โ€” disables the cryptographic extension ๐Ÿ™ˆ
  • +nofp โ€” disables the floating-point, Advanced SIMD and cryptographic instructions all at once ๐Ÿ’€
  • +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 ๐ŸŒˆ The extension +vfpv3xd can be used as an alias for this one
  • +fp โ€” the VFPv3 floating-point instructions with 16 double-precision registers ๐Ÿ’œ The extension +vfpv3-d16 can be used as an alias for this one
  • +vfpv3xd-d16-fp16 โ€” the single-precision VFPv3 floating-point instructions with 16 double-precision registers, plus the half-precision floating-point conversion operations ๐Ÿฆ‹
  • +vfpv3-d16-fp16 โ€” the VFPv3 floating-point instructions with 16 double-precision registers, plus the half-precision floating-point conversion operations โœจ
  • +nofp โ€” disables the floating-point extension ๐Ÿ™ˆ
  • +idiv โ€” the ARM-state integer division instructions ๐Ÿ”ฅ
  • +noidiv โ€” disables the ARM-state integer division extension ๐Ÿ’€

๐ŸŒธ armv7e-m

  • +fp โ€” the single-precision VFPv4 floating-point instructions ๐Ÿ’–
  • +fpv5 โ€” the single-precision FPv5 floating-point instructions ๐Ÿงš
  • +fp.dp โ€” the single- and double-precision FPv5 floating-point instructions ๐Ÿ‘‘
  • +nofp โ€” disables the floating-point extensions ๐Ÿ™ˆ

๐Ÿฆ‹ armv8.1-m.main

  • +dsp โ€” the DSP instructions ๐Ÿ’…
  • +mve โ€” the M-Profile Vector Extension (MVE) integer instructions ๐ŸŒˆ
  • +mve.fp โ€” the M-Profile Vector Extension (MVE) integer and single precision floating-point instructions ๐Ÿ”ฅ
  • +fp โ€” the single-precision floating-point instructions โญ
  • +fp.dp โ€” the single- and double-precision floating-point instructions ๐Ÿ‘‘
  • +nofp โ€” disables the floating-point extension ๐Ÿ™ˆ
  • +cdecp0, +cdecp1, ... , +cdecp7 โ€” enables the Custom Datapath Extension (CDE) on selected coprocessors, going by the numbers you give in the options, in the range 0 to 7 ๐Ÿงš

๐Ÿ’œ armv8-m.main

  • +dsp โ€” the DSP instructions ๐Ÿ’…
  • +nodsp โ€” disables the DSP extension ๐Ÿ™ˆ
  • +fp โ€” the single-precision floating-point instructions โญ
  • +fp.dp โ€” the single- and double-precision floating-point instructions ๐Ÿ‘‘
  • +nofp โ€” disables the floating-point extension ๐Ÿ™ˆ
  • +cdecp0, +cdecp1, ... , +cdecp7 โ€” enables the Custom Datapath Extension (CDE) on selected coprocessors, going by the numbers you give in the options, in the range 0 to 7 ๐Ÿงš

๐Ÿ“ armv8-r

  • +crc โ€” the Cyclic Redundancy Check (CRC) instructions ๐Ÿ”ฅ
  • +fp.sp โ€” the single-precision FPv5 floating-point instructions ๐ŸŒธ
  • +simd โ€” the ARMv8-A Advanced SIMD and floating-point instructions ๐Ÿ’…
  • +crypto โ€” the cryptographic instructions ๐Ÿ”
  • +nocrypto โ€” disables the cryptographic instructions ๐Ÿ™ˆ
  • +nofp โ€” disables the floating-point, Advanced SIMD and cryptographic instructions ๐Ÿ’€

-march=native tells the compiler to auto-detect the architecture of the build computer โœจ Lowkey the best part is that you don't have to type it out yourself.

โš ๏ธ bestie, this one is picky. It's only supported 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 tells GCC which target ARM processor to tune the performance of your code for ๐ŸŽ€ For some ARM implementations you can get better performance by using it. The permissible names are:

arm7tdmi, arm7tdmi-s, arm710t, arm720t, arm740t, strongarm, strongarm110, strongarm1100, 0strongarm1110, arm8, arm810, arm9, arm9e, arm920, arm920t, arm922t, arm946e-s, arm966e-s, arm968e-s, arm926ej-s, arm940t, arm9tdmi, arm10tdmi, arm1020t, arm1026ej-s, arm10e, arm1020e, arm1022e, arm1136j-s, arm1136jf-s, mpcore, mpcorenovfp, arm1156t2-s, arm1156t2f-s, arm1176jz-s, arm1176jzf-s, generic-armv7-a, cortex-a5, cortex-a7, cortex-a8, cortex-a9, cortex-a12, cortex-a15, cortex-a17, cortex-a32, cortex-a35, cortex-a53, cortex-a55, cortex-a57, cortex-a72, cortex-a73, cortex-a75, cortex-a76, cortex-a76ae, cortex-a77, ares, cortex-r4, cortex-r4f, cortex-r5, cortex-r7, cortex-r8, cortex-r52, cortex-m0, cortex-m0plus, cortex-m1, cortex-m3, cortex-m4, cortex-m7, cortex-m23, cortex-m33, cortex-m35p, cortex-m55, cortex-m1.small-multiply, cortex-m0.small-multiply, cortex-m0plus.small-multiply, exynos-m1, marvell-pj4, neoverse-n1, neoverse-n2, neoverse-v1, xscale, iwmmxt, iwmmxt2, ep9312, fa526, fa626, fa606te, fa626te, fmp626, fa726te, xgene1

Okay, and get this, -mtune can also tell GCC to tune for a big.LITTLE system ๐Ÿ˜ญ The permissible names for that are:

cortex-a15.cortex-a7, cortex-a17.cortex-a7, cortex-a57.cortex-a53, cortex-a72.cortex-a53, cortex-a72.cortex-a35, cortex-a73.cortex-a53, cortex-a75.cortex-a55, cortex-a76.cortex-a55

-mtune=generic-arch tells GCC to tune for a blend of processors within the architecture arch ๐Ÿฆ‹ The goal is code that runs well on the most popular processors right now, balancing the optimizations that help some CPUs in the range while dodging the performance pitfalls of the others. Heads up, the effects of this option may change in future GCC versions as CPU models come and go ๐ŸŒธ

-mtune takes the same extension options as -mcpu, but the extension options don't 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: it's only supported on GNU/Linux, not every architecture is recognized, and if the auto-detect fails the option has no effect ๐Ÿ’€

-mcpu=name[+extension...]

This one specifies the name of the target ARM processor ๐Ÿ‘‘ GCC uses that name to figure out the target ARM architecture (as if you'd passed -march) and the ARM processor type to tune for (as if you'd passed -mtune). If you use this option alongside -march or -mtune, those options take precedence over the matching part of this one ๐Ÿ’…

A lot of the supported CPUs have optional architectural extensions ๐Ÿงš When that's the case, those extensions are normally enabled by default. If there are implementations that lack the extension, you can use the extension syntax to disable the ones that have been left out. For floating-point and Advanced SIMD (Neon) instructions, you also have to think about -mfloat-abi and -mfpu. Floating-point and Advanced SIMD instructions only get used if -mfloat-abi is not set to soft, and any setting of -mfpu other than auto will override the available floating-point and SIMD extension instructions ๐Ÿ”ฅ

For example, cortex-a9 shows up in three major configurations: integer only, with just a floating-point unit, or with floating-point and Advanced SIMD. The default enables all the instructions, but you can use +nosimd and +nofp to disable just the SIMD instructions, or both the SIMD and floating-point instructions, respectively ๐ŸŒˆ

The permissible names for this option are the same as the ones for -mtune ๐Ÿ’–

The following extension options are common to the listed CPUs:

  • +nodsp โ€” disables the DSP instructions on cortex-m33, cortex-m35p ๐Ÿ™ˆ
  • +nofp โ€” disables the floating-point instructions on arm9e, arm946e-s, arm966e-s, arm968e-s, arm10e, arm1020e, arm1022e, arm926ej-s, arm1026ej-s, cortex-r5, cortex-r7, cortex-r8, cortex-m4, cortex-m7, cortex-m33 and cortex-m35p ๐Ÿ’€ It also disables the floating-point and SIMD instructions on generic-armv7-a, cortex-a5, cortex-a7, cortex-a8, cortex-a9, cortex-a12, cortex-a15, cortex-a17, cortex-a15.cortex-a7, cortex-a17.cortex-a7, cortex-a32, cortex-a35, cortex-a53 and cortex-a55 ๐Ÿ™ˆ
  • +nofp.dp โ€” disables the double-precision part of the floating-point instructions on cortex-r5, cortex-r7, cortex-r8, cortex-r52 and cortex-m7 ๐Ÿฆ‹
  • +nosimd โ€” disables the SIMD (but not floating-point) instructions on generic-armv7-a, cortex-a5, cortex-a7 and cortex-a9 ๐Ÿงš
  • +crypto โ€” enables the cryptographic instructions on cortex-a32, cortex-a35, cortex-a53, cortex-a55, cortex-a57, cortex-a72, cortex-a73, cortex-a75, exynos-m1, xgene1, cortex-a57.cortex-a53, cortex-a72.cortex-a53, cortex-a73.cortex-a35, cortex-a73.cortex-a53 and cortex-a75.cortex-a55 ๐Ÿ”

Additionally, the generic-armv7-a pseudo target defaults to VFPv3 with 16 double-precision registers ๐Ÿ‘‘ It supports these extension options: mp, sec, vfpv3-d16, vfpv3, vfpv3-d16-fp16, vfpv3-fp16, vfpv4-d16, vfpv4, neon, neon-vfpv3, neon-fp16, neon-vfpv4. The meanings are the same as for the extensions to -march=armv7-a โœจ

-mcpu=generic-arch is also permissible, and it's equivalent to -march=arch -mtune=generic-arch ๐Ÿซถ Check out -mtune for more info.

So -mcpu=native is giving auto-detect energy โœจ. The compiler sniffs out the CPU of the build computer ๐Ÿ–ฅ๏ธ so you don't have to. 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 has no effect ๐Ÿซ .

  • -mfpu=name โ€” tells the compiler what floating-point hardware (or hardware emulation) the target has ๐Ÿงฎ. 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. Note that neon is an alias for neon-vfpv3 and vfp is an alias for vfpv2 ๐Ÿซถ.
    • The setting auto is the default and it's super special ๐Ÿ‘‘. It makes the compiler pick the floating-point and Advanced SIMD instructions based on -mcpu and -march.
    • If the floating-point hardware you pick has the NEON extension (e.g. -mfpu=neon), heads up bestie ๐Ÿšจ: floating-point operations are not generated by GCC's auto-vectorization pass unless -funsafe-math-optimizations is also specified. Why? NEON hardware doesn't fully implement the IEEE 754 standard for floating-point arithmetic (in particular, denormal values are treated as zero), so using NEON instructions may lead to a loss of precision ๐Ÿ˜ญ.
    • You can also set the fpu name at function level using the target("fpu=") function attributes or pragmas ๐Ÿ’–.
  • -mfp16-format=name โ€” sets the format of the "__fp16" half-precision floating-point type ๐ŸŒธ. Permissible names are none, ieee, and alternative. The default is none, and in that case the "__fp16" type is not defined ๐Ÿ™ˆ.
  • -mstructure-size-boundary=n โ€” rounds the sizes of all structures and unions up to a multiple of the number of bits you set ๐Ÿ“. Permissible values are 8, 32 and 64. The default varies between toolchains. For the COFF targeted toolchain the default is 8. A value of 64 is only allowed if the underlying ABI supports it ๐Ÿง.
    • A larger number can produce faster, more efficient code ๐ŸŽ๏ธ, but it can also increase the size of the program ๐Ÿ˜.
    • Different values are potentially incompatible ๐Ÿ’”. Code compiled with one value cannot necessarily expect to work with code or libraries compiled with another value, if they exchange information using structures or unions.
โš ๏ธ This option is deprecated, bestie ๐Ÿ’€.
  • -mabort-on-noreturn โ€” generates a call to the function abort at the end of a noreturn function ๐Ÿ›‘. It is executed if the function tries to return.
  • -mlong-calls, -mno-long-calls โ€” tells the compiler to make function calls by first loading the address of the function into a register, then doing a subroutine call on that register ๐Ÿ“ž. This switch is needed if the target function lies outside the 64-megabyte addressing range of the offset-based version of the subroutine call instruction ๐Ÿ—บ๏ธ.
    • Even with this switch on, not every function call becomes a long call ๐Ÿ™…. Static functions, functions with the short_call attribute, functions inside the scope of a #pragma no_long_calls directive, and functions whose definitions have already been compiled within the current compilation unit stay as regular calls. The exceptions are always long calls ๐Ÿ’…: weak function definitions, functions with the long_call attribute or the section attribute, and functions inside the scope of a #pragma long_calls directive.
    • This feature is not enabled by default. -mno-long-calls restores the default behavior, as does placing the function calls within the scope of a #pragma long_calls_off directive ๐Ÿ”„. Note these switches have no effect on how the compiler generates code to handle function calls via function pointers ๐Ÿ™ˆ.
  • -msingle-pic-base โ€” treats the register used for PIC addressing as read-only ๐Ÿ”’, instead of loading it in the prologue for each function. The runtime system is responsible for initializing this register with an appropriate value before execution begins ๐Ÿ.
  • -mpic-register=reg โ€” specifies the register to be used for PIC addressing ๐ŸŽฏ. For the standard PIC base case, the default is any suitable register determined by the compiler. For the single PIC base case, the default is R9 if the target is EABI based or stack-checking is enabled, otherwise the default is R10.
  • -mpic-data-is-text-relative โ€” assumes the displacement between the text and data segments is fixed at static link time ๐Ÿงฉ. This permits using PC-relative addressing operations to access data known to be in the data segment. For non-VxWorks RTP targets, this option is enabled by default. When it's disabled on such targets, it will enable -msingle-pic-base by default ๐Ÿ”.
  • -mpoke-function-name โ€” writes the name of each function into the text section, directly preceding the function prologue โœ๏ธ. The generated code is similar to this:
t0
    .ascii "arm_poke_function_name", 0
    .align
t1
    .word 0xff000000 + (t1 - t0)
arm_poke_function_name
    mov     ip, sp
    stmfd   sp!, {fp, ip, lr, pc}
    sub     fp, ip, #4

When performing a stack backtrace, code can inspect the value of pc stored at fp + 0. If the trace function then looks at location pc - 12 and the top 8 bits are set, then we know there is a function name embedded immediately preceding this location, and it has length ((pc[-3]) & 0xff000000) ๐Ÿ•ต๏ธโ€โ™€๏ธ.


  • -mthumb, -marm โ€” lets you pick between generating code that executes in ARM and Thumb states ๐Ÿงต. The default for most configurations is ARM state, but you can change that default by configuring GCC with the --with-mode=state configure option โš™๏ธ.
    • You can also override ARM and Thumb mode for each function using the target("thumb") and target("arm") function attributes or pragmas ๐Ÿช„.
  • -mflip-thumb โ€” switches ARM/Thumb modes on alternating functions ๐Ÿ”€. It's provided for regression testing of mixed Thumb/ARM code generation, and it is not intended for ordinary code compiling ๐Ÿšซ.
  • -mtpcs-frame โ€” generates a stack frame that complies with the Thumb Procedure Call Standard for all non-leaf functions. (A leaf function is one that does not call any other functions ๐Ÿƒ.) The default is -mno-tpcs-frame.
  • -mtpcs-leaf-frame โ€” generates a stack frame that complies with the Thumb Procedure Call Standard for all leaf functions. (A leaf function is one that does not call any other functions.) The default is -mno-apcs-leaf-frame.
  • -mcallee-super-interworking โ€” gives all externally visible functions in the file being compiled an ARM instruction set header that switches to Thumb mode before executing the rest of the function ๐Ÿ”. This lets them be called from non-interworking code. This option is not valid in AAPCS configurations, because interworking is enabled by default ๐Ÿšซ.
  • -mcaller-super-interworking โ€” lets calls via function pointers (including virtual functions) execute correctly, whether or not the target code was compiled for interworking ๐Ÿค. There's a small overhead in the cost of executing a function pointer when this option is enabled ๐Ÿข. This option is not valid in AAPCS configurations, because interworking is enabled by default ๐Ÿšซ.
  • -mtp=name โ€” specifies the access model for the thread local storage pointer ๐Ÿงต. The valid models are soft, which generates calls to "__aeabi_read_tp"; cp15, which fetches the thread pointer from cp15 directly (supported in the arm6k architecture); and auto, which uses the best available method for the selected processor. The default setting is auto.
  • -mtls-dialect=dialect โ€” specifies the dialect to use for accessing thread local storage ๐Ÿ“š. Two dialects are supportedโ€”gnu and gnu2. The gnu dialect selects the original GNU scheme for supporting local and global dynamic TLS models. The gnu2 dialect selects the GNU descriptor scheme, which provides better performance for shared libraries ๐Ÿš€. The GNU descriptor scheme is compatible with the original scheme, but it does require new assembler, linker and library support. Initial and local exec TLS models are unaffected by this option and always use the original scheme.
  • -mword-relocations โ€” only generates absolute relocations on word-sized values (i.e. R_ARM_ABS32) ๐ŸŽฏ. This is enabled by default on targets (uClinux, SymbianOS) where the runtime loader imposes this restriction, and when -fpic or -fPIC is specified. This option conflicts with -mslow-flash-data โš ๏ธ.
  • -mfix-cortex-m3-ldrd โ€” some Cortex-M3 cores can cause data corruption when ldrd instructions with overlapping destination and base registers are used ๐Ÿ˜ฑ. This option avoids generating these instructions. It is enabled by default when -mcpu=cortex-m3 is specified ๐Ÿ’–.
  • -munaligned-access, -mno-unaligned-access โ€” enables (or disables) reading and writing of 16- and 32-bit values from addresses that are not 16- or 32-bit aligned ๐Ÿ“. By default, unaligned access is disabled for all pre-ARMv6, all ARMv6-M and for ARMv8-M Baseline architectures, and enabled for all other architectures. If unaligned access is not enabled, then words in packed data structures are accessed a byte at a time ๐Ÿข.
    • The ARM attribute "Tag_CPU_unaligned_access" is set in the generated object file to either true or false, depending on the setting of this option. If unaligned access is enabled, then the preprocessor symbol "__ARM_FEATURE_UNALIGNED" is also defined ๐Ÿง .
  • -mneon-for-64bits โ€” this option is deprecated and has no effect ๐Ÿ’€.
  • -mslow-flash-data โ€” assumes loading data from flash is slower than fetching instructions ๐ŸŒ. Therefore, literal loads are minimized for better performance โšก. This option is only supported when compiling for ARMv7 M-profile and it's off by default. It conflicts with -mword-relocations โš ๏ธ.

-masm-syntax-unified ๐ŸŽ€ Okay so this one is about inline assembler syntax, bestie ๐Ÿ’… By default it's currently off, which means you get divided syntax. This option has no impact on Thumb2 ๐Ÿฆ‹ But heads up, GCC might change this in future releases, and divided syntax is considered deprecated, so like, don't get too attached ๐Ÿ˜ญ

-mrestrict-it ๐ŸŒธ This one restricts how IT blocks get generated so they follow the ARMv8-A rules. An IT block can only contain a single 16-bit instruction from a specific set of instructions โœจ It's on by default for ARMv8-A Thumb mode, so you're already set ๐Ÿ‘‘

-mprint-tune-info ๐Ÿงš This prints CPU tuning information as a comment in the assembler file ๐Ÿ’œ Real talk, it's only for regression testing of the compiler, not for normal code compiling ๐Ÿ™ˆ It's disabled by default, so you don't need to do anything.

-mverbose-cost-dump ๐Ÿ”ฅ This enables verbose cost model dumping in the debug dump files. It's provided for debugging the compiler itself, so it's giving compiler-dev energy ๐Ÿ“

-mpure-code ๐Ÿซถ This one doesn't allow constant data to be placed in code sections. Also, when you're compiling for ELF object format, it gives all text sections the ELF processor-specific section attribute SHF_ARM_PURECODE ๐Ÿ’– It's only available when you're generating non-PIC code for M-profile targets, so keep that in mind, bestie โญ

-mcmse ๐ŸŒˆ This generates secure code following the "ARMv8-M Security Extensions: Requirements on Development Tools Engineering Specification" ๐Ÿ” You can find that spec at <https://developer.arm.com/documentation/ecm0359818/latest/> ๐Ÿฆ‹

-mfix-cmse-cve-2021-35465 ๐Ÿ’… This one mitigates a potential security issue with the "VLLDM" instruction on some M-profile devices when you're using CMSE (CVE-2021-365465) ๐Ÿ˜ญ It's enabled by default when -mcpu= is used with "cortex-m33", "cortex-m35p" or "cortex-m55". If you want to turn the mitigation off, you can use -mno-fix-cmse-cve-2021-35465 ๐Ÿ™ˆ

-mfdpic -mno-fdpic ๐Ÿ‘‘ Okay this one is the FDPIC ABI, which uses 64-bit function descriptors to represent pointers to functions โœจ When the compiler is configured for "arm-*-uclinuxfdpiceabi" targets, -mfdpic is on by default and implies -fPIE if none of the PIC/PIE-related options is provided. On other targets, it only enables the FDPIC-specific code generation features, so you have to explicitly provide the PIC/PIE-related options yourself, as needed ๐Ÿ’–

Static linking is not supported ๐Ÿšซ 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, is useful (and required) for building the Linux kernel with the same ("arm-*-uclinuxfdpiceabi") toolchain you used to build your userland programs ๐Ÿงš๐ŸŒˆ

AVR Options ๐Ÿฆ‹

These options are defined for AVR implementations ๐Ÿ’œ

-mmcu=mcu ๐Ÿ”ฅ Specify Atmel AVR instruction set architectures (ISA) or MCU type ๐Ÿ“ The default for this option is avr2.

GCC supports the following AVR devices and ISAs, and I'm obsessed with how many there are ๐Ÿ˜ญ

  • avr2 โ€” "Classic" devices with up to 8 KiB of program memory. MCUs: "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. MCUs: "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. MCUs: "at76c711", "at43usb355" ๐ŸŽ€
  • avr31 โ€” "Classic" devices with 128 KiB of program memory. MCUs: "atmega103", "at43usb320" ๐Ÿ’…
  • avr35 โ€” "Classic" devices with 16 KiB up to 64 KiB of program memory and with the "MOVW" instruction. MCUs: "attiny167", "attiny1634", "atmega8u2", "atmega16u2", "atmega32u2", "ata5505", "ata6617c", "ata664251", "at90usb82", "at90usb162" ๐Ÿฆ‹
  • avr4 โ€” "Enhanced" devices with up to 8 KiB of program memory. MCUs: "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. MCUs: "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. MCUs: "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. MCUs: "atmega256rfr2", "atmega2560", "atmega2561", "atmega2564rfr2" โญ
  • avrxmega2 โ€” "XMEGA" devices with more than 8 KiB and up to 64 KiB of program memory. MCUs: "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. MCUs: "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. MCUs: "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. MCUs: "atxmega64a1", "atxmega64a1u" ๐Ÿ“
  • avrxmega6 โ€” "XMEGA" devices with more than 128 KiB of program memory. MCUs: "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. MCUs: "atxmega128a1", "atxmega128a1u", "atxmega128a4u" โœจ
  • avrtiny โ€” "TINY" Tiny core devices with 512 B up to 4 KiB of program memory. MCUs: "attiny4", "attiny5", "attiny9", "attiny10", "attiny20", "attiny40" ๐ŸŒธ
  • avr1 โ€” This ISA is implemented by the minimal AVR core and supported for assembler only. MCUs: "attiny11", "attiny12", "attiny15", "attiny28", "at90s1200" ๐ŸŽ€

-mabsdata ๐Ÿ’… Assume that all data in static storage can be accessed by LDS / STS instructions. This option only has an effect on reduced Tiny devices like ATtiny40 ๐Ÿ˜ญ See also the "absdata" AVR Variable Attributes, variable attribute.

-maccumulate-args ๐Ÿฆ‹ This accumulates outgoing function arguments and acquires/releases the needed stack space for them once, in the function prologue/epilogue ๐Ÿซถ Without this option, outgoing arguments are pushed before calling a function and popped afterwards.

Popping the arguments after the call can be expensive on AVR, so accumulating the stack space might lead to smaller executables, since arguments don't need to be removed from the stack after the call ๐Ÿงš This can reduce code size for functions that make several calls to functions taking their arguments on the stack, like printf-like functions ๐Ÿ’–

-mbranch-cost=cost ๐ŸŒˆ This 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 right subroutines instead of inline code, so your code size comes out smaller โœจ
  • -mdouble=bits
  • -mlong-double=bits โ€” ๐ŸŽ€ These set the size, in bits, of the double or long double type. The only possible values are 32 and 64. Whether a value is allowed depends on the --with-double= and --with-long-double= configure options (https://gcc.gnu.org/install/configure.html#avr), and the same goes for the defaults of these options.
  • -mgas-isr-prologues โ€” ๐Ÿฆ‹ Interrupt service routines (ISRs) can use the __gcc_isr pseudo instruction, which GNU Binutils supports. If this option is on, you can still turn the feature off for individual ISRs with the no_gccisr function attribute from AVR Function Attributes. It's switched on by default when optimization is on (but not with -Og, @pxref{Optimize Options}), and only if GNU Binutils supports PR21683 (https://sourceware.org/PR21683).
  • -mint8 โ€” ๐Ÿงš This makes int an 8-bit integer, which changes the sizes of every type: a char is 1 byte, an int is 1 byte, a long is 2 bytes, and a long long is 4 bytes. Heads up, this is not C standard compliant, but the code ends up smaller ngl ๐Ÿ’€
  • -mmain-is-OS_task โ€” ๐Ÿ‘‘ main won't save registers. It does the same thing as slapping the OS_task attribute from AVR Function Attributes onto main. It's on by default when optimization is on.
  • -mn-flash=num โ€” ๐ŸŒธ Tells the compiler to assume the flash memory is num times 64 KiB.
  • -mno-interrupts โ€” ๐Ÿ™ˆ The generated code is not compatible with hardware interrupts. The upside is that the code size gets smaller.
  • -mrelax โ€” โœจ This tries to swap CALL or JMP for the shorter RCALL or RJMP when that's allowed. All it really does is add --mlink-relax to the assembler's command line and --relax to the linker's command line.

Jump relaxing happens in the linker, because jump offsets aren't known until the code gets placed. So the assembler code the compiler generates stays the same, but the instructions in the executable might look different from the assembler code. ๐Ÿซถ

You have to turn relaxing on if linker stubs are needed. Check out the section on "EIND" and linker stubs below.

  • -mrmw โ€” ๐Ÿ”ฅ Assumes the device supports the Read-Modify-Write instructions XCH, LAC, LAS and LAT.
  • -mshort-calls โ€” ๐Ÿฆ‹ Assumes that RJMP and RCALL can reach the whole program memory.

This one is used internally for multilib selection. It's not an optimization option, so you don't need to set it yourself, bestie ๐Ÿ’œ

  • -msp8 โ€” ๐Ÿ’– Treats the stack pointer register as an 8-bit register, which basically means it assumes the high byte of the stack pointer is zero. Generally you don't need to set this one by hand.

The compiler uses this internally to pick and build multilibs for the avr2 and avr25 architectures. Those architectures mix devices that have SPH with devices that don't. For any setting other than -mmcu=avr2 or -mmcu=avr25, the compiler driver adds or removes this option from the compiler proper's command line. That's because the compiler already knows whether the device or architecture has an 8-bit stack pointer, and therefore no SPH register, or not. ๐Ÿง 

  • -mstrict-X โ€” ๐Ÿ“ Uses the X address register the way the hardware intends. That means X only gets used for indirect, post-increment, or pre-decrement addressing.

Without this option, X can be used the same way as Y or Z, but then it gets emulated with extra instructions. For example, loading a value with X+const addressing, where const is small, non-negative and const < 64, into a register Rn is done like this:

adiw r26, const   ; X += const
ld   <Rn>, X        ; <Rn> = *X
sbiw r26, const   ; X -= const
  • -mtiny-stack โ€” ๐ŸŽ€ Only the lower 8 bits of the stack pointer get changed.
  • -mfract-convert-truncate โ€” โœจ Lets you use truncation instead of rounding toward zero for fractional fixed-point types.
  • -nodevicelib โ€” ๐ŸŒˆ Don't link against AVR-LibC's device-specific library lib<mcu>.a.
  • -nodevicespecs โ€” ๐Ÿ’… Stops the compiler driver from adding -specs=device-specs/specs-mcu to its command line. This means you are responsible for giving the subprocesses (the compiler proper, the assembler, and the linker) the right command line options. You'll have to supply your own private device specs file with -specs=path-to-specs-file. Once you do that, there's no more need for -mmcu=mcu ๐Ÿซถ

This option also works as a replacement for the older way of specifying custom device-specs files. The old way needed -B some-path to point at a directory containing a folder named device-specs, and that folder had to contain a specs file named specs-mcu, where mcu was the value given with -mmcu=mcu. That's a lot of setup, so this option is way more iconic โœจ

  • -Waddr-space-convert โ€” โญ Warns about conversions between address spaces when the resulting address space is not contained in the incoming address space.
  • -Wmisspelled-isr โ€” ๐Ÿ”ฅ Warns if an ISR is misspelled, meaning it's missing the __vector prefix. This one is enabled by default.

โœจ "EIND" and Devices With More Than 128 Ki Bytes of Flash โœจ

Pointers in the implementation are 16 bits wide. The address of a function or label is represented as a word address, so indirect jumps and calls can target any code address in the range of 64 Ki words. ๐Ÿงš

To make indirect jumps work on devices with more than 128 Ki bytes of program memory 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 it might read EIND directly in order to emulate an indirect call/jump by means of a RET instruction.
  • The compiler assumes that EIND never changes during the startup code or during the application. In particular, EIND is not saved or restored in function or interrupt service routine prologues and epilogues.
  • For indirect calls to functions and computed gotos, the linker generates stubs. Stubs are jump pads, sometimes also called trampolines. So the indirect call or jump actually jumps to such a stub, and the stub contains a direct jump to the desired address. ๐Ÿฆ‹
  • Linker relaxation must be turned on so the linker generates the stubs correctly in all situations. See the compiler option -mrelax and the linker option --relax. Watch out, though: there are corner cases where the linker is supposed to generate stubs but aborts without relaxation and without a helpful error message. ๐Ÿ˜ญ
  • The default linker script is arranged for code with EIND = 0. If your code is supposed to work with EIND != 0, you'll need a custom linker script to place the sections whose names start with .trampolines into the segment that EIND points to. ๐ŸŽ€
  • The startup code from libgcc never sets EIND. Notice that the startup code is a blend of code from libgcc and AVR-LibC. For the impact of AVR-LibC on EIND, see the AVR-LibC user manual (http://nongnu.org/avr-libc/user-manual/). ๐Ÿ“š
  • It's totally legit for user-specific startup code to set up EIND early, for example with initialization code located in section .init3. That code runs before the general startup code that initializes RAM and calls constructors, but after the bit of AVR-LibC startup code that sets EIND to the segment where the vector table is located. ๐Ÿซถ

#include <avr/io.h>

static void __attribute__((section(".init3"),naked,used,no_instrument_function)) init3_set_eind (void) { __asm volatile ("ldi r24,pm_hh8(__trampolines_start)\n\t" "out %i0,r24" :: "n" (&EIND) : "r24","memory"); }

The __trampolines_start symbol is defined in the linker script. ๐Ÿ’–

  • Stubs are generated automatically by the linker if both of the following conditions are met:
    • The address of a label is taken by means of the gs modifier (short for generate stubs), like so:

LDI r24, lo8(gs(<func>)) LDI r25, hi8(gs(<func>))

  • The final location of that label is in a code segment outside the segment where the stubs are located.
  • The compiler emits gs modifiers for code labels in the following situations:
    • Taking the address of a function or code label.
    • Computed goto.
    • If a prologue-save function is used, see the -mcall-prologues command-line option.
    • Switch/case dispatch tables. If you don't want such dispatch tables, you can specify the -fno-jump-tables command-line option.
    • C and C++ constructors and destructors called during startup or shutdown.
    • If the tools hit a gs() modifier explained above.
  • Jumping to non-symbolic addresses like this is not supported ๐Ÿ™…โ€โ™€๏ธ

int main (void) { /* Call function at word address 0x2 / return ((int()(void)) 0x2)(); }

Instead, you have to set up a stub, meaning the function has to be called through a symbol (func_4 in the example):

int main (void) { extern int func_4 (void);

/* Call function at byte address 0x4 */ return func_4(); }

And the application has to be linked with -Wl,--defsym,func_4=0x4. Alternatively, func_4 can be defined in the linker script. ๐ŸŒธ


โœจ Handling of the RAMPD, RAMPX, RAMPY and RAMPZ Special Function Registers โœจ

Some AVR devices support memories larger than the 64 KiB range that can be accessed with 16-bit pointers. To reach memory locations outside this 64 KiB range, the contents of a RAMP register are used as the high part of the address. The X, Y, and Z address registers are concatenated with the RAMPX, RAMPY, and RAMPZ special function registers, respectively, to get a wide address. Similarly, RAMPD is used together with direct addressing. ๐ŸŒˆ

  • The startup code initializes the RAMP special function registers with zero. ๐Ÿ“

Okay so we're picking up mid-thought with the RAMPZ stuff, and the rules are kinda intense ๐Ÿ’…

  • If you use a named address space that isn't generic or "__flash", RAMPZ gets set up as needed before the operation ๐ŸŒธ
  • If the device has more than 64 KiB of RAM and the compiler needs to change RAMPZ for 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 have to reset it to zero after the access. No skipping this, bestie ๐Ÿ™ˆ

๐ŸŒธ AVR Built-in Macros ๐ŸŒธ

GCC defines a bunch of built-in macros so your code can check whether certain features are there or not, and honestly it's giving very helpful energy ๐Ÿงš Almost all of the following are deduced from device capabilities, so they get triggered by the -mmcu= command-line option.

For even more AVR-specific built-in macros, see AVR Named Address Spaces and AVR Built-in Functions ๐Ÿ’œ

  • "__AVR_ARCH__" โ€” a built-in macro that resolves to a decimal number identifying the architecture, which 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 macro gets set accordingly. For example, with -mmcu=atmega8 the macro is defined to 4 ๐Ÿฆ‹
  • "__AVR_Device__" โ€” setting -mmcu=device defines this macro, which reflects the device's name. For example, -mmcu=atmega8 defines "__AVR_ATmega8__", and -mmcu=attiny261a defines "__AVR_ATtiny261A__", etc. โœจ
    • The names follow the scheme "__AVR_Device__", where Device is the device name as written in the AVR user manual. The difference between Device in the macro and device in -mmcu=device is that the latter is always lowercase.
    • If device isn't an actual device but just a core architecture like avr51, this macro is not defined.
  • "__AVR_DEVICE_NAME__" โ€” setting -mmcu=device defines this macro to the device's name. For example, with -mmcu=atmega8 the macro is defined to "atmega8" ๐Ÿ“
    • If device is only a core architecture like avr51 and not a device, this macro is not defined.
  • "__AVR_XMEGA__" โ€” the device or architecture belongs to the XMEGA family of devices ๐Ÿ‘‘
  • "__AVR_HAVE_ELPM__" โ€” the device has the ELPM instruction ๐ŸŒˆ
  • "__AVR_HAVE_ELPMX__" โ€” the device has the ELPM Rn,Z and ELPM Rn,Z+ instructions ๐Ÿ’…
  • "__AVR_HAVE_MOVW__" โ€” the device has the MOVW instruction for 16-bit register-to-register moves ๐Ÿซถ
  • "__AVR_HAVE_LPMX__" โ€” the device has the LPM Rn,Z and LPM Rn,Z+ instructions ๐Ÿฆ‹
  • "__AVR_HAVE_MUL__" โ€” the device has a hardware multiplier ๐Ÿ”ฅ
  • "__AVR_HAVE_JMP_CALL__" โ€” the device has the JMP and CALL instructions. This is the case for devices with more than 8 KiB of program memory ๐ŸŒธ
  • "__AVR_HAVE_EIJMP_EICALL__" and "__AVR_3_BYTE_PC__" โ€” the device has the EIJMP and EICALL instructions. This is the case for devices with more than 128 KiB of program memory. It also means the program counter (PC) is 3 bytes wide ๐Ÿงš
  • "__AVR_2_BYTE_PC__" โ€” the program counter (PC) is 2 bytes wide. This is the case for devices with up to 128 KiB of program memory ๐Ÿ’–
  • "__AVR_HAVE_8BIT_SP__" and "__AVR_HAVE_16BIT_SP__" โ€” the compiler treats the stack pointer (SP) register as an 8-bit or 16-bit register, respectively. Defining these macros is affected by -mtiny-stack โœจ
  • "__AVR_HAVE_SPH__" and "__AVR_SP8__" โ€” the device has the SPH (high part of stack pointer) special function register, or has an 8-bit stack pointer, respectively. Defining these macros is affected by -mmcu=, and in the cases of -mmcu=avr2 and -mmcu=avr25 also by -msp8 ๐Ÿ‘‘
  • "__AVR_HAVE_RAMPD__", "__AVR_HAVE_RAMPX__", "__AVR_HAVE_RAMPY__", and "__AVR_HAVE_RAMPZ__" โ€” the device has the RAMPD, RAMPX, RAMPY, and RAMPZ special function registers, respectively ๐ŸŒˆ
  • "__NO_INTERRUPTS__" โ€” this macro reflects the -mno-interrupts command-line option ๐Ÿ™ˆ
  • "__AVR_ERRATA_SKIP__" and "__AVR_ERRATA_SKIP_JMP_CALL__" โ€” some AVR devices (AT90S8515, ATmega103) must not skip 32-bit instructions because of a hardware erratum. The skip instructions are SBRS, SBRC, SBIS, SBIC, and CPSE. The second macro is only defined if "__AVR_HAVE_JMP_CALL__" is also set ๐Ÿ’€
  • "__AVR_ISA_RMW__" โ€” the device has Read-Modify-Write instructions (XCH, LAC, LAS, and LAT) ๐Ÿ”ฅ
  • "__AVR_SFR_OFFSET__=offset" โ€” instructions that can address I/O special function registers directly, like IN, OUT, SBI, etc., may use a different address than an instruction accessing RAM, like LD or STS. This offset depends on the device architecture and has to be subtracted from the RAM address to get the respective I/O address ๐Ÿฆ‹
  • "__AVR_SHORT_CALLS__" โ€” the -mshort-calls command-line option is set ๐Ÿ“
  • "__AVR_PM_BASE_ADDRESS__=addr" โ€” some devices can read from flash memory using LD* instructions. The flash memory shows up in the data address space at an offset of "__AVR_PM_BASE_ADDRESS__". If this macro isn't defined, the feature isn't available. If it is defined, the address space is linear and there's no need to put .rodata into RAM. The default linker description file handles this, and it's currently available for avrtiny and avrxmega3. Even more convenient, there's no need for address spaces like "__flash" or the attribute progmem and pgm_read_* ๐ŸŒธ
  • "__WITH_AVRLIBC__" โ€” the compiler is configured to be used together with AVR-Libc. See the --with-avrlibc configure option ๐Ÿงš
  • "__HAVE_DOUBLE_MULTILIB__" โ€” defined if -mdouble= acts as a multilib option ๐Ÿ’œ
  • "__HAVE_DOUBLE32__" and "__HAVE_DOUBLE64__" โ€” defined if the compiler supports 32-bit double or 64-bit double, respectively. The actual layout is specified by option -mdouble= โœจ
  • "__DEFAULT_DOUBLE__" โ€” the size in bits of double if -mdouble= isn't set. To test the layout of double in a program, use the built-in macro "__SIZEOF_DOUBLE__" ๐Ÿ‘‘
  • "__HAVE_LONG_DOUBLE32__", "__HAVE_LONG_DOUBLE64__", "__HAVE_LONG_DOUBLE_MULTILIB__", and "__DEFAULT_LONG_DOUBLE__" โ€” same as above, but for long double instead of double ๐ŸŒˆ
  • "__WITH_DOUBLE_COMPARISON__" โ€” reflects the --with-double-comparison={tristate|bool|libf7} configure option (https://gcc.gnu.org/install/configure.html#avr) and is defined to 2 or 3 ๐Ÿ’–
  • "__WITH_LIBF7_LIBGCC__", "__WITH_LIBF7_MATH__", and "__WITH_LIBF7_MATH_SYMBOLS__" โ€” reflect the --with-libf7={libgcc|math|math-symbols} configure option (https://gcc.gnu.org/install/configure.html#avr) ๐Ÿ”ฅ

๐Ÿฆ‹ Blackfin Options ๐Ÿฆ‹

  • -mcpu=cpu[-sirevision] โ€” specifies the name of the target Blackfin processor. Right now, cpu can be one of bf512, bf514, bf516, bf518, bf522, bf523, bf524, bf525, bf526, bf527, bf531, bf532, bf533, bf534, bf536, bf537, bf538, bf539, bf542, bf544, bf547, bf548, bf549, bf542m, bf544m, bf547m, bf548m, bf549m, bf561, bf592 ๐Ÿงš
    • The optional sirevision specifies the silicon revision of the target Blackfin processor. Any workarounds available for that silicon revision get enabled. If sirevision is none, no workarounds are enabled. If sirevision is any, all workarounds for the targeted processor are enabled.
    • The "__SILICON_REVISION__" macro is defined to two hexadecimal digits representing the major and minor numbers in the silicon revision. If sirevision is none, "__SILICON_REVISION__" is not defined. If sirevision is any, "__SILICON_REVISION__" is defined to be 0xffff.
    • If this optional sirevision isn't 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 isn't 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 run on the simulator, which causes the simulator BSP provided by libgloss to be linked in. This option only has an effect for the bfin-elf toolchain. Certain other options, such as -mid-shared-library and -mfdpic, imply -msim ๐ŸŒธ
  • -momit-leaf-frame-pointer โ€” don't keep the frame pointer in a register for leaf functions. This skips the instructions that save, set up, and restore frame pointers, and makes an extra register available in leaf functions ๐Ÿ“
  • -mspecld-anomaly โ€” when enabled, the compiler makes sure the generated code doesn't contain speculative loads after jump instructions. If this option is used, "__WORKAROUND_SPECULATIVE_LOADS" is defined ๐Ÿ”ฅ
  • -mno-specld-anomaly โ€” don't generate extra code to prevent speculative loads from happening ๐Ÿ™ˆ
  • -mcsync-anomaly โ€” when enabled, the compiler makes sure the generated code doesn't contain CSYNC or SSYNC instructions too soon after conditional branches. If this option is used, "__WORKAROUND_SPECULATIVE_SYNCS" is defined ๐Ÿ’…
  • -mno-csync-anomaly โ€” don't generate extra code to prevent CSYNC or SSYNC instructions from happening too soon after a conditional branch ๐Ÿซถ
  • -mlow64k โ€” when enabled, the compiler is free to take advantage of the knowledge that the entire program fits into the low 64k of memory โœจ
  • -mno-low64k โ€” assume the program is arbitrarily large. This is the default ๐ŸŒˆ
  • -mstack-check-l1 โ€” do stack checking using information placed into L1 scratchpad memory by the uClinux kernel ๐Ÿ‘‘
  • -mid-shared-library โ€” generates code that supports shared libraries via the library ID method. This allows execute-in-place and shared libraries in an environment without virtual memory management. This option implies -fPIC. With a bfin-elf target, this option implies -msim ๐Ÿ’–
  • -mno-id-shared-library โ€” Skip the assumption that ID-based shared libraries are in play. This is the default ๐ŸŒธ
  • -mleaf-id-shared-library โ€” Support shared libraries through the library ID method, but assume this library or executable won't link against any other ID shared libraries. That lets the compiler use faster code for jumps and calls โœจ
  • -mno-leaf-id-shared-library โ€” Don't assume the code being compiled avoids linking against ID shared libraries. You get slower code for jump and call insns ๐Ÿข
  • -mshared-library-id=n โ€” Sets the identification number of the ID-based shared library being compiled. Passing 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 leaving this option out ๐ŸŽ€
  • -msep-data โ€” Lets the data segment live in a different area of memory from the text segment. This allows execute in place in an environment without virtual memory management, because it gets rid of relocations against the text section ๐Ÿฆ‹
  • -mno-sep-data โ€” Assumes the data segment follows the text segment. This is the default ๐Ÿ’œ
  • -mlong-calls, -mno-long-calls โ€” The compiler makes function calls by loading the function's address into a register first, then doing a subroutine call on that register. You need this switch if the target function sits outside the 24-bit addressing range of the offset-based subroutine call instruction. It's not on by default, and -mno-long-calls puts you back to default behavior. These switches do nothing for function calls made through function pointers ๐Ÿ™ˆ
  • -mfast-fp โ€” Links with the fast floating-point library. It loosens some of the IEEE floating-point standard's rules for checking inputs against Not-a-Number (NAN), all for the sake of speed ๐Ÿ”ฅ
  • -minline-plt โ€” Inlines PLT entries in function calls to functions that aren't known to bind locally. It does nothing without -mfdpic ๐ŸŒˆ
  • -mmulticore โ€” Builds a standalone application for multicore Blackfin processors. This uses the proper start files and link scripts for multicore and defines the macro "__BFIN_MULTICORE". It can only be used with -mcpu=bf561[-sirevision] ๐Ÿ‘‘
    • With -mcorea or -mcoreb, you get the one-application-per-core programming model. Without either one, you get the single-application/dual-core model, where Core B's main function should be named "coreb_main" ๐Ÿ’…
    • If you skip this option entirely, you get the single-core application programming model ๐Ÿงš
  • -mcorea โ€” Builds a standalone application for Core A of BF561 in the one-application-per-core model. It uses the right start files and link scripts for Core A and defines "__BFIN_COREA". Only works alongside -mmulticore ๐Ÿซถ
  • -mcoreb โ€” Builds a standalone application for Core B of BF561 in the one-application-per-core model. It uses the right start files and link scripts for Core B and defines "__BFIN_COREB". When you use this, "coreb_main" replaces "main". Only works alongside -mmulticore ๐Ÿ’–
  • -msdram โ€” Builds a standalone application for SDRAM. Start files and link scripts put the app into SDRAM and define "__BFIN_SDRAM". The loader needs to initialize SDRAM before loading the application ๐Ÿง 
  • -micplb โ€” Assumes ICPLBs are enabled at run time. This affects certain anomaly workarounds. On Linux targets, the default is to assume ICPLBs are enabled. For standalone applications, it's off by default ๐ŸŒŸ

C6X Options

  • -march=name โ€” Picks the target architecture. GCC uses this to figure out which instructions it's allowed to emit when generating assembly code. Valid names are c62x, c64x, c64x+, c67x, c67x+, and c674x ๐ŸŒธ
  • -mbig-endian โ€” Generates code for a big-endian target ๐Ÿ“
  • -mlittle-endian โ€” Generates code for a little-endian target. This is the default ๐Ÿ’œ
  • -msim โ€” Picks startup files and a linker script that work with the simulator ๐ŸŽ€
  • -msdata=default โ€” Puts small global and static data in the .neardata section, which is pointed to by register B14. Small uninitialized global and static data goes in the .bss section, which sits right next to .neardata. Small read-only data goes in the .rodata section. The sections for big chunks of data are .fardata, .far, and .const ๐Ÿฆ‹
  • -msdata=all โ€” Puts all data, not just the small stuff, into the small-data sections, and uses addressing relative to the B14 register to get at it ๐Ÿ”ฅ
  • -msdata=none โ€” Doesn't use the small-data sections at all, and uses absolute addresses for all data. All initialized global and static data goes in .fardata, all uninitialized data goes in .far, and all constant data goes in .const ๐Ÿ’…

CRIS Options

These are defined specifically for the CRIS ports, so they're a special little club ๐Ÿงš

  • -march=architecture-type, -mcpu=architecture-type โ€” Generates code for the architecture you pick. The choices for architecture-type are v3, v8, and v10, which map to ETRAX 4, ETRAX 100, and ETRAX 100 LX, respectively. The default is v0, except for cris-axis-linux-gnu, where the default is v10 โœจ
  • -mtune=architecture-type โ€” Tunes everything that applies to the generated code for the architecture you pick, except the ABI and the set of available instructions. The choices are the same as for -march=architecture-type ๐ŸŒˆ
  • -mmax-stack-frame=n โ€” Warns when a function's stack frame goes over n bytes ๐Ÿ‘€
  • -metrax4, -metrax100 โ€” These are synonyms for -march=v3 and -march=v8, respectively ๐Ÿ“
  • -mmul-bug-workaround, -mno-mul-bug-workaround โ€” Works around a bug in the muls and mulu instructions on CPU models where it applies. This one is active by default ๐Ÿ› ๏ธ
  • -mpdebug โ€” Turns on CRIS-specific verbose debug info in the assembly code. It also turns off the #NO_APP formatted-code indicator that the assembler normally gets at the top of the assembly file ๐Ÿ’œ
  • -mcc-init โ€” Doesn't reuse condition-code results from earlier instructions. It always emits compare and test instructions before using condition codes ๐Ÿซถ
  • -mno-side-effects โ€” Doesn't emit instructions with side effects in addressing modes other than post-increment ๐ŸŒธ
  • -mstack-align, -mno-stack-align, -mdata-align, -mno-data-align, -mconst-align, -mno-const-align โ€” These arrange (or, with the no- versions, un-arrange) alignment so the stack frame, individual data, and constants line up with the biggest single data access size for your chosen CPU model. The default is 32-bit alignment. ABI details like structure layout aren't affected by these ๐ŸŽ€
  • -m32-bit, -m16-bit, -m8-bit โ€” Like the stack, data, and const align options above, these make the stack frame, writable data, and constants 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 get dropped, and no return instructions or return sequences are generated. Only use this with visual inspection of the compiled code ๐Ÿ‘€
โš ๏ธ Heads up bestie: with -mno-prologue-epilogue, no warnings or errors come up when call-saved registers need saving or when storage for local variables needs allocating. You have to check it yourself ๐Ÿ’€
  • -mno-gotplt, -mgotplt โ€” With -fpic and -fPIC, -mno-gotplt stops generating instruction sequences that load function addresses from the PLT part of the GOT, instead of calling through the PLT the traditional way used on other architectures. -mgotplt turns that back on. The default is -mgotplt ๐ŸŒˆ
  • -melf โ€” A legacy no-op, only recognized with the cris-axis-elf and cris-axis-linux-gnu targets ๐Ÿง“
  • -mlinux โ€” A legacy no-op, only recognized with the cris-axis-linux-gnu target ๐Ÿง“
  • -sim โ€” Recognized for cris-axis-elf. It links with input-output functions from a simulator library. Code, initialized data, and zero-initialized data get allocated back to back ๐Ÿงช
  • -sim2 โ€” Like -sim, but passes linker options to put initialized data at 0x40000000 and zero-initialized data at 0x80000000 ๐Ÿš€

CR16 Options

These are defined specifically for the CR16 ports, so they're another exclusive little group ๐ŸŒธ

  • -mmac โ€” Enables multiply-accumulate instructions. It's disabled by default ๐Ÿ”ฅ
  • -mcr16cplus, -mcr16c โ€” Generates code for the CR16C or CR16C+ architecture. CR16C+ is the default โœจ
  • -msim โ€” Links the library libsim.a, which works with the simulator. This only applies to the ELF compiler ๐ŸŽ€
  • -mint32 โ€” Makes the integer type 32-bit wide ๐Ÿ’–
  • -mbit-ops โ€” Generates "sbit" and "cbit" instructions for bit manipulations ๐Ÿฆ‹
  • -mdata-model=model โ€” Picks a data model. The choices are near, far, or medium, and medium is the default. Heads up though: far isn't valid with -mcr16c, because the CR16C architecture doesn't support the far data model ๐Ÿ™…โ€โ™€๏ธ

C-SKY Options

GCC supports these when compiling for C-SKY V2 processors ๐ŸŒˆ

  • -march=arch โ€” Specifies the C-SKY target architecture. Valid values for arch are ck801, ck802, ck803, ck807, and ck810. The default is ck810 ๐Ÿ‘‘
  • -mcpu=cpu โ€” okay bestie, this one lets you pick your C-SKY target processor ๐Ÿ’– The valid values for cpu are ck801, ck801t, ck802, ck802t, ck802j, ck803, ck803h, ck803t, ck803ht, ck803f, ck803fh, ck803e, ck803eh, ck803et, ck803eht, ck803ef, ck803efh, ck803ft, ck803eft, ck803efht, ck803r1, ck803hr1, ck803tr1, ck803htr1, ck803fr1, ck803fhr1, ck803er1, ck803ehr1, ck803etr1, ck803ehtr1, ck803efr1, ck803efhr1, ck803ftr1, ck803eftr1, ck803efhtr1, ck803s, ck803st, ck803se, ck803sf, ck803sef, ck803seft, ck807e, ck807ef, ck807, ck807f, ck810e, ck810et, ck810ef, ck810eft, ck810, ck810v, ck810f, ck810t, ck810fv, ck810tv, ck810ft, and ck810ftv ๐Ÿ”ฅ
  • -mbig-endian, -EB, -mlittle-endian, -EL โ€” pick your endian era ๐ŸŒˆ You get big-endian or little-endian code, and little-endian is the default, so you're already winning ๐Ÿ’…
  • -mhard-float, -msoft-float โ€” hardware or software floating-point, your call ๐Ÿงš Soft float is the default, so that's what you get unless you ask for more.
  • -mdouble-float, -mno-double-float โ€” when -mhard-float is in effect, this turns on double-precision float instructions ๐Ÿ’œ It's on by default except when you're compiling for CK803, so keep that in mind, bestie ๐Ÿ™ˆ
  • -mfdivdu, -mno-fdivdu โ€” when -mhard-float is in effect, this lets the compiler generate frecipd, fsqrtd, and fdivd instructions โœจ Same deal as above: it's the default except for CK803.
  • -mfpu=fpu โ€” pick your floating-point processor ๐Ÿฆ‹ This one only works with -mhard-float. The values are fpv2_sf (basically the same as -mno-double-float -mno-fdivdu), fpv2 (-mdouble-float -mno-divdu), and fpv2_divd (-mdouble-float -mdivdu).
  • -melrw, -mno-elrw โ€” turns on the extended lrw instruction ๐ŸŒธ It's on for CK801 and off for everything else.
  • -mistack, -mno-istack โ€” enables interrupt stack instructions, and it's off by default ๐Ÿ™ˆ Heads up: you need -mistack to handle the interrupt and isr function attributes, so don't skip it.
  • -mmp โ€” enables multiprocessor instructions, off by default ๐Ÿ‘‘
  • -mcp โ€” enables coprocessor instructions, off by default ๐Ÿ“
  • -mcache โ€” also enables coprocessor instructions, off by default ๐Ÿ“
  • -msecurity โ€” enables C-SKY security instructions, off by default ๐Ÿ”
  • -mtrust โ€” enables C-SKY trust instructions, off by default ๐Ÿซถ
  • -mdsp, -medsp, -mvdsp โ€” enable C-SKY DSP, Enhanced DSP, or Vector DSP instructions, respectively ๐ŸŽ€ All three are off by default.
  • -mdiv, -mno-div โ€” generates divide instructions, but it's off by default so you have to ask ๐Ÿ’…
  • -msmart, -mno-smart โ€” generates code for Smart Mode, which only uses registers 0-7 so you can use those cute 16-bit instructions ๐Ÿงš It's ignored for CK801 (where this is required anyway), it's on by default for CK802, and it's off for other targets.
  • -mhigh-registers, -mno-high-registers โ€” generates code that uses the high registers 16-31 โœจ This isn't supported on CK801, CK802, or CK803, but it's on by default for other processors.
  • -manchor, -mno-anchor โ€” generates code that uses global anchor symbol addresses ๐Ÿฆ‹
  • -mpushpop, -mno-pushpop โ€” generates code with push and pop instructions, and it's on by default ๐Ÿ’–
  • -mmultiple-stld, -mstm, -mno-multiple-stld, -mno-stm โ€” generates code using stm and ldm instructions ๐Ÿ”ฅ This isn't supported on CK801, but it's enabled by default on other processors.
  • -mconstpool, -mno-constpool โ€” creates constant pools in the compiler instead of handing that job off to the assembler ๐Ÿงš This is the default and it's required for correct code generation on CK801 and CK802, and it's optional on other processors.
  • -mstack-size, -mno-stack-size โ€” emits .stack_size directives for each function in the assembly output ๐ŸŒˆ It's off by default.
  • -mccrt, -mno-ccrt โ€” generates code for the C-SKY compiler runtime instead of libgcc ๐Ÿ’œ It's off by default.
  • -mbranch-cost=n โ€” sets the branch costs to roughly n instructions ๐Ÿ“ The default is 1.
  • -msched-prolog, -mno-sched-prolog โ€” lets the scheduler mess with function prologue and epilogue sequences ๐Ÿ™ˆ Okay, real talk: using this can give you code that isn't compliant with the C-SKY V2 ABI prologue requirements, and that code can't be debugged or backtraced. It's disabled by default.

Darwin Options ๐ŸŽ

These options are defined for all architectures running the Darwin operating system ๐ŸŒธ

FSF GCC on Darwin doesn't make "fat" object files. It makes an object file for the one architecture 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 (like ppc7400 or ppc970 or i686) is decided by the flags that specify the ISA GCC is targeting, like -mcpu or -march โœจ If you want to override that, the -force_cpusubtype_ALL option can do it.

The Darwin tools are kind of inconsistent when they hit an ISA mismatch ๐Ÿ™ˆ The assembler, as, only lets you use instructions that are valid for the subtype of the file it's generating, so you can't put 64-bit instructions in a ppc750 object file. The linker for shared libraries, /usr/bin/libtool, fails and prints an error if you ask it to make a shared library with a less restrictive subtype than its input files (like trying to put a ppc970 object file in a ppc7400 library). 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 front of the list of directories searched for header files ๐Ÿงš These directories get interleaved with the ones from -I options and get scanned left to right.

A framework directory is just a directory full of frameworks ๐Ÿ’– A framework is a directory that has a Headers and/or PrivateHeaders directory sitting directly inside it and ends in .framework. The framework's name is the directory name without the .framework part. Its headers live in one of those two folders, 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're 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 change later. The standard frameworks live in /System/Library/Frameworks and /Library/Frameworks ๐ŸŒˆ An example include looks like #include <Framework/header.h>, where Framework is the framework's name and header.h is found in the PrivateHeaders or Headers directory.

  • -iframeworkdir โ€” basically -F, except the directory gets treated as a system directory ๐ŸŽ€ The big difference is that with -iframework, the compiler won't warn you about constructs inside header files found through dir. This option is only valid for the C family of languages.
  • -gused โ€” emits debugging information for symbols that are used ๐Ÿ”ฅ For the stabs debugging format, this turns on -feliminate-unused-debug-symbols. It's ON by default.
  • -gfull โ€” emits debugging information for all symbols and types ๐Ÿ‘‘
  • -mmacosx-version-min=version โ€” tells you the earliest version of MacOS X this executable will run on ๐ŸŽ Typical values of version include 10.1, 10.2, and 10.3.9.

If the compiler was built to use the system's headers by default, then the default for this option is whatever system version the compiler is running on ๐Ÿ’… Otherwise, the default is to make choices that are compatible with as many systems and code bases as possible.

  • -mkernel โ€” enables kernel development mode ๐Ÿงš 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 does nothing on x86.
โš ๏ธ Warning, bestie: -mone-byte-bool makes GCC generate code that is not binary compatible with code generated without that switch ๐Ÿ˜ญ You may need to recompile every other module in your program, including system libraries. Only use this to conform to a non-default data model.
  • -mfix-and-continue, -ffix-and-continue, -findirect-data โ€” generates code for fast turnaround development, like letting GDB dynamically load .o files into programs that are already running ๐Ÿฆ‹ -findirect-data and -ffix-and-continue are only here for backwards compatibility.
  • -all_load โ€” loads all members of static archive libraries ๐Ÿ“ฆ See man ld(1) for more information.
  • -arch_errors_fatal โ€” makes errors about files with the wrong architecture fatal ๐Ÿ’€
  • -bind_at_load โ€” marks the output file so the dynamic linker binds all undefined references when the file is loaded or launched โœจ
  • -bundle โ€” produces a Mach-o bundle format file ๐ŸŽ€ See man ld(1) for more information.
  • -bundle_loader executable โ€” specifies the executable that will load the build output file being linked ๐Ÿงš See man ld(1) for more information.
  • -dynamiclib โ€” when you pass this, GCC makes a dynamic library instead of an executable when linking, using the Darwin libtool command ๐ŸŒˆ
  • -force_cpusubtype_ALL โ€” gives GCC's output file the ALL subtype, instead of one controlled by -mcpu or -march ๐Ÿ‘‘

okay so the Darwin flags are a whole list ๐ŸŽโœจ every single one of these gets handed straight to the Darwin linker, bestie:

  • -allowable_client client_name
  • -client_name
  • -compatibility_version
  • -current_version
  • -dead_strip
  • -dependency-file
  • -dylib_file
  • -dylinker_install_name
  • -dynamic
  • -exported_symbols_list
  • -filelist
  • -flat_namespace
  • -force_flat_namespace
  • -headerpad_max_install_names
  • -image_base
  • -init
  • -install_name
  • -keep_private_externs
  • -multi_module
  • -multiply_defined
  • -multiply_defined_unused
  • -noall_load
  • -no_dead_strip_inits_and_terms
  • -nofixprebinding
  • -nomultidefs
  • -noprebind
  • -noseglinkedit
  • -pagezero_size
  • -prebind
  • -prebind_all_twolevel_modules
  • -private_bundle
  • -read_only_relocs
  • -sectalign
  • -sectobjectsymbols
  • -whyload
  • -seg1addr
  • -sectcreate
  • -sectobjectsymbols
  • -sectorder
  • -segaddr
  • -segs_read_only_addr
  • -segs_read_write_addr
  • -seg_addr_table
  • -seg_addr_table_filename
  • -seglinkedit
  • -segprot
  • -segs_read_only_addr
  • -segs_read_write_addr
  • -single_module
  • -static
  • -sub_library
  • -sub_umbrella
  • -twolevel_namespace
  • -umbrella
  • -undefined
  • -unexported_symbols_list
  • -weak_reference_mismatches
  • -whatsloaded

Real talk: all of these get passed to the Darwin linker ๐Ÿ’…, and its man page is where you go for the full tea on each one ๐Ÿซถ


โœจ DEC Alpha Options โœจ

These -m options are defined for the DEC Alpha implementations ๐Ÿฆ‹

  • -mno-soft-float, -msoft-float โ€” these two are opposites ๐Ÿ’… -msoft-float means GCC skips the hardware floating-point instructions, and -mno-soft-float keeps them. With -msoft-float, the floating-point operations go through functions in libgcc.a. Unless those get replaced with routines that emulate the float ops (or get compiled to call those emulations), they'll still issue floating-point operations. So if you're compiling for an Alpha with no floating-point operations, you have to make sure the library is built so it doesn't call them ๐Ÿ˜ญ Heads up: Alpha implementations without floating-point operations are still required to have floating-point registers.
  • -mfp-reg, -mno-fp-regs โ€” -mfp-reg makes GCC generate code that uses the floating-point register set, and -mno-fp-regs makes it not use it. -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 back in $0 instead of $f0. This is a non-standard calling sequence, so any function with a floating-point argument or return value that's called by code compiled with -mno-fp-regs must also be compiled with that option โš ๏ธ A typical use of -mno-fp-regs is building a kernel that doesn't use, and so doesn't need to save and restore, any floating-point registers โœจ
  • -mieee โ€” the Alpha architecture has floating-point hardware tuned for max performance. It's mostly compliant with the IEEE floating-point standard, but full compliance needs software help. This option generates fully IEEE-compliant code, except that the inexact-flag isn't maintained (see below). Turning it on defines the preprocessor macro _IEEE_FP during compilation. The result is less efficient, but it can correctly support denormalized numbers and exceptional IEEE values like not-a-number and plus/minus infinity. Other Alpha compilers call this option -ieee_with_no_inexact.
  • -mieee-with-inexact โ€” this is like -mieee, except the generated code also maintains the IEEE inexact-flag ๐Ÿ‘‘ Turning it on makes the code implement fully-compliant IEEE math. On top of _IEEE_FP, the preprocessor macro _IEEE_FP_EXACT is defined too. On some Alpha implementations, the code can run significantly slower than the default. There's very little code that depends on the inexact-flag, so you should normally not specify this option. Other Alpha compilers call this option -ieee_with_inexact.
  • -mfp-trap-mode=trap-mode โ€” this 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 (like the division by zero trap).
    • u โ€” in addition to the traps enabled by n, underflow traps are enabled as well.
    • su โ€” like u, but the instructions are marked as safe for software completion (see the Alpha architecture manual for details).
    • sui โ€” like su, but inexact traps are enabled as well.
  • -mfp-rounding-mode=rounding-mode โ€” selects the IEEE rounding mode. Other Alpha compilers call this option -fprm rounding-mode. The rounding-mode can be one of:
    • n โ€” normal IEEE rounding mode. Floating-point numbers are rounded towards the nearest machine number, or towards the even machine number in case of a tie.
    • m โ€” round towards minus infinity.
    • c โ€” chopped rounding mode. Floating-point numbers are rounded towards zero.
    • d โ€” dynamic rounding mode. A field in the floating-point control register (fpcr, see the Alpha architecture reference manual) controls the rounding mode in effect. The C library initializes this register for rounding towards plus infinity. So unless your program modifies the fpcr, d corresponds to round towards plus infinity.
  • -mtrap-precision=trap-precision โ€” in the Alpha architecture, floating-point traps are imprecise ๐Ÿ˜ตโ€๐Ÿ’ซ That means without software help, it's impossible to recover from a floating trap, and program execution normally has to be terminated. GCC can generate code that helps operating system trap handlers figure out the exact location that caused a floating-point trap. Depending on what your application needs, you can pick different levels of precision. Other Alpha compilers provide the equivalent options called -scope_safe and -resumption_safe.
    • p โ€” program precision. This option is the default, and it means a trap handler can only identify which program caused a floating-point exception.
    • f โ€” function precision. The trap handler can determine the function that caused a floating-point exception.
    • i โ€” instruction precision. The trap handler can determine the exact instruction that caused a floating-point exception.
  • -mieee-conformant โ€” this marks the generated code as IEEE conformant.
Bestie, be careful: you must not use this option unless you also specify -mtrap-precision=i and either -mfp-trap-mode=su or -mfp-trap-mode=sui. Its only effect is to emit the line .eflag 48 in the function prologue of the generated assembly file.
  • -mbuild-constants โ€” normally, GCC looks at a 32- or 64-bit integer constant to see if it can construct it from smaller constants in two or three instructions. If it can't, it outputs the constant as a literal and generates code to load it from the data segment at run time. Use this option to require GCC to construct all integer constants using code, even if it takes more instructions (the maximum is six). You typically use this to build a shared library dynamic loader ๐Ÿงš Since it's itself a shared library, it has to relocate itself in memory before it can find the variables and constants in its own data segment.
  • -mbwx, -mno-bwx, -mcix, -mno-cix, -mfix, -mno-fix, -mmax, -mno-max โ€” these indicate whether GCC should generate code that uses the optional BWX, CIX, FIX and MAX instruction sets. The default is to use the instruction sets supported by the CPU type specified via the -mcpu= option, or the CPU GCC was built on if none is specified ๐Ÿ’œ
  • -mfloat-vax, -mfloat-ieee โ€” -mfloat-vax generates code that uses VAX F and G floating-point arithmetic instead of IEEE single and double precision, and -mfloat-ieee generates code that does not use it ๐ŸŒธ
  • -mexplicit-relocs, -mno-explicit-relocs โ€” older Alpha assemblers had no way to generate symbol relocations except through 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 should apply to which instructions. This option is mostly useful for debugging, since GCC detects the capabilities of the assembler when it's built and sets the default accordingly.
  • -msmall-data, -mlarge-data โ€” when -mexplicit-relocs is in effect, static data is accessed via gp-relative relocations. When -msmall-data is used, objects 8 bytes long or smaller are placed in a small data area (the .sdata and .sbss sections) and are accessed via 16-bit relocations off of the $gp register. This limits the size of the small data area to 64KB, but lets the variables be accessed directly via a single instruction. The default is -mlarge-data. With this option, the data area is limited to just below 2GB. Programs that need more than 2GB of data must use malloc or mmap to allocate the data in the heap instead of in the program's data segment ๐Ÿซฃ When generating code for shared libraries, -fpic implies -msmall-data and -fPIC implies -mlarge-data.
  • -msmall-text, -mlarge-text โ€” when -msmall-text is used, the compiler assumes the code of the entire program (or shared library) fits in 4MB, so it's reachable with a branch instruction. When -msmall-data is used, the compiler can assume all local symbols share the same $gp value, which reduces the number of instructions required for a function call from 4 to 1 ๐Ÿ“ The default is -mlarge-text.
  • -mcpu=cpu_type โ€” sets the instruction set and instruction scheduling parameters for machine type cpu_type. You can specify either the EV style name or the corresponding chip number. GCC supports scheduling parameters for the EV4, EV5 and EV6 family of processors, and it picks the default instruction set values from the processor you specify. If you don't specify a processor type, GCC defaults to the processor the compiler was built on. Supported values for cpu_type are:
    • ev4, ev45, 21064 โ€” schedules as an EV4 and has no instruction set extensions.

okay so the Alpha processor list is next, and bestie, these are the chip names you can hand to -mcpu= ๐Ÿ’–

  • ev5 or 21164 โ€” schedules as an EV5 and has no instruction set extensions ๐ŸŒธ
  • ev56 or 21164a โ€” schedules as an EV5 and supports the BWX extension ๐Ÿฆ‹
  • pca56, 21164pc, or 21164PC โ€” schedules as an EV5 and supports the BWX and MAX extensions ๐Ÿ’œ
  • ev6 or 21264 โ€” schedules as an EV6 and supports the BWX, FIX, and MAX extensions ๐Ÿ”ฅ
  • ev67 or 21264a โ€” schedules as an EV6 and supports the BWX, CIX, FIX, and MAX extensions ๐Ÿ‘‘

Native toolchains also get the value native, which picks the best architecture option for the host processor โœจ -mcpu=native does absolutely nothing if GCC doesn't recognize the processor ๐Ÿ™ˆ

  • -mtune=cpu_type โ€” sets only the instruction scheduling parameters for machine type cpu_type. The instruction set stays exactly the same ๐ŸŽ€

Native toolchains also support native here, which selects the best architecture option for the host processor. -mtune=native has no effect if GCC doesn't recognize the processor ๐Ÿงš

  • -mmemory-latency=time โ€” tells the scheduler what latency to assume for typical memory references the application makes. This number depends a lot 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 of clock cycles ๐Ÿ’…
  • L1, L2, L3, main โ€” the compiler has estimates of clock cycles for "typical" EV4 & EV5 hardware at the Level 1, 2 & 3 caches (also called Dcache, Scache, and Bcache), plus main memory. Heads up: L3 is only valid for EV5 โš ๏ธ

๐Ÿงš eBPF Options ๐Ÿงš

  • -mframe-limit=bytes โ€” sets the hard limit for frame sizes, in bytes. Right now the value you give should be less than or equal to 32767. By default it's whatever limit the targeted Linux kernel version imposes ๐Ÿ’œ
  • -mkernel=version โ€” the minimum kernel version that will run your compiled program. GCC uses it to decide 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 that relaxes some of the restrictions the BPF architecture puts on you ๐Ÿฆ‹

-<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 โ€” says the program will run on the simulator. This links in an alternate runtime startup and library.
๐Ÿšจ Do NOT use this option when generating programs that will run on real hardware! You have to provide your own runtime library for whatever I/O functions you need.
  • -mlra โ€” enables Local Register Allocation. It's still experimental for FT32, so by default the compiler uses standard reload ๐Ÿ”ฅ
  • -mnodiv โ€” don't use div and mod instructions ๐Ÿ™ˆ
  • -mft32b โ€” enables use of the extended instructions of the FT32B processor ๐Ÿ‘‘
  • -mcompress โ€” compresses all code using the Ft32B code compression scheme ๐Ÿงš
  • -mnopm โ€” don't generate code that reads program memory ๐Ÿ’€

๐Ÿ‘‘ FRV Options ๐Ÿ‘‘

  • -mgpr-32 โ€” only uses the first 32 general-purpose registers ๐Ÿ’…
  • -mgpr-64 โ€” uses all 64 general-purpose registers ๐Ÿ”ฅ
  • -mfpr-32 โ€” uses only the first 32 floating-point registers ๐ŸŒธ
  • -mfpr-64 โ€” uses all 64 floating-point registers ๐Ÿ’–
  • -mhard-float โ€” uses hardware instructions for floating-point operations โœจ
  • -msoft-float โ€” uses library routines for floating-point operations instead ๐Ÿซถ
  • -malloc-cc โ€” dynamically allocates condition code registers ๐Ÿฆ‹
  • -mfixed-cc โ€” doesn't try to dynamically allocate condition code registers. It only uses icc0 and fcc0 ๐ŸŽ€
  • -mdword โ€” changes the ABI to use double word insns ๐Ÿ’œ
  • -mno-dword โ€” doesn't use double word instructions ๐Ÿ™…
  • -mdouble โ€” uses floating-point double instructions ๐Ÿ”ฅ
  • -mno-double โ€” doesn't use floating-point double instructions ๐Ÿ’€
  • -mmedia โ€” uses media instructions ๐ŸŒˆ
  • -mno-media โ€” doesn't use media instructions ๐Ÿฅ€
  • -mmuladd โ€” uses multiply and add/subtract instructions ๐Ÿ‘‘
  • -mno-muladd โ€” doesn't use multiply and add/subtract instructions ๐Ÿ™ˆ
  • -mfdpic โ€” selects the FDPIC ABI, which uses function descriptors to represent pointers to functions. Without any PIC/PIE-related options, it implies -fPIE. With -fpic or -fpie, it assumes GOT entries and small data are within a 12-bit range from the GOT base address. With -fPIC or -fPIE, GOT offsets are computed with 32 bits. With a bfin-elf target, this option implies -msim ๐Ÿงš
  • -minline-plt โ€” enables inlining of PLT entries in function calls to functions that aren't known to bind locally. It has no effect without -mfdpic. It's enabled by default if you're optimizing for speed and compiling for shared libraries (that's -fPIC or -fpic), or when an optimization option like -O3 or above is on the command line ๐Ÿ’–
  • -mTLS โ€” assumes a large TLS segment when generating thread-local code ๐Ÿฆ‹
  • -mtls โ€” doesn't assume a large TLS segment when generating thread-local code ๐ŸŒธ
  • -mgprel-ro โ€” enables the use of "GPREL" relocations in the FDPIC ABI for data known to be in read-only sections. It's enabled by default, except for -fpic or -fpie. Even though it may help make the global offset table smaller, it trades 1 instruction for 4. With -fPIC or -fPIE, it trades 3 instructions for 4, one of which may be shared by multiple symbols, and it avoids the need for a GOT entry for the referenced symbol, so it's more likely to be a win. If it isn't, you can use -mno-gprel-ro to disable it ๐Ÿซถ
  • -multilib-library-pic โ€” links with the (library, not FD) pic libraries. It's implied by -mlibrary-pic, and by -fPIC and -fpic without -mfdpic. You should basically never have to use it explicitly ๐Ÿ™ˆ
  • -mlinked-fp โ€” follows the EABI requirement of always creating a frame pointer whenever a stack frame is allocated. It's enabled by default and can be turned off with -mno-linked-fp ๐Ÿ’…
  • -mlong-calls โ€” uses indirect addressing to call functions outside the current compilation unit. This lets the functions be placed anywhere within the 32-bit address space ๐Ÿ‘‘
  • -malign-labels โ€” tries to align labels to an 8-byte boundary by inserting NOPs into the previous packet. This option only has an effect when VLIW packing is enabled. It doesn't create new packets; it just adds NOPs to existing ones ๐ŸŒˆ
  • -mlibrary-pic โ€” generates position-independent EABI code ๐ŸŽ€
  • -macc-4 โ€” uses only the first four media accumulator registers ๐Ÿ’œ
  • -macc-8 โ€” uses all eight media accumulator registers ๐Ÿ”ฅ
  • -mpack โ€” packs VLIW instructions โœจ
  • -mno-pack โ€” doesn't pack VLIW instructions ๐Ÿฅ€
  • -mno-eflags โ€” doesn't mark ABI switches in e_flags ๐Ÿงš
  • -mcond-move โ€” enables the use of conditional-move instructions (the default) ๐Ÿฆ‹
๐Ÿ› This switch is mainly for debugging the compiler and will likely be removed in a future version.
  • -mno-cond-move โ€” disables the use of conditional-move instructions ๐Ÿ™…
๐Ÿ› This switch is mainly for debugging the compiler and will likely be removed in a future version.
  • -mscc โ€” enables the use of conditional set instructions (the default) ๐Ÿ’–
๐Ÿ› This switch is mainly for debugging the compiler and will likely be removed in a future version.
  • -mno-scc โ€” disables the use of conditional set instructions ๐Ÿ’€
๐Ÿ› This switch is mainly for debugging the compiler and will likely be removed in a future version.
  • -mcond-exec โ€” enables the use of conditional execution (the default) ๐ŸŒธ
๐Ÿ› This switch is mainly for debugging the compiler and will likely be removed in a future version.
  • -mno-cond-exec โ€” disables the use of conditional execution ๐Ÿฅ€
๐Ÿ› This switch is mainly for debugging the compiler and will likely be removed in a future version.
  • -mvliw-branch โ€” runs a pass to pack branches into VLIW instructions (the default) ๐Ÿ‘‘
๐Ÿ› This switch is mainly for debugging the compiler and will likely be removed in a future version.
  • -mno-vliw-branch โ€” doesn't run a pass to pack branches into VLIW instructions ๐Ÿ™ˆ
๐Ÿ› This switch is mainly for debugging the compiler and will likely be removed in a future version.
  • -mmulti-cond-exec โ€” enables optimization of && and || in conditional execution (the default) ๐Ÿซถ
๐Ÿ› This switch is mainly for debugging the compiler and will likely be removed in a future version.
  • -mno-multi-cond-exec โ€” disables optimization of && and || in conditional execution ๐ŸŒˆ
๐Ÿ› This switch is mainly for debugging the compiler and will likely be removed in a future version.
  • -mnested-cond-exec โ€” enables nested conditional execution optimizations (the default) โœจ
๐Ÿ› This switch is mainly for debugging the compiler and will likely be removed in a future version.
  • -mno-nested-cond-exec โ€” disables nested conditional execution optimizations ๐Ÿ’…
๐Ÿ› This switch is mainly for debugging the compiler and will likely be removed in a future version.
  • -moptimize-membar โ€” removes redundant membar instructions from the compiler-generated code. It's enabled by default ๐Ÿงš
  • -mno-optimize-membar โ€” disables the automatic removal of redundant membar instructions from the generated code ๐Ÿ™…
  • -mtomcat-stats โ€” makes gas print out tomcat statistics ๐ŸŽ€
  • -mcpu=cpu โ€” selects the processor type to generate code for. Possible values are frv, fr550, tomcat, fr500, fr450, fr405, fr400, fr300, and simple ๐Ÿ‘‘

๐ŸŒˆ GNU/Linux Options ๐ŸŒˆ

Okay bestie, these -m options are defined for GNU/Linux targets ๐Ÿงโœจ

  • -mglibc โ€” Uses the GNU C library ๐Ÿ’–. It's the default, except on *-*-linux-*uclibc*, *-*-linux-*musl* and *-*-linux-*android* targets, so don't get it twisted ๐Ÿ™ˆ
  • -muclibc โ€” Uses the uClibc C library ๐ŸŒธ. This is the default on *-*-linux-*uclibc* targets.
  • -mmusl โ€” Uses the musl C library ๐Ÿ“. This is the default on *-*-linux-*musl* targets.
  • -mbionic โ€” Uses the Bionic C library ๐Ÿค–. This is the default on *-*-linux-*android* targets.
  • -mandroid โ€” Compiles code that's compatible with the Android platform ๐Ÿ“ฑ. This is the default on *-*-linux-*android* targets.
    • When compiling, this option turns on -mbionic, -fPIC, -fno-exceptions and -fno-rtti by default. When linking, it makes the GCC driver pass Android-specific options to the linker. Finally, it makes the preprocessor macro "__ANDROID__" get defined โœจ
  • -tno-android-cc โ€” Turns off the compilation effects of -mandroid, so -mbionic, -fPIC, -fno-exceptions and -fno-rtti are NOT enabled by default ๐Ÿ™…โ€โ™€๏ธ
  • -tno-android-ld โ€” Turns off the linking effects of -mandroid, so the linker gets standard Linux linking options instead ๐Ÿ”—

๐Ÿฆ‹ H8/300 Options ๐Ÿฆ‹

Okay, these -m options are defined for the H8/300 implementations ๐Ÿฆ‹:

  • -mrelax โ€” Shortens some address references at link time, when it's possible. It does this by using 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 normal mode. This switch has to be used with either -mh or -ms, no cap ๐Ÿงš
  • -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 only works 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 only works for H8S targets too ๐Ÿ’€
  • -mint32 โ€” Makes "int" data 32 bits by default ๐ŸŽ€
  • -malign-300 โ€” On the H8/300H and H8S, this uses the same alignment rules as the H8/300. The H8/300H and H8S normally align longs and floats on 4-byte boundaries, but -malign-300 bumps them down to 2-byte boundaries. It has no effect on the H8/300 at all ๐Ÿฆ‹

โšก HPPA Options โšก

Okay, these -m options are defined for the HPPA family of computers ๐Ÿ–ฅ๏ธ:

  • -march=architecture-type โ€” Generates code for the architecture you pick. The choices for architecture-type are 1.0 for PA 1.0, 1.1 for PA 1.1, and 2.0 for PA 2.0 processors. Peek at /usr/lib/sched.models on an HP-UX system to find the right architecture option for your machine ๐Ÿ”. Code compiled for lower numbered architectures runs on higher numbered ones, but not the other way around, so keep that in mind ๐ŸŒˆ
  • -mpa-risc-1-0, -mpa-risc-1-1, -mpa-risc-2-0 โ€” These are synonyms for -march=1.0, -march=1.1, and -march=2.0 respectively ๐Ÿ’œ
  • -mcaller-copies โ€” The caller copies function arguments that get passed by hidden reference. Use this one with care, because it isn't 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 one gets ignored. It's only here for compatibility purposes ๐Ÿ™ƒ
  • -mdisable-fpregs โ€” Stops floating-point registers from being used in any way. This is necessary when compiling kernels that do lazy context switching of floating-point registers ๐ŸงŠ. If you use this option and then try floating-point operations, the compiler aborts ๐Ÿ’€
  • -mdisable-indexing โ€” Stops the compiler from using indexing address modes. This dodges some rather obscure problems when compiling MIG generated code under MACH ๐Ÿ•ต๏ธโ€โ™€๏ธ
  • -mno-space-regs โ€” Generates code that assumes the target has no space registers. This lets GCC make faster indirect calls and use unscaled index address modes โšก
    • This kind of code is suitable for level 0 PA systems and kernels ๐Ÿง 
  • -mfast-indirect-calls โ€” Generates code that assumes calls never cross space boundaries. This lets GCC emit code with faster indirect calls ๐Ÿƒโ€โ™€๏ธ
    • ๐Ÿ’€ This option does not work in the presence of shared libraries or nested functions, so watch out!
  • -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 ๐ŸŽ€
  • -mlong-load-store โ€” Generates 3-instruction load and store sequences, which the HP-UX 10 linker sometimes needs. This is the same as the +k option on the HP compilers ๐Ÿฐ
  • -mportable-runtime โ€” Uses the portable calling conventions HP proposed for ELF systems ๐ŸŒ
  • -mgas โ€” Lets you use assembler directives that only GAS understands โœจ
  • -mschedule=cpu-type โ€” Schedules code based on the constraints for the machine type cpu-type. The choices are 700 7100, 7100LC, 7200, 7300 and 8000. Check /usr/lib/sched.models on an HP-UX system to find the right scheduling option for your machine ๐Ÿ—“๏ธ. The default scheduling is 8000 ๐Ÿ’–
  • -mlinker-opt โ€” Turns on the optimization pass in the HP-UX linker. Heads up, this makes symbolic debugging impossible ๐Ÿ˜ญ. It also triggers a bug in the HP-UX 8 and HP-UX 9 linkers, where they throw bogus error messages when linking some programs ๐Ÿ™ˆ
  • -msoft-float โ€” Generates output that contains 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 get used, but this can't be done directly in cross-compilation. You have to make your own arrangements to provide suitable library functions for cross-compilation, bestie ๐Ÿ˜ค
  • -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. That one generates the predefines "__hp9000s700", "__hp9000s700__" and "_WSIO" for workstation IO ๐Ÿ–ฅ๏ธ. These options are available under HP-UX and HI-UX ๐ŸŒธ
  • -mgnu-ld โ€” Uses options specific to GNU ld. This passes -shared to ld when building a shared library. It's the default when GCC is configured (explicitly or implicitly) with the GNU linker ๐Ÿฆ‹. This option doesn't change which ld gets called, it only changes what parameters get passed to that ld. The ld that gets called is decided by the --with-ld configure option, GCC's program search path, and finally the user's PATH ๐Ÿ—บ๏ธ. You can print the linker GCC uses with which gcc -print-prog-name=ld. This option is only available on the 64-bit HP-UX GCC, i.e. configured with hppa*64*-*-hpux* ๐Ÿ’…
  • -mhp-ld โ€” Uses options specific to HP ld. This passes -b to ld when building a shared library, and passes +Accept TypeMismatch to ld on all links ๐Ÿงฉ. It's the default when GCC is configured (explicitly or implicitly) with the HP linker. Same deal as before: this option doesn't change which ld gets called, only the parameters passed to it. The ld that gets called is decided by the --with-ld configure option, GCC's program search path, and finally the user's PATH ๐Ÿ›ค๏ธ. You can print the linker GCC uses with which gcc -print-prog-name=ld. This option is only available on the 64-bit HP-UX GCC, i.e. configured with hppa*64*-*-hpux* ๐ŸŒˆ
  • -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 (whichever applies) goes past a 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 you use the -ffunction-sections option, or when you use the -mgas and -mno-portable-runtime options together under HP-UX with the SOM linker ๐Ÿ”ญ
    • You usually don't want this option, since it degrades performance ๐Ÿ˜ฉ. It might still be useful in large applications, especially when partial linking is used to build the application ๐Ÿ—๏ธ
    • The types of long calls used depend on what the assembler and linker can do, and the type of code being generated. The impact on systems that support long absolute calls, and long pic symbol-difference or pc-relative calls, should be pretty small. However, an indirect call is used on 32-bit ELF systems in pic code, and it's quite long ๐Ÿข
  • -munix=unix-std โ€” Generates compiler predefines and picks a startfile for the UNIX standard you specify. The choices for unix-std are 93, 95 and 98. 93 is supported on all HP-UX versions. 95 is available on HP-UX 10.10 and later. 98 is available on HP-UX 11.11 and later. The defaults are 93 for HP-UX 10.00, 95 for HP-UX 10.10 through 11.00, and 98 for HP-UX 11.11 and later ๐Ÿ“š
    • -munix=93 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 ๐Ÿง
    • > ๐Ÿšจ This option changes the interfaces for various library routines, and it also affects the operational behavior of the C library. So extreme care is needed when you use it, no cap.
    • 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 appropriate. Most GNU software doesn't offer this capability ๐Ÿซฅ
  • -nolibdld โ€” Suppresses the generation of link options that search libdld.sl when the -static option is specified on HP-UX 10 and later ๐Ÿšซ
  • -static โ€” ๐Ÿ’€ okay so the HP-UX setlocale in libc depends on libdld.sl, and there is no archive version of it, so -static needs some special link options to untangle that mess. On HP-UX 10 and later, the GCC driver adds the necessary options to link with libdld.sl whenever you use -static, which means the binary ends up dynamic anyway ๐Ÿซ . On the 64-bit port, the linkers make dynamic binaries by default regardless, so it's giving consistency. If you don't want the driver adding those link options, use -nolibdld ๐Ÿ™…โ€โ™€๏ธ.
  • -threads โ€” ๐Ÿงต adds multithreading support with the dce thread library under HP-UX. It sets flags for both the preprocessor and the linker, so you get both at once. Main character energy โœจ.

๐Ÿฆ‹ IA-64 Options ๐Ÿฆ‹

These are the -m options defined for the Intel IA-64 architecture ๐Ÿ’œ.

  • -mbig-endian โ€” generates code for a big-endian target. This is the default for HP-UX ๐Ÿ“.
  • -mlittle-endian โ€” generates code for a little-endian target. This is the default for AIX5 and GNU/Linux ๐ŸŒˆ.
  • -mgnu-as, -mno-gnu-as โ€” generates (or doesn't) code for the GNU assembler. -mgnu-as is the default โœจ.
  • -mgnu-ld, -mno-gnu-ld โ€” generates (or doesn't) code for the GNU linker. -mgnu-ld is the default ๐Ÿ’….
  • -mno-pic โ€” generates code that does not use a global pointer register. The result is not position independent code, and it violates the IA-64 ABI ๐Ÿ™ˆ.
Heads up, bestie: -mno-pic gives you non-position-independent code and breaks the IA-64 ABI. Only reach for it if you know exactly why you need it ๐Ÿ’€.
  • -mvolatile-asm-stop, -mno-volatile-asm-stop โ€” generates (or doesn't) a stop bit immediately before and after volatile asm statements ๐Ÿ”ฅ.
  • -mregister-names, -mno-register-names โ€” generates (or doesn't) in, loc, and out register names for the stacked registers. This can make the assembler output way more readable ๐Ÿ“–.
  • -mno-sdata, -msdata โ€” disables (or enables) optimizations that use the small data section. This can be handy for working around optimizer bugs ๐Ÿ›.
  • -mconstant-gp โ€” generates code that uses a single constant global pointer value. Super useful when you're compiling kernel code ๐Ÿง .
  • -mauto-pic โ€” generates code that is self-relocatable. This implies -mconstant-gp, and it's useful when compiling firmware code ๐Ÿ”ง.
  • -minline-float-divide-min-latency โ€” generates code for inline divides of floating-point values using the minimum latency algorithm โšก.
  • -minline-float-divide-max-throughput โ€” generates code for inline divides of floating-point values using the maximum throughput algorithm ๐Ÿš€.
  • -mno-inline-float-divide โ€” no inline code for divides of floating-point values, period ๐Ÿ™…โ€โ™€๏ธ.
  • -minline-int-divide-min-latency โ€” generates code for inline divides of integer values using the minimum latency algorithm โšก.
  • -minline-int-divide-max-throughput โ€” generates code for inline divides of integer values using the maximum throughput algorithm ๐Ÿš€.
  • -mno-inline-int-divide โ€” no inline code for divides of integer values ๐Ÿ’….
  • -minline-sqrt-min-latency โ€” generates code for inline square roots using the minimum latency algorithm โšก.
  • -minline-sqrt-max-throughput โ€” generates code for inline square roots using the maximum throughput algorithm ๐Ÿš€.
  • -mno-inline-sqrt โ€” no inline code for sqrt ๐Ÿซ .
  • -mfused-madd, -mno-fused-madd โ€” does (or doesn't) generate code that uses the fused multiply/add or multiply/subtract instructions. The default is to use these instructions ๐Ÿ”ฅ.
  • -mno-dwarf2-asm, -mdwarf2-asm โ€” doesn't (or does) generate assembler code for the DWARF line number debugging info. This may be useful when you're not using the GNU assembler ๐Ÿฆ‹.
  • -mearly-stop-bits, -mno-early-stop-bits โ€” allows stop bits to be placed earlier than immediately preceding the instruction that triggered the stop bit. This can improve instruction scheduling, but it doesn't always do so ๐Ÿคทโ€โ™€๏ธ.
  • -mfixed-range=register-range โ€” generates code treating the given register range as fixed registers. A fixed register is one the register allocator can't use, which is 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 โœจ.
  • -mtls-size=tls-size โ€” specifies the bit size of immediate TLS offsets. Valid values are 14, 22, and 64 ๐Ÿ”ข.
  • -mtune=cpu-type โ€” tunes the instruction scheduling for a particular CPU. Valid values are itanium, itanium1, merced, itanium2, and mckinley ๐ŸŽฏ.
  • -milp32, -mlp64 โ€” generates code for a 32-bit or 64-bit environment. The 32-bit environment sets int, long, and pointer to 32 bits. The 64-bit environment sets int to 32 bits and long and pointer to 64 bits. These are HP-UX specific flags ๐Ÿ“.
  • -mno-sched-br-data-spec, -msched-br-data-spec โ€” (dis/en)ables data speculative scheduling before reload. This results in generation of ld.a instructions and the corresponding check instructions (ld.c / chk.a). The default setting is disabled ๐Ÿ™ƒ.
  • -msched-ar-data-spec, -mno-sched-ar-data-spec โ€” (en/dis)ables data speculative scheduling after reload. This results in generation of ld.a instructions and the corresponding check instructions (ld.c / chk.a). The default setting is enabled ๐Ÿ’–.
  • -mno-sched-control-spec, -msched-control-spec โ€” (dis/en)ables control speculative scheduling. This feature is only available during region scheduling (i.e., before reload). It results in generation of the ld.s instructions and the corresponding check instructions chk.s. The default setting is disabled ๐Ÿซถ.
  • -msched-br-in-data-spec, -mno-sched-br-in-data-spec โ€” (en/dis)ables speculative scheduling of the instructions that depend on the data speculative loads before reload. This only works if -msched-br-data-spec is enabled. The default setting is enabled ๐Ÿ’œ.
  • -msched-ar-in-data-spec, -mno-sched-ar-in-data-spec โ€” (en/dis)ables speculative scheduling of the instructions that depend on the data speculative loads after reload. This only works if -msched-ar-data-spec is enabled. The default setting is enabled ๐Ÿ’œ.
  • -msched-in-control-spec, -mno-sched-in-control-spec โ€” (en/dis)ables speculative scheduling of the instructions that depend on the control speculative loads. This only works if -msched-control-spec is enabled. The default setting is enabled ๐ŸŒธ.
  • -mno-sched-prefer-non-data-spec-insns, -msched-prefer-non-data-spec-insns โ€” if enabled, data-speculative instructions get scheduled only when there are no other choices at the moment. This makes data speculation much more conservative. The default setting is disabled ๐Ÿข.
  • -mno-sched-prefer-non-control-spec-insns, -msched-prefer-non-control-spec-insns โ€” if enabled, control-speculative instructions get scheduled only when there are no other choices at the moment. This makes control speculation much more conservative. The default setting is disabled ๐Ÿข.
  • -mno-sched-count-spec-in-critical-path, -msched-count-spec-in-critical-path โ€” if enabled, speculative dependencies are considered when computing instruction priorities. This makes speculation a bit more conservative. The default setting is disabled ๐Ÿง.
  • -msched-spec-ldc โ€” uses a simple data speculation check. This option is on by default โœ….
  • -msched-control-spec-ldc โ€” uses a simple check for control speculation. This option is on by default โœ….
  • -msched-stop-bits-after-every-cycle โ€” places a stop bit after every cycle when scheduling. This option is on by default โœ….
  • -msched-fp-mem-deps-zero-cost โ€” assumes floating-point stores and loads are not likely to conflict when placed into the same instruction group. This option is disabled by default ๐Ÿ™…โ€โ™€๏ธ.
  • -msel-sched-dont-check-control-spec โ€” generates checks for control speculation in selective scheduling. This flag is disabled by default ๐Ÿ™…โ€โ™€๏ธ.
  • -msched-max-memory-insns=max-insns โ€” sets a limit on the number of memory insns per instruction group, giving lower priority to subsequent memory insns trying 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 โ€” makes the limit set by msched-max-memory-insns a hard limit, so no more than that many get placed in an instruction group. Otherwise the limit is "soft", meaning non-memory operations are preferred once the limit is reached, but memory operations may still be scheduled ๐Ÿซ .

๐ŸŒธ LM32 Options ๐ŸŒธ

These -m options are defined for the LatticeMico32 architecture ๐ŸŒท:

  • -mbarrel-shift-enabled โ€” enables barrel-shift instructions ๐Ÿ”„.
  • -mdivide-enabled โ€” enables divide and modulus instructions โž—.
  • -mmultiply-enabled โ€” enables multiply instructions โœ–๏ธ.
  • -msign-extend-enabled โ€” enables sign extend instructions ๐Ÿงฉ.
  • -muser-enabled โ€” enables user-defined instructions ๐Ÿ‘‘.

๐Ÿ’… M32C Options ๐Ÿ’…

  • -mcpu=name โ€” selects the CPU that code is 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 โ€” tells GCC the program will run on the simulator. This links in an alternate runtime library that supports things like file I/O ๐Ÿ–ฅ๏ธ.
Bestie, never use -msim for programs that will run on real hardware. For that you have to provide your own runtime library for whatever I/O functions you need ๐Ÿ’€.
  • -memregs=number โ€” specifies the number of memory-based pseudo-registers GCC uses during code generation. These pseudo-registers get used like real registers, so there's a tradeoff between GCC's ability to fit code into the available registers and the performance penalty of using memory instead of registers โš–๏ธ. All modules in a program must be compiled with the same value for this option ๐Ÿซถ.
Also, you must not use -memregs with GCC's default runtime libraries. Super important, no cap ๐Ÿ˜ญ.

๐Ÿงš M32R/D Options ๐Ÿงš

These -m options are defined for Renesas M32R/D architectures ๐ŸŒˆ:

  • -m32r2 โ€” generates code for the M32R/2 ๐Ÿฆ‹.
  • -m32rx โ€” generates code for the M32R/X ๐Ÿฆ‹.
  • -m32r โ€” generates code for the M32R. This is the default ๐Ÿ’–.
  • -mmodel=small โ€” ๐ŸŽ€ This is the default and the cosy one! Every object is assumed to live in the lower 16MB of memory, so its address can be loaded with the ld24 instruction, and every subroutine is assumed reachable with the bl instruction. The addressability of a particular object can be set with the model attribute. ๐Ÿ’–
  • -mmodel=medium โ€” ๐Ÿฆ‹ Objects can be anywhere in the 32-bit address space, and the compiler generates seth/add3 instructions to load their addresses. Subroutines are still assumed reachable with the bl instruction.
  • -mmodel=large โ€” ๐ŸŒˆ Objects can be anywhere in the 32-bit address space (the compiler generates seth/add3 instructions to load their addresses). Subroutines may not be reachable with the bl instruction, so the compiler generates the much slower seth/add3/jl instruction sequence. ๐Ÿ˜ญ
  • -msdata=none โ€” ๐Ÿ’… Disables the small data area. Variables go into one of .data, .bss, or .rodata (unless the section attribute has been specified). This is the default. The small data area is made up of the .sdata and .sbss sections, and objects can be explicitly put in it with the section attribute using one of these sections. โœจ
  • -msdata=sdata โ€” ๐Ÿงš Puts small global and static data in the small data area, but doesn't generate any special code to reference them.
  • -msdata=use โ€” ๐Ÿ”ฅ Puts small global and static data in the small data area and generates special instructions to reference them.
  • -G num โ€” ๐Ÿ“ Puts global and static objects less than or equal to num bytes into the small data or BSS sections instead of the normal data or BSS sections. The default value of num is 8. The -msdata option must be set to one of sdata or use for this option to have any effect.

All modules should be compiled with the same -G num value. Compiling with different values of num may or may not work. If it doesn't, the linker gives an error message---incorrect code is not generated. ๐Ÿซถ

  • -mdebug โ€” ๐Ÿ” Makes the M32R-specific code in the compiler display some statistics that might help in debugging programs.
  • -malign-loops โ€” ๐ŸŒธ Aligns all loops to a 32-byte boundary.
  • -mno-align-loops โ€” ๐Ÿ™ˆ Doesn't enforce a 32-byte alignment for loops. This is the default.
  • -missue-rate=number โ€” โšก Issues number instructions per cycle. number can only be 1 or 2.
  • -mbranch-cost=number โ€” ๐Ÿ”€ number can only be 1 or 2. If it's 1, branches are preferred over conditional code. If it's 2, the opposite applies.
  • -mflush-trap=number โ€” ๐Ÿชค Specifies the trap number to use to flush the cache. The default is 12. Valid numbers are between 0 and 15 inclusive.
  • -mno-flush-trap โ€” ๐Ÿšซ Specifies that the cache cannot be flushed by using a trap.
  • -mflush-func=name โ€” ๐Ÿงน Specifies the name of the operating system function to call to flush the cache. The default is _flush_cache, but a function call is only used if a trap is not available.
  • -mno-flush-func โ€” ๐Ÿ™… Indicates that there is no OS function for flushing the cache.

โœจ M680x0 Options โœจ

These are the -m options defined for M680x0 and ColdFire processors. The default settings depend on which architecture was selected when the compiler was configured, so the defaults for the most common choices are given below. ๐Ÿง 

  • -march=arch โ€” ๐Ÿ—๏ธ Generates code for a specific M680x0 or ColdFire instruction set architecture. Permissible values of arch for M680x0 architectures are: 68000, 68010, 68020, 68030, 68040, 68060 and cpu32. ColdFire architectures are selected according to Freescale's ISA classification, and the permissible values are: isaa, isaaplus, isab and isac.
    • ๐Ÿ”Ž GCC defines a macro __mcfarch__ whenever it's generating code for a ColdFire target. The arch in this macro is one of the -march arguments given above.
    • ๐Ÿค When used together, -march and -mtune select code that runs on a family of similar processors but that is optimized for a particular microarchitecture.
  • -mcpu=cpu โ€” ๐ŸŽฏ Generates code for a specific M680x0 or ColdFire processor. The M680x0 CPUs are: 68000, 68010, 68020, 68030, 68040, 68060, 68302, 68332 and cpu32. The ColdFire CPUs are given by the table below, which also sorts them into families:
Family : -mcpu arguments
51 : 51 51ac 51ag 51cn 51em 51je 51jf 51jg 51jm 51mm 51qe 51qm
5206 : 5202 5204 5206
5206e : 5206e
5208 : 5207 5208
5211a : 5210a 5211a
5213 : 5211 5212 5213
5216 : 5214 5216
52235 : 52230 52231 52232 52233 52234 52235
5225 : 5224 5225
52259 : 52252 52254 52255 52256 52258 52259
5235 : 5232 5233 5234 5235 523x
5249 : 5249
5250 : 5250
5271 : 5270 5271
5272 : 5272
5275 : 5274 5275
5282 : 5280 5281 5282 528x
53017 : 53011 53012 53013 53014 53015 53016 53017
5307 : 5307
5329 : 5327 5328 5329 532x
5373 : 5372 5373 537x
5407 : 5407
5475 : 5470 5471 5472 5473 5474 5475 547x 5480 5481 5482 5483 5484
5485

-mcpu=cpu overrides -march=arch if arch is compatible with cpu. Other combinations of -mcpu and -march are rejected. ๐Ÿšซ

GCC defines the macro __mcf_cpu_cpu when a ColdFire target CPU is selected. It also defines __mcf_family_family, where the value of family is given by the table above. ๐Ÿ’œ

  • -mtune=tune โ€” ๐ŸŽถ Tunes the code for a particular microarchitecture within the constraints set by -march and -mcpu. The M680x0 microarchitectures are: 68000, 68010, 68020, 68030, 68040, 68060 and cpu32. The ColdFire microarchitectures are: cfv1, cfv2, cfv3, cfv4 and cfv4e.
    • ๐Ÿช„ You can also use -mtune=68020-40 for code that needs to run relatively well on 68020, 68030 and 68040 targets. -mtune=68020-60 is similar but includes 68060 targets as well. These two options select the same tuning decisions as -m68020-40 and -m68020-60 respectively.
    • ๐Ÿท๏ธ GCC defines the macros __mcarch and __mcarch__ when tuning for 680x0 architecture arch. It also defines mcarch unless either -ansi or a non-GNU -std option is used. If GCC is tuning for a range of architectures, as selected by -mtune=68020-40 or -mtune=68020-60, it defines the macros for every architecture in the range.
    • ๐Ÿท๏ธ GCC also defines the macro __muarch__ when tuning for ColdFire microarchitecture uarch, where uarch is one of the arguments given above.
  • -m68000, -mc68000 โ€” ๐Ÿฃ Generates output for a 68000. This is the default when the compiler is configured for 68000-based systems. It's equivalent to -march=68000. Use this option for microcontrollers with a 68000 or EC000 core, including the 68008, 68302, 68306, 68307, 68322, 68328 and 68356.
  • -m68010 โ€” ๐ŸŒฑ Generates output for a 68010. This is the default when the compiler is configured for 68010-based systems. It's equivalent to -march=68010.
  • -m68020, -mc68020 โ€” ๐ŸŒฟ Generates output for a 68020. This is the default when the compiler is configured for 68020-based systems. It's equivalent to -march=68020.
  • -m68030 โ€” ๐ŸŒณ Generates output for a 68030. This is the default when the compiler is configured for 68030-based systems. It's equivalent to -march=68030.
  • -m68040 โ€” ๐Ÿ› ๏ธ Generates output for a 68040. This is the default when the compiler is configured for 68040-based systems. It's equivalent to -march=68040. This option inhibits the use of 68881/68882 instructions that have to be emulated by software on the 68040. Use this option if your 68040 doesn't have code to emulate those instructions. ๐Ÿ™Œ
  • -m68060 โ€” ๐Ÿš€ Generates output for a 68060. This is the default when the compiler is configured for 68060-based systems. It's equivalent to -march=68060. This option inhibits the use of 68020 and 68881/68882 instructions that have to be emulated by software on the 68060. Use this option if your 68060 doesn't have code to emulate those instructions. ๐Ÿ’…
  • -mcpu32 โ€” ๐ŸŽ›๏ธ Generates output for a CPU32. This is the default when the compiler is configured for CPU32-based systems. It's equivalent to -march=cpu32. Use this option for microcontrollers with a CPU32 or CPU32+ core, including the 68330, 68331, 68332, 68333, 68334, 68336, 68340, 68341, 68349 and 68360.
  • -m5200 โ€” ๐Ÿ“Ÿ Generates output for a 520X ColdFire CPU. This is the default when the compiler is configured for 520X-based systems. It's equivalent to -mcpu=5206, and is now deprecated in favor of that option. Use this option 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 โ€” ๐Ÿฅ€ Generates output for a ColdFire 5407 CPU. This option is now deprecated in favor of the equivalent -mcpu=5407.
  • -mcfv4e โ€” ๐ŸŒŸ Generates output for a ColdFire V4e family CPU (e.g. 547x/548x). This includes use of hardware floating-point instructions. The option is equivalent to -mcpu=547x, and is now deprecated in favor of that option.
  • -m68020-40 โ€” ๐Ÿงฉ Generates output for a 68040, without using any of the new instructions. This results in code that can run relatively efficiently on either a 68020/68881 or a 68030 or a 68040. The generated code does use the 68881 instructions that are emulated on the 68040. The option is equivalent to -march=68020 -mtune=68020-40.
  • -m68020-60 โ€” ๐Ÿงฉ Generates output for a 68060, without using any of the new instructions. This results in code that can run relatively efficiently on either a 68020/68881 or a 68030 or a 68040. The generated code does use the 68881 instructions that are emulated on the 68060. The option is equivalent to -march=68020 -mtune=68020-60.
  • -mhard-float, -m68881 โ€” โšก Generates floating-point instructions. This is the default for 68020 and above, and for ColdFire devices that have an FPU. It defines the macro __HAVE_68881__ on M680x0 targets and __mcffpu__ on ColdFire targets.
  • -msoft-float โ€” okay so this one tells GCC to skip floating-point instructions entirely ๐Ÿซถ and call library routines instead. It's the default for 68000, 68010, and 68832 targets, and also for ColdFire devices that have no FPU.
  • -mdiv, -mno-div โ€” these let you turn ColdFire hardware divide and remainder instructions on (-mdiv) or off (-mno-div) ๐Ÿงฎ. If you use -march without -mcpu, the default is "on" for ColdFire architectures and "off" for M680x0 architectures. Otherwise the default comes from the target CPU, which is 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 type int 16 bits wide, just like short int ๐Ÿ’…. Parameters passed on the stack also get aligned to a 16-bit boundary, even on targets whose API mandates promotion to 32-bit.
  • -mno-short โ€” doesn't treat int as 16 bits wide. This is the default ๐ŸŒธ.
  • -mnobitfield, -mno-bitfield โ€” no bit-field instructions for you ๐Ÿ™…โ€โ™€๏ธ. The -m68000, -mcpu32 and -m5200 options imply -mnobitfield.
  • -mbitfield โ€” yes to bit-field instructions ๐Ÿฆ‹. The -m68020 option implies -mbitfield, and this is the default if you're using a configuration designed for a 68020.
  • -mrtd โ€” this one switches to a different function-calling convention, where functions that take a fixed number of arguments return using the rtd instruction. That instruction pops their arguments on the way out, which saves one instruction in the caller since the caller doesn't have to pop them ๐Ÿง .
๐Ÿšจ This calling convention is incompatible with the one normally used on Unix, so you can't use it if you need to call libraries compiled with the Unix compiler.

You also have to provide function prototypes for all functions that take variable numbers of arguments (including printf). If you don't, GCC generates incorrect code for calls to those functions ๐Ÿ˜ญ.

And seriously, seriously incorrect code results if you call a function with too many arguments. Normally extra arguments are harmlessly ignored, but not here ๐Ÿ’€.

The rtd instruction is supported by the 68010, 68020, 68030, 68040, 68060 and CPU32 processors, but not by the 68000 or 5200.

The default is -mno-rtd.

  • -malign-int, -mno-align-int โ€” these control 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 you code that runs somewhat faster on processors with 32-bit busses, but you pay for it with 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.
  • -mno-strict-align, -mstrict-align โ€” -mno-strict-align means GCC does not assume that unaligned memory references are handled by the system, while -mstrict-align means it does assume that ๐Ÿคทโ€โ™€๏ธ.
  • -mpcrel โ€” uses the pc-relative addressing mode of the 68000 directly, instead of a global offset table ๐Ÿงญ. At the moment this option implies -fpic, which allows at most a 16-bit offset for pc-relative addressing. -fPIC isn't supported with -mpcrel right now, though it could be supported for 68020 and higher processors.
  • -msep-data โ€” generates code that lets the data segment live in a different area of memory from the text segment ๐Ÿ—บ๏ธ. This allows execute-in-place in an environment without virtual memory management. This option implies -fPIC.
  • -mno-sep-data โ€” generates code that assumes the data segment follows the text segment. This is the default.
  • -mid-shared-library โ€” generates code that supports shared libraries through the library ID method ๐Ÿ“š. This 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 ๐Ÿ”ข. A value of 0 generates more compact code. Other values force the allocation of that number to the current library, but that's no more space- or time-efficient than leaving this option out.
  • -mxgot, -mno-xgot โ€” when you're generating position-independent code for ColdFire, -mxgot generates code that works even if the GOT has more than 8192 entries ๐Ÿข. This code is larger and slower than code generated without this option. On M680x0 processors you don't need this option, since -fPIC is enough.

GCC normally uses a single instruction to load values from the GOT. That's pretty efficient, but it only works if the GOT is smaller than about 64k. Anything bigger makes the linker report an error like this:

relocation truncated to fit: R_68K_GOT16O foobar

If you see that, recompile your code with -mxgot and it should work with very large GOTs. Just know that code generated with -mxgot is less efficient, since it takes 4 instructions to fetch the value of a global symbol ๐Ÿ˜ฉ.

Some linkers, including newer versions of the GNU linker, can create multiple GOTs and sort GOT entries. If you have one of those, you should only need -mxgot when compiling a single object file that accesses more than 8192 GOT entries. Very few do.

These options have no effect unless GCC is generating position-independent code.

  • -mlong-jump-table-offsets โ€” uses 32-bit offsets in switch tables ๐Ÿ“ˆ. The default is 16-bit offsets.

๐Ÿ MCore Options

These are the -m options defined for the Motorola M*Core processors ๐Ÿ”ง.

  • -mhardlit, -mno-hardlit โ€” inlines constants into the code stream if it can be done in two instructions or less ๐Ÿงฉ.
  • -mdiv, -mno-div โ€” uses the divide instruction. This is enabled by default โž—.
  • -mrelax-immediate, -mno-relax-immediate โ€” allows arbitrary-sized immediates in bit operations ๐ŸŒˆ.
  • -mwide-bitfields, -mno-wide-bitfields โ€” always treats bit-fields as int-sized ๐Ÿ“ฆ.
  • -m4byte-functions, -mno-4byte-functions โ€” forces all functions to be aligned to a 4-byte boundary ๐Ÿงฑ.
  • -mcallgraph-data, -mno-callgraph-data โ€” emits callgraph information ๐Ÿ•ธ๏ธ.
  • -mslow-bytes, -mno-slow-bytes โ€” prefers word access when reading byte quantities ๐Ÿ’พ.
  • -mlittle-endian, -mbig-endian โ€” generates code for a little-endian target ๐Ÿ”.
  • -m210, -m340 โ€” generates code for the 210 processor ๐Ÿ–ฅ๏ธ.
  • -mno-lsim โ€” assumes runtime support has already been provided, so the simulator library (libsim.a) gets left off the linker command line ๐Ÿ™…โ€โ™€๏ธ.
  • -mstack-increment=size โ€” sets the maximum amount for a single stack increment operation ๐Ÿ“š. Large values can speed up programs with functions that need a lot of stack space, but they can also trigger a segmentation fault if the stack gets extended too much ๐Ÿ’ฅ. The default value is 0x1000.

๐ŸŒŠ MeP Options

  • -mabsdiff โ€” enables the abs instruction, which gives the absolute difference between two registers ๐Ÿงฎ.
  • -mall-opts โ€” 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 isn't part of GCC, provides these configurations through this option. Using this option is the same as using all the corresponding command-line options. The default configuration is default.
  • -mcop โ€” enables the coprocessor instructions ๐Ÿค–. By default this is a 32-bit coprocessor. The coprocessor is normally enabled through the -mconfig= option.
  • -mcop32 โ€” enables the 32-bit coprocessor's instructions ๐Ÿ”ฉ.
  • -mcop64 โ€” enables the 64-bit coprocessor's instructions ๐Ÿš€.
  • -mivc2 โ€” enables IVC2 scheduling ๐Ÿง . IVC2 is a 64-bit VLIW coprocessor.
  • -mdc โ€” causes constant variables to be placed in the .near section ๐Ÿ“.
  • -mdiv โ€” enables the div and divu instructions โž—.
  • -meb โ€” generates big-endian code ๐ŸŒ….
  • -mel โ€” generates little-endian code ๐ŸŒ„.
  • -mio-volatile โ€” tells the compiler that any variable marked with the io attribute should be considered volatile ๐Ÿ”Œ.
  • -ml โ€” causes variables to be assigned to the .far section by default ๐Ÿ”๏ธ.
  • -mleadz โ€” enables the leadz (leading zero) instruction 0๏ธโƒฃ.
  • -mm โ€” causes variables to be assigned to the .near section by default ๐Ÿก.
  • -mminmax โ€” enables the min and max instructions ๐Ÿ“Š.
  • -mmult โ€” enables the multiplication and multiply-accumulate instructions โœ–๏ธ.
  • -mno-opts โ€” disables all the optional instructions that -mall-opts enabled ๐Ÿ™…โ€โ™€๏ธ.
  • -mrepeat โ€” enables the repeat and erepeat instructions, which are used for low-overhead looping ๐Ÿ”.
  • -ms โ€” causes all variables to default to the .tiny section ๐Ÿœ. There's a 65536-byte limit to this section, and accesses to these variables use the %gp base register.
  • -msatur โ€” enables the saturation instructions ๐Ÿ’ซ. The compiler doesn't currently generate these itself, but this option is included for compatibility with other tools, like as.
  • -msdram โ€” links the SDRAM-based runtime instead of the default ROM-based runtime ๐Ÿ’พ.
  • -msim โ€” links the simulator run-time libraries ๐Ÿ•น๏ธ.
  • -msimnovec โ€” links the simulator runtime libraries, but leaves out the built-in support for reset and exception vectors and tables ๐Ÿงน.
  • -mtf โ€” okay so this one makes every function default to the .far section ๐Ÿฆ‹ Without it, functions chill in the .near section instead โœจ
  • -mtiny=n โ€” variables that are n bytes or smaller get tucked into the .tiny section ๐ŸŽ€ They lean on the $gp base register ๐Ÿ’… The default is 4.
Heads up, bestie: the .tiny section has a 65536-byte limit ๐Ÿ’€

๐ŸŒธ MicroBlaze Options ๐ŸŒธ

  • -msoft-float โ€” software emulation for floating point ๐Ÿซถ This is the default.
  • -mhard-float โ€” use hardware floating-point instructions ๐Ÿ”ฅ
  • -mmemcpy โ€” don't optimize block moves, just use memcpy ๐Ÿ’–
  • -mno-clearbss โ€” deprecated, so please switch to -fno-zero-initialized-in-bss instead ๐Ÿ’€
  • -mcpu=cpu-type โ€” use the features of, and schedule code for, the CPU you pick ๐Ÿ‘‘ Values follow the format vX.YY.Z, where X is a major version, YY is the minor version, and Z is compatibility code. Example values are v3.00.a, v4.00.b, v5.00.a, v5.00.b, and v6.00.a ๐ŸŒˆ
  • -mxl-soft-mul โ€” software multiply emulation (default) ๐Ÿง
  • -mxl-soft-div โ€” software emulation for divides (default) ๐Ÿง
  • -mxl-barrel-shift โ€” use the hardware barrel shifter โญ
  • -mxl-pattern-compare โ€” use pattern compare instructions ๐Ÿ”
  • -msmall-divides โ€” table lookup optimization for small signed integer divisions ๐Ÿงฎ
  • -mxl-stack-check โ€” deprecated, so use -fstack-check instead ๐Ÿ’€
  • -mxl-gp-opt โ€” use GP-relative .sdata and .sbss sections ๐ŸŒธ
  • -mxl-multiply-high โ€” use multiply high instructions for the high part of a 32x32 multiply โœจ
  • -mxl-float-convert โ€” use hardware floating-point conversion instructions ๐Ÿฆ‹
  • -mxl-float-sqrt โ€” use the hardware floating-point square root instruction ๐ŸŒŸ
  • -mbig-endian โ€” generate code for a big-endian target ๐Ÿ’œ
  • -mlittle-endian โ€” generate code for a little-endian target ๐Ÿ’œ
  • -mxl-reorder โ€” use reorder instructions (swap and byte reversed load/store) ๐Ÿ”„
  • -mxl-mode-app-model โ€” select the application model app-model. The valid models are:
    • executable โ€” normal executable, and the default ๐Ÿ  It uses the startup code crt0.o.
    • -mpic-data-is-text-relative โ€” assume 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 ๐Ÿ› It uses the startup file crt1.o and sets the program's start address to 0x800.
    • bootstrap โ€” for applications loaded by a bootloader ๐Ÿฅพ This model uses the startup file crt2.o, which does not contain a processor reset vector handler. It's suitable for handing control to the bootloader on a processor reset instead of the application.
    • novectors โ€” for applications that don't need any of the MicroBlaze vectors ๐Ÿ™… This can be handy for apps running inside a monitoring application. This model uses crt3.o as its startup file.
-xl-mode-app-model is a deprecated alias for -mxl-mode-app-model, so it's giving old news ๐Ÿ•ฐ๏ธ

๐Ÿงš MIPS Options ๐Ÿงš

  • -EB โ€” generate big-endian code ๐Ÿ’–
  • -EL โ€” generate little-endian code. This is the default for mips*el-*-* configurations ๐Ÿ’–
  • -march=arch โ€” generate code that runs on arch, which can be a generic MIPS ISA name 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, so no cap, it just does nothing.

In processor names, a final 000 can be abbreviated as k, so 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 listed above. In other words, it has the full prefix and does not abbreviate 000 as k. In the case of from-abi, the macro names the resolved architecture, which is either mips1 or mips3. It names the default architecture when no -march option is given.

  • -mtune=arch โ€” optimize for arch ๐ŸŽฏ Among other things, this option controls the way instructions are scheduled and the perceived cost of arithmetic operations. The list of arch values is the same as for -march.

When this option 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 โ€” generate (or don'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 using the mips16 and nomips16 attributes ๐ŸŽ€

  • -mflip-mips16 โ€” generate MIPS16 code on alternating functions ๐Ÿงช This option exists for regression testing of mixed MIPS16/non-MIPS16 code generation. It is not intended for ordinary use when compiling user code, so please don't go using it in your everyday builds ๐Ÿ™ˆ
  • -minterlink-compressed, -mno-interlink-compressed โ€” require (or don't require) that code using the standard, uncompressed MIPS ISA be link-compatible with MIPS16 and microMIPS code, and vice versa ๐Ÿ”—

For example, code using the standard ISA encoding cannot jump directly to MIPS16 or microMIPS code. It has to use either a call or an indirect jump. So -minterlink-compressed disables direct jumps unless GCC knows 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 โ€” generate code for the given ABI ๐ŸŽ€

The EABI comes in a 32-bit and a 64-bit variant. GCC normally generates 64-bit code when you pick a 64-bit architecture, but you can use -mgp32 to get 32-bit code instead ๐Ÿ’œ

For info about the O64 ABI, check out http://gcc.gnu.org/projects/mipso64-abi.html ๐Ÿ“š

GCC supports a variant of the o32 ABI where the floating-point registers are 64 bits wide instead of 32 ๐Ÿฆ‹ You can select this combo with -mabi=32 -mfp64. 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 the same, but each scalar value is passed in a single 64-bit register instead of a pair of 32-bit registers. For example, scalar floating-point values are returned in $f0 only, not a $f0/$f1 pair. The set of call-saved registers also stays the same, in that the even-numbered double-precision registers are saved ๐Ÿง 

Two more variants of the o32 ABI exist to help with the move from 32-bit to 64-bit registers: FPXX (-mfpxx) and FP64A (-mfp64 -mno-odd-spreg) ๐ŸŒ‰ The FPXX extension requires that all code run correctly with either 32-bit or 64-bit registers. That code can be interlinked with either FP32 or FP64, but not both. FP64A is similar to the FP64 extension, but it forbids the use of odd-numbered single-precision registers. It can be used together with the FRE mode of FPUs in MIPS32R5 processors, and it lets both FP32 and FP64A code interlink and run in the same process without changing FPU modes ๐Ÿซถ

  • -mabicalls, -mno-abicalls โ€” generate (or don't generate) code suitable for SVR4-style dynamic objects ๐ŸŒˆ -mabicalls is the default for SVR4-based systems.
  • -mshared, -mno-shared โ€” okay so these decide whether the code is fully position-independent ๐Ÿฆ‹, which means it can be linked into shared libraries ๐Ÿ“š. -mshared turns that on and -mno-shared turns it off. Both only affect -mabicalls ๐Ÿ’…

Quick lore: all -mabicalls code has traditionally been position-independent no matter what -fPIC or -fpic say ๐ŸŒธ. BUT the GNU toolchain has a sneaky extension where executables can use absolute accesses for locally-binding symbols, use shorter GP initialization sequences, and generate direct calls to locally-defined functions ๐Ÿ”ฅ. That whole mode is what -mno-shared selects.

-mno-shared needs binutils 2.16 or higher and makes objects that only the GNU linker can link ๐Ÿ’€. It doesn't change the ABI of the final executable, only the ABI of relocatable objects. Using -mno-shared generally makes executables both smaller and quicker ๐Ÿ˜ญ

-mshared is the default ๐Ÿ’–

  • -mplt, -mno-plt โ€” you can tell GCC to assume (or not assume) that the static and dynamic linkers support PLTs and copy relocations ๐ŸŽ€. This only affects -mno-shared -mabicalls. For the n64 ABI, it does nothing without -msym32.

You can make -mplt the default by configuring GCC with --with-mips-plt. Otherwise the default is -mno-plt ๐Ÿงš.

  • -mxgot, -mno-xgot โ€” lift (or don't lift) the usual limits on how big the global offset table can be ๐Ÿ“.

GCC normally uses a single instruction to load values from the GOT. That's pretty efficient, but it only works if the GOT is smaller than about 64k. Anything bigger and the linker throws an error like this:

relocation truncated to fit: R_MIPS_GOT16 foobar

If that happens, recompile your code with -mxgot โœจ. It works with very large GOTs, but the code is a bit less efficient, since it takes three instructions to fetch the value of a global symbol.

Some linkers can create multiple GOTs. If you've got one of those, you should only need -mxgot when a single object file touches 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 anything about how wide the floating-point registers are ๐Ÿฆ‹.
  • -mhard-float โ€” use the floating-point coprocessor instructions ๐Ÿ”ฅ.
  • -msoft-float โ€” don't use the floating-point coprocessor instructions. Floating-point math gets handled with library calls instead ๐Ÿซถ.
  • -mno-float โ€” works like -msoft-float, but also promises that the program never does any floating-point operations ๐Ÿคž. This is only supported by some bare-metal MIPS configurations, where it might pick a special set of libraries with zero floating-point support (so no floating-point printf formats either, for example).
If code compiled with -mno-float accidentally has floating-point operations in it, it's likely to crash and burn with a link-time or run-time failure ๐Ÿ’€.
  • -msingle-float โ€” assume the floating-point coprocessor only does single-precision operations ๐ŸŒธ.
  • -mdouble-float โ€” assume the floating-point coprocessor does double-precision operations. This is the default ๐Ÿ’….
  • -modd-spreg, -mno-odd-spreg โ€” turn on (or off) the use of odd-numbered single-precision floating-point registers for the o32 ABI โœจ. On 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 treated by the abs.fmt and neg.fmt machine instructions ๐Ÿ™ˆ.

By default, or when you use -mabs=legacy, the legacy treatment kicks in. Here, those instructions count as arithmetic, so they get avoided wherever correct operation matters and the input might be a NaN. Instead, a longer sequence that manipulates the sign bit of the floating-point datum by hand gets used, unless -ffinite-math-only has also been specified.

-mabs=2008 picks the IEEE 754-2008 treatment. Now those instructions count as non-arithmetic, so they work correctly in every case, including when the input operand is a NaN. That means they're always used for the respective operations ๐Ÿ‘‘.

  • -mnan=2008, -mnan=legacy โ€” these control how the special not-a-number (NaN) IEEE 754 floating-point data gets encoded ๐Ÿฆ‹.

-mnan=legacy picks the legacy encoding. Quiet NaNs (qNaNs) are marked by the first bit of their trailing significand field being 0, and signaling NaNs (sNaNs) are marked by that first bit being 1.

-mnan=2008 picks the IEEE 754-2008 encoding. Now qNaNs have that first bit set to 1, and sNaNs have it set to 0.

The default is -mnan=legacy, unless GCC was configured with --with-nan=2008 ๐ŸŒˆ.

  • -mllsc, -mno-llsc โ€” use (or don't use) the ll, sc, and sync instructions to implement the atomic memory built-in functions โšก. If you don't specify either one, GCC uses those instructions as long as the target architecture supports them.

-mllsc is handy if the runtime environment can emulate the instructions. -mno-llsc can be useful when you're compiling for nonstandard ISAs. You can make either one the default by configuring GCC with --with-llsc or --without-llsc respectively. --with-llsc is the default for some configurations, so check the installation documentation for the details ๐Ÿ“–.

  • -mdsp, -mno-dsp โ€” use (or don't use) revision 1 of the MIPS DSP ASE ๐ŸŽถ. This option defines the preprocessor macro __mips_dsp, and it also sets __mips_dsp_rev to 1.
  • -mdspr2, -mno-dspr2 โ€” use (or don't use) revision 2 of the MIPS DSP ASE ๐ŸŽถ. This option defines the preprocessor macros __mips_dsp and __mips_dspr2, and it also sets __mips_dsp_rev to 2.
  • -msmartmips, -mno-smartmips โ€” use (or don't use) the MIPS SmartMIPS ASE ๐Ÿง .
  • -mpaired-single, -mno-paired-single โ€” use (or don't use) paired-single floating-point instructions ๐Ÿ‘ฏ. This one needs hardware floating-point support to be enabled first.
  • -mdmx, -mno-dmx โ€” wait, correction, it's -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 needs hardware floating-point support enabled.
  • -mips3d, -mno-mips3d โ€” use (or don't use) the MIPS-3D ASE ๐ŸŒŸ. The option -mips3d implies -mpaired-single.
  • -mmicromips, -mno-micromips โ€” generate (or don't generate) microMIPS code ๐ŸŒธ.

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 ๐Ÿ’–. Check out -mlong32 for the full story on the default and how the pointer size gets decided.
  • -mlong32 โ€” force long, int, and pointer types to be 32 bits wide ๐Ÿ’œ.

The default sizes of int, long, and pointers depend on the ABI. Every supported ABI uses 32-bit ints. The n64 ABI uses 64-bit longs, and so does the 64-bit EABI. The others use 32-bit longs. Pointers match the size of longs, or the size of 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 super useful with -mabi=64 and -mno-abicalls, since it lets GCC generate shorter and faster references to symbolic addresses โšก.
  • -G num โ€” put definitions of externally-visible data into a small data section, as long as that data is no bigger than num bytes ๐Ÿ“ฆ. GCC can then generate more efficient accesses to the data. Check out -mgpopt for the details ๐Ÿ”.

The default -G value depends on the configuration.

  • -mlocal-sdata, -mno-local-sdata โ€” extend (or don't extend) the -G behavior to local data too, like static variables in C ๐Ÿก. -mlocal-sdata is the default for all configurations.
If the linker complains that your app is using too much small data, try rebuilding the less performance-critical parts with -mno-local-sdata ๐Ÿ˜ญ. You might also want to build big libraries with -mno-local-sdata, so they leave more room for the main program.
  • -mextern-sdata, -mno-extern-sdata โ€” assume (or don't assume) that externally-defined data lives in a small data section, as long as its size is within the -G limit ๐Ÿซถ. -mextern-sdata is the default for all configurations.

okay bestie, listen up ๐Ÿ‘‚โœจ 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 have to make sure Var ends up in a small data section. no skipping this ๐Ÿ’… if another module defines Var, you've got two options: compile that module with a high-enough -G setting, or attach a section attribute to Var's definition. and if Var is common? then you need to link the application with a high-enough -G setting ๐Ÿ”ฅ

the easiest way to slay these restrictions is to compile and link every module with the same -G option ๐ŸŽ€ but ngl, you might want a library that supports a bunch of different small data limits. the move there is to compile the library with the highest supported -G setting and also use -mno-extern-sdata, which stops the library from making assumptions about externally-defined data ๐Ÿงš


  • -mgpopt, -mno-gpopt โ€” okay so -mgpopt lets GCC use GP-relative accesses for symbols it knows are in a small data section (see -G, -mlocal-sdata and -mextern-sdata) ๐ŸŒธ and -mno-gpopt turns that off. -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 get used in a boot monitor, programs that call boot monitor routines pass an unknown value in $gp. (the boot monitor itself is usually compiled with -G0 ๐Ÿงš)
    • -mno-gpopt implies -mno-local-sdata and -mno-extern-sdata ๐Ÿ’€
  • -membedded-data, -mno-embedded-data โ€” allocate variables to the read-only data section first if possible, then the small data section if possible, otherwise plain data ๐Ÿ“ it's slightly slower code than the default, but it cuts down on the RAM needed while executing, so it might be your fave for some embedded systems โœจ
  • -muninit-const-in-rodata, -mno-uninit-const-in-rodata โ€” put uninitialized "const" variables in the read-only data section. this only means something together with -membedded-data ๐Ÿซถ
  • -mcode-readable=setting โ€” choose whether GCC may generate code that reads from executable sections. there are three possible settings, bestie:
    • -mcode-readable=yes โ€” instructions can freely access executable sections. this is the default ๐Ÿ’œ
    • -mcode-readable=pcrel โ€” MIPS16 PC-relative load instructions can access executable sections, but other instructions must NOT ๐Ÿ™… this one's useful on 4KSc and 4KSd processors when the code TLBs have the Read Inhibit bit set ๐Ÿ˜ญ it's also useful on processors that can be configured to have a dual instruction/data SRAM interface and that, like the M4K, automatically redirect PC-relative loads to the instruction RAM.
    • -mcode-readable=no โ€” instructions must not access executable sections. this can be useful on targets configured with a dual instruction/data SRAM interface that (unlike the M4K) do not automatically redirect PC-relative loads to the instruction RAM ๐Ÿง 
  • -msplit-addresses, -mno-split-addresses โ€” enable (or disable) use of the %hi() and %lo() assembler relocation operators. this one's been superseded by -mexplicit-relocs ๐Ÿฅ€ but it's kept around for backwards compatibility ๐Ÿ•ฐ๏ธ
  • -mexplicit-relocs, -mno-explicit-relocs โ€” use (or don't use) assembler relocation operators when dealing with symbolic addresses. the alternative, picked by -mno-explicit-relocs, is to use assembler macros instead ๐Ÿงฉ -mexplicit-relocs is the default if GCC was configured to use an assembler that supports relocation operators โœจ
  • -mcheck-zero-division, -mno-check-zero-division โ€” trap (or don't trap) on integer division by zero. the default is -mcheck-zero-division ๐Ÿ’…
  • -mdivide-traps, -mdivide-breaks โ€” MIPS systems check for division by zero by generating either a conditional trap or a break instruction. traps give you smaller code, but they're only supported on MIPS II and later ๐Ÿ“‰ also, some versions of the Linux kernel have a bug that stops trap from generating the proper signal ("SIGFPE") ๐Ÿ˜ฉ so 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 it can be overridden at configure time using --with-divide=breaks. divide-by-zero checks can be completely disabled using -mno-check-zero-division ๐Ÿ™ˆ
  • -mload-store-pairs, -mno-load-store-pairs โ€” enable (or disable) an optimization that pairs consecutive load or store instructions to enable load/store bonding ๐Ÿ”— it's on by default, but it only takes effect when the selected architecture is known to support bonding.
  • -mmemcpy, -mno-memcpy โ€” force (or don't force) the use of "memcpy" for non-trivial block moves. the default is -mno-memcpy, which lets GCC inline most constant-sized copies ๐Ÿช„
  • -mlong-calls, -mno-long-calls โ€” -mlong-calls turns off use of the jal instruction, while -mno-long-calls doesn't. calling functions with jal is more efficient, but it requires the caller and callee to be in the same 256 megabyte segment ๐Ÿ—บ๏ธ this option has no effect on abicalls code. the default is -mno-long-calls.
  • -mmad, -mno-mad โ€” enable (or disable) use of the mad, madu and mul instructions, as provided by the R4650 ISA ๐Ÿฆ‹
  • -mimadd, -mno-imadd โ€” enable (or disable) use of the madd and msub integer instructions. the default is -mimadd on architectures that support madd and msub, except for the 74k architecture, where it was found to generate slower code ๐Ÿข
  • -mfused-madd, -mno-fused-madd โ€” enable (or disable) use of the floating-point multiply-accumulate instructions, when they're available. the default is -mfused-madd.
    • on the R8000 CPU, when multiply-accumulate instructions are used, the intermediate product is calculated to infinite precision and is not subject to the FCSR Flush to Zero bit. this may be undesirable in some circumstances ๐Ÿ™ƒ
    • on other processors, the result is numerically identical to the equivalent computation using separate multiply, add, subtract and negate instructions โœจ
  • -nocpp โ€” tells the MIPS assembler to NOT run its preprocessor over user assembler files (with a .s suffix) when assembling them ๐Ÿ™…
  • -mfix-24k, -mno-fix-24k โ€” work 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 โ€” work around certain R4000 CPU errata:
    • a double-word or a variable shift may give an incorrect result if executed immediately after starting an integer division.
    • a double-word or a variable shift may give an incorrect result if executed while an integer multiplication is in progress.
    • an integer division may give an incorrect result if started in a delay slot of a taken branch or a jump.
  • -mfix-r4400, -mno-fix-r4400 โ€” work around certain R4400 CPU errata:
    • a double-word or a variable shift may give an incorrect result if executed immediately after starting an integer division.
  • -mfix-r10000, -mno-fix-r10000 โ€” work around certain R10000 errata:
    • "ll"/"sc" sequences may not behave atomically on revisions prior to 3.0. they may deadlock on revisions 2.6 and earlier ๐Ÿ˜ฌ
    • this option can only be used if the target architecture supports branch-likely instructions. -mfix-r10000 is the default when -march=r10000 is used; -mno-fix-r10000 is the default otherwise.
  • -mfix-r5900, -mno-fix-r5900 โ€” don't try to schedule the preceding instruction into the delay slot of a branch instruction placed at the end of a short loop of six instructions or fewer, and 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 GCC.
  • -mfix-rm7000, -mno-fix-rm7000 โ€” work around the RM7000 "dmult"/"dmultu" errata ๐Ÿ› ๏ธ the workarounds are implemented by the assembler rather than by GCC.
  • -mfix-vr4120, -mno-fix-vr4120 โ€” work around certain VR4120 errata:
    • "dmultu" does not always produce the correct result.
    • "div" and "ddiv" do not always produce the correct result if one of the operands is negative.
    • the workarounds for the division errata rely on special functions in libgcc.a. at present, these functions are only provided by the "mips64vr*-elf" configurations ๐Ÿงš
    • other VR4120 errata require a NOP to be inserted between certain pairs of instructions. these are handled by the assembler, not by GCC itself.
  • -mfix-vr4130 โ€” work 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 โ€” work 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 โ€” specify whether GCC should insert cache barriers to avoid the side effects of speculation on R10K processors ๐Ÿšง
    • in common with many processors, the R10K tries to predict the outcome of a conditional branch and speculatively executes instructions from the "taken" branch. it later aborts these instructions if the predicted outcome is wrong. however, on the R10K, even aborted instructions can have side effects ๐Ÿ˜ฑ
    • this problem only affects kernel stores and, depending on the system, kernel loads. as an example, a speculatively-executed store may load the target memory into cache and mark the cache line as dirty, even if the store itself is later aborted. if a DMA operation writes to the same area of memory before the "dirty" line is flushed, the cached data overwrites the DMA-ed data. see the R10K processor manual for a full description, including other potential problems ๐Ÿ“–
this is the kind of thing that's genuinely sneaky, so read the R10K manual before you trust a cache barrier to be a magic fix ๐Ÿ™ˆ

Okay so one workaround is to slap cache barrier instructions in front of every memory access that might get speculatively executed and could have side effects even if it gets aborted ๐Ÿ™ˆ. -mr10k-cache-barrier=setting is the knob that controls how GCC does this workaround ๐Ÿ’…. It assumes that aborted accesses to any byte in these 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 is the kernel's responsibility to make sure speculative accesses to these regions are actually safe ๐Ÿซถ.

If the input program contains a function declaration like this one:

void foo (void);

then the implementation of foo must allow j foo and jal foo to be executed speculatively. GCC honors this restriction for functions it compiles itself ๐Ÿ’–. It expects non-GCC functions (such as hand-written assembly code) to do the same.

The option comes in three forms:

  • -mr10k-cache-barrier=load-store โ€” Inserts a cache barrier before a load or store that might be speculatively executed and that might have side effects even if aborted ๐Ÿ”ฅ.
  • -mr10k-cache-barrier=store โ€” Inserts a cache barrier before a store that might be speculatively executed and that might have side effects even if aborted โœจ.
  • -mr10k-cache-barrier=none โ€” Turns off cache barrier insertion entirely. This is the default setting ๐ŸŒธ.
  • -mflush-func=func, -mno-flush-func โ€” Picks the function to call to flush the I and D caches, or tells GCC to not call any such function ๐Ÿงš. If it gets called, the function must take the same arguments as the common _flush_func: the address of the memory range being flushed, the size of that memory range, and the number 3 (to flush both caches) ๐Ÿ’œ. The default depends on the target GCC was configured for, but it's commonly either _flush_func or __cpu_flush.
  • mbranch-cost=num โ€” Sets the cost of branches to roughly num "simple" instructions ๐Ÿฆ‹. This cost is only a heuristic, so it's not guaranteed to give consistent results across releases ๐Ÿ™ˆ. A zero cost redundantly selects the default, which is based on the -mtune setting.
  • -mbranch-likely, -mno-branch-likely โ€” Enables or disables Branch Likely instructions, no matter what the default is for the selected architecture ๐Ÿ’…. By default, Branch Likely instructions may be generated if the selected architecture supports them. The exception is the MIPS32 and MIPS64 architectures, plus processors that implement those architectures. For those, Branch Likely instructions are not generated by default, because the MIPS32 and MIPS64 architectures specifically deprecate their use ๐Ÿ’€.
  • -mcompact-branches=never โ€” Makes sure compact branch instructions are never generated ๐Ÿ™….
  • -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 isn't filled, a compact branch gets picked instead, as long as one is available ๐Ÿ‘‘. This is the default.
  • -mcompact-branches=always โ€” Makes sure a compact branch instruction gets generated if one is available. If it isn't, a delay slot form of the branch gets used instead ๐ŸŒˆ.

This option is supported from MIPS Release 6 onwards ๐ŸŽ€.

  • -mfp-exceptions, -mno-fp-exceptions โ€” Specifies whether FP exceptions are enabled ๐Ÿซง. This affects how FP instructions get scheduled for some processors. The default is that FP exceptions are enabled.

For instance, on the SB-1, if FP exceptions are disabled and we're emitting 64-bit code, then we can use both FP pipes. Otherwise, we can only use one FP pipe ๐Ÿ”ฅ.

  • -mvr4130-align, -mno-vr4130-align โ€” The VR4130 pipeline is two-way superscalar, but it can only issue two instructions together if the first one is 8-byte aligned ๐Ÿ“. When this option is enabled, GCC aligns pairs of instructions that it thinks should execute in parallel โœจ.

This option only has an effect when optimizing for the VR4130. It usually makes code faster, but the tradeoff is that the code gets bigger ๐Ÿฃ. It is 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) get generated when __builtin___clear_cache is compiled.

This option defaults to -mno-synci, but you can override the default by configuring GCC with --with-synci ๐ŸŒธ.

Heads up bestie โš ๏ธ: when compiling 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 ๐Ÿ’€.
  • -mrelax-pic-calls, -mno-relax-pic-calls โ€” Tries to turn PIC calls that are normally dispatched via register $25 into direct calls ๐Ÿฆ‹. This only works if the linker can resolve the destination at link time and the destination is within range for a direct call.

-mrelax-pic-calls is the default if GCC was configured to use an assembler and a linker that support the .reloc assembly directive and -mexplicit-relocs is in effect. With -mno-explicit-relocs, this optimization can be done by the assembler and the linker alone, without any help from the compiler ๐Ÿ’….

  • -mmcount-ra-address, -mno-mcount-ra-address โ€” Emits (or doesn't emit) code that lets _mcount modify the calling function's return address ๐Ÿ”ฎ. When enabled, this option extends the usual _mcount interface with a new ra-address parameter. It has type intptr_t * and gets passed in register $12. _mcount can then 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're using 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 that frame header allocation 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 โ€” 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, rather than the default mmo format used by the mmix simulator ๐ŸŒธ.
  • -mbranch-predict, -mno-branch-predict โ€” Uses (or doesn't use) the probable-branch instructions, when static branch prediction indicates a probable branch ๐Ÿ”ฎ.
  • -mbase-addresses, -mno-base-addresses โ€” 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. That means a program that uses lots of static data may need -mno-base-addresses ๐Ÿ™ˆ.
  • -msingle-exit, -mno-single-exit โ€” Forces (or doesn't force) generated code to have a single exit point in each function ๐Ÿšช.

๐Ÿฆ‹ MN10300 Options ๐Ÿฆ‹

These -m options are defined for Matsushita MN10300 architectures ๐Ÿ’…:

  • -mmult-bug โ€” Generates code to avoid bugs in the multiply instructions for the MN10300 processors. This is the default โœจ.
  • -mno-mult-bug โ€” Doesn't generate code to avoid bugs in the multiply instructions for the MN10300 processors ๐Ÿ™ƒ.
  • -mam33 โ€” Generates code using features specific to the AM33 processor ๐ŸŽ€.
  • -mno-am33 โ€” Doesn't generate code using features specific to the AM33 processor. This is the default ๐Ÿ’ค.
  • -mam33-2 โ€” Generates code using features specific to the AM33/2.0 processor ๐ŸŒธ.
  • -mam34 โ€” Generates code using features specific to the AM34 processor ๐Ÿงš.
  • -mtune=cpu-type โ€” Uses the timing characteristics of the indicated CPU type when scheduling instructions ๐Ÿฆ‹. This doesn't change the targeted processor type. The CPU type must be one of mn10300, am33, am33-2, or am34 ๐Ÿ‘‘.

-mreturn-pointer-on-d0 ๐Ÿ’–

Okay so this one is about functions that hand back a pointer ๐ŸŽ€. When GCC generates one of those, it can return the pointer in both "a0" and "d0" ๐Ÿซถ. Otherwise the pointer only goes in "a0", and if you try to call those functions without a prototype, you get errors ๐Ÿ’€. Heads up, this option is on by default โœจ, and if you want it off, use -mno-return-pointer-on-d0 ๐Ÿ’….

  • -mno-crt0 โ€” Skips linking in the C run-time initialization object file ๐Ÿงš
  • -mrelax โ€” Tells the linker to run a relaxation pass โญ that shortens branches, calls and absolute memory addresses. It only does anything when you pass it on the command line for the final link step ๐Ÿ”ฅ
This option makes symbolic debugging impossible ๐Ÿ˜ญ so keep that in mind before you reach for it ๐Ÿ™ˆ
  • -mliw โ€” Lets the compiler generate Long Instruction Word instructions when the target is AM33 or later ๐ŸŒˆ This one is the default ๐Ÿ‘‘. It also defines the preprocessor macro "__LIW__" ๐Ÿ’œ
  • -mno-liw โ€” Stops the compiler from generating Long Instruction Word instructions ๐Ÿ™… It defines the preprocessor macro "__NO_LIW__" ๐Ÿฆ‹
  • -msetlb โ€” Lets the compiler generate SETLB and Lcc instructions when the target is AM33 or later ๐Ÿ“ Also the default ๐Ÿ’–. It defines the preprocessor macro "__SETLB__" โœจ
  • -mno-setlb โ€” No SETLB or Lcc instructions for you ๐Ÿ™ˆ This one defines the preprocessor macro "__NO_SETLB__" ๐ŸŒธ

โœจ Moxie Options โœจ

  • -meb โ€” Generates big-endian code ๐ŸŒธ This is the default for moxie-*-* configurations ๐Ÿ‘‘
  • -mel โ€” Generates little-endian code ๐Ÿซถ
  • -mmul.x โ€” Generates mul.x and umul.x instructions ๐Ÿ’… This is the default for moxiebox-*-* configurations ๐Ÿ”ฅ
  • -mno-crt0 โ€” Skips linking in the C run-time initialization object file ๐Ÿงš

โœจ MSP430 Options โœจ

These options are defined for the MSP430 ๐Ÿ’œ

  • -masm-hex โ€” Forces assembly output to always use hex constants ๐ŸŽ€ Normally these are signed decimals, but this is handy for testsuite and/or aesthetic purposes ๐Ÿฆ‹
  • -mmcu= โ€” Picks the MCU you're targeting ๐ŸŽฏ It creates a C preprocessor symbol based on the MCU name, converted to upper case and wrapped in __ on both ends โœจ The msp430.h header then uses that symbol to pick an MCU-specific supplementary header file ๐Ÿ’–

The option also sets the ISA. If the MCU is one that only supports the 430 ISA, that's the one you get ๐ŸŒˆ Otherwise you get the 430X ISA โญ The generic MCU name msp430 selects the 430 ISA, and the generic msp430x selects the 430X ISA ๐Ÿซถ

An MCU-specific linker script also gets added to the linker command line ๐Ÿ”ฅ Its name is the MCU name with .ld appended. So -mmcu=xxx defines the C preprocessor symbol "__XXX__" and makes the linker search for a script called xxx.ld ๐Ÿ’…

The ISA and hardware multiply support for each MCU is hard-coded into GCC ๐Ÿงš But you can extend device support with an external devices.csv file ๐Ÿฆ‹

GCC looks for devices.csv using these methods, in this precedence order: the first method beats the second, and the second beats the third ๐Ÿ‘‘

  1. Include path specified with "-I" and "-L" โ€” devices.csv gets searched for in each directory given by the include paths and linker library search paths ๐ŸŽ€
  2. Path specified by the environment variable MSP430_GCC_INCLUDE_DIR โ€” Set the global environment variable MSP430_GCC_INCLUDE_DIR to the full path of the directory holding devices.csv, and GCC searches there ๐Ÿ’œ If it finds the file, that directory also gets registered as an include path and linker library path ๐ŸŒธ Header files and linker scripts in there can be used without typing "-I" and "-L" on the command line ๐Ÿ™Œ
  3. The msp430-elf{,bare}/include/devices directory โ€” GCC also checks msp430-elf{,bare}/include/devices from the toolchain root directory ๐Ÿ“ This directory doesn't exist in a default installation ๐Ÿ˜ญ But if you made it and copied devices.csv in there, the MCU data gets read ๐Ÿซถ Same deal as above: it's also registered as an include path and linker library path โœจ

If none of those methods find devices.csv, the hard-coded MCU data is used ๐Ÿ™ˆ

  • -mwarn-mcu / -mno-warn-mcu โ€” Turns warnings on or off about conflicts between the MCU name from -mmcu and the ISA from -mcpu and/or the hardware multiply support from -mhwmult ๐Ÿ”ฅ It also toggles warnings about unrecognized MCU names ๐Ÿ’€ This one 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 ๐Ÿงช It overrides any scripts that -mmcu= would have picked ๐Ÿ‘‘
  • -mlarge โ€” Uses large-model addressing (20-bit pointers, 32-bit "size_t") ๐ŸŒˆ
  • -msmall โ€” Uses small-model addressing (16-bit pointers, 16-bit "size_t") ๐Ÿงš
  • -mrelax โ€” Passed on to the assembler and linker, so the linker can do certain optimizations that can't happen until the final link โญ
  • mhwmult= โ€” Describes the type of hardware multiply the target supports ๐Ÿ’– Accepted values are none for no hardware multiply, 16bit for the original 16-bit-only multiply from early MCUs, 32bit for the 16/32-bit multiply in later MCUs, and f5series for the 16/32-bit multiply in F5-series MCUs ๐Ÿฆ‹ You can also give auto, which tells GCC to figure out the hardware multiply support from the MCU name given with -mmcu ๐Ÿซถ If there's no -mmcu or the MCU name isn't recognized, no hardware multiply support is assumed ๐Ÿ’€ "auto" is the default setting ๐Ÿ‘‘

Hardware multiplies are normally done by calling a library routine, which saves space in the generated code ๐ŸŒธ At -O3 or higher, though, the hardware multiplier gets invoked inline ๐Ÿ”ฅ That makes the code bigger but faster โœจ

The hardware multiply routines disable interrupts while they run and restore the previous interrupt state when they finish ๐Ÿ›ก๏ธ So they're safe to use inside interrupt handlers as well as in normal code ๐Ÿ’…

  • -minrt โ€” Turns on a minimum runtime environment with no static initializers or constructors ๐Ÿ“ It's meant for memory-constrained devices ๐Ÿฅน The compiler puts special symbols in some objects that tell the linker and runtime which code fragments are required ๐Ÿงš
  • -mtiny-printf โ€” Enables reduced code size "printf" and "puts" library functions โœจ The tiny versions aren't reentrant, so be careful with them in multi-threaded apps ๐Ÿ˜ญ

Stream support has been removed, and the string to print always goes to stdout via the "write" syscall ๐ŸŽ€ The string isn't buffered before it's sent to write ๐Ÿ™ˆ

This option requires Newlib Nano IO, so GCC has to be configured with --enable-newlib-nano-formatted-io ๐Ÿ’œ

  • -mcode-region= / -mdata-region= โ€” These tell the compiler where to place functions and data that don't have a "lower", "upper", "either" or "section" attribute ๐ŸŒˆ The possible values are "lower", "upper", "either" or "any" ๐Ÿฆ‹ The first three behave like the matching attribute ๐Ÿ’– The fourth, "any", is the default, and it leaves placement entirely up to the linker script and how it assigns the standard sections (".text", ".data", etc) to memory regions ๐Ÿซถ
  • -msilicon-errata= โ€” Passes a request to the assembler to enable fixes for the named silicon errata ๐Ÿ”ง
  • -msilicon-errata-warn= โ€” Passes a request to the assembler to turn on warning messages when a silicon erratum might need to be applied ๐Ÿšจ
  • -mwarn-devices-csv / -mno-warn-devices-csv โ€” Warns if devices.csv isn't found or there's a problem parsing it (default: on) ๐ŸŒธ

โœจ NDS32 Options โœจ

These options are defined for NDS32 implementations ๐Ÿงš

  • -mbig-endian โ€” Generates code in big-endian mode ๐ŸŒธ
  • -mlittle-endian โ€” Generates code in little-endian mode ๐Ÿซถ
  • -mreduced-regs โ€” Uses reduced-set registers for register allocation ๐Ÿ’…
  • -mfull-regs โ€” Uses full-set registers for register allocation ๐Ÿ‘‘
  • -mcmov โ€” Generates conditional move instructions ๐Ÿฆ‹
  • -mno-cmov โ€” Doesn't generate conditional move instructions ๐Ÿ™ˆ
  • -mext-perf โ€” Generates performance extension instructions โญ
  • -mno-ext-perf โ€” Doesn't generate performance extension instructions ๐Ÿ˜ญ
  • -mext-perf2 โ€” Generates performance extension 2 instructions ๐Ÿ”ฅ
  • -mno-ext-perf2 โ€” Doesn't generate performance extension 2 instructions ๐Ÿ’€
  • -mext-string โ€” Generates string extension instructions ๐ŸŒˆ
  • -mno-ext-string โ€” Doesn't generate string extension instructions ๐Ÿ™…
  • -mv3push โ€” Generates v3 push25/pop25 instructions ๐Ÿงš
  • -mno-v3push โ€” Doesn't generate v3 push25/pop25 instructions ๐Ÿ“
  • -m16-bit โ€” Generates 16-bit instructions ๐Ÿ’–
  • -mno-16-bit โ€” Doesn't generate 16-bit instructions ๐Ÿฆ‹
  • -misr-vector-size=num โ€” Specifies the size of each interrupt vector, which must be 4 or 16 ๐ŸŽ€
  • -mcache-block-size=num โ€” Specifies the size of each cache block, which must be a power of 2 between 4 and 512 ๐Ÿ’œ
  • -march=arch โ€” Specifies the name of the target architecture ๐ŸŒธ
  • -mcmodel=code-model โ€” Sets the code model to one of the following ๐Ÿซถ
    • small โ€” All the data and read-only data segments must be within 512KB of addressing space. The text segment must be within 16MB of addressing space ๐Ÿงธ
    • medium โ€” The data segment must be within 512KB, while the read-only data segment can be within 4GB of addressing space. The text segment should still be within 16MB of addressing space ๐ŸŒˆ
    • large โ€” All the text and data segments can be within 4GB of addressing space ๐Ÿ‘‘
  • -mctor-dtor โ€” Enables the constructor/destructor feature ๐Ÿ”ฅ
  • -mrelax โ€” Guides the linker to relax instructions โญ

โœจ Nios II Options โœจ

okay bestie, this next batch is all about the Altera Nios II processor ๐Ÿงš these are the options that only matter when you're building for that chip, so let's get into it ๐Ÿ’…

  • -G num โ€” this one decides which global and static objects get tucked into the small data or BSS sections ๐ŸŒธ anything less than or equal to num bytes goes there instead of the normal data or BSS sections. the default value of num is 8 โœจ
  • -mgpopt=option, -mgpopt, -mno-gpopt โ€” this is how you turn GP-relative accesses on (or off) ๐Ÿฆ‹ these are the option names it recognizes:
    • none โ€” no GP-relative accesses at all, bye ๐Ÿ‘‹
    • local โ€” GP-relative accesses for small data objects that aren't external, weak, or uninitialized common symbols ๐ŸŽ€ it also uses GP-relative addressing for objects you've explicitly put in a small data section with a "section" attribute.
    • global โ€” same as local, but it also does GP-relative accesses for small data objects that are external, weak, or common ๐Ÿ˜ญ if you pick this one, you must make sure every part of your program (including libraries) is compiled with the same -G setting. no skipping!
    • data โ€” GP-relative accesses for all data objects in the program ๐Ÿ’€
heads up: if you use this, the entire data and BSS segments of your program have to fit in 64K of memory, and you need an appropriate linker script to allocate them within the addressable range of the global pointer.
  • all โ€” GP-relative addresses for function pointers as well as data pointers ๐ŸŒˆ
same energy here: 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 the same as -mgpopt=local, and -mno-gpopt is the same as -mgpopt=none ๐Ÿ™Œ the default is -mgpopt, except when you specify -fpic or -fPIC to make position-independent code. also, the Nios II ABI doesn't allow GP-relative accesses from shared libraries, so don't try it ๐Ÿ™… You might need to specify -mno-gpopt explicitly when you're building programs with a ton of small data, including large GOT data sections ๐Ÿฅบ in that case the 16-bit offset for GP-relative addressing might not be big enough to reach the entire small data section.

  • -mgprel-sec=regexp โ€” this 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. this option doesn't change how -G behaves, and the sections you list are in addition to the standard ".sdata" and ".sbss" small-data sections that -mgpopt already recognizes.
  • -mr0rel-sec=regexp โ€” this one names sections that can be accessed via a 16-bit offset from "r0", so basically the low 32K or high 32K of the 32-bit address space ๐Ÿง  it's most useful with "section" attributes on variable declarations and a custom linker script. the regexp is a POSIX Extended Regular Expression. Lowkey different from the GP-relative stuff: zero-based addressing is never generated by default, and there are no conventional section names used in standard linker scripts for sections in the low or high areas of memory ๐Ÿ™ƒ
  • -mel, -meb โ€” generates little-endian (the default) or big-endian (experimental) code, respectively ๐Ÿงช
  • -march=arch โ€” this sets the name of the target Nios II architecture ๐Ÿ›๏ธ GCC uses it to figure out what kinds of instructions it can emit when generating assembly code. the permissible names are: r1, r2. The preprocessor macro "__nios2_arch__" is available to your programs, with the value 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 I/O variants of the instructions ๐Ÿƒโ€โ™€๏ธ the default is not to bypass the cache.
  • -mno-cache-volatile, -mcache-volatile โ€” volatile memory access bypasses the cache using the I/O variants of the load and store instructions โšก the default is not to bypass the cache.
  • -mno-fast-sw-div, -mfast-sw-div โ€” -mno-fast-sw-div means don't use table-based fast divide for small numbers ๐Ÿ™…โ€โ™€๏ธ the default is to use the fast divide at -O3 and above.
  • -mno-hw-mul, -mhw-mul, -mno-hw-mulx, -mhw-mulx, -mno-hw-div, -mhw-div โ€” these enable or disable the compiler emitting the "mul", "mulx", and "div" family 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 ๐Ÿ’œ enabling these also requires -march=r2. since they're optional extensions to the R2 architecture, the default is not to emit them.
  • -mcustom-insn=N, -mno-custom-insn โ€” each -mcustom-insn=N option enables use of a custom instruction with encoding N when generating code that uses insn ๐Ÿฆ‹ for example, -mcustom-fadds=253 generates custom instruction 253 for single-precision floating-point add operations, instead of the default behavior of using a library call. The following values of insn are supported. Except as otherwise noted, floating-point operations are expected to be implemented with normal IEEE 754 semantics and 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 are only generated if -ffinite-math-only is specified.
      • fsqrts โ€” unary square root operation.
      • fcoss, fsins, ftans, fatans, fexps, flogs โ€” floating-point trigonometric and exponential functions. these are only generated if -funsafe-math-optimizations is also specified.
    • Double-precision floating point:
      • faddd, fsubd, fdivd, fmuld โ€” binary arithmetic operations.
      • fnegd โ€” unary negation.
      • fabsd โ€” unary absolute value.
      • fcmpeqd, fcmpged, fcmpgtd, fcmpled, fcmpltd, fcmpned โ€” comparison operations.
      • fmind, fmaxd โ€” double-precision minimum and maximum. these are only generated if -ffinite-math-only is specified.
      • fsqrtd โ€” unary square root operation.
      • fcosd, fsind, ftand, fatand, fexpd, flogd โ€” double-precision trigonometric and exponential functions. these are only generated if -funsafe-math-optimizations is also specified.
    • Conversions:
      • fextsd โ€” conversion from single precision to double precision.
      • ftruncds โ€” conversion from double precision to single precision.
      • fixsi, fixsu, fixdi, fixdu โ€” conversion from floating point to signed or unsigned integer types, with truncation towards zero.
      • round โ€” conversion from single-precision floating point to signed integer, rounding to the nearest integer and ties away from zero. this corresponds to the "__builtin_lroundf" function when -fno-math-errno is used.
      • floatis, floatus, floatid, floatud โ€” conversion from signed or unsigned integer types to floating-point types.
    • Transfer instructions for internal registers X and Y: you have to provide all of these to use any of the double-precision floating-point instructions ๐Ÿ˜ค custom instructions taking two double-precision source operands expect the first operand in the 64-bit register X. the other operand (or 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, so you don't have to do it yourself ๐Ÿซถ
      • fwrx โ€” write src1 into the least significant half of X and src2 into the most significant half of X.
      • fwry โ€” write src1 into Y.
      • frdxhi, frdxlo โ€” read the most or least (respectively) significant half of X and store it in dest.
      • frdy โ€” read the value of Y and store it into dest.

Note that you can gain more local control over generation of Nios II custom instructions by using the target("custom-insn=N") and target("no-custom-insn") function attributes or pragmas ๐ŸŽ€

  • -mcustom-fpu-cfg=name โ€” this enables a predefined, named set of custom instruction encodings (see -mcustom-insn above) โœจ right now, these sets are defined:
    • -mcustom-fpu-cfg=60-1 is equivalent to: -mcustom-fmuls=252 -mcustom-fadds=253 -mcustom-fsubs=254 -fsingle-precision-constant
    • -mcustom-fpu-cfg=60-2 is equivalent to: -mcustom-fmuls=252 -mcustom-fadds=253 -mcustom-fsubs=254 -mcustom-fdivs=255 -fsingle-precision-constant
    • -mcustom-fpu-cfg=72-3 is equivalent to: -mcustom-floatus=243 -mcustom-fixsi=244 -mcustom-floatis=245 -mcustom-fcmpgts=246 -mcustom-fcmples=249 -mcustom-fcmpeqs=250 -mcustom-fcmpnes=251 -mcustom-fmuls=252 -mcustom-fadds=253 -mcustom-fsubs=254 -mcustom-fdivs=255 -fsingle-precision-constant

Custom instruction assignments given by individual -mcustom-insn= options override those given by -mcustom-fpu-cfg=, regardless of the order of the options on the command line ๐Ÿ‘‘ and you can gain more local control over selection of an FPU configuration by using the target("custom-fpu-cfg=name") function attribute or pragma ๐ŸŒธ


These additional -m options are available for the Altera Nios II ELF (bare-metal) target:

  • -mhal โ€” ๐Ÿ’– Links with the HAL BSP! This skips the GCC-provided C runtime startup and termination code, and it's usually paired with -msys-crt0= to point at the alternate startup code that comes with the HAL BSP. ๐Ÿฆ‹
  • -msmallc โ€” ๐ŸŒธ Links with a slimmed-down C library, -lsmallc, instead of Newlib. โœจ
  • -msys-crt0=startfile โ€” ๐Ÿงš startfile is the file name of the startfile (crt0) you want to use while linking. This one's only useful together with -mhal. ๐Ÿ’…
  • -msys-lib=systemlib โ€” ๐Ÿซถ systemlib is the library name for the library that provides the low-level system calls the C library needs, like "read" and "write". You'll usually use this to link with a library provided by a HAL BSP. ๐Ÿ”ฅ

โœจ Nvidia PTX Options โœจ

These options are defined for Nvidia PTX: ๐Ÿ’š

  • -m32, -m64 โ€” Generates code for the 32-bit or 64-bit ABI. ๐ŸŽ€
  • -misa=ISA-string โ€” Generates code for the specific PTX ISA you pick (e.g. sm_35). ISA strings must be lower-case! Valid ISA strings include sm_30 and sm_35, and the default is sm_30. ๐Ÿ‘‘
  • -mmainkernel โ€” Links in code for a __main kernel. This is for stand-alone execution instead of offloading execution. ๐Ÿฆ‹
  • -moptimize โ€” Applies partitioned execution optimizations. This is the default whenever any level of optimization is selected. โœจ
  • -msoft-stack โ€” Generates code that doesn't use ".local" memory directly for stack storage. Instead, a per-warp stack pointer is maintained explicitly. This enables variable-length stack allocation (with variable-length arrays or "alloca"), and when global memory is the underlying storage, it makes it possible to access automatic variables from other threads, or with atomic instructions. This code generation variant is used for OpenMP offloading, but the option is exposed on its own so you can test the compiler. To generate code that's suitable for linking into programs using OpenMP offloading, use option -mgomp. ๐Ÿง ๐Ÿ’œ
  • -muniform-simt โ€” Switches to a code generation variant that lets all threads in each warp execute, while keeping memory state and side effects as if only one thread in each warp was active outside OpenMP SIMD regions. All atomic operations and calls to the runtime (malloc, free, vprintf) are conditionally executed (iff current lane index equals the master lane index), and the register being assigned is copied via a shuffle instruction from the master lane. Outside of SIMD regions, lane 0 is the master; inside, each thread sees itself as the master. The shared memory array int __nvptx_uni[] stores all-zeros or all-ones bitmasks for each warp, indicating the current mode (0 outside of SIMD regions). Each thread can bitwise-and the bitmask at position tid.y with the current lane index to compute the master lane index. ๐ŸŒˆ
  • -mgomp โ€” Generates code for use in OpenMP offloading: it enables -msoft-stack and -muniform-simt, and selects the corresponding multilib variant. ๐Ÿ”ฅ

โœจ OpenRISC Options โœจ

These options are defined for OpenRISC: ๐ŸŒธ

  • -mboard=name โ€” Configures a board-specific runtime. This gets passed to the linker for newlib board library linking. The default is "or1ksim". ๐Ÿ“
  • -mnewlib โ€” This option is ignored; it's just here for compatibility purposes. It used to select linker and preprocessor options for use with 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 enables generation of double-precision floating point instructions. By default, functions from libgcc are used to perform double-precision floating point operations. ๐Ÿ’…
  • -munordered-float โ€” When -mhard-float is selected, this enables generation of unordered floating point compare and set flag (lf.sfun*) instructions. By default, functions from libgcc are used to perform unordered floating point compare and set flag operations. ๐Ÿ’…
  • -mcmov โ€” Enables generation of conditional move (l.cmov) instructions. By default, the equivalent is generated using set and branch. ๐Ÿฆ‹
  • -mror โ€” Enables generation of rotate right (l.ror) instructions. By default, functions from libgcc are used to perform rotate right operations. ๐ŸŒ€
  • -mrori โ€” Enables generation of rotate right with immediate (l.rori) instructions. By default, functions from libgcc are used to perform rotate right with immediate operations. ๐ŸŒ€
  • -msext โ€” Enables generation of sign extension (l.ext*) instructions. By default, memory loads are used to perform sign extension. ๐Ÿซถ
  • -msfimm โ€” Enables generation of compare and set flag with immediate (l.sf*i) instructions. By default, extra instructions are generated to store the immediate to a register first. ๐Ÿ˜ญ
  • -mshftimm โ€” Enables generation of shift with immediate (l.srai, l.srli, l.slli) instructions. By default, extra instructions are generated to store the immediate to 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 is not supported.) Implies -m45. ๐Ÿ”ฅ
  • -msoft-float โ€” Doesn't use hardware floating point. ๐Ÿ™…โ€โ™€๏ธ
  • -mac0 โ€” Returns floating-point results in ac0 (fr0 in Unix assembler syntax). ๐ŸŽ€
  • -mno-ac0 โ€” Returns floating-point results in memory. This is the default. ๐Ÿ’œ
  • -m40 โ€” Generates code for a PDP-11/40. Implies -msoft-float -mno-split. ๐Ÿ“
  • -m45 โ€” Generates code for a PDP-11/45. This is the default. ๐Ÿ‘‘
  • -m10 โ€” Generates code for a PDP-11/10. Implies -msoft-float -mno-split. ๐Ÿ“
  • -mint16, -mno-int32 โ€” Uses 16-bit "int". This is the default. โœจ
  • -mint32, -mno-int16 โ€” Uses 32-bit "int". โœจ
  • -msplit โ€” The target has split instruction and data space. Implies -m45. ๐Ÿฆ‹
  • -munix-asm โ€” Uses Unix assembler syntax. ๐Ÿงš
  • -mdec-asm โ€” Uses DEC assembler syntax. ๐Ÿงš
  • -mgnu-asm โ€” Uses GNU assembler syntax. This is the default. ๐ŸŒˆ
  • -mlra โ€” Uses the new LRA register allocator. By default, the old "reload" allocator is used. ๐Ÿง 

โœจ picoChip Options โœจ

These -m options are defined for picoChip implementations: ๐Ÿฉต

  • -mae=ae_type โ€” Sets the instruction set, register set, and instruction scheduling parameters for array element type ae_type. Supported values for ae_type are ANY, MUL, and MAC. ๐Ÿ’–
    • -mae=ANY โ€” Selects a completely generic AE type. Code generated with this option runs on any of the other AE types. The code isn't as efficient as it would be if compiled for a specific AE type, and some types of operation (e.g., multiplication) don't work properly on all types of AE. ๐Ÿ˜ฌ
    • -mae=MUL โ€” Selects a MUL AE type. This is the most useful AE type for compiled code, and it's the default. ๐Ÿ‘‘
    • -mae=MAC โ€” Selects a DSP-style MAC AE. Code compiled with this option may suffer from poor performance of byte (char) manipulation, since the DSP AE doesn't provide hardware support for byte load/stores. ๐Ÿ’€
  • -msymbol-as-address โ€” Lets the compiler directly use a symbol name as an address in a load/store instruction, without first loading it into a register. This usually generates larger programs that run faster than when the option isn't used. However, the results vary from program to program, so it's left as a user option rather than being permanently enabled. ๐Ÿซถ
  • -mno-inefficient-warnings โ€” Disables warnings about the generation of inefficient code. These warnings can be generated, for example, when compiling code that performs byte-level memory operations on the MAC AE type. The MAC AE has no hardware support for byte-level memory operations, so all byte load/stores must be synthesized from word load/store operations. This is inefficient, and a warning is generated to tell you to rewrite the code to avoid byte operations, or to target an AE type that has the necessary hardware support. This option turns those warnings off. ๐Ÿ™ˆ

โœจ PowerPC Options โœจ

These are listed under

โœจ PRU Options โœจ

These command-line options are defined for PRU target: ๐Ÿงš

  • -minrt โ€” Links with a minimum runtime environment, with no support for static initializers and constructors. Using this can significantly reduce the size of the final ELF binary. Beware: the compiler could still generate code with static initializers and constructors, so it's up to the programmer to make sure the source program won't use those features. โš ๏ธ
  • -mmcu=mcu โ€” Specifies the PRU MCU variant to use. Check Newlib for the exact list of supported MCUs. ๐ŸŽ€
  • -mno-relax โ€” Makes GCC pass the --no-relax command-line option to the linker instead of the --relax option. ๐Ÿฆ‹
  • -mloop โ€” Allows (or does not allow) GCC to use the LOOP instruction. ๐ŸŒธ
  • -mabi=variant โ€” Specifies the ABI variant to output code for. -mabi=ti selects the unmodified TI ABI, while -mabi=gnu selects a GNU variant that copes more naturally with certain GCC assumptions. These are the differences: ๐Ÿ‘‘
    • Function Pointer Size โ€” TI ABI specifies that function (code) pointers are 16-bit, whereas GNU supports only 32-bit data and code pointers. ๐Ÿง 
    • Optional Return Value Pointer โ€” Function return values larger than 64 bits are passed by using a hidden pointer as the first argument of the function. TI ABI, though, mandates that the pointer can be NULL in case the caller is not using the returned value. GNU always passes and expects a valid return value pointer. ๐Ÿง 

The current -mabi=ti implementation simply raises a compile error when any of the above code constructs is detected. As a consequence, the standard C library cannot be built, and it is omitted when linking with -mabi=ti. ๐Ÿ’€

Relaxation is a GNU feature and, for safety reasons, is disabled when using -mabi=ti. The TI toolchain does not emit relocations for QBBx instructions, so the GNU linker cannot adjust them when shortening adjacent LDI32 pseudo instructions. ๐Ÿ™ˆ

โœจ RISC-V Options โœจ

These command-line options are defined for RISC-V targets: ๐ŸŒˆ

  • -mbranch-cost=n โ€” okay so this one 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, and the default is -mplt ๐ŸŒธ
  • -mabi=ABI-string โ€” this sets the integer and floating-point calling convention, and the vibe is very specific ๐ŸŽ€ The ABI-string has two parts: the size of integer types, and which registers get used for floating-point types.
    • For example, -march=rv64ifd -mabi=lp64d means long and pointers are 64-bit (which implicitly makes int 32-bit), and floating-point values up to 64 bits wide get passed in F registers ๐Ÿ’–
    • Now contrast that with -march=rv64ifd -mabi=lp64f. The compiler can still generate code that uses the F and D extensions, but only floating-point values up to 32 bits long get passed in registers ๐Ÿฅบ
    • Or 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, you should specify one explicitly, bestie ๐Ÿซถ The valid calling conventions are: ilp32, ilp32f, ilp32d, lp64, lp64f, and lp64d. Some of them are literally 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.

๐Ÿ’€ Warning: the ilp32e ABI is not well specified at present, and it is subject to change. Don't get too attached to it yet ๐Ÿ˜ญ
  • -mfdiv, -mno-fdiv โ€” do or don't use hardware floating-point divide and square root instructions ๐Ÿ”ฅ This needs the F or D extensions for floating-point registers. The default is to use them if the specified architecture has these instructions โœจ
  • -mdiv, -mno-div โ€” do or don't use hardware instructions for integer division ๐Ÿงš This needs the M extension. The default is to use them if the specified architecture has these instructions ๐Ÿ’œ
  • -march=ISA-string โ€” generates code for the given RISC-V ISA, like rv64im ๐ŸŒˆ ISA strings must be lower-case, no exceptions, no cap. Examples include rv64i, rv32g, rv32e, and rv32imaf ๐Ÿ‘‘
  • -mtune=processor-string โ€” optimizes the output for the processor you pick, by microarchitecture name ๐Ÿ“ The permissible values for this option are: rocket, sifive-3-series, sifive-5-series, sifive-7-series, and size.
    • When -mtune= isn't specified, the default is rocket โญ
    • The size choice is not intended for end-users, honestly. It's used when -Os is specified. It overrides the instruction cost info provided by -mtune=, but it does not override the pipeline info. This helps reduce code size while still giving good performance ๐Ÿฆ‹
  • -mpreferred-stack-boundary=num โ€” attempts to keep the stack boundary aligned to a 2 raised to num byte boundary ๐ŸŽ€ If -mpreferred-stack-boundary isn't specified, the default is 4 (16 bytes, or 128-bits).
๐Ÿ’€ Warning: if you use this switch, then you must build all modules with the same value, including any libraries. This includes the system libraries and startup modules. No skipping, periodt ๐Ÿ˜ญ
  • -msmall-data-limit=n โ€” puts global and static data smaller than n bytes into a special section (on some targets) ๐ŸŒธ
  • -msave-restore, -mno-save-restore โ€” do or don't use smaller but slower prologue and epilogue code that uses library function calls ๐Ÿข The default is to use fast inline prologues and epilogues โšก
  • -mstrict-align, -mno-strict-align โ€” toggles whether unaligned memory accesses are generated, which is giving "do not" vs "do" energy ๐Ÿ™ƒ 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 โ€” uses or doesn'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 required to materialize symbol addresses โšก The default is to take advantage of linker relaxations ๐Ÿ’…
  • -memit-attribute, -mno-emit-attribute โ€” emits (or doesn't emit) a RISC-V attribute to record extra information into ELF objects ๐Ÿ“ฆ This feature requires at least binutils 2.32 ๐Ÿซถ
  • -malign-data=type โ€” controls how GCC aligns variables and constants of array, structure, or union types ๐Ÿ“ The supported values for type are xlen, which uses the x register width as the alignment value, and natural, which uses natural alignment. xlen is the default ๐Ÿ’œ

๐ŸŒธ RL78 Options ๐ŸŒธ

  • -msim โ€” links in additional target libraries so you can run inside a simulator ๐ŸŽฎ
  • -mmul=none, -mmul=g10, -mmul=g13, -mmul=g14, -mmul=rl78 โ€” picks the type of hardware multiplication and division support to use ๐Ÿงฎ
    • The simplest one 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 use of the multiplication and division instructions supported by the RL78/G14 (S3 core) parts โญ
    • The value "rl78" is an alias for "g14", and the value "mg10" is an alias for "none" ๐Ÿฆ‹

Also, a C preprocessor macro gets defined based on the setting of this option. 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 these operations ๐Ÿ› ๏ธ
    • The G10 or S1 core doesn't have register banks, so it uses a different calling convention ๐Ÿ™ˆ

If this option is set, it also selects the type of hardware multiply support to use, unless you override that with an explicit -mmul=none option on the command line. So -mcpu=g13 enables the use of the G13 hardware multiply peripheral, and -mcpu=g10 disables hardware multiplications altogether ๐Ÿ’…

Note: even though the RL78/G14 core is the default target, specifying -mcpu=g14 or -mcpu=rl78 on the command line does change the behavior of the toolchain, since it also enables G14 hardware multiply support ๐Ÿ”ฅ If these options aren't specified on the command line, software multiplication routines get used even though the code targets the RL78 core. This is for backwards compatibility with older toolchains that didn't have hardware multiply and divide support ๐Ÿฅน

And yes, a C preprocessor macro gets defined based on this option too. The possible values are: "__RL78_G10__", "__RL78_G13__", or "__RL78_G14__" ๐Ÿ’–

  • -mg10, -mg13, -mg14, -mrl78 โ€” these are aliases for the corresponding -mcpu= option, kept around for backwards compatibility ๐Ÿ•ฐ๏ธ
  • -mallregs โ€” lets the compiler use all of the available registers ๐ŸŒˆ By default, registers r24..r31 are reserved for use in interrupt handlers. With this option enabled, those registers can be used in ordinary functions as well โœจ
  • -m64bit-doubles, -m32bit-doubles โ€” makes the "double" data type 64 bits (-m64bit-doubles) or 32 bits (-m32bit-doubles) in size ๐Ÿ“ The default is -m32bit-doubles ๐Ÿ’…
  • -msave-mduc-in-interrupts, -mno-save-mduc-in-interrupts โ€” specifies that interrupt handler functions should preserve the MDUC registers ๐Ÿ›ก๏ธ This is only necessary if normal code might use the MDUC registers, for example because it performs multiplication and division operations. The default is to ignore the MDUC registers, because that makes the interrupt handlers faster ๐Ÿƒโ€โ™€๏ธ The target option -mg13 needs to be passed for this to work, since this feature is only available on the G13 target (S2 core) ๐Ÿซถ The MDUC registers only get saved if the interrupt handler performs a multiplication or division operation, or if it calls another function.

๐Ÿฆ‹ IBM RS/6000 and PowerPC Options ๐Ÿฆ‹

These -m options are defined for the IBM RS/6000 and PowerPC ๐Ÿ’œ

  • -mpowerpc-gpopt, -mno-powerpc-gpopt โ€” one of the instruction-availability switches ๐ŸŒŸ
  • -mpowerpc-gfxopt, -mno-powerpc-gfxopt โ€” one of the instruction-availability switches ๐ŸŒŸ
  • -mpowerpc64, -mno-powerpc64 โ€” one of the instruction-availability switches ๐ŸŒŸ
  • -mmfcrf, -mno-mfcrf โ€” one of the instruction-availability switches ๐ŸŒŸ
  • -mpopcntb, -mno-popcntb โ€” one of the instruction-availability switches ๐ŸŒŸ
  • -mpopcntd, -mno-popcntd โ€” one of the instruction-availability switches ๐ŸŒŸ
  • -mfprnd, -mno-fprnd โ€” one of the instruction-availability switches ๐ŸŒŸ
  • -mcmpb, -mno-cmpb โ€” one of the instruction-availability switches ๐ŸŒŸ
  • -mhard-dfp, -mno-hard-dfp โ€” one of the instruction-availability switches ๐ŸŒŸ

You use these options to specify which instructions are available on the processor you're using ๐Ÿ–ฅ๏ธ The default value of these options is determined when configuring GCC. Specifying -mcpu=cpu_type overrides the specification of these options. We recommend you use the -mcpu=cpu_type option rather than the options listed above, bestie ๐Ÿซถ

Specifying -mpowerpc-gpopt allows GCC to use the optional PowerPC architecture instructions in the General Purpose group, including floating-point square root โœจ Specifying -mpowerpc-gfxopt allows GCC to use the optional PowerPC architecture instructions in the Graphics group, including floating-point select ๐ŸŽ€

I'm going to start with the PowerPC ISA flags and the rest of the CPU-tuning goodies, bestie ๐Ÿ’–

  • -mmfcrf โ€” okay so this one lets GCC generate the move from condition register field instruction ๐Ÿฆ‹. It's on the POWER4 processor and any other chip that supports the PowerPC V2.01 architecture โœจ
  • -mpopcntb โ€” lets GCC generate the popcount and double-precision FP reciprocal estimate instruction ๐ŸŒธ. Lives on the POWER5 processor and other chips with the PowerPC V2.02 architecture ๐Ÿ’œ
  • -mpopcntd โ€” lets GCC generate the popcount instruction ๐Ÿซถ. It's on the POWER7 processor and other chips with the PowerPC V2.06 architecture ๐Ÿ‘‘
  • -mfprnd โ€” lets GCC generate the FP round to integer instructions ๐Ÿ”ฅ. Found on the POWER5+ processor and other chips with the PowerPC V2.03 architecture ๐ŸŒˆ
  • -mcmpb โ€” lets GCC generate the compare bytes instruction โญ. It's on the POWER6 processor and other chips with the PowerPC V2.05 architecture ๐Ÿงš
  • -mhard-dfp โ€” lets GCC generate the decimal floating-point instructions ๐Ÿ“. These show up on some POWER processors, so not every chip gets them ๐Ÿ™ˆ
  • -mpowerpc64 โ€” unlocks the extra 64-bit instructions from the full PowerPC64 architecture ๐Ÿ’…. It also treats GPRs as 64-bit, doubleword quantities. GCC defaults to -mno-powerpc64, so you have to ask for it ๐ŸŽ€

๐Ÿ‘‘ -mcpu=cpu_type

This one sets the architecture type, register usage, and instruction scheduling parameters for the machine type cpu_type ๐Ÿ’–. The supported values are:

401, 403, 405, 405fp, 440, 440fp, 464, 464fp, 476, 476fp, 505,
601, 602, 603, 603e, 604, 604e, 620, 630, 740, 7400, 7450, 750, 801,
821, 823, 860, 970, 8540, a2, e300c2, e300c3, e500mc, e500mc64,
e5500, e6500, ec603e, G3, G4, G5, titan, power3, power4, power5,
power5+, power6, power6x, power7, power8, power9, power10, powerpc,
powerpc64, powerpc64le, rs64, and native

-mcpu=powerpc, -mcpu=powerpc64, and -mcpu=powerpc64le are the generic ones ๐ŸŒธ. They give you pure 32-bit PowerPC (either endian), 64-bit big endian PowerPC, and 64-bit little endian PowerPC machine types. A generic processor model gets assumed for scheduling, so it's not chasing one specific chip โœจ

Specifying native as the CPU type is main character energy ๐Ÿ’…. GCC detects the host processor of the system doing the compiling and picks the matching architecture option. -mcpu=native does absolutely nothing if GCC doesn't recognize the processor ๐Ÿ™ˆ

The other options point at one specific processor. Code generated for that chip runs its best there, and it may not run at all on others ๐Ÿ‘€

Heads up bestie: code tuned for one specific chip may not run at all on other chips ๐Ÿ’€

The -mcpu options automatically enable or disable the following options ๐Ÿฆ‹:

-maltivec  -mfprnd  -mhard-float  -mmfcrf  -mmultiple -mpopcntb
-mpopcntd  -mpowerpc64 -mpowerpc-gpopt  -mpowerpc-gfxopt -mmulhw
-mdlmzb  -mmfpgpr  -mvsx -mcrypto  -mhtm  -mpower8-fusion
-mpower8-vector -mquad-memory  -mquad-memory-atomic  -mfloat128
-mfloat128-hardware -mprefixed -mpcrel -mmma

The exact set for each CPU changes between compiler versions ๐ŸŒˆ. It depends on what GCC thinks makes the best code for that chip, so it doesn't always match what the hardware can actually do ๐Ÿคทโ€โ™€๏ธ. If you want to set one option by hand, put it after the -mcpu option, like -mcpu=970 -mno-altivec ๐Ÿ’œ

On AIX, -maltivec and -mpowerpc64 aren't turned on or off by -mcpu right now ๐Ÿ“. That's because AIX doesn't fully support those options yet. You can still enable or disable them one at a time if you're sure it'll work in your environment โœจ

  • -mtune=cpu_type โ€” this sets only the instruction scheduling parameters for cpu_type ๐ŸŽ€. It doesn't touch the architecture type or register usage the way -mcpu=cpu_type does. The same values work for -mtune as for -mcpu. If you use both, the code keeps the architecture and registers from -mcpu, but the scheduling comes from -mtune ๐Ÿ’…
  • -mcmodel=small โ€” generates PowerPC64 code for the small model ๐Ÿงš. The TOC is limited to 64k
  • -mcmodel=medium โ€” generates PowerPC64 code for the medium model ๐ŸŒธ. The TOC and other static data can total up to 4G in size. This is the default for 64-bit Linux ๐Ÿ‘‘
  • -mcmodel=large โ€” generates PowerPC64 code for the large model ๐ŸŒˆ. The TOC can be up to 4G in size. Other data and code is only limited by the 64-bit address space โญ
  • -maltivec, -mno-altivec โ€” generates code that uses (or doesn't use) AltiVec instructions ๐Ÿ”ฅ. It also turns on 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 like vec_splat, vec_extract, and vec_insert matches the array element order for the target's endianness ๐Ÿ’…. Element zero is the leftmost element in a vector register on a big-endian target. On a little-endian target, element zero is the rightmost element in a vector register ๐Ÿ™ˆ

  • -mvrsave, -mno-vrsave โ€” generates VRSAVE instructions when generating AltiVec code ๐Ÿฆ‹
  • -msecure-plt โ€” generates code that lets ld and ld.so build executables and shared libraries with non-executable .plt and .got sections ๐Ÿ”. This is a PowerPC 32-bit SYSV ABI option ๐ŸŽ€
  • -mbss-plt โ€” generates code that uses a BSS .plt section that ld.so fills in ๐ŸŒธ. It needs .plt and .got sections that are both writable and executable ๐Ÿ’€. This is also a PowerPC 32-bit SYSV ABI option โœจ
  • -misel, -mno-isel โ€” enables or disables the generation of ISEL instructions ๐Ÿงš
  • -mvsx, -mno-vsx โ€” generates code that uses (or doesn't use) vector/scalar (VSX) instructions ๐ŸŒˆ. It also enables built-in functions for more direct access to the VSX instruction set ๐Ÿ‘‘
  • -mcrypto, -mno-crypto โ€” enables (or disables) the built-in functions for direct access to the cryptographic instructions added in version 2.07 of the PowerPC ISA ๐Ÿ”ฅ
  • -mhtm, -mno-htm โ€” enables (or disables) the built-in functions for direct access to the Hardware Transactional Memory (HTM) instructions added in version 2.07 of the PowerPC ISA ๐Ÿ’œ
  • -mpower8-fusion, -mno-power8-fusion โ€” the first one keeps some integer operations adjacent so they can be fused together on POWER8 and later processors ๐Ÿ“. The second one does not 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 64-bit mode ๐Ÿงš
  • -mquad-memory-atomic, -mno-quad-memory-atomic โ€” generates code that uses (or doesn't use) the atomic quad word memory instructions ๐ŸŒธ. The -mquad-memory-atomic option requires 64-bit mode too ๐Ÿ‘‘
  • -mfloat128, -mno-float128 โ€” enables or disables the __float128 keyword for IEEE 128-bit floating point ๐ŸŒˆ. It also picks whether IEEE 128-bit floating point uses software emulation or hardware instructions โœจ

The VSX instruction set (-mvsx) has to be enabled before you can use IEEE 128-bit floating point support ๐Ÿซถ. This support is only available on Linux ๐Ÿง

The default for -mfloat128 is enabled on PowerPC Linux systems that use the VSX instruction set ๐Ÿ’–. It's disabled on other systems ๐Ÿ™ˆ

If you use the ISA 3.0 instruction set (-mpower9-vector or -mcpu=power9) on a 64-bit system, IEEE 128-bit floating point support also enables the generation of ISA 3.0 IEEE 128-bit floating point instructions ๐Ÿ”ฅ. If you don't ask for ISA 3.0 instructions, or you're targeting a 32-bit big endian system, IEEE 128-bit floating point gets done with software emulation instead ๐Ÿฆ‹

  • -mfloat128-hardware, -mno-float128-hardware โ€” enables or disables using ISA 3.0 hardware instructions to support the __float128 data type ๐Ÿ’œ

The default for -mfloat128-hardware is enabled on PowerPC Linux systems using the ISA 3.0 instruction set ๐ŸŒˆ. It's disabled on other systems ๐Ÿ“

  • -m32, -m64 โ€” generates code for 32-bit or 64-bit environments on Darwin and SVR4 targets (including GNU/Linux) ๐Ÿงš. The 32-bit environment sets int, long, and pointer to 32 bits, and generates code that runs on any PowerPC variant ๐ŸŽ€. The 64-bit environment sets int to 32 bits and long and pointer to 64 bits, and generates code for PowerPC64, as for -mpowerpc64 ๐Ÿ‘‘
  • -mfull-toc, -mno-fp-in-toc, -mno-sum-in-toc, -mminimal-toc โ€” these change how the TOC (Table Of Contents) gets generated ๐Ÿ“–. Every executable file gets one. -mfull-toc is selected by default ๐Ÿ’…. In that case, GCC allocates at least one TOC entry for each unique non-automatic variable reference in your program ๐Ÿซถ. GCC also puts floating-point constants in the TOC ๐ŸŒธ. The catch is that only 16,384 entries are available in the TOC ๐Ÿ˜ญ

If the linker throws an error saying you've overflowed the available TOC space, you can shrink the TOC usage with -mno-fp-in-toc and -mno-sum-in-toc ๐Ÿ™. -mno-fp-in-toc stops GCC from putting floating-point constants in the TOC ๐Ÿฆ‹. -mno-sum-in-toc makes GCC generate code that calculates the sum of an address and a constant at run time, instead of stuffing that sum into the TOC โœจ. You can use one or both of them. Each one makes the code very slightly slower and larger, but it saves TOC space ๐Ÿ’œ

If you still run out of TOC space even with both of those options, try -mminimal-toc instead ๐Ÿงš. It makes only one TOC entry for every file ๐ŸŒˆ. The code is slower and larger, but it uses extremely little TOC space ๐Ÿ“. You might only want to use it on files that have less frequently-executed code ๐Ÿฅบ

  • -maix64, -maix32 โ€” okay so this one flips the 64-bit AIX ABI and calling convention on or off ๐Ÿ’…. You get 64-bit pointers, a 64-bit long type, and all the infrastructure needed to make them work ๐Ÿ”ฅ. -maix64 implies -mpowerpc64, while -maix32 turns the 64-bit ABI off and implies -mno-powerpc64. Also, GCC defaults to -maix32 ๐ŸŒธ
  • -mxl-compat, -mno-xl-compat โ€” this one is giving IBM XL compiler energy ๐ŸŽ€ When you're using the AIX-compatible ABI, it makes the output match XL semantics more closely. That means floating-point args to prototyped functions past the register save area (RSA) go on the stack too, not just in the argument FPRs. It also means GCC won't assume the most significant double in a 128-bit long double is properly rounded when comparing and converting to double, and it uses XL symbol names for the long double support routines โœจ

The AIX calling convention got extended without any initial docs to handle an obscure K&R C situation: calling a function that takes the address of its arguments with fewer arguments than it declares ๐Ÿ™ˆ IBM XL compilers read floating-point args that don't fit in the RSA from the stack when a subroutine is compiled without optimization. Always storing FP args on the stack is inefficient and rarely needed, so this option is not on by default ๐Ÿ’€ You only really need it when calling subroutines compiled by IBM XL compilers without optimization.

  • -mpe โ€” main character energy for the IBM RS/6000 SP Parallel Environment (PE) ๐Ÿ‘‘ It links your message-passing app with special startup code so it can actually run. The system needs PE installed in the standard location (/usr/lpp/ppe.poe/), or you need to override the specs file with -specs= to point at the right directory ๐Ÿงš Also, PE doesn't do threads, so -mpe and -pthread are incompatible ๐Ÿ˜ญ
  • -malign-natural, -malign-power โ€” on AIX, 32-bit Darwin, and 64-bit PowerPC GNU/Linux, -malign-natural overrides the ABI's alignment for bigger types (like floating-point doubles) and puts them on their natural size-based boundary ๐Ÿฆ‹ -malign-power tells GCC to follow the ABI's alignment rules instead. The default is the standard alignment defined in the ABI ๐Ÿ’œ

On 64-bit Darwin, natural alignment is already the default, and -malign-power is not supported ๐Ÿ™…โ€โ™€๏ธ

  • -msoft-float, -mhard-float โ€” -msoft-float generates code that does not use the floating-point register set, and -mhard-float generates code that does use it ๐Ÿซถ With -msoft-float, software floating-point emulation is provided, but you have to pass the option to GCC when linking too, so don't forget that bestie ๐Ÿ”ฅ
  • -mmultiple, -mno-multiple โ€” these make the code use (or not use) the load multiple word and store multiple word instructions ๐ŸŒˆ They're on by default on POWER systems and off by default on PowerPC systems. Don't use -mmultiple on little-endian PowerPC systems, because those instructions don't work in little-endian mode ๐Ÿ’€ The exceptions are PPC740 and PPC750, which allow them in little-endian mode ๐Ÿ“
  • -mupdate, -mno-update โ€” these make the code use (or not use) the load and store instructions that update the base register to the address of the calculated memory location โœจ They're on by default. Heads up: if you use -mno-update, there's a tiny window between the stack pointer being updated and the previous frame's address being stored. That means code that walks the stack across interrupts or signals might end up with corrupted data ๐Ÿ˜ญ
  • -mavoid-indexed-addresses, -mno-avoid-indexed-addresses โ€” these make the code try to avoid (or not avoid) indexed load and store instructions ๐Ÿงš Those can be a performance hit on Power6 processors in certain situations, like stepping through big arrays that cross a 16M boundary. This is enabled by default when targeting Power6 and disabled otherwise ๐Ÿ’–
  • -mfused-madd, -mno-fused-madd โ€” these make the code use (or not use) the floating-point multiply and accumulate instructions ๐Ÿฆ‹ They're generated by default if hardware floating point is in use. Also, the machine-dependent -mfused-madd is now mapped to the machine-independent -ffp-contract=fast, and -mno-fused-madd is mapped to -ffp-contract=off โœจ
  • -mmulhw, -mno-mulhw โ€” these make the code use (or not use) the half-word multiply and multiply-accumulate instructions on the IBM 405, 440, 464, and 476 processors ๐ŸŒธ They're on by default when you're targeting those processors ๐Ÿ’…
  • -mdlmzb, -mno-dlmzb โ€” these make the code use (or not use) the string-search dlmzb instruction on the IBM 405, 440, 464, and 476 processors ๐Ÿ”ฅ It's on by default when targeting those processors ๐Ÿซถ
  • -mno-bit-align, -mbit-align โ€” on System V.4 and embedded PowerPC systems, -mno-bit-align means structures and unions containing bit-fields are not forced to align to the base type of the bit-field, and -mbit-align means they are ๐ŸŽ€

Okay, example time ๐Ÿ™ˆ By default, a structure with nothing but 8 "unsigned" bit-fields of length 1 gets aligned to a 4-byte boundary and ends up 4 bytes in size. With -mno-bit-align, that same structure is aligned to a 1-byte boundary and is just 1 byte in size. Iconic ๐Ÿ‘‘

  • -mno-strict-align, -mstrict-align โ€” on System V.4 and embedded PowerPC systems, -mno-strict-align means GCC does not assume the system handles unaligned memory references, and -mstrict-align means it does assume that ๐Ÿ’œ
  • -mrelocatable, -mno-relocatable โ€” these make the code allow (or not allow) a static executable to be relocated to a different address at run time ๐ŸŒˆ A simple embedded PowerPC system loader should relocate the entire contents of ".got2" and the 4-byte locations listed in the ".fixup" section. That's a table of 32-bit addresses this option generates ๐Ÿงš For this to work, every object linked together has to be compiled with -mrelocatable or -mrelocatable-lib. Also, -mrelocatable code aligns the stack to an 8-byte boundary โœจ
  • -mrelocatable-lib, -mno-relocatable-lib โ€” like -mrelocatable, this generates a ".fixup" section so static executables can be relocated at run time ๐Ÿฆ‹ The difference is that -mrelocatable-lib doesn't use the smaller stack alignment that -mrelocatable does. Objects compiled with -mrelocatable-lib can be linked with objects compiled with any combination of the -mrelocatable options ๐Ÿซถ
  • -mno-toc, -mtoc โ€” on System V.4 and embedded PowerPC systems, -mno-toc means GCC does not assume register 2 holds a pointer to a global area with the addresses the program uses, and -mtoc means it does ๐ŸŒธ
  • -mlittle, -mlittle-endian โ€” on System V.4 and embedded PowerPC systems, this compiles code for the processor in little-endian mode ๐Ÿ’– -mlittle-endian is the same as -mlittle ๐Ÿ’…
  • -mbig, -mbig-endian โ€” on System V.4 and embedded PowerPC systems, this compiles code for the processor in big-endian mode ๐Ÿ”ฅ -mbig-endian is the same as -mbig ๐Ÿซถ
  • -mdynamic-no-pic โ€” on Darwin and Mac OS X systems, this compiles code so it is not relocatable, but its external references are relocatable ๐Ÿฆ‹ The result is suitable for applications, but not shared libraries ๐Ÿ™…โ€โ™€๏ธ
  • -msingle-pic-base โ€” this treats the register used for PIC addressing as read-only, instead of loading it in the prologue for each function โœจ The runtime system is responsible for initializing that register with an appropriate value before execution 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, which assign no priority, the highest priority, or the second-highest priority (respectively) to those instructions ๐Ÿ’œ
  • -msched-costly-dep=dependence_type โ€” this controls which dependences the target considers costly during instruction scheduling ๐ŸŒˆ The dependence_type argument takes one of these values:
    • no โ€” No dependence is costly ๐Ÿ’€
    • all โ€” All dependences are costly ๐Ÿ”ฅ
    • true_store_to_load โ€” A true dependence from store to load is costly ๐ŸŽ€
    • store_to_load โ€” Any dependence from store to load is costly ๐ŸŒธ
    • number โ€” Any dependence whose latency is greater than or equal to number is costly โœจ
  • -minsert-sched-nops=scheme โ€” this controls which NOP insertion scheme is used during the second scheduling pass ๐Ÿงš The scheme argument takes one of these values:
    • no โ€” Don't insert NOPs ๐Ÿ™…โ€โ™€๏ธ
    • pad โ€” Pad with NOPs any dispatch group that has vacant issue slots, according to the scheduler's grouping ๐Ÿ“
    • regroup_exact โ€” Insert NOPs to force costly dependent insns into separate groups. Insert exactly as many NOPs as needed to force an insn into a new group, according to the estimated processor grouping ๐Ÿฆ‹
    • number โ€” Insert NOPs to force costly dependent insns into separate groups. Insert number NOPs to force an insn into a new group ๐Ÿ’–
  • -mcall-sysv โ€” on System V.4 and embedded PowerPC systems, this compiles code using calling conventions that follow the March 1995 draft of the System V Application Binary Interface, PowerPC processor supplement ๐Ÿ’… This is the default unless you configured GCC using powerpc-*-eabiaix ๐Ÿซถ
  • -mcall-sysv-eabi, -mcall-eabi โ€” these are 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 โ€” this selects the type of traceback table ๐Ÿ’œ Valid values for traceback_type are full, part, and no ๐Ÿงš
  • -maix-struct-return โ€” this returns all structures in memory, as specified by the AIX ABI ๐Ÿ‘‘
  • -msvr4-struct-return โ€” this returns structures smaller than 8 bytes in registers, as specified by the SVR4 ABI ๐ŸŽ€

Okay bestie, -mabi=abi-type is the big one ๐Ÿ’– It lets you extend the current ABI with a particular extension, or remove one. The valid values are altivec, no-altivec, ibmlongdouble, ieeelongdouble, elfv1, and elfv2. For AIX there are also vec-extabi and vec-default ๐Ÿฆ‹

  • -mabi=ibmlongdouble โ€” switches the 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 away from IEEE extended-precision, the compiler issues a warning unless you use -Wno-psabi. You also need -mlong-double-128 enabled for this one ๐ŸŽ€
  • -mabi=ieeelongdouble โ€” switches the 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 away from IBM extended-precision, the compiler issues a warning unless you use -Wno-psabi. This also requires -mlong-double-128 to be enabled ๐ŸŽ€
  • -mabi=elfv1 โ€” the ELFv1 ABI, which is the default for big-endian PowerPC 64-bit Linux ๐ŸŒธ. Overriding the default needs special system support and is likely to fail in spectacular ways ๐Ÿ˜ญ
  • -mabi=elfv2 โ€” the ELFv2 ABI, which is the default for little-endian PowerPC 64-bit Linux โœจ. Overriding the default needs special system support and is likely to fail in spectacular ways ๐Ÿ˜ญ
  • -mgnu-attribute, -mno-gnu-attribute โ€” emits .gnu_attribute assembly directives that set tag/value pairs in a .gnu.attributes section. These describe ABI variations in function parameters or return values ๐Ÿฆ‹
  • -mprototype, -mno-prototype โ€” on System V.4 and embedded PowerPC systems, this assumes 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 says whether floating-point values are passed in the floating-point registers, in case the function takes variable arguments. With -mprototype, only calls to prototyped variable argument functions set or clear the bit ๐ŸŒˆ
  • -msim โ€” on embedded PowerPC systems, 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, assumes the startup module is crt0.o and the standard C libraries are libmvme.a and libc.a ๐Ÿ“
  • -mads โ€” on embedded PowerPC systems, assumes the startup module is crt0.o and the standard C libraries are libads.a and libc.a ๐Ÿ’…
  • -myellowknife โ€” on embedded PowerPC systems, 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, tells the compiler you're building for a VxWorks system ๐Ÿ›ธ
  • -memb โ€” on embedded PowerPC systems, sets the PPC_EMB bit in the ELF flags header. This indicates that eabi extended relocations are used ๐Ÿฆ‹
  • -meabi, -mno-eabi โ€” on System V.4 and embedded PowerPC systems, this makes you adhere to (or not adhere to) the Embedded Applications Binary Interface (EABI), a set of modifications to the System V.4 specifications ๐ŸŽ€

With -meabi, the stack is aligned to an 8-byte boundary, a function __eabi is called from main to set up the EABI environment, and the -msdata option can use both r2 and r13 to point to two separate small data areas ๐Ÿซถ With -mno-eabi, the stack is aligned to a 16-byte boundary, no EABI initialization function is called from main, and 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, puts small initialized const global and static data 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, right next to .sdata ๐ŸŒ™ Heads up: -msdata=eabi is incompatible with -mrelocatable. It also sets -memb ๐Ÿšซ
  • -msdata=sysv โ€” on System V.4 and embedded PowerPC systems, puts small global and static data in the .sdata section, which r13 points to ๐ŸŒท Small uninitialized global and static data goes in the .sbss section, next to .sdata. This is incompatible with -mrelocatable ๐Ÿ™…โ€โ™€๏ธ
  • -msdata=default, -msdata โ€” on System V.4 and embedded PowerPC systems, if -meabi is used, the code compiles the same as -msdata=eabi. Otherwise it compiles the same as -msdata=sysv ๐Ÿ”ฎ
  • -msdata=data โ€” on System V.4 and embedded PowerPC systems, puts small global data in the .sdata section and small uninitialized global data 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, puts all initialized global and static data in the .data section, and all uninitialized data in the .bss section ๐Ÿซง
  • -mreadonly-in-sdata โ€” puts read-only objects in the .sdata section too. This is the default ๐Ÿ’–
  • -mblock-move-inline-limit=num โ€” inlines all block moves (like calls to memcpy or structure copies) that are less than or equal to num bytes ๐Ÿšš The minimum value for num is 32 bytes on 32-bit targets and 64 bytes on 64-bit targets. The default is target-specific ๐ŸŽฏ
  • -mblock-compare-inline-limit=num โ€” generates non-looping inline code for all block compares (like calls to memcmp or structure compares) that are less than or equal to num bytes โš–๏ธ If num is 0, all inline expansion (non-loop and loop) of block compare is disabled ๐Ÿ™… The default is target-specific ๐ŸŒˆ
  • -mblock-compare-inline-loop-limit=num โ€” generates an inline expansion using loop code for all block compares that are less than or equal to num bytes but greater than the limit for non-loop inline block compare expansion ๐Ÿ” If the block length isn't constant, at most num bytes get compared before memcmp is called to compare the rest of the block. The default is target-specific ๐Ÿง 
  • -mstring-compare-inline-limit=num โ€” compares at most num string bytes with inline code ๐Ÿงต If the difference or end of string isn't found at the end of the inline compare, a call to strcmp or strncmp takes care of the rest. The default is 64 bytes ๐Ÿ’…
  • -G num โ€” on embedded PowerPC systems, puts global and static items 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 โ€” on System V.4 and embedded PowerPC systems, this makes you (or doesn't make you) emit register names in the assembly output using symbolic forms ๐Ÿท๏ธ
  • -mlongcall, -mno-longcall โ€” by default, the compiler assumes all calls are far away, so a longer and more expensive calling sequence is required ๐Ÿข This is needed for calls farther than 32 megabytes (33,554,432 bytes) from the current location. A short call is generated if the compiler knows the call can't be that far away ๐Ÿ‡ You can override this with the shortcall function attribute, or with #pragma longcall(0) ๐Ÿ’ซ

Some linkers can detect out-of-range calls and generate glue code on the fly. On those systems, long calls are unnecessary and generate slower code ๐ŸŒ As of this writing, the AIX linker can do this, and so can the GNU linker for PowerPC/64. It is 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 is appended to the body of the calling function. It computes the full 32-bit address of the callee and jumps to it ๐Ÿฆ˜

On Mach-O (Darwin) systems, this option directs the compiler to emit the glue for every direct call, and the Darwin linker decides whether to use it or discard it ๐Ÿงƒ

In the future, GCC may ignore all longcall specifications when the linker is known to generate glue ๐Ÿ”ฎ

  • -mpltseq, -mno-pltseq โ€” implements (or doesn't implement) -fno-plt and long calls using an inline PLT call sequence. That sequence supports lazy linking and long calls to functions in dlopen'd shared libraries ๐Ÿงฉ Inline PLT calls are only supported on PowerPC64 ELFv2 and 32-bit PowerPC systems with newer GNU linkers. They're enabled by default if support is detected when configuring GCC, and, for 32-bit PowerPC, if GCC is configured with --enable-secureplt ๐Ÿ” Heads up: -mpltseq code and -mbss-plt 32-bit PowerPC relocatable objects may not be linked together ๐Ÿšซ
  • -mtls-markers, -mno-tls-markers โ€” marks (or doesn't mark) calls to __tls_get_addr with a relocation that specifies the function argument ๐Ÿท๏ธ That relocation lets the linker reliably connect the function call with the argument setup instructions for TLS optimization. That in turn lets GCC schedule the sequence better ๐ŸŽ€
  • -mrecip, -mno-recip โ€” okay bestie, this one is a speed boost ๐Ÿš€โœจ It turns on the reciprocal estimate and reciprocal square root estimate instructions, plus extra Newton-Raphson steps to win back precision, so you don't have to do a divide or a square root and then a divide for your floating-point arguments ๐Ÿงฎ. If you're using -mrecip, you should also use -ffast-math (or at the very least -funsafe-math-optimizations, -ffinite-math-only, -freciprocal-math and -fno-trapping-math) ๐Ÿ’…. The sequence usually has higher throughput than the non-reciprocal instruction, but for reciprocal square roots the precision can drop by up to 2 ulp (i.e. the inverse of 1.0 comes out as 0.99999994) ๐Ÿ˜ญ
  • -mrecip=opt โ€” this lets you pick exactly which reciprocal estimate instructions are allowed ๐ŸŽฏ opt is a comma-separated list, and you can put a ! in front of any option to flip it. Here's the menu:
    • all โ€” Enable all estimate instructions. ๐ŸŒˆ
    • default โ€” Enable the default instructions, equivalent to -mrecip.
    • none โ€” Disable all estimate instructions, equivalent to -mno-recip. ๐Ÿ™…โ€โ™€๏ธ
    • div โ€” Enable the reciprocal approximation instructions for both single and double precision.
    • divf โ€” Enable the single-precision reciprocal approximation instructions.
    • divd โ€” Enable the double-precision reciprocal approximation instructions.
    • rsqrt โ€” Enable the reciprocal square root approximation instructions for both single and double precision.
    • rsqrtf โ€” Enable the single-precision reciprocal square root approximation instructions.
    • rsqrtd โ€” Enable the double-precision reciprocal square root approximation instructions.

So, for example, -mrecip=all,!rsqrtd enables all of the reciprocal estimate instructions, except for the "FRSQRTE", "XSRSQRTEDP", and "XVRSQRTEDP" instructions, which handle the double-precision reciprocal square root calculations ๐Ÿฆ‹

  • -mrecip-precision, -mno-recip-precision โ€” basically you're telling the compiler to assume (or not assume) that the reciprocal estimate instructions are more precise than the PowerPC ABI requires โœจ Picking -mcpu=power6, -mcpu=power7 or -mcpu=power8 turns -mrecip-precision on automatically ๐Ÿ’– Also, the double-precision square root estimate instructions aren't generated by default on low-precision machines, because they don't converge after three steps ๐Ÿ™ˆ
  • -mveclibabi=type โ€” this sets the ABI type for vectorizing intrinsics with an external library ๐Ÿ“š The only type supported right now is mass, which means using IBM's Mathematical Acceleration Subsystem (MASS) 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, and 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 ๐ŸงŠ > 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 that loads up the static chain register (r11) when calling through a pointer on AIX and 64-bit Linux systems ๐Ÿงš This is 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 cannot 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 that saves the TOC value in the reserved stack location in the function prologue, if the function calls through a pointer on AIX and 64-bit Linux systems ๐ŸŒธ If the TOC value isn't saved in the prologue, it gets saved just before the call through the pointer. -mno-save-toc-indirect is the default, so that's the main character by default ๐Ÿ’œ
  • -mcompat-align-parm, -mno-compat-align-parm โ€” generate (or don't generate) code that passes structure parameters with a maximum alignment of 64 bits, for compatibility with older versions of GCC ๐Ÿ•ฐ๏ธ Older versions (prior to 4.9.0) incorrectly didn't align a structure parameter on a 128-bit boundary when that structure had a member needing 128-bit alignment. Newer versions fixed this, but this option lets you generate code that plays nicely with functions compiled by the older versions ๐Ÿซถ -mno-compat-align-parm is the default.
  • -mstack-protector-guard=guard โ€” 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).
  • -mstack-protector-guard-reg=reg โ€” with the tls choice, this picks which register to use as the base register for reading the canary ๐Ÿงญ The default is whatever the relevant ABI specifies.
  • -mstack-protector-guard-offset=offset โ€” with the tls choice, this sets the offset from that base register where the canary is read ๐Ÿ“ The default is whatever the relevant ABI specifies.
  • -mstack-protector-guard-symbol=symbol โ€” this 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 ๐ŸŽ€ -mpcrel needs the medium code model (-mcmodel=medium) and prefixed addressing (-mprefixed) to be enabled too.
  • -mprefixed, -mno-prefixed โ€” generate (or don't generate) addressing modes using prefixed load and store instructions ๐ŸŒˆ -mprefixed requires -mcpu=power10 (or later) to be enabled.
  • -mmma, -mno-mma โ€” generate (or don't generate) the MMA instructions ๐Ÿ”ฅ The -mma option requires -mcpu=power10 (or later) to be enabled.

๐ŸŽ€ RX Options ๐ŸŽ€

These command-line options are defined for RX targets ๐Ÿฆ‹

  • -m64bit-doubles, -m32bit-doubles โ€” this makes the double data type 64 bits (-m64bit-doubles) or 32 bits (-m32bit-doubles) in size ๐Ÿ“ The default is -m32bit-doubles, and that's because RX floating-point hardware only works on 32-bit values ๐Ÿ™ƒ
  • -fpu, -nofpu โ€” -fpu enables and -nofpu disables the use of RX floating-point hardware โšก It's enabled by default for the RX600 series and disabled for the RX200 series. Floating-point instructions are only generated for 32-bit floating-point values, though, so the FPU hardware isn't used for doubles if -m64bit-doubles is used ๐Ÿซ 
If -fpu is enabled, then -funsafe-math-optimizations is also enabled automatically, because the RX FPU instructions are themselves unsafe. ๐Ÿ’€
  • -mcpu=name โ€” this selects the type of RX CPU you're targeting ๐Ÿ–ฅ๏ธ Three types are supported right now: the generic RX600 and RX200 series hardware, and the specific RX610 CPU. The default is RX600. The only difference between RX600 and RX610 is that the RX610 doesn't support the "MVTIPL" instruction. The RX200 series doesn't have a hardware floating-point unit, so -nofpu is enabled by default when this type is selected ๐Ÿ™…โ€โ™€๏ธ
  • -mbig-endian-data, -mlittle-endian-data โ€” this stores data (but not code) in the big-endian format ๐Ÿ“ The default is -mlittle-endian-data, which means data is stored in the little-endian format.
  • -msmall-data-limit=N โ€” this sets the maximum size in bytes of global and static variables that can be placed into the small data area ๐Ÿง The small data area can lead to smaller and faster code, but the area is limited, so it's up to you to make sure it doesn't overflow ๐Ÿ˜ฌ Also, when the small data area is used, one of the RX's registers (usually "r13") is reserved to point to this area, so the compiler can't use it anymore. That could make code slower and/or larger if variables get pushed onto the stack instead of being held in this register ๐Ÿฅฒ

Note, common variables (variables that haven't been initialized) and constants are not placed into the small data area, since they're assigned to other sections in the output executable ๐Ÿง 

The default value is zero, which disables this feature ๐Ÿ™ˆ This feature isn't enabled by default with higher optimization levels (-O2 etc) because of the potentially detrimental effects of reserving a register. It's up to you to experiment and see whether it benefits your program. See the description of the -mpid option for how the actual register that holds the small data area pointer is chosen ๐Ÿ”

  • -msim, -mno-sim โ€” use the simulator runtime ๐Ÿ–ฅ๏ธ The default is to use 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 โ€” ๐Ÿ’… This sets the biggest a constant can be, in bytes, when it's used as an operand in an RX instruction. RX can technically fit constants up to 4 bytes, but a longer value makes the instruction longer too, so sometimes it's worth shrinking the limit. Constants that are too big get shoved into a constant pool and reached through register indirection instead. The value N can be between 0 and 4. A value of 0 (the default) or 4 means constants of any size are allowed. ๐ŸŒธ
  • -mrelax โ€” ๐Ÿฆ‹ Turns on linker relaxation. That's when the linker hunts for shorter versions of various instructions to shrink your program. It's off by default.
  • -mint-register=N โ€” โœจ Reserves a number of registers for fast interrupt handler functions. N can be between 0 and 4. A value of 1 keeps "r13" reserved for the exclusive use of fast interrupt handlers. 2 reserves "r13" and "r12". 3 reserves "r13", "r12" and "r11", and 4 reserves "r13" through "r10". The default, 0, doesn't reserve any registers. ๐Ÿ‘‘
  • -msave-acc-in-interrupts โ€” ๐Ÿ”ฅ Tells interrupt handler functions to preserve the accumulator register. You only need this if normal code might use the accumulator, like if it's doing 64-bit multiplications. By default the accumulator gets ignored, because that makes the interrupt handlers faster. ๐Ÿงš
  • -mpid, -mno-pid โ€” ๐Ÿ’– Turns on the generation of position independent data. When it's on, any access to constant data happens through 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, bestie: using this feature reserves a register, usually "r13", for the constant data base address. That can make code slower and/or larger, especially in complicated functions. ๐Ÿ™ˆ

The actual register that holds the constant data base address depends on whether -msmall-data-limit and/or -mint-register are turned on. Starting at "r13" and working downwards, registers get allocated first to satisfy -mint-register, then -mpid, and finally -msmall-data-limit. So the small data area register can totally end up being "r8" if both -mint-register=4 and -mpid are on the command line. ๐Ÿ“

By default this feature is not enabled. You can restore the default with the -mno-pid command-line option. ๐Ÿ’…

  • -mno-warn-multiple-fast-interrupts, -mwarn-multiple-fast-interrupts โ€” ๐ŸŒˆ Stops GCC from 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, since the RX only supports one of those. โญ
  • -mallow-string-insns, -mno-allow-string-insns โ€” ๐ŸŽ€ Turns the string manipulation instructions SMOVF, SCMPU, SMOVB, SMOVU, SUNTIL, SWHILE and also the RMPA instruction on or off. These instructions might prefetch data, which isn't safe if you're accessing an I/O register. (Check section 12.2.7 of the RX62N Group User's Manual for more deets.) ๐Ÿง

The default is to allow these instructions. Sadly GCC can't reliably detect every situation where a string instruction might touch an I/O register, so it can't turn them off on its own. Instead, it's on the programmer to use -mno-allow-string-insns if their 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 clutch when your code size goes past the range of BSR instructions. Note that -mno-jsr doesn't mean "don't use JSR" ๐Ÿ’€. It means any type of branch may be used instead.

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 when the normal use of those registers has been restricted with -ffixed-reg or -mint-register on the command line. ๐Ÿซถ


โœจ 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 do the floating-point work instead. With -mhard-float, the compiler generates IEEE floating-point instructions. -mhard-float 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 handle decimal-floating-point operations. 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" the same as "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 debug with tools that don't understand DWARF call frame information. When -mno-packed-stack is in effect, the backchain pointer goes at the bottom of the stack frame. When -mpacked-stack is in effect, the backchain goes into the topmost word of the 96/160 byte register save area. ๐Ÿฆ‹

In general, code compiled with -mbackchain is call-compatible with code compiled with -mmo-backchain. However, using the backchain for debugging usually means the whole binary has to be built with -mbackchain. Also, the combination of -mbackchain, -mpacked-stack and -mhard-float is not supported. If you want to build a Linux kernel, use -msoft-float. โš ๏ธ

The default is to not maintain the backchain. ๐ŸŒ™

  • -mpacked-stack, -mno-packed-stack โ€” ๐Ÿ“ฆ Uses (or doesn't use) the packed stack layout. With -mno-packed-stack, the compiler uses all the fields of the 96/160 byte register save area only for their default purpose. Unused fields still eat up stack space. With -mpacked-stack, register save slots get densely packed at the top of the register save area, and unused space gets reused for other purposes. That means more efficient use of the stack space. ๐Ÿง 

However, when -mbackchain is also in effect, the topmost word of the save area is always used to store the backchain, and the return address register is always saved two words below the backchain. ๐Ÿ’…

As long as the stack frame backchain isn't used, code generated with -mpacked-stack is call-compatible with code generated with -mno-packed-stack. 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. And, again, the combination of -mbackchain, -mpacked-stack and -mhard-float is not supported. To build a Linux kernel, use -msoft-float. ๐Ÿšซ

The default is to not use the packed stack layout. ๐Ÿซ 

  • -msmall-exec, -mno-small-exec โ€” ๐Ÿƒ Generates (or doesn't generate) code that uses the bras instruction for subroutine calls. This only works reliably if the total executable size doesn't go over 64k. By default it uses the basr instruction instead, which doesn't have that limit. ๐Ÿงš
  • -m64, -m31 โ€” ๐Ÿ’œ With -m31, code is generated to comply with the GNU/Linux for S/390 ABI. With -m64, code is generated to comply with the GNU/Linux for zSeries ABI. This lets GCC in particular generate 64-bit instructions. For the s390 targets the default is -m31, while the s390x targets default to -m64. ๐ŸŒˆ
  • -mzarch, -mesa โ€” ๐Ÿฆ‹ With -mzarch, code is generated using the instructions available on z/Architecture. With -mesa, code is generated using the instructions available on ESA/390. Note that -mesa is not possible with -m64. When generating code for the GNU/Linux for S/390 ABI, the default is -mesa. When generating code for the GNU/Linux for zSeries ABI, the default is -mzarch. โœจ
  • -mhtm, -mno-htm โ€” ๐ŸŒธ The -mhtm option enables a set of builtins that use instructions from the transactional execution facility. That facility was introduced with the IBM zEnterprise EC12 machine generation, and the builtins are part of the S/390 System z Built-in Functions. -mhtm is enabled by default when using -march=zEC12. ๐Ÿ”ฅ
  • -mvx, -mno-vx โ€” ๐ŸŒŸ With -mvx, code is generated using the instructions available with the vector extension facility, which was introduced with the IBM z13 machine generation. This option changes the ABI for some vector type values when it comes to alignment and calling conventions. If vector type values are used in an ABI-relevant context, a GAS .gnu_attribute command gets added to mark the resulting binary with the ABI that was used. -mvx is enabled by default when using -march=z13. ๐Ÿ‘‘
  • -mzvector, -mno-zvector โ€” Turns on vector language extensions and builtins that use the vector instructions from the z13 era and later. ๐Ÿ’– It makes vector a keyword for declaring vector type variables and arguments, but only with GNU extensions on. With strict standard compliance, like -std=c99, vector won't work. โœจ On top of the GCC low-level builtins, you also get builtins for AltiVec-style compatibility, the kind you'd see on Power and Cell. To use them, include the header vecintrin.h. ๐ŸŽ€ It's off by default.
  • -mmvcle, -mno-mvcle โ€” Use (or skip) the "mvcle" instruction for block moves. ๐Ÿฆ‹ With -mno-mvcle, you get 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 no debug printing.
  • -march=cpu-type โ€” Generate code that runs on cpu-type, which is the name of a processor type. ๐Ÿ‘‘ The possible values are z900/arch5, z990/arch6, z9-109, z9-ec/arch7, z10/arch8, z196/arch9, zEC12, z13/arch11, z14/arch12, z15/arch13, and native. ๐ŸŒธ The default is -march=z900.

Picking native tells GCC to choose the best architecture option for the host processor. โญ -march=native does nothing if GCC doesn't recognize your processor.

  • -mtune=cpu-type โ€” Tune everything applicable in the generated code to cpu-type, except for the ABI and the set of available instructions. ๐Ÿงš The list of values is the same as for -march. The default is whatever value -march is using.
  • -mtpf-trace, -mno-tpf-trace โ€” Add (or don't add) TPF OS specific branches to trace routines in the operating system. ๐ŸŒˆ This is off by default, even when you're compiling for TPF OS.
  • -mtpf-trace-skip, -mno-tpf-trace-skip โ€” Change (or don't change) the default branch targets enabled by -mtpf-trace so they point to specialized trace routines. ๐Ÿ’… These let you selectively skip function trace entries for TPF OS. It's off by default, even when you're compiling for TPF OS and also passing -mtpf-trace.
  • -mfused-madd, -mno-fused-madd โ€” Use (or don't use) the floating-point multiply and accumulate instructions. ๐Ÿ”ฅ These get generated by default if hardware floating point is in use.
  • -mwarn-framesize=framesize โ€” Emit a warning if the current function goes over the given frame size. ๐Ÿซถ This is a compile-time check, so it doesn't have to be a real problem when the program runs. It's meant to flag functions that are likely to cause a stack overflow, which makes it super useful in environments with a limited stack size, like the Linux kernel. ๐Ÿฆ‹
  • -mwarn-dynamicstack โ€” Emit a warning if the function calls alloca or uses dynamically-sized arrays. ๐Ÿ’€ That's generally a bad idea when the stack size is limited.
  • -mstack-guard=stack-guard, -mstack-size=stack-size โ€” If you pass these, the S/390 back end adds extra instructions to the function prologue. Those instructions trigger a trap if the stack size goes stack-guard bytes above stack-size. (Heads up: on S/390, the stack grows downward. ๐Ÿ™ˆ) If you leave out stack-guard, GCC picks the smallest power of 2 that's bigger than the compiled function's frame size. ๐Ÿ“ These are meant for debugging stack overflow problems. The extra code adds only a little overhead, so you can use it on production-like systems without a big performance hit.
The values have to be exact powers of 2, and stack-size has to be bigger than stack-guard without going over 64k. To be efficient, the extra code assumes the stack starts at an address aligned to the value of stack-size. ALSO stack-guard can only be used together with stack-size. ๐Ÿ˜ญ
  • -mhotpatch=pre-halfwords,post-halfwords โ€” If hotpatch is enabled, GCC generates a "hot-patching" function prologue for every function in the compilation unit. ๐Ÿงš The function label gets the given number of two-byte NOP instructions stuck in front of it (pre-halfwords, max 1000000). After the label, 2 * post-halfwords bytes get appended, using the largest NOP-like instructions the architecture allows (post-halfwords max 1000000). ๐ŸŽ€

If both arguments are zero, hotpatching is disabled. โœจ You can override this for individual functions with the "hotpatch" attribute.

๐Ÿ’œ Score Options ๐Ÿ’œ

These options are defined for Score implementations:

  • -meb โ€” Compile for big-endian mode. ๐ŸŒธ This is the default.
  • -mel โ€” Compile for little-endian mode.
  • -mnhwloop โ€” Disable generation of "bcnz" instructions. ๐Ÿ™…
  • -muls โ€” Enable generation of unaligned load and store instructions. ๐Ÿ”ฅ
  • -mmac โ€” Enable multiply-accumulate instructions. ๐Ÿฆ‹ These are disabled by default.
  • -mscore5 โ€” Set SCORE5 as the target architecture.
  • -mscore5u โ€” Set SCORE5U as the target architecture.
  • -mscore7 โ€” Set SCORE7 as the target architecture. ๐Ÿ‘‘ This is the default.
  • -mscore7d โ€” Set SCORE7D as the target architecture.

๐ŸŒˆ SH Options ๐ŸŒˆ

These -m options are defined for the SH implementations:

  • -m1 โ€” Generate code for the SH1. ๐Ÿ’–
  • -m2 โ€” Generate code for the SH2. ๐Ÿ’–
  • -m2e โ€” Generate code for the SH2e.
  • -m2a-nofpu โ€” Generate code for the SH2a without an FPU, or for an SH2a-FPU in a way that the floating-point unit isn't used. ๐Ÿซถ
  • -m2a-single-only โ€” Generate code for the SH2a-FPU so that no double-precision floating-point operations get used. ๐Ÿ“
  • -m2a-single โ€” Generate code for the SH2a-FPU, assuming the floating-point unit is in single-precision mode by default. โœจ
  • -m2a โ€” Generate code for the SH2a-FPU, assuming the floating-point unit is in double-precision mode by default. โœจ
  • -m3 โ€” Generate code for the SH3. ๐Ÿ’–
  • -m3e โ€” Generate code for the SH3e.
  • -m4-nofpu โ€” Generate code for the SH4 without a floating-point unit. ๐ŸŒธ
  • -m4-single-only โ€” Generate code for the SH4 with a floating-point unit that only supports single-precision arithmetic. ๐Ÿ’…
  • -m4-single โ€” Generate code for the SH4, assuming the floating-point unit is in single-precision mode by default. โœจ
  • -m4 โ€” Generate code for the SH4. ๐Ÿ’–
  • -m4-100 โ€” Generate code for SH4-100. ๐Ÿ’œ
  • -m4-100-nofpu โ€” Generate code for SH4-100 in a way that the floating-point unit isn't used. ๐Ÿ™ˆ
  • -m4-100-single โ€” Generate code for SH4-100, assuming the floating-point unit is in single-precision mode by default. โœจ
  • -m4-100-single-only โ€” Generate code for SH4-100 so that no double-precision floating-point operations get used. ๐Ÿ“
  • -m4-200 โ€” Generate code for SH4-200. ๐Ÿ’œ
  • -m4-200-nofpu โ€” Generate code for SH4-200 without the floating-point unit being used. ๐Ÿ™ˆ
  • -m4-200-single โ€” Generate code for SH4-200, assuming the floating-point unit is in single-precision mode by default. โœจ
  • -m4-200-single-only โ€” Generate code for SH4-200 so that no double-precision floating-point operations get used. ๐Ÿ“
  • -m4-300 โ€” Generate code for SH4-300. ๐Ÿ’œ
  • -m4-300-nofpu โ€” Generate code for SH4-300 without the floating-point unit being used. ๐Ÿ™ˆ
  • -m4-300-single โ€” Generate code for SH4-300 so that no double-precision floating-point operations get used. ๐Ÿ“
  • -m4-300-single-only โ€” Generate code for SH4-300 so that no double-precision floating-point operations get used. ๐Ÿ“
  • -m4-340 โ€” Generate code for SH4-340 (no MMU, no FPU). ๐Ÿงš
  • -m4-500 โ€” Generate code for SH4-500 (no FPU). ๐ŸŒˆ It passes -isa=sh4-nofpu to the assembler.
  • -m4a-nofpu โ€” Generate code for the SH4al-dsp, or for an SH4a in a way that the floating-point unit isn't used. ๐Ÿซถ
  • -m4a-single-only โ€” Generate code for the SH4a so that no double-precision floating-point operations get used. ๐Ÿ“
  • -m4a-single โ€” Generate code for the SH4a, assuming the floating-point unit is in single-precision mode by default. โœจ
  • -m4a โ€” Generate code for the SH4a. ๐Ÿ’–
  • -m4al โ€” Same as -m4a-nofpu, except it implicitly passes -dsp to the assembler. ๐ŸŽ€ GCC doesn't generate any DSP instructions at the moment, so don't expect them. ๐Ÿ’€
  • -mb โ€” Compile code for the processor in big-endian mode. ๐ŸŒธ
  • -ml โ€” Compile code for the processor in little-endian mode. ๐ŸŒธ
  • -mdalign โ€” Align doubles on 64-bit boundaries.
This changes the calling conventions, so some functions from the standard C library won't work unless you recompile the library first with -mdalign. ๐Ÿ˜ญ
  • -mrelax โ€” When possible, shorten some address references at link time. ๐Ÿฆ‹ This uses the linker option -relax.
  • -mbigtable โ€” Use 32-bit offsets in "switch" tables. ๐Ÿ“ The default is 16-bit offsets.
  • -mbitops โ€” Enable bit manipulation instructions on SH2A. ๐Ÿ”ฅ
  • -mfmovd โ€” Enable the "fmovd" instruction. ๐Ÿฆ‹ Check -mdalign for alignment constraints.
  • -mrenesas โ€” Follow the calling conventions defined by Renesas. ๐Ÿ‘‘
  • -mno-renesas โ€” Follow the calling conventions GCC used before Renesas conventions existed. ๐Ÿ•ฐ๏ธ This is the default for all targets of the SH toolchain.
  • -mnomacsave โ€” Mark the "MAC" register as call-clobbered, even when -mrenesas is given. ๐Ÿ’…
  • -mieee, -mno-ieee โ€” Control the IEEE compliance of floating-point comparisons, which affects how cases where the comparison result is unordered get handled. ๐Ÿงš -mieee is implicitly enabled by default. If -ffinite-math-only is on, -mno-ieee gets implicitly set, which makes floating-point greater-equal and less-equal comparisons faster. โญ You can override either implicit setting by explicitly passing -mieee or -mno-ieee. ๐Ÿ’œ
  • -minline-ic_invalidate โ€” okay bestie, this one inlines code that invalidates instruction cache entries right after it sets up nested function trampolines ๐Ÿงšโœจ. Heads up though: if -musermode is in effect and your code generation option (like -m4) doesn't allow the "icbi" instruction, this does absolutely nothing ๐Ÿ’€. If the "icbi" instruction isn't allowed and -musermode isn't in effect, the inlined code pokes the instruction cache address array directly with an associative write ๐Ÿซฃ.
โš ๏ธ That associative write requires privileged mode at run time, and it fails if the cache line had been mapped via the TLB and has become unmapped. Lowkey scary stuff, so be careful!
  • -misize โ€” dumps the instruction size and location into the assembly code ๐Ÿ“๐ŸŒธ.
  • -mpadstruct โ€” this one is deprecated ๐Ÿ™…โ€โ™€๏ธ. It pads structures to a multiple of 4 bytes, which is incompatible with the SH ABI, so it's giving outdated energy ๐Ÿ’€.
  • -matomic-model=model โ€” sets the model of atomic operations, plus any extra parameters, as a comma separated list ๐Ÿงƒ. For the deets on atomic built-in functions, check out __atomic Builtins. These models and parameters are supported:
    • none โ€” turns off compiler generated atomic sequences and emits library calls for atomic operations instead. This is the default if the target is not "sh*-*-linux*".
    • soft-gusa โ€” generates GNU/Linux compatible gUSA software atomic sequences for the atomic built-in functions. These sequences need extra help from the system's interrupt/exception handling code, and they're only suitable for SH3* and SH4* single-core systems. This is enabled by default when the target is "sh*-*-linux*" and SH3* or SH4*. When the target is SH4A, it also partially 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 can also be used on SH1* and SH2* targets ๐ŸŽ€. These sequences need extra help from the interrupt/exception handling code and are only suitable for single-core systems. When using this model, the gbr-offset= parameter has to be specified as well.
    • soft-imask โ€” 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. Extra support from the interrupt/exception handling code isn't required. It's enabled by default when the target is "sh*-*-linux*" and SH1* or SH2*.
    • hard-llcs โ€” generates hardware atomic sequences using only the "movli.l" and "movco.l" instructions ๐Ÿ’ช. This is only available on SH4A and is suitable for multi-core systems. Since the hardware instructions only support 32 bit atomic variable access, 8 or 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's executed on an SH4A system. Extra support from the interrupt/exception handling code isn't required for this model.
    • gbr-offset= โ€” specifies the offset in bytes of the variable in the thread control block structure that the generated atomic sequences should use when the soft-tcb model has been selected ๐Ÿงต. For other models this parameter gets ignored. The value must be an integer multiple of four and in the range 0-1020.
    • strict โ€” prevents mixing multiple atomic models, even if they're compatible, and makes the compiler generate atomic sequences of the specified model only ๐Ÿšซ.
  • -mtas โ€” generates the "tas.b" opcode for __atomic_test_and_set ๐Ÿงช. Notice that depending on your hardware and software configuration, this can degrade overall performance because of the operand cache line flushes that the "tas.b" instruction implies.
โš ๏ธ On multi-core SH4A processors, the "tas.b" instruction must be used with caution, since it can result in data corruption for certain cache configurations.
  • -mprefergot โ€” when generating position-independent code, emits function calls using the Global Offset Table instead of the Procedure Linkage Table ๐ŸŒ.
  • -musermode, -mno-usermode โ€” -musermode means don't allow the compiler to generate privileged mode code ๐Ÿ™…, while -mno-usermode means allow it ๐Ÿ”“. Specifying -musermode also implies -mno-inline-ic_invalidate if the inlined code wouldn't work in user mode. -musermode is the default when the target is "sh*-*-linux*". If the target is SH1* or SH2*, -musermode has no effect, since there's no user mode at all ๐Ÿซ .
  • -multcost=number โ€” sets the cost to assume for a multiply insn ๐Ÿ”ข.
  • -mdiv=strategy โ€” sets the division strategy used for integer division operations ๐Ÿฐ. strategy can be one of:
    • call-div1 โ€” calls a library function that uses the single-step division instruction "div1" to do the operation. Division by zero 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 performs 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 larger 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 a division strategy hasn't been specified, the default strategy gets picked based on the current target. For SH2A, the default strategy is to use the "divs" and "divu" instructions instead of library function calls โœจ.

  • -maccumulate-outgoing-args โ€” reserves space once for outgoing arguments in the function prologue, rather than around each call ๐Ÿงบ. This is generally beneficial for performance and size. It's also needed for unwinding, so the stack frame doesn't get changed around conditional code.
  • -mdivsi3_libfunc=name โ€” sets the name of the library function used for 32-bit signed division to name ๐Ÿท๏ธ. This only affects the name used in the call division strategies, and the compiler still expects the same sets of input/output/clobbered registers as if this option weren't present.
  • -mfixed-range=register-range โ€” generates code that treats the given register range as fixed registers ๐Ÿ“Œ. A fixed register is one that the register allocator can't use, which is super useful when compiling kernel code ๐Ÿ‘‘. A register range is specified as two registers separated by a dash, and multiple register ranges can be specified separated by a comma.
  • -mbranch-cost=num โ€” assumes num is the cost for a branch instruction ๐ŸŒฟ. Higher numbers make the compiler try to generate more branch-free code when it's possible. If it isn't specified, the value gets selected based on the processor type being compiled for.
  • -mzdcbranch, -mno-zdcbranch โ€” assumes (or doesn't assume) that zero displacement conditional branch instructions "bt" and "bf" are fast ๐ŸŽ๏ธ. With -mzdcbranch, the compiler prefers zero displacement branch code sequences. This is enabled by default when generating code for SH4 and SH4A. It can be explicitly disabled by specifying -mno-zdcbranch.
  • -mcbranch-force-delay-slot โ€” forces the use of delay slots for conditional branches, which stuffs the delay slot with a "nop" if a suitable instruction can't be found ๐Ÿซ™. This is disabled by default. Turn it on to work around hardware bugs like the ones found in the original SH7055 ๐Ÿ› ๏ธ.
  • -mfused-madd, -mno-fused-madd โ€” generates code that uses (or doesn't use) the floating-point multiply and accumulate instructions ๐Ÿงฎ. These are generated by default if hardware floating point is used. The machine-dependent -mfused-madd option is now mapped to the machine-independent -ffp-contract=fast option, and -mno-fused-madd is mapped to -ffp-contract=off.
  • -mfsca, -mno-fsca โ€” allows or disallows the compiler from emitting the "fsca" instruction for sine and cosine approximations ๐Ÿ“. The option -mfsca must be used in combination with -funsafe-math-optimizations. It's enabled by default when generating code for SH4A. Using -mno-fsca disables sine and cosine approximations, even if -funsafe-math-optimizations is in effect.
  • -mfsrra, -mno-fsrra โ€” allows or disallows the compiler from emitting the "fsrra" instruction for reciprocal square root approximations ๐ŸŒ€. The option -mfsrra must be used in combination with -funsafe-math-optimizations and -ffinite-math-only. It's enabled by default when generating code for SH4A. Using -mno-fsrra disables reciprocal square root approximations, even if -funsafe-math-optimizations and -ffinite-math-only are in effect.
  • -mpretend-cmove โ€” prefers zero-displacement conditional branches for conditional move instruction patterns ๐Ÿ’ซ. This can result in faster code on the SH4 processor.
  • -mfdpic โ€” generates code using the FDPIC ABI ๐Ÿงฉ.

โœจ Solaris 2 Options โœจ

These -m options are supported on Solaris 2 ๐ŸŒž:

  • -mclear-hwcap โ€” tells the compiler to remove the hardware capabilities generated by the Solaris assembler ๐Ÿงน. This is only necessary when object files use ISA extensions that aren't supported by the current machine, but check at runtime whether or not to use them.
  • -mimpure-text โ€” used in addition to -shared, this tells the compiler to not pass -z text to the linker when linking a shared object ๐Ÿฆ‹. With this option, you can link position-dependent code into a shared object.

Okay so, -mimpure-text is lowkey a trap ๐Ÿชค. It does make the linker stop yelling about "relocations remain against allocatable but non-writable sections" ๐Ÿค, BUT those relocations trigger copy-on-write, so the shared object is not actually shared across processes anymore ๐Ÿ’€. Instead, bestie, compile ALL your source code with -fpic or -fPIC โœจ๐Ÿซถ.

These switches also work on Solaris 2, on top of everything above ๐ŸŒˆ:

  • -pthreads โ€” literally just a synonym for -pthread ๐Ÿฆ‹

๐ŸŒธ SPARC Options ๐ŸŒธ

These -m options work on the SPARC ๐Ÿ’…:

  • -mno-app-regs, -mapp-regs โ€” Okay so -mapp-regs makes the compiler use global registers 2 through 4, which the SPARC SVR4 ABI reserves for applications ๐Ÿ“. Just like global register 1, each of 2 through 4 becomes an allocable register that gets clobbered by function calls. This is the default โœจ. If you want to be fully SVR4 ABI-compliant (with a bit of a performance hit ๐Ÿ˜ญ), go with -mno-app-regs. Libraries and system software should be compiled with this one ๐Ÿ‘‘.
  • -mflat, -mno-flat โ€” With -mflat, the compiler skips the save/restore instructions and uses a "flat" or single register window model ๐Ÿงš. It's still compatible with the regular register window model, and the local registers and input registers (0--5) are still "call-saved" and get stashed on the stack as needed. With -mno-flat (the default ๐Ÿ’–), the compiler makes save/restore instructions, except for leaf functions. That's the normal operating mode, no notes.
  • -mfpu, -mhard-float โ€” Generates output with floating-point instructions. This is the default ๐Ÿ”ฅ.
  • -mno-fpu, -msoft-float โ€” Generates output with library calls for floating point instead ๐ŸŒธ. Here's the tea:
Warning: the requisite libraries are NOT available for every SPARC target ๐Ÿ’€. Normally the machine's usual C compiler facilities get used, but that can't happen directly in cross-compilation. You'll have to make your own arrangements to provide suitable library functions for cross-compilation. The embedded targets sparc-*-aout and sparclite-*-* do come with software floating-point support.

Also, -msoft-float changes the calling convention in the output file, so it's only useful if you compile your WHOLE program with it ๐Ÿ™ˆ. Specifically, you need to compile libgcc.a (the library that comes with GCC) with -msoft-float for it to work.

  • -mhard-quad-float โ€” Generates output with quad-word (long double) floating-point instructions ๐ŸŽ€.
  • -msoft-quad-float โ€” Generates output with library calls for quad-word (long double) floating-point instructions instead โœจ. The functions called are the ones 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 what the instruction does. Because of that overhead, it's way slower than calling the ABI library routines, which is why -msoft-quad-float is the default. Iconic behavior, honestly ๐Ÿ’….

  • -mno-unaligned-doubles, -munaligned-doubles โ€” -mno-unaligned-doubles assumes doubles have 8-byte alignment, and it's the default ๐Ÿฆ‹. With -munaligned-doubles, GCC only assumes 8-byte alignment if the doubles are contained in another type, or if they have an absolute address. Otherwise it assumes 4-byte alignment. This avoids some rare compatibility problems with code from other compilers ๐Ÿซถ. It's not the default because it causes a performance loss, especially for floating-point code ๐Ÿ˜ฌ.
  • -muser-mode, -mno-user-mode โ€” -muser-mode (the default ๐Ÿ’œ) means the compiler won't generate code that can only run in supervisor mode. This only matters for the casa instruction emitted for the LEON3 processor ๐Ÿง .
  • -mfaster-structs, -mno-faster-structs โ€” With -mfaster-structs, the compiler assumes structures should have 8-byte alignment ๐Ÿš€. That lets it use pairs of ldd and std instructions for copies in structure assignment, instead of twice as many ld and st pairs. BUT, this changed alignment directly violates the SPARC ABI.
Heads up bestie: this is ONLY for targets where the developer knows and accepts that the resulting code isn't in line with the ABI rules ๐Ÿ’€.
  • -mstd-struct-return, -mno-std-struct-return โ€” With -mstd-struct-return, the compiler generates checking code in functions that return structures or unions ๐Ÿ”. It catches 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, so it's not giving anything there ๐Ÿ™ˆ.
  • -mlra, -mno-lra โ€” Enables Local Register Allocation โœจ. This has been the default for SPARC since GCC 7, so if you want the old Reload, you need to pass -mno-lra ๐Ÿ•ฐ๏ธ.
  • -mcpu=cpu_type โ€” Sets the instruction set, register set, and instruction scheduling parameters for the machine type cpu_type ๐Ÿ“. The supported values are v7, cypress, v8, supersparc, hypersparc, leon, leon3, leon3v7, leon5, sparclite, f930, f934, sparclite86x, sparclet, tsc701, v9, ultrasparc, ultrasparc3, niagara, niagara2, niagara3, niagara4, niagara7 and m8 ๐Ÿ’–.

Native Solaris and GNU/Linux toolchains also accept native, which picks the best architecture option for your host processor ๐Ÿงš. -mcpu=native does nothing if GCC doesn't recognize the processor ๐Ÿคทโ€โ™€๏ธ.

Default instruction scheduling parameters are used for the values that pick an architecture instead of an implementation. Those are v7, v8, sparclite, sparclet, and v9 ๐Ÿ’….

Here's the full lineup of each architecture and its implementations, bestie ๐Ÿ“‹:

  • v7 โ€” cypress, leon3v7
  • v8 โ€” supersparc, hypersparc, leon, leon3, leon5
  • sparclite โ€” f930, f934, sparclite86x
  • sparclet โ€” tsc701
  • v9 โ€” ultrasparc, ultrasparc3, niagara, niagara2, niagara3, niagara4, niagara7, m8

By default (unless configured otherwise), GCC generates code for the V7 variant of SPARC ๐ŸŒธ. With -mcpu=cypress, it's also optimized for the Cypress CY7C602 chip, the one used in the SPARCStation/SPARCServer 3xx series. That's also a good fit for the older SPARCStation 1, 2, IPX, etc. ๐Ÿ–ฅ๏ธ

With -mcpu=v8, GCC generates code for the V8 variant. The only difference from V7 code is that it emits the integer multiply and integer divide instructions that exist in SPARC-V8 but not SPARC-V7 โœจ. With -mcpu=supersparc, it's additionally optimized for the SuperSPARC chip, used in the SPARCStation 10, 1000 and 2000 series ๐Ÿ”ฅ.

With -mcpu=sparclite, GCC generates code for the SPARClite variant ๐Ÿฆ‹. This adds the integer multiply, integer divide step, and scan ("ffs") instructions that exist in SPARClite but not SPARC-V7. With -mcpu=f930, it's optimized for the Fujitsu MB86930 chip, the original SPARClite, which has no FPU ๐Ÿ™ˆ. With -mcpu=f934, it's optimized for the Fujitsu MB86934 chip, the more recent SPARClite that does have an FPU ๐Ÿ’œ.

With -mcpu=sparclet, GCC generates code for the SPARClet variant ๐Ÿงš. This adds the integer multiply, multiply/accumulate, integer divide step, and scan ("ffs") instructions that exist in SPARClet but not SPARC-V7. With -mcpu=tsc701, it's optimized for the TEMIC SPARClet chip ๐ŸŒˆ.

With -mcpu=v9, GCC generates code for the V9 variant ๐Ÿ‘‘. This adds 64-bit integer and floating-point move instructions, 3 additional floating-point condition code registers, and conditional move instructions. -mcpu=ultrasparc optimizes for the Sun UltraSPARC I/II/IIi chips. -mcpu=ultrasparc3 optimizes for the Sun UltraSPARC III/III+/IIIi/IIIi+/IV/IV+ chips ๐Ÿ”ฅ. -mcpu=niagara optimizes for Sun UltraSPARC T1 chips, -mcpu=niagara2 for Sun UltraSPARC T2 chips, -mcpu=niagara3 for Sun UltraSPARC T3 chips, and -mcpu=niagara4 for Sun UltraSPARC T4 chips ๐Ÿ“. -mcpu=niagara7 optimizes for Oracle SPARC M7 chips, and -mcpu=m8 optimizes for Oracle M8 chips ๐Ÿ’….

  • -mtune=cpu_type โ€” Sets the instruction scheduling parameters for cpu_type, but NOT the instruction set or register set that -mcpu=cpu_type sets ๐ŸŽ€. The same values work for -mtune=cpu_type, but only the ones that pick a particular CPU implementation are useful there: 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, you can also use native ๐Ÿซถ.
  • -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. It's 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 those 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 those instructions, such as niagara-3 and later. Setting -mvis3 also sets -mvis2 and -mvis ๐ŸŒˆ.
  • -mvis4, -mno-vis4 โ€” okay bestie, -mvis4 tells GCC to write code that uses version 4.0 of the UltraSPARC Visual Instruction Set extensions ๐Ÿฆ‹ It's the default when you target a cpu that has them, like niagara-7 and later. Turning it on also flips on -mvis3, -mvis2 and -mvis ๐Ÿ’œ
  • -mvis4b, -mno-vis4b โ€” -mvis4b is giving version 4.0 of the UltraSPARC VIS extensions plus the extra VIS instructions added in the Oracle SPARC Architecture 2017 โœจ It's the default when targeting a cpu that supports them, like m8 and later. Setting it also sets -mvis4, -mvis3, -mvis2 and -mvis ๐Ÿ”ฅ
  • -mcbcond, -mno-cbcond โ€” -mcbcond lets GCC use the UltraSPARC Compare-and-Branch-on-Condition instructions ๐ŸŒธ It's the default when targeting a CPU that supports them, like Niagara-4 and later.
  • -mfmaf, -mno-fmaf โ€” -mfmaf opens the door to the UltraSPARC Fused Multiply-Add Floating-point instructions ๐Ÿงš It's the default when targeting a CPU that supports them, like Niagara-3 and later.
  • -mfsmuld, -mno-fsmuld โ€” -mfsmuld lets GCC use the Floating-point Multiply Single to Double (FsMULd) instruction ๐Ÿ’– It's the default when targeting a CPU supporting the architecture versions V8 or V9 with FPU, except -mcpu=leon.
  • -mpopc, -mno-popc โ€” -mpopc is for the UltraSPARC Population Count instruction ๐Ÿ“ It's the default when targeting a CPU that supports it, like Niagara-2 and later.
  • -msubxc, -mno-subxc โ€” -msubxc is the UltraSPARC Subtract-Extended-with-Carry instruction, and GCC will use it when you're aiming for it ๐Ÿ’… It's the default when targeting a CPU that supports it, like Niagara-7 and later.
  • -mfix-at697f โ€” literal bodyguard energy ๐Ÿ›ก๏ธ Turns on the documented workaround for the single erratum of the Atmel AT697F processor (which corresponds to erratum #13 of the AT697E processor).
  • -mfix-ut699 โ€” turns on the documented workarounds for the floating-point errata and the data cache nullify errata of the UT699 processor ๐Ÿซถ
  • -mfix-ut700 โ€” turns on the documented workaround for the back-to-back store errata of the UT699E/UT700 processor โญ
  • -mfix-gr712rc โ€” turns on the documented workaround for the back-to-back store errata of the GR712RC processor ๐ŸŒˆ

These -m options are supported in addition to the above on SPARC-V9 processors in 64-bit environments, and they're giving main character energy ๐Ÿ‘‘

  • -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 ๐ŸŽ€
  • -mcmodel=which โ€” set the code model to one of these, bestie, pick your fighter ๐Ÿฆ‹
    • 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 โ€” set the memory model in force on the processor to one of these vibes ๐Ÿ’œ
    • default โ€” The default memory model for the processor and operating system.
    • rmo โ€” Relaxed Memory Order
    • pso โ€” Partial Store Order
    • tso โ€” Total Store Order
    • sc โ€” Sequential Consistency

These memory models are formally defined in Appendix D of the SPARC-V9 architecture manual, as set in the processor's "PSTATE.MM" field ๐Ÿ“š

  • -mstack-bias, -mno-stack-bias โ€” with -mstack-bias, GCC assumes the stack pointer, and 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, so they're here for the group project energy ๐Ÿซถ

  • -G โ€” create a shared object. It is recommended that -symbolic or -shared be used instead ๐Ÿ’…
  • -Qy โ€” identify the versions of each tool used by the compiler, in a .ident assembler directive in the output ๐Ÿ”ฅ
  • -Qn โ€” refrain from adding .ident directives to the output file (this is the default) ๐ŸŒธ
  • -YP,dirs โ€” search the directories dirs, and no others, for libraries specified with -l โœจ
  • -Ym,dir โ€” look 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 โ€” generate 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 โ€” generate 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/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 โ€” generate 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, and this section is lowkey a lot ๐Ÿ˜ญ

  • -mlong-calls, -mno-long-calls โ€” treat 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 โ€” do not optimize (do optimize) basic blocks that use the same index pointer 4 or more times to copy pointer into the "ep" register, and use the shorter "sld" and "sst" instructions. The -mep option is on by default if you optimize โœจ
  • -mno-prolog-function, -mprolog-function โ€” do not use (do use) external functions to save and restore registers at the prologue and epilogue of a function. The external functions are slower, but use less code space if more than one function saves the same number of registers. The -mprolog-function option is on by default if you optimize ๐Ÿงš
  • -mspace โ€” try to make the code as small as possible. At present, this just turns on the -mep and -mprolog-function options ๐Ÿซถ
  • -mtda=n โ€” put static or global variables whose size is n bytes or less into the tiny data area that register "ep" points to. The tiny data area can hold up to 256 bytes in total (128 bytes for byte references) ๐ŸŒˆ
  • -msda=n โ€” put static or global variables whose size is n bytes or less into the small data area that register "gp" points to. The small data area can hold up to 64 kilobytes ๐Ÿ“
  • -mzda=n โ€” put static or global variables whose size is n bytes or less into the first 32 kilobytes of memory ๐ŸŒธ
  • -mv850 โ€” specify that the target processor is the V850 ๐Ÿ’–
  • -mv850e3v5 โ€” specify that the target processor is the V850E3V5. The preprocessor constant "__v850e3v5__" is defined if this option is used ๐Ÿ”ฅ
  • -mv850e2v4 โ€” specify that the target processor is the V850E3V5. This is an alias for the -mv850e3v5 option ๐Ÿ’€
  • -mv850e2v3 โ€” specify that the target processor is the V850E2V3. The preprocessor constant "__v850e2v3__" is defined if this option is used ๐Ÿ‘‘
  • -mv850e2 โ€” specify that the target processor is the V850E2. The preprocessor constant "__v850e2__" is defined if this option is used โญ
  • -mv850e1 โ€” specify that the target processor is the V850E1. The preprocessor constants "__v850e1__" and "__v850e__" are defined if this option is used ๐Ÿฆ‹
  • -mv850es โ€” specify that the target processor is the V850ES. This is an alias for the -mv850e1 option ๐ŸŽ€
  • -mv850e โ€” specify that the target processor is the V850E. The preprocessor constant "__v850e__" is defined if this option is used ๐Ÿ’…

If neither -mv850 nor -mv850e nor -mv850e1 nor -mv850e2 nor -mv850e2v3 nor -mv850e3v5 are defined, then a default target processor is chosen and the relevant __v850*__ preprocessor constant is defined ๐Ÿ™ˆ

The preprocessor constants "__v850" and "__v851__" are always defined, regardless of which processor variant is the target ๐Ÿซถ

  • -mdisable-callt, -mno-disable-callt โ€” this option suppresses generation of the "CALLT" instruction for the v850e, v850e1, v850e2, v850e2v3 and v850e3v5 flavors of the v850 architecture ๐ŸŒˆ

This option is enabled by default when the RH850 ABI is in use (see -mrh850-abi), and disabled by default when the GCC ABI is in use. If "CALLT" instructions are being generated, then the C preprocessor symbol "__V850_CALLT__" is defined ๐Ÿ“

  • -mrelax, -mno-relax โ€” pass on (or do not pass on) the -mrelax command-line option to the assembler ๐ŸŒธ
  • -mlong-jumps, -mno-long-jumps โ€” disable (or re-enable) the generation of PC-relative jump instructions ๐Ÿ’–
  • -msoft-float, -mhard-float โ€” Turn hardware floating point instruction generation off (or back on) ๐Ÿ’…. This only matters when the target is V850E2V3 or higher โœจ. When hardware FP is being generated, the __FPU_OK__ preprocessor symbol gets defined. Otherwise you get __NO_FPU__ ๐ŸŒธ.
  • -mloop โ€” Lets you use the e3v5 LOOP instruction ๐Ÿ”. It's not on by default when e3v5 is selected, because it's still experimental ๐Ÿ™ˆ.
  • -mrh850-abi, -mghs โ€” Turns on support for the RH850 version of the V850 ABI ๐Ÿ‘‘. This is the default, and with it these rules apply:
    • Integer sized structures and unions come back through a memory pointer, not a register.
    • Big structures and unions (more than 8 bytes) get passed by value.
    • Functions are aligned to 16-bit boundaries.
    • -m8byte-align is supported.
    • -mdisable-callt is on by default. -mno-disable-callt is not supported, so don't even try ๐Ÿ’€.

When this ABI is active, the __V850_RH850_ABI__ preprocessor symbol gets defined ๐ŸŽ€.

  • -mgcc-abi โ€” Turns on support for the old GCC version of the V850 ABI ๐Ÿ•ฐ๏ธ. With this one:
    • Integer sized structures and unions get returned in register r10.
    • Big structures and unions (more than 8 bytes) get passed by reference.
    • Functions are aligned to 32-bit boundaries, unless you're optimizing for size.
    • -m8byte-align is not supported.
    • -mdisable-callt is supported, but not enabled by default.

With this ABI on, the __V850_GCC_ABI__ preprocessor symbol is defined ๐Ÿงš.

  • -m8byte-align, -mno-8byte-align โ€” Lets double and long long get aligned on 8-byte boundaries ๐Ÿ’œ. By default, everything gets capped at 4-byte alignment. When -m8byte-align is in effect, the __V850_8BYTE_ALIGN__ preprocessor symbol gets defined โœจ.
  • -mbig-switch โ€” Generates code that's suitable for big switch tables ๐Ÿ“. Only reach for this if the assembler or linker starts complaining about out of range branches inside a switch table ๐Ÿ˜ญ.
  • -mapp-regs โ€” Makes r2 and r5 get used in the generated code ๐Ÿซถ. This is the default โœจ.
  • -mno-app-regs โ€” Makes r2 and r5 get treated as fixed registers ๐Ÿ”’.

๐Ÿฆ‹ VAX Options ๐Ÿฆ‹

These -m options are defined for the VAX ๐Ÿ’–:

  • -munix โ€” Don't output certain jump instructions (like aobleq and so on) that the Unix assembler for the VAX can't handle across long ranges ๐Ÿ™…โ€โ™€๏ธ.
  • -mgnu โ€” Do output those jump instructions ๐ŸŒˆ, on the assumption that you're using the GNU assembler.
  • -mg โ€” Output 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 ๐ŸŽฏ. That causes the libc.a and libdebug.a libraries to get linked. 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 the option ๐Ÿ–ฅ๏ธ. That causes libc.a and libsim.a to get linked.
  • -mfpu, -mhard-float โ€” Generate code with floating-point instructions ๐Ÿ’…. This is the default โœจ.
  • -mno-fpu, -msoft-float โ€” Generate code that uses library calls for floating-point instead ๐Ÿ“š.
-msoft-float changes the calling convention in the output file, so it's only useful if you compile your entire program with it ๐Ÿšจ. You also need to compile libgcc.a (the library that comes with GCC) with -msoft-float for this to work ๐Ÿ˜ฌ.
  • -mcpu=cpu_type โ€” Sets the instruction set, register set, and instruction scheduling parameters for the machine type cpu_type ๐Ÿค–. The supported values are mcm, gr5 and gr6 ๐Ÿ’œ.
    • mcm is a synonym for gr5, kept around for backward compatibility ๐Ÿ•ฐ๏ธ.

By default (unless it was configured otherwise), GCC generates code for the GR5 variant of the Visium architecture ๐ŸŒŸ.

With -mcpu=gr6, GCC generates code for the GR6 variant. 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 โ€” Generate code for supervisor mode, where there are no restrictions on access to general registers ๐Ÿ‘‘. This is the default.
  • -muser-mode โ€” Generate 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 โ€” Return VMS condition codes from main. The default is POSIX-style condition (like error) codes ๐ŸŽ€.
  • -mdebug-main=prefix โ€” Flags the first routine whose name starts with prefix as the main routine for the debugger ๐Ÿ”.
  • -mmalloc64 โ€” Defaults to 64-bit memory allocation routines ๐Ÿง .
  • -mpointer-size=size โ€” Sets the default size of pointers ๐Ÿ“. The possible values for size are 32 or short for 32-bit pointers, 64 or long for 64-bit pointers, and no for supporting only 32-bit pointers ๐Ÿซ . That last 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 __RTP__ preprocessor macro ๐Ÿ’–.
  • -non-static โ€” Links an RTP executable against shared libraries instead of static libraries ๐Ÿ“ฆ. The options -static and -shared can also be used for RTPs, and -static is the default ๐Ÿซถ.
  • -Bstatic, -Bdynamic โ€” These get passed down to the linker ๐Ÿ”—. They're there for compatibility with Diab ๐Ÿ’œ.
  • -Xbind-lazy โ€” Enables lazy binding of function calls ๐Ÿ˜ด. This is equivalent to -Wl,-z,now and is there for compatibility with Diab ๐ŸŒธ.
  • -Xbind-now โ€” Disables lazy binding of function calls โšก. This is the default, and it's there for compatibility with Diab ๐Ÿ’….

๐Ÿ‘‘ x86 Options ๐Ÿ‘‘

These -m options are defined for the x86 family of computers ๐Ÿ’ป.

  • -march=cpu-type โ€” Generates instructions for the machine type cpu-type ๐Ÿš€. Unlike -mtune=cpu-type, which only tunes the generated code for the specified cpu-type, -march=cpu-type lets GCC generate code that may not run at all on processors other than the one you picked ๐Ÿ˜ญ. Specifying -march=cpu-type implies -mtune=cpu-type, except where noted otherwise โœจ.

The choices for cpu-type are:

  • native โ€” Picks the CPU to generate code for at compile time by detecting the processor type of the compiling machine ๐Ÿ”. Using -march=native enables all instruction subsets the local machine supports, so the result might not run on different machines ๐Ÿ™ˆ. Using -mtune=native produces code optimized for the local machine, within the limits of the chosen instruction set ๐ŸŽฏ.
  • x86-64 โ€” A generic CPU with 64-bit extensions ๐ŸŒ.
  • 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 select the same CPU features the x86-64 psABI documents for that micro-architecture level ๐Ÿ“œ.

Since these cpu-type values don't have a matching -mtune setting, using -march with them enables generic tuning ๐ŸŽต. If you want specific tuning, use -mtune=other-cpu-type with an appropriate other-cpu-type value ๐Ÿซถ.

  • i386 โ€” The original Intel i386 CPU ๐Ÿฆ•.
  • i486 โ€” The Intel i486 CPU ๐ŸŒ™. (No scheduling is implemented for this chip ๐Ÿ™ƒ.)
  • i586, pentium โ€” 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 โ€” With -march, the Pentium Pro instruction set gets used, so the code runs on all i686 family chips ๐Ÿ’–. With -mtune, it means the same thing 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 ๐Ÿ’ป. It's used by Centrino notebooks ๐Ÿ’œ.
  • pentium4, pentium4m โ€” Intel Pentium 4 CPU with MMX, SSE and SSE2 instruction set support ๐Ÿ”ฅ.
  • prescott โ€” An improved version of the Intel Pentium 4 CPU with MMX, SSE, SSE2 and SSE3 instruction set support ๐ŸŒธ.
  • nocona โ€” An improved version of the Intel Pentium 4 CPU with 64-bit extensions, MMX, SSE, SSE2 and SSE3 instruction set support ๐Ÿงš.
  • core2 โ€” 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.
  • k6 ๐Ÿฆ‹ โ€” AMD K6 CPU with MMX instruction set support.
  • k6-2, k6-3 ๐ŸŒˆ โ€” Improved versions of AMD K6 CPU with MMX and 3DNow! instruction set support.
  • athlon, athlon-tbird โญ โ€” AMD Athlon CPU with MMX, 3dNOW!, enhanced 3DNow! and SSE prefetch instructions support.
  • athlon-4, athlon-xp, athlon-mp ๐Ÿ”ฅ โ€” Improved AMD Athlon CPU with MMX, 3DNow!, enhanced 3DNow! and full SSE instruction set support.
  • k8, opteron, athlon64, athlon-fx ๐Ÿ’œ โ€” Processors based on the AMD K8 core with x86-64 instruction set support, including the AMD Opteron, Athlon 64, and Athlon 64 FX processors. (This supersets MMX, SSE, SSE2, 3DNow!, enhanced 3DNow! and 64-bit instruction set extensions.)
  • k8-sse3, opteron-sse3, athlon64-sse3 ๐Ÿงš โ€” Improved versions of AMD K8 cores with SSE3 instruction set support.
  • amdfam10, barcelona ๐Ÿ‘‘ โ€” CPUs based on AMD Family 10h cores with x86-64 instruction set support. (This supersets MMX, SSE, SSE2, SSE3, SSE4A, 3DNow!, enhanced 3DNow!, ABM and 64-bit instruction set extensions.)
  • bdver1 ๐Ÿ’– โ€” CPUs based on AMD Family 15h cores with x86-64 instruction set support. (This supersets FMA4, AVX, XOP, LWP, AES, PCLMUL, CX16, MMX, SSE, SSE2, SSE3, SSE4A, SSSE3, SSE4.1, SSE4.2, ABM and 64-bit instruction set extensions.)
  • bdver2 ๐ŸŽ€ โ€” AMD Family 15h core based CPUs with x86-64 instruction set support. (This supersets BMI, TBM, F16C, FMA, FMA4, AVX, XOP, LWP, AES, PCLMUL, CX16, MMX, SSE, SSE2, SSE3, SSE4A, SSSE3, SSE4.1, SSE4.2, ABM and 64-bit instruction set extensions.)
  • bdver3 ๐Ÿฆ‹ โ€” AMD Family 15h core based CPUs with x86-64 instruction set support. (This supersets BMI, TBM, F16C, FMA, FMA4, FSGSBASE, AVX, XOP, LWP, AES, PCLMUL, CX16, MMX, SSE, SSE2, SSE3, SSE4A, SSSE3, SSE4.1, SSE4.2, ABM and 64-bit instruction set extensions.)
  • bdver4 ๐ŸŒธ โ€” AMD Family 15h core based CPUs with x86-64 instruction set support. (This supersets BMI, BMI2, TBM, F16C, FMA, FMA4, FSGSBASE, AVX, AVX2, XOP, LWP, AES, PCLMUL, CX16, MOVBE, MMX, SSE, SSE2, SSE3, SSE4A, SSSE3, SSE4.1, SSE4.2, ABM and 64-bit instruction set extensions.)
  • znver1 โœจ โ€” AMD Family 17h core based CPUs with x86-64 instruction set support. (This supersets BMI, BMI2, F16C, FMA, FSGSBASE, AVX, AVX2, ADCX, RDSEED, MWAITX, SHA, CLZERO, AES, PCLMUL, CX16, MOVBE, MMX, SSE, SSE2, SSE3, SSE4A, SSSE3, SSE4.1, SSE4.2, ABM, XSAVEC, XSAVES, CLFLUSHOPT, POPCNT, and 64-bit instruction set extensions.)
  • znver2 ๐Ÿซถ โ€” AMD Family 17h core based CPUs with x86-64 instruction set support. (This supersets BMI, BMI2, CLWB, F16C, FMA, FSGSBASE, AVX, AVX2, ADCX, RDSEED, MWAITX, SHA, CLZERO, AES, PCLMUL, CX16, MOVBE, MMX, SSE, SSE2, SSE3, SSE4A, SSSE3, SSE4.1, SSE4.2, ABM, XSAVEC, XSAVES, CLFLUSHOPT, POPCNT, RDPID, WBNOINVD, and 64-bit instruction set extensions.)
  • znver3 ๐Ÿ’… โ€” AMD Family 19h core based CPUs with x86-64 instruction set support. (This supersets BMI, BMI2, CLWB, F16C, FMA, FSGSBASE, AVX, AVX2, ADCX, RDSEED, MWAITX, SHA, CLZERO, AES, PCLMUL, CX16, MOVBE, MMX, SSE, SSE2, SSE3, SSE4A, SSSE3, SSE4.1, SSE4.2, ABM, XSAVEC, XSAVES, CLFLUSHOPT, POPCNT, RDPID, WBNOINVD, PKU, VPCLMULQDQ, VAES, and 64-bit instruction set extensions.)
  • btver1 ๐ŸŒˆ โ€” CPUs based on AMD Family 14h cores with x86-64 instruction set support. (This supersets MMX, SSE, SSE2, SSE3, SSSE3, SSE4A, CX16, ABM and 64-bit instruction set extensions.)
  • btver2 ๐Ÿ“ โ€” CPUs based on AMD Family 16h cores with x86-64 instruction set support. This includes MOVBE, F16C, BMI, AVX, PCLMUL, AES, SSE4.2, SSE4.1, CX16, ABM, SSE4A, SSSE3, SSE3, SSE2, SSE, MMX and 64-bit instruction set extensions.
  • winchip-c6 ๐Ÿงธ โ€” IDT WinChip C6 CPU, dealt in same way as i486 with additional MMX instruction set support.
  • winchip2 ๐ŸŒท โ€” IDT WinChip 2 CPU, dealt in same way as i486 with additional MMX and 3DNow! instruction set support.
  • c3 โ€” the VIA C3 CPU ๐ŸŽ€, with MMX and 3DNow! instruction set support. (No scheduling is implemented for this chip ๐Ÿ™ˆ.)
  • c3-2 โ€” the VIA C3-2 ๐ŸŒธ, also called Nehemiah/C5XL, with MMX and SSE instruction set support. (No scheduling is implemented for this chip.)
  • c7 โ€” the VIA C7 ๐Ÿ’…, also called Esther, with MMX, SSE, SSE2 and SSE3 instruction set support. (No scheduling is implemented for this chip.)
  • samuel-2 โ€” the VIA Eden Samuel 2 ๐Ÿฆ‹, with MMX and 3DNow! instruction set support. (No scheduling is implemented for this chip.)
  • nehemiah โ€” the VIA Eden Nehemiah ๐Ÿ“, with MMX and SSE instruction set support. (No scheduling is implemented for this chip.)
  • esther โ€” the VIA Eden Esther ๐Ÿงš, with MMX, SSE, SSE2 and SSE3 instruction set support. (No scheduling is implemented for this chip.)
  • eden-x2 โ€” the VIA Eden X2 ๐Ÿ’œ, with x86-64, MMX, SSE, SSE2 and SSE3 instruction set support. (No scheduling is implemented for this chip.)
  • eden-x4 โ€” the VIA Eden X4 ๐Ÿ‘‘, with x86-64, MMX, SSE, SSE2, SSE3, SSSE3, SSE4.1, SSE4.2, AVX and AVX2 instruction set support. (No scheduling is implemented for this chip.)
  • nano โ€” the generic VIA Nano โญ, with x86-64, MMX, SSE, SSE2, SSE3 and SSSE3 instruction set support. (No scheduling is implemented for this chip.)
  • nano-1000 โ€” the VIA Nano 1xxx ๐ŸŒˆ, with x86-64, MMX, SSE, SSE2, SSE3 and SSSE3 instruction set support. (No scheduling is implemented for this chip.)
  • nano-2000 โ€” the VIA Nano 2xxx ๐Ÿ’–, with x86-64, MMX, SSE, SSE2, SSE3 and SSSE3 instruction set support. (No scheduling is implemented for this chip.)
  • nano-3000 โ€” the VIA Nano 3xxx โœจ, with x86-64, MMX, SSE, SSE2, SSE3, SSSE3 and SSE4.1 instruction set support. (No scheduling is implemented for this chip.)
  • nano-x2 โ€” the VIA Nano Dual Core ๐Ÿฆ‹, with x86-64, MMX, SSE, SSE2, SSE3, SSSE3 and SSE4.1 instruction set support. (No scheduling is implemented for this chip.)
  • nano-x4 โ€” the VIA Nano Quad Core ๐Ÿ”ฅ, with x86-64, MMX, SSE, SSE2, SSE3, SSSE3 and SSE4.1 instruction set support. (No scheduling is implemented for this chip.)
  • geode โ€” the AMD Geode embedded processor ๐Ÿงš, with MMX and 3DNow! instruction set support.
  • -mtune=cpu-type โ€” okay so this one is lowkey iconic ๐Ÿ’…. It tunes everything applicable in the generated code to cpu-type, except for the ABI and the set of available instructions. Picking a specific cpu-type schedules things nicely for that particular chip, but 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 tuned for Pentium 4 that still runs on i686 machines ๐Ÿซถ.
    • The choices for cpu-type are the same as for -march. On top of that, -mtune gives you 2 extra choices for cpu-type โœจ:
    • generic โ€” code optimized for the most common IA32/AMD64/EM64T processors ๐ŸŒธ. If you know which 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 get deployed in the marketplace, the behavior of this option will change. So if you upgrade to a newer GCC, the code generation controlled by this option will shift to reflect whichever processors are most common when that GCC version is released.
      • There is no -march=generic option, because -march indicates the instruction set the compiler can use, and there's no generic instruction set that applies to all processors. -mtune is different: it indicates the processor (or, in this case, the collection of processors) the code is optimized for.
    • intel โ€” code optimized for the most current Intel processors, which for this version of GCC are Haswell and Silvermont ๐Ÿงš. If you know your CPU, use the corresponding -mtune or -march option instead of -mtune=intel. But if you want your application to perform better on both Haswell and Silvermont, this is the move ๐Ÿ’–.
      • As new Intel processors get deployed in the marketplace, the behavior of this option will change. So if you upgrade to a newer GCC, the code generation controlled by this option will reflect the most current Intel processors at the time that version of GCC is released.
      • There is no -march=intel option, because -march indicates the instruction set the compiler can use, and there's no common instruction set that applies to all processors. -mtune indicates the processor (or collection of processors) the code is optimized for.
  • -mcpu=cpu-type โ€” an old nickname for -mtune. It's deprecated, so please don't reach for it ๐Ÿ™ˆ.
  • -mfpmath=unit โ€” generate floating-point arithmetic for the selected unit. The choices for unit are ๐Ÿงฎ:
    • 387 โ€” use the standard 387 floating-point coprocessor that's on most chips, and emulate it otherwise. Code compiled with this option runs almost everywhere ๐ŸŒˆ. The temporary results are computed in 80-bit precision instead of the precision the type specifies, so your results may differ slightly from most other chips. See -ffloat-store for a more detailed description.
      • This is the default choice for non-Darwin x86-32 targets.
    • sse โ€” use the scalar floating-point instructions in the SSE instruction set ๐Ÿ”ฅ. This is supported by Pentium III and newer chips, and in the AMD line by Athlon-4, Athlon XP and Athlon MP chips. The earlier version of SSE only supports single-precision arithmetic, so double and extended-precision still get done using 387. A later version, only in Pentium 4 and AMD x86-64 chips, supports double-precision too.
      • For the x86-32 compiler, you must use -march=cpu-type, -msse or -msse2 to enable the SSE extensions and make this option work. For the x86-64 compiler, these extensions are enabled by default.
      • The resulting code should be considerably faster in most cases and avoid the numerical instability problems of 387 code. Heads up though: it may break some existing code that expects temporaries to be 80 bits ๐Ÿ’€.
      • This is the default choice for the x86-64 compiler, Darwin x86-32 targets, and x86-32 targets with the SSE2 instruction set when -ffast-math is enabled.
    • sse,387, sse+387, both โ€” attempt to use both instruction sets at once. This effectively doubles the amount of available registers, and on chips with separate execution units for 387 and SSE, the execution resources too ๐Ÿฆ‹. Use this 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 โ€” output assembly instructions using the selected dialect ๐ŸŽ€. This also affects which dialect is used for basic asm and extended asm. The supported choices (in dialect order) are att or intel. The default is att. Darwin does not support intel.
  • -mieee-fp, -mno-ieee-fp โ€” control whether or not the compiler uses IEEE floating-point comparisons. These correctly handle the case where the result of a comparison is unordered ๐Ÿง .
  • -m80387, -mhard-float โ€” generate output containing 80387 instructions for floating point ๐Ÿ’œ.
  • -mno-80387, -msoft-float โ€” generate output containing library calls for floating point ๐Ÿซถ.
Warning: the requisite libraries are NOT part of GCC ๐Ÿ˜ญ. Normally the facilities of the machine's usual C compiler are used, but this cannot be done directly in cross-compilation. You must make your own arrangements to provide suitable library functions for cross-compilation.
Also, 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 โ€” do not use the FPU registers for function return values ๐Ÿ‘‘.
    • The usual calling convention has functions return float and double values in an FPU register, even if there's no FPU. The idea is that the operating system should emulate an FPU.
    • The option -mno-fp-ret-in-387 causes those values to be returned in ordinary CPU registers instead.
  • -mno-fancy-math-387 โ€” some 387 emulators don't support the sin, cos and sqrt instructions for the 387 ๐ŸŒธ. Specify this option to avoid generating those instructions. It gets overridden when -march says the target CPU always has an FPU, because then the instruction doesn't need emulating. These instructions aren't generated unless you also use the -funsafe-math-optimizations switch.
  • -malign-double, -mno-align-double โ€” control whether GCC aligns double, long double, and long long variables on a two-word boundary or a one-word boundary ๐Ÿ“. Aligning double variables on a two-word boundary produces code that runs somewhat faster on a Pentium, at the expense of more memory.
    • On x86-64, -malign-double is enabled by default.
Warning: if you use the -malign-double switch, structures containing the above types are aligned differently than the published application binary interface specifications for x86-32, and they are NOT binary compatible with structures in code compiled without that switch ๐Ÿ’€.
  • -m96bit-long-double, -m128bit-long-double โ€” these switches control the size of the long double type โœจ. The x86-32 application binary interface specifies the size to be 96 bits, so -m96bit-long-double is the default in 32-bit mode.

Okay so modern chips (Pentium and newer) really, really want long double lined up on an 8- or 16-byte boundary ๐Ÿซถ But in arrays and structs that follow the ABI, that's just not possible ๐Ÿ˜ญ So -m128bit-long-double pads the long double with an extra 32-bit zero to push it onto a 16-byte boundary โœจ

On the x86-64 compiler, -m128bit-long-double is already the default, because its ABI says long double gets aligned on a 16-byte boundary ๐Ÿ’…

Notice that neither of these options unlocks any extra precision over the x87 standard of 80 bits for a long double ๐Ÿ™ˆ

Warning: bestie, if you override the default value for your target ABI, this changes the size of structures and arrays containing long double variables. It also changes the function calling convention for functions taking long double. Hence they are not binary-compatible with code compiled without that switch ๐Ÿ’€
  • -mlong-double-64 โ€” gives long double a 64-bit size, making it equivalent to double ๐ŸŒธ This is the default for the 32-bit Bionic C library.
  • -mlong-double-80 โ€” one of the three size switches for long double, the 80-bit one ๐Ÿงš
  • -mlong-double-128 โ€” gives long double a 128-bit size, making it equivalent to __float128 ๐Ÿ‘‘ This is the default for the 64-bit Bionic C library.
Warning: same energy as before, bestie. Overriding the default value for your target ABI changes the size of structures and arrays containing long double variables, and it also modifies the function calling convention for functions taking long double. Hence they are not binary-compatible with code compiled without that switch ๐Ÿ™ˆ
  • -malign-data=type โ€” controls how GCC aligns variables ๐ŸŽ€ The supported values for type are compat, which uses an increased alignment value that's compatible with GCC 4.8 and earlier; abi, which uses the alignment value specified by the psABI; and cacheline, which uses an increased alignment value to match the cache line size. compat is the default, so no stress ๐Ÿ’–
  • -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, where functions that take a fixed number of arguments return with the ret num instruction, which pops their arguments while returning โœจ This saves one instruction in the caller, since there's no need to pop the arguments there.

You can give a single function this calling sequence with the function attribute stdcall. You can also override -mrtd for one function by using the function attribute cdecl ๐Ÿ’…

Warning: this calling convention is incompatible with the one normally used on Unix, so you cannot use it if you need to call libraries compiled with the Unix compiler ๐Ÿ˜ญ Also, you must provide function prototypes for all functions that take variable numbers of arguments (including printf), 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 get 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, then 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 made by those older compiler versions or older versions of GCC.
  • -mpc32 โ€” sets 80387 floating-point precision to 32 bits ๐ŸŒˆ The significands of floating-point operation results get rounded to 24 bits (single precision).
  • -mpc64 โ€” sets 80387 floating-point precision to 64 bits ๐ŸŒˆ The significands get rounded to 53 bits (double precision).
  • -mpc80 โ€” sets 80387 floating-point precision to 80 bits ๐Ÿ‘‘ The significands get rounded to 64 bits (extended double precision), and this is the default.

When -mpc32 (or -mpc64, or -mpc80) is used, floating-point operations in higher precisions aren't available to the programmer unless you set the FPU control word explicitly ๐Ÿค“

Setting the rounding of floating-point operations to less than the default 80 bits can speed some programs up by 2% or more ๐Ÿƒโ€โ™€๏ธ But some math libraries assume extended-precision (80-bit) floating-point operations are on by default. Routines in those libraries could suffer serious accuracy loss, usually through so-called "catastrophic cancellation", if you use this option to drop the precision below extended precision ๐Ÿ˜ญ

  • -mstackrealign โ€” realigns the stack at entry ๐Ÿช„ On x86, -mstackrealign generates an alternate prologue and epilogue that realigns the run-time stack if necessary. This lets legacy code that keeps 4-byte stack alignment mix with modern code that keeps 16-byte stack alignment for SSE compatibility. See also the attribute force_align_arg_pointer, which applies to individual functions.
  • -mpreferred-stack-boundary=num โ€” tries to keep the stack boundary aligned to a 2 raised to num byte boundary ๐Ÿ’– If -mpreferred-stack-boundary isn't specified, the default is 4 (16 bytes or 128 bits).
Warning: when generating code for the x86-64 architecture with SSE extensions disabled, -mpreferred-stack-boundary=3 can keep the stack boundary aligned to an 8-byte boundary. The x86-64 ABI requires 16-byte stack alignment, so this is ABI incompatible and only meant for a controlled environment where stack space is a seriously limited resource ๐Ÿงธ This option leads to wrong code when functions compiled with 16-byte stack alignment (like functions from a standard library) get called with a misaligned stack. In that case, SSE instructions may cause misaligned memory access traps. Variable arguments are also handled incorrectly for 16-byte aligned objects (including x87 long double and __int128), which leads to wrong results. You must build all modules with -mpreferred-stack-boundary=3, including any libraries. That includes the system libraries and startup modules ๐Ÿ’€
  • -mincoming-stack-boundary=num โ€” assumes the incoming stack is aligned to a 2 raised to num byte boundary ๐Ÿฆ‹ If -mincoming-stack-boundary isn't specified, the one set by -mpreferred-stack-boundary gets used.

On Pentium and Pentium Pro, double and long double values should be aligned to an 8-byte boundary (see -malign-double), or you'll take significant run-time performance penalties ๐Ÿข On Pentium III, the Streaming SIMD Extension (SSE) data type __m128 may not work properly if it isn't 16-byte aligned.

To keep values properly aligned on the stack, the stack boundary has to be as aligned as the strictest value stored on the stack. Every function also has to be generated so it keeps the stack aligned. So calling a function compiled with a higher preferred stack boundary from a function compiled with a lower one will most likely misalign the stack ๐Ÿ˜ต It's recommended that libraries using callbacks always use the default setting.

This extra alignment does eat up extra stack space and generally increases code size. Code that is sensitive to stack space usage, like embedded systems and operating system kernels, may want to reduce the preferred alignment to -mpreferred-stack-boundary=2 ๐ŸŒธ


These next switches are the ISA extension party ๐ŸŽ‰ Each one turns on its matching instruction set, and each has a corresponding -mno- option to disable it again. These extensions are also available as built-in functions: see x86 Built-in Functions for details of the functions enabled and disabled by these switches ๐Ÿ’œ

  • -mmmx โ€” enables the MMX instructions ๐ŸŽ€
  • -msse โ€” enables the SSE instructions ๐ŸŽ€
  • -msse2 โ€” enables the SSE2 instructions ๐ŸŽ€
  • -msse3 โ€” enables the SSE3 instructions ๐ŸŽ€
  • -mssse3 โ€” enables the SSSE3 instructions ๐ŸŽ€
  • -msse4 โ€” enables the SSE4 instructions ๐ŸŽ€
  • -msse4a โ€” enables the SSE4A instructions ๐ŸŽ€
  • -msse4.1 โ€” enables the SSE4.1 instructions ๐ŸŽ€
  • -msse4.2 โ€” enables the SSE4.2 instructions ๐ŸŽ€
  • -mavx โ€” enables the AVX instructions ๐Ÿฆ‹
  • -mavx2 โ€” enables the AVX2 instructions ๐Ÿฆ‹
  • -mavx512f โ€” enables the AVX512F instructions ๐Ÿฆ‹
  • -mavx512pf โ€” enables the AVX512PF instructions ๐Ÿฆ‹
  • -mavx512er โ€” enables the AVX512ER instructions ๐Ÿฆ‹
  • -mavx512cd โ€” enables the AVX512CD instructions ๐Ÿฆ‹
  • -mavx512vl โ€” enables the AVX512VL instructions ๐Ÿฆ‹
  • -mavx512bw โ€” enables the AVX512BW instructions ๐Ÿฆ‹
  • -mavx512dq โ€” enables the AVX512DQ instructions ๐Ÿฆ‹
  • -mavx512ifma โ€” enables the AVX512IFMA instructions ๐Ÿฆ‹
  • -mavx512vbmi โ€” enables the AVX512VBMI instructions ๐Ÿฆ‹
  • -msha โ€” enables the SHA instructions ๐Ÿ”
  • -maes โ€” enables the AES instructions ๐Ÿ”
  • -mpclmul โ€” enables the PCLMUL instructions ๐Ÿ”
  • -mclflushopt โ€” enables the CLFLUSHOPT instructions ๐Ÿงน
  • -mclwb โ€” enables the CLWB instructions ๐Ÿงน
  • -mfsgsbase โ€” enables the FSGSBASE instructions ๐ŸŒˆ
  • -mptwrite โ€” enables the PTWRITE instructions โœ๏ธ
  • -mrdrnd โ€” enables the RDRND instructions ๐ŸŽฒ
  • -mf16c โ€” enables the F16C instructions ๐Ÿ”ฅ
  • -mfma โ€” enables the FMA instructions ๐Ÿ”ฅ
  • -mpconfig โ€” enables the PCONFIG instructions โญ
  • -mwbnoinvd โ€” enables the WBNOINVD instructions โญ
  • -mfma4 โ€” enables the FMA4 instructions ๐Ÿ”ฅ
  • -mprfchw โ€” enables the PREFETCHW instructions ๐Ÿƒโ€โ™€๏ธ
  • -mrdpid โ€” enables the RDPID instructions ๐Ÿชช
  • -mprefetchwt1 โ€” enables the PREFETCHWT1 instructions ๐Ÿƒโ€โ™€๏ธ
  • -mrdseed โ€” enables the RDSEED instructions ๐ŸŽฒ
  • -msgx โ€” enables the SGX instructions ๐Ÿฐ
  • -mxop โ€” enables the XOP instructions ๐Ÿง 
  • -mlwp โ€” enables the LWP instructions ๐Ÿง 
  • -m3dnow โ€” enables the 3DNow! instructions ๐Ÿ•น๏ธ
  • -m3dnowa โ€” enables the enhanced 3DNow! instructions ๐Ÿ•น๏ธ
  • -mpopcnt โ€” enables the POPCNT instructions ๐Ÿฟ
  • -mabm โ€” enables the ABM instructions ๐Ÿงฎ
  • -madx โ€” enables the ADX instructions ๐Ÿงฎ
  • -mbmi โ€” enables the BMI instructions ๐Ÿงฎ
  • -mbmi2 โ€” enables the BMI2 instructions ๐Ÿงฎ
  • -mlzcnt โ€” enables the LZCNT instructions ๐Ÿงฎ
  • -mfxsr โ€” enables the FXSR instructions ๐Ÿ’พ
  • -mxsave โ€” enables the XSAVE instructions ๐Ÿ’พ
  • -mxsaveopt โ€” enables the XSAVEOPT instructions ๐Ÿ’พ
  • -mxsavec โ€” enables the XSAVEC instructions ๐Ÿ’พ
  • -mxsaves โ€” enables the XSAVES instructions ๐Ÿ’พ
  • -mrtm โ€” enables the RTM instructions ๐Ÿงต
  • -mhle โ€” enables the HLE instructions ๐Ÿงต
  • -mtbm โ€” enables the TBM instructions ๐Ÿงฎ
  • -mmwaitx โ€” enables the MWAITX instructions โณ
  • -mclzero โ€” enables the CLZERO instructions ๐Ÿงฝ
  • -mpku โ€” enables the PKU instructions ๐Ÿ”
  • -mavx512vbmi2 โ€” enables the AVX512VBMI2 instructions ๐Ÿฆ‹
  • -mavx512bf16 โ€” enables the AVX512BF16 instructions ๐Ÿฆ‹
  • -mgfni โ€” enables the GFNI instructions ๐ŸŒธ
  • -mvaes โ€” enables the VAES instructions ๐Ÿ”
  • -mwaitpkg โ€” enables the WAITPKG instructions โณ
  • -mvpclmulqdq โ€” enables the VPCLMULQDQ instructions ๐Ÿ”
  • -mavx512bitalg โ€” enables the AVX512BITALG instructions ๐Ÿฆ‹
  • -mmovdiri โ€” enables the MOVDIRI instructions ๐Ÿšš
  • -mmovdir64b โ€” enables the MOVDIR64B instructions ๐Ÿšš
  • -menqcmd โ€” enables the ENQCMD instructions ๐Ÿšš
  • -mavx512vpopcntdq โ€” enables the AVX512VPOPCNTDQ instructions ๐Ÿฆ‹
  • -mavx512vp2intersect โ€” enables the AVX512VP2INTERSECT instructions ๐Ÿฆ‹
  • -mavx5124fmaps โ€” enables the AVX5124FMAPS instructions ๐Ÿฆ‹
  • -mavx512vnni โ€” enables the AVX512VNNI instructions ๐Ÿฆ‹
  • -mavx5124vnniw โ€” enables the AVX5124VNNIW instructions ๐Ÿฆ‹
  • -mcldemote โ€” enables the CLDEMOTE instructions ๐Ÿงน

To generate SSE/SSE2 instructions automatically from floating-point code (instead of 387 instructions), bestie, check out -mfpmath=sse. ๐Ÿ’…โœจ

โš ๏ธ Heads up: when -mavx is on, GCC kinda benches the SSEx instructions ๐Ÿ˜ญ It swaps in brand new AVX instructions, or AVX equivalents for all the SSEx ones, whenever it needs them. Major glow-up energy ๐Ÿฆ‹

These options let GCC use those extended instructions in the generated code, even without -mfpmath=sse. ๐ŸŒธ If your app does run-time CPU detection, you have to compile separate files for each supported architecture, using the right flags for each one. Lowkey the file with the CPU detection code should be compiled without these options. This is the step people always mess up, so pls be careful ๐Ÿซถ


  • -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-grain control over x86 code generation features ๐Ÿ‘‘ feature-list is a comma-separated list of feature names (see also -mdump-tune-features). A feature gets turned on if it's not preceded by ^, and turned off if it is. This one is really meant for GCC developers, so proceed with care ๐Ÿ’€
โš ๏ธ Using -mtune-ctrl=feature-list may lead to code paths that aren't covered by testing, and it can potentially result in compiler ICEs or runtime errors. Not the vibe if you're not ready for that ๐Ÿ˜ญ
  • -mno-default โ€” turns off all tunable features. See also -mtune-ctrl=feature-list and -mdump-tune-features. ๐Ÿ™ˆ
  • -mcld โ€” makes GCC emit a cld instruction in the prologue of functions that use string instructions. Here's the tea โ˜• 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 run with DF set, which gives you the wrong direction mode when string instructions are used. This 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 โ€” makes GCC emit a vzeroupper instruction before control flow leaves the function. This minimizes the AVX to SSE transition penalty and removes unnecessary zeroupper intrinsics. Clean girl energy ๐Ÿงผโœจ
  • -mprefer-avx128 โ€” tells GCC to use 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 limitations are applied to GCC beyond what the selected platform defines.
    • 128 โ€” prefer 128-bit vector width for instructions.
    • 256 โ€” prefer 256-bit vector width for instructions.
    • 512 โ€” prefer 512-bit vector width for instructions.
  • -mcx16 โ€” lets GCC generate CMPXCHG16B instructions in 64-bit code to implement 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. However, for __atomic Builtins operating on 128-bit integers, a library call is always used.
  • -msahf โ€” enables generation of SAHF instructions in 64-bit code. Okay so, early Intel Pentium 4 CPUs with Intel 64 support (before the Pentium 4 G1 step in December 2005) didn't have the LAHF and SAHF instructions that AMD64 supports ๐Ÿ™ˆ These are load and store instructions, respectively, for certain status flags. In 64-bit mode, the SAHF instruction is used to optimize the fmod, drem, and remainder built-in functions; see Other Builtins for details.
  • -mmovbe โ€” enables use of the movbe instruction to 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 to generate the crc32 machine instruction. ๐ŸŒˆ
  • -mrecip โ€” enables use of RCPSS and RSQRTSS instructions (and their vectorized variants RCPPS and RSQRTPS) with an extra Newton-Raphson step for better precision. They're used instead of DIVSS and SQRTSS (and their vectorized variants) for single-precision floating-point arguments. These instructions are generated only when -funsafe-math-optimizations is enabled together with -ffinite-math-only and -fno-trapping-math. Note that while the throughput of the sequence is higher than the non-reciprocal instruction, the precision can drop by up to 2 ulp (i.e. the inverse of 1.0 equals 0.99999994). ๐Ÿฅฒ

Also, GCC implements 1.0f/sqrtf(x) in terms of RSQRTSS (or RSQRTPS) already with -ffast-math (or the option combination above), so you don't need -mrecip for that โœจ

And GCC emits the sequence with the additional Newton-Raphson step for vectorized single-float division and vectorized sqrtf(x) already with -ffast-math (or the option combination above), so again, no -mrecip needed ๐Ÿ’…

  • -mrecip=opt โ€” controls which reciprocal estimate instructions may be used. opt is a comma-separated list of options, and any of them can be preceded by a ! to invert it ๐Ÿงš
    • all โ€” enable all estimate instructions.
    • default โ€” enable the default instructions, equivalent to -mrecip.
    • none โ€” disable all estimate instructions, equivalent to -mno-recip.
    • div โ€” enable the approximation for scalar division.
    • vec-div โ€” enable the approximation for vectorized division.
    • sqrt โ€” enable the approximation for scalar square root.
    • vec-sqrt โ€” enable the approximation for vectorized square root.

So, for example, -mrecip=all,!sqrt enables all of the reciprocal approximations except for square root. Main character decision ๐Ÿ‘‘

  • -mveclibabi=type โ€” specifies the ABI type to use when vectorizing intrinsics with an external library. Supported values for type are svml for the Intel short vector math library and acml for the AMD math core library. To use this option, you need both -ftree-vectorize and -funsafe-math-optimizations enabled, plus an SVML or ACML ABI-compatible library specified at link time ๐Ÿซถ

GCC currently emits calls to these functions for -mveclibabi=svml:

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

and these for the corresponding function type when -mveclibabi=acml is used:

"__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"
  • -mabi=name โ€” generates code for the specified calling convention. Permissible values are sysv (the ABI used on GNU/Linux and other systems) and ms (the Microsoft ABI). The default is the Microsoft ABI when targeting Microsoft Windows, and the SysV ABI on all other systems. You can control this for specific functions with the function attributes ms_abi and sysv_abi ๐ŸŽ€
  • -mforce-indirect-call โ€” forces all function calls to be indirect. This is handy with Intel Processor Trace, since it gives more precise timing information for function calls ๐Ÿ”
  • -mmanual-endbr โ€” inserts an ENDBR instruction at function entry only via the cf_check function attribute. This is useful with -fcf-protection=branch to control ENDBR insertion at function entry ๐Ÿงš
  • -mcall-ms2sysv-xlogues โ€” because of differences 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 that saves and restores these registers is emitted inline, which makes prologues and epilogues pretty lengthy. Using -mcall-ms2sysv-xlogues emits prologues and epilogues that use stubs in the static portion of libgcc to do those saves and restores. That shrinks function size at the cost of a few extra instructions ๐ŸŒธ
  • -mtls-dialect=type โ€” generates code to access thread-local storage using the gnu or gnu2 conventions. gnu is the conservative default. gnu2 is more efficient, but it may add compile- and run-time requirements that can't be satisfied on all systems โš ๏ธ
  • -mpush-args, -mno-push-args โ€” uses PUSH operations to store outgoing parameters. This method is shorter and usually just as fast as the SUB/MOV method, and it's enabled by default. In some cases, disabling it may improve performance because of better scheduling and fewer dependencies ๐Ÿ’–
  • -maccumulate-outgoing-args โ€” if enabled, the maximum amount of space needed for outgoing arguments is computed in the function prologue. This is faster on most modern CPUs thanks to fewer dependencies, better scheduling, and reduced stack usage when the preferred stack boundary isn't equal to 2. The drawback? A notable increase in code size ๐Ÿ™ˆ This switch implies -mno-push-args.
  • -mthreads โ€” supports thread-safe exception handling on MinGW. Programs that rely on thread-safe exception handling must compile and link all code with -mthreads. When compiling, -mthreads defines -D_MT. When linking, it pulls in a special thread helper library, -lmingwthrd, which cleans up per-thread exception-handling data ๐Ÿงต
  • -mms-bitfields, -mno-ms-bitfields โ€” enables or disables bit-field layout that's compatible with the native Microsoft Windows compiler ๐Ÿฆ‹

Okay so, if "packed" is used on a structure or bit-fields show up, the Microsoft ABI might lay that structure out differently than GCC normally does ๐Ÿ˜ญ. This gets extra messy when you're passing packed data between GCC-compiled functions and the native Microsoft compiler, whether through a function call or as data in a file. You might need to access either format ๐Ÿซถ.

This option is enabled by default for Microsoft Windows targets ๐ŸŒธ. You can also control it locally with variable or type attributes โœจ. For more info, check out 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, that requirement is either the size of the object or the current packing size (set with the "aligned" attribute or the "pack" pragma), whichever is less. For structures, unions, and arrays, the alignment requirement is the largest alignment requirement of any of their members. Every object gets an offset so that:
offset % alignment_requirement == 0
  1. Adjacent bit-fields get packed into the same 1-, 2-, or 4-byte allocation unit if their integral types are the same size, and if the next bit-field fits into the current allocation unit without crossing the boundary set by the common alignment requirements of the bit-fields ๐Ÿ”ฅ.

MSVC interprets zero-length bit-fields in these ways, and it's lowkey wild ๐Ÿ’€:

  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 you removed the zero-length bit-field, t1's size would be 4 bytes ๐Ÿ‘‘.

  1. If a zero-length bit-field is inserted after a bit-field called foo, and the alignment of the zero-length bit-field is greater than that of the member that follows it, bar, then bar gets aligned as the type of the zero-length bit-field ๐Ÿงš.

For example:

struct
 {
   char foo : 4;
   short : 0;
   char bar;
 } t2;

struct
 {
   char foo : 4;
   short : 0;
   double bar;
 } t3;

For t2, bar is placed at offset 2 instead of offset 1, so the size of t2 is 4. For t3, the zero-length bit-field doesn't affect the alignment of bar or, as a result, the size of the 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 can affect the alignment of the structure as a whole. For example, t2 has a size of 4 bytes, since the zero-length bit-field follows a normal bit-field and is of type short โœจ.
  2. Even if a zero-length bit-field isn't followed by a normal bit-field, it can still affect the alignment of the structure:
struct
 {
   char foo : 6;
   long : 0;
 } t4;

Here, t4 takes up 4 bytes ๐ŸŒˆ.

  1. Zero-length bit-fields that follow non-bit-field members are ignored:
struct
 {
   char foo;
   long : 0;
   char bar;
 } t5;

Here, t5 takes up 2 bytes ๐Ÿ’œ.


  • -mno-align-stringops โ€” Skip aligning the destination of inlined string operations. This makes the code smaller and can be faster if the destination is already aligned but GCC doesn't know it ๐ŸŒธ.
  • -minline-all-stringops โ€” By default, GCC only inlines string operations when the destination is known to be aligned to at least a 4-byte boundary. This option inlines more, which bumps up code size but can speed up code that relies on quick memcpy and memset for short lengths ๐Ÿ”ฅ. It also turns on inline expansion of strlen for all pointer alignments ๐Ÿ’….
  • -minline-stringops-dynamically โ€” For string operations of unknown size, use run-time checks. Small blocks get inline code, and large blocks get a library call ๐Ÿงš.
  • -mstringop-strategy=alg โ€” Override GCC's internal heuristic for picking which algorithm to inline string operations with. The allowed values for alg are:
    • rep_byte, rep_4byte, rep_8byte โ€” Expand using the i386 rep prefix of the specified size.
    • byte_loop, loop, unrolled_loop โ€” Expand into an inline loop.
    • libcall โ€” Always use a library call.
  • -mmemcpy-strategy=strategy โ€” Override the internal heuristic that decides whether __builtin_memcpy gets inlined, and which inline algorithm to use, when the expected size of the copy 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, and max_size is the max byte size that alg is allowed to handle. The last triplet must have a max_size of -1. The max_size values in the list have to be in increasing order. The minimum byte size for alg is 0 for the first triplet, and max_size + 1 of the preceding range for every other triplet ๐ŸŽ€.
  • -mmemset-strategy=strategy โ€” 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 that might make debugging harder ๐Ÿ™ˆ.
  • -mtls-direct-seg-refs, -mno-tls-direct-seg-refs โ€” Controls whether TLS variables can be accessed with offsets from the TLS segment register (%gs for 32-bit, %fs for 64-bit), or whether the thread base pointer has to be added. Whether that's valid depends on the operating system, and on whether it maps the segment to cover the entire TLS area ๐Ÿ’….

For systems that use the GNU C Library, the default is on โœจ.

  • -msse2avx, -mno-sse2avx โ€” Tell 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), put the profiling counter call before the prologue. Note: on x86 architectures, the attribute "ms_hook_prologue" isn't possible for -mfentry and -pg right now ๐Ÿ˜ญ.
  • -mrecord-mcount, -mno-record-mcount โ€” If profiling is active (-pg), generate a __mcount_loc section that holds pointers to each profiling call. This is handy for automatically patching and out calls ๐Ÿ’œ.
  • -mnop-mcount, -mno-nop-mcount โ€” If profiling is active (-pg), generate the calls to the profiling functions as NOPs. This is useful when they should get patched in later, dynamically. This is likely only useful together with -mrecord-mcount โœจ.
  • -minstrument-return=type โ€” Instrument function exit in -pg -mfentry instrumented functions with a call to the specified function. This only instruments true returns that end with ret, not sibling calls that end with a jump ๐Ÿ”ฅ. The valid types are none to not instrument, call to generate a call to __return__, or nop5 to generate a 5-byte NOP ๐Ÿงš.
  • -mrecord-return, -mno-record-return โ€” Generate a __return_loc section that points to all of the return instrumentation code ๐ŸŒธ.
  • -mfentry-name=name โ€” Set the name of the __fentry__ symbol that gets called at function entry for -pg -mfentry functions ๐Ÿ‘‘.
  • -mfentry-section=name โ€” Set the name of the section that records -mrecord-mcount calls (default __mcount_loc) ๐ŸŽ€.
  • -mskip-rax-setup, -mno-skip-rax-setup โ€” When generating code for the x86-64 architecture with SSE extensions disabled, -mskip-rax-setup can skip setting up the RAX register when no variable arguments are passed in vector registers ๐Ÿซถ.
Warning: The RAX register is used to avoid unnecessarily saving vector registers on the stack when passing variable arguments. So the impacts of this option are that callees may waste some stack space, misbehave, or jump to a random location. GCC 4.4 or newer doesn't have those issues, regardless of the RAX register value ๐Ÿ˜ญ.
  • -m8bit-idiv, -mno-8bit-idiv โ€” On some processors, like Intel Atom, 8-bit unsigned integer divide is way faster than 32-bit/64-bit integer divide ๐Ÿ”ฅ. This option generates a run-time check. If both the dividend and divisor are within the range of 0 to 255, 8-bit unsigned integer divide is used instead of 32-bit/64-bit integer divide ๐Ÿ’….
  • -mavx256-split-unaligned-load, -mavx256-split-unaligned-store โ€” Split 32-byte AVX unaligned loads and stores ๐Ÿฆ‹.
  • -mstack-protector-guard=guard, -mstack-protector-guard-reg=reg, -mstack-protector-guard-offset=offset โ€” 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) ๐Ÿ’–. This option only has an effect when -fstack-protector or -fstack-protector-all is specified ๐ŸŒˆ.

Okay so, with that latter choice ๐Ÿ’… the options -mstack-protector-guard-reg=reg and -mstack-protector-guard-offset=offset also decide which segment register (%fs or %gs) gets used as the base register for reading the canary, and what offset from that base it starts at. If you don't pick, the defaults come from whatever the relevant ABI says ๐Ÿซถ

  • -mgeneral-regs-only โ€” Generate code that only uses the general-purpose registers ๐Ÿงš. The compiler is NOT allowed to touch floating-point, vector, mask, or bound registers. Strict bestie energy, but iconic.
  • -mindirect-branch=choice โ€” Converts indirect calls and jumps based on choice ๐Ÿฆ‹. The default is keep, which leaves indirect call and jump totally unmodified. The other options are:
    • thunk converts indirect call and jump 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 one specific function with the function attribute "indirect_branch" โœจ

Note that -mcmodel=large is incompatible with -mindirect-branch=thunk and -mindirect-branch=thunk-extern since the thunk function may not be reachable in the large code model. ๐Ÿ™ˆ
Note that -mindirect-branch=thunk-extern is compatible with -fcf-protection=branch since the external thunk can be made to enable control-flow check. ๐Ÿ’œ
  • -mfunction-return=choice โ€” Converts function return based on choice ๐ŸŒธ. The default is keep, which keeps function return unmodified. The other options are:
    • thunk converts function return to a call and return thunk.
    • thunk-inline converts function return to an inlined call and return thunk.
    • thunk-extern converts function return to an external call and return thunk provided in a separate object file.

You can control this for one specific function with the function attribute "function_return" ๐ŸŽ€

Note that -mindirect-return=thunk-extern is compatible with -fcf-protection=branch since the external thunk can be made to enable control-flow check. ๐Ÿ’–
Note that -mcmodel=large is incompatible with -mfunction-return=thunk and -mfunction-return=thunk-extern since the thunk function may not be reachable in the large code model. ๐Ÿ’€
  • -mindirect-branch-register โ€” Forces indirect calls and jumps to go through a register ๐Ÿš€
  • -mharden-sls=choice โ€” Generates code to mitigate straight line speculation (SLS) with choice ๐Ÿ›ก๏ธ. The default is none, which disables all SLS hardening. return turns on SLS hardening for function returns, indirect-jmp turns it on for indirect jumps, and all enables every SLS hardening.
  • -mindirect-branch-cs-prefix โ€” Adds a CS prefix to call and jmp to an indirect thunk whose branch target is in r8-r15 registers โญ. That makes the call and jmp instruction length 6 bytes, so they can be swapped at run-time for lfence; call *%r8-r15 or lfence; jmp *%r8-r15.

These -m switches are supported in addition to the above on x86-64 processors in 64-bit environments ๐Ÿ’…

  • -m32, -m64, -mx32, -m16, -miamcu โ€” Generate code for a 16-bit, 32-bit or 64-bit environment ๐Ÿ“ Here's the breakdown:
    • -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 โ€” 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 the -m32 option 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 location of the stack pointer that signal or interrupt handlers don't modify, so it can hold temporary data without adjusting the stack pointer. The flag -mno-red-zone disables this red zone.
  • -mcmodel=small โ€” Generate code for the small code model ๐ŸŒธ: the program and its symbols must be linked in the lower 2 GB of the address space. Pointers are 64 bits. Programs can be statically or dynamically linked. This is the default code model.
  • -mcmodel=kernel โ€” Generate code for the kernel code model. The kernel runs in the negative 2 GB of the address space. This model has to be used for Linux kernel code ๐Ÿ‘‘
  • -mcmodel=medium โ€” Generate code for the medium model: the program is linked in the lower 2 GB of the address space, and small symbols are placed there too. Symbols with sizes larger than -mlarge-data-threshold get put into large data or BSS sections and can be located above 2GB. Programs can be statically or dynamically linked.
  • -mcmodel=large โ€” Generate code for the large model. It makes no assumptions about addresses and sizes of sections ๐ŸŒ
  • -maddress-mode=long โ€” Generate code for long address mode. This is only supported for 64-bit and x32 environments. It's the default address mode for 64-bit environments.
  • -maddress-mode=short โ€” Generate code for short address mode. This is only supported for 32-bit and x32 environments. It's the default address mode for 32-bit and x32 environments.

โœจ x86 Windows Options โœจ

These additional options are available for Microsoft Windows targets ๐ŸชŸ

  • -mconsole โ€” Generates a console application by instructing the linker to set the PE header subsystem type required for console applications. Available for Cygwin and MinGW targets, and enabled by default on those targets.
  • -mdll โ€” Available for Cygwin and MinGW targets. Generates a DLL (a dynamic link library), which enables selecting the required runtime startup object and entry point ๐Ÿฆ‹
  • -mnop-fun-dllimport โ€” Available for Cygwin and MinGW targets. The "dllimport" attribute should be ignored.
  • -mthread โ€” Available for MinGW targets. Uses MinGW-specific thread support ๐Ÿงต
  • -municode โ€” Available for MinGW-w64 targets. Predefines the "UNICODE" preprocessor macro and chooses Unicode-capable runtime startup code ๐Ÿ’œ
  • -mwin32 โ€” Available for Cygwin and MinGW targets. Sets the typical Microsoft Windows predefined macros in the pre-processor, but doesn't influence the choice of runtime library/startup code.
  • -mwindows โ€” Available for Cygwin and MinGW targets. Generates a GUI application by instructing the linker to set the PE header subsystem type appropriately ๐ŸŒˆ
  • -fno-set-stack-executable โ€” Available for MinGW targets. The executable flag for the stack used by nested functions isn't set. This is necessary for binaries running in kernel mode of Microsoft Windows, because the User32 API (which is used to set executable privileges) isn't available there ๐Ÿ’€
  • -fwritable-relocated-rdata โ€” Available for MinGW and Cygwin targets. Relocated data in a read-only section gets put into the ".data" section. This is necessary for older runtimes that don't support modifying ".rdata" sections for pseudo-relocation ๐ŸŽ€
  • -mpe-aligned-commons โ€” Available for Cygwin and MinGW targets. Uses the GNU extension to the PE file format that permits correct alignment of COMMON variables when generating code. It's enabled by default if GCC detects that the target assembler found during configuration supports the feature โœจ

See also under x86 Options for standard options ๐Ÿซถ


โœจ Xstormy16 Options โœจ

These options are defined for Xstormy16:

  • -msim โ€” Chooses startup files and a linker script suitable for the simulator ๐Ÿงš

โœจ Xtensa Options โœจ

These options are supported for Xtensa targets:

  • -mconst16, -mno-const16 โ€” Enable or disable use of "CONST16" instructions for loading constant values ๐Ÿ’–. The "CONST16" instruction is currently not a standard option from Tensilica. When enabled, "CONST16" instructions are always used in place of the standard "L32R" instructions. The use of "CONST16" is enabled by default only if the "L32R" instruction is not available.
  • -mfused-madd, -mno-fused-madd โ€” Enable or disable use of fused multiply/add and multiply/subtract instructions in the floating-point option ๐Ÿ”ฅ. This has no effect if the floating-point option is not also enabled. Disabling them forces the compiler to use separate instructions for the multiply and add/subtract operations. That can be desirable when strict IEEE 754-compliant results are required, because the fused multiply add/subtract instructions don't round the intermediate result, so they produce results with more bits of precision than the IEEE standard specifies. Disabling them also ensures the program output isn't sensitive to the compiler's ability to combine multiply and add/subtract operations ๐ŸŒธ
  • -mserialize-volatile, -mno-serialize-volatile โ€” When enabled, GCC inserts MEMW instructions before "volatile" memory references to guarantee sequential consistency ๐Ÿ”’. The default is -mserialize-volatile. Use -mno-serialize-volatile to omit the MEMW instructions.
  • -mforce-no-pic โ€” For targets like GNU/Linux, where all user-mode Xtensa code must be position-independent code (PIC), this option disables PIC for compiling kernel code ๐Ÿ‘‘

Okay so these four are all about where the literal pools end up ๐Ÿงš and they're lowkey very important for code size ๐Ÿ’…

  • -mtext-section-literals, -mno-text-section-literals โ€” The default is -mno-text-section-literals, which puts literals in their own separate section of the output file. That lets the literal pool live in data RAM/ROM, and it lets the linker combine literal pools from different object files to get rid of redundant literals and shrink the code ๐ŸŒธ With -mtext-section-literals, the literals get interspersed right into the text section so they stay as close as possible to where they're used. This might be necessary for large assembly files ๐Ÿซถ Literals for each function get placed right before that function โœจ
  • -mauto-litpools, -mno-auto-litpools โ€” The default is -mno-auto-litpools, which puts literals in a separate section in the output file unless -mtext-section-literals is used ๐Ÿฆ‹ With -mauto-litpools, the assembler is the one that interleaves literals into the text section. The compiler doesn't produce explicit .literal directives and instead loads literals into registers with MOVI instructions instead of L32R, so the assembler can do relaxation and place literals wherever they're needed ๐Ÿงš This option lets the assembler make several literal pools per function and assemble very big functions, which might not be possible with -mtext-section-literals. Literally main character energy ๐Ÿ‘‘
  • -mtarget-align, -mno-target-align โ€” When this is enabled, GCC tells the assembler to automatically align instructions so branch penalties go down, at the cost of a little code density ๐Ÿ’– The assembler tries to widen density instructions so that branch targets and the instructions after call instructions are aligned. 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 change how auto-aligned instructions like LOOP are handled. The assembler always aligns those, either by widening density instructions or by inserting NOP instructions โœจ
  • -mlongcalls, -mno-longcalls โ€” When this is enabled, GCC tells the assembler to turn direct calls into indirect calls, unless it can tell that the target of a direct call is within the range the call instruction allows ๐Ÿ˜ญ This usually happens for calls to functions in other source files. Specifically, the assembler swaps a direct CALL instruction for an L32R followed by a CALLX instruction ๐Ÿ’€ The default is -mno-longcalls. Use this option in programs where the call target could potentially be out of range ๐ŸŽ€ This option is implemented in the assembler, not the compiler, so the assembly code GCC generates still shows direct call instructions---so go look at 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. Iykyk ๐Ÿ™ˆ

zSeries Options ๐ŸŒˆ

These are listed under

โœจ ENVIRONMENT โœจ

Okay so bestie, this section is all about the environment variables that tweak how GCC behaves ๐ŸŒธ Some of them tell GCC which directories or prefixes to dig through when hunting for files, and others set up the rest of the compilation vibe ๐Ÿ’…

Quick tea โ˜•: you can also tell GCC where to search with options like -B, -I and -L. Those beat environment variables, and environment variables beat whatever GCC was configured with. The hierarchy is real ๐Ÿ‘‘

LANG, LC_CTYPE, LC_MESSAGES, LC_ALL ๐ŸŒ

These are how GCC handles different national conventions ๐Ÿ‡ฌ๐Ÿ‡ง GCC looks at LC_CTYPE and LC_MESSAGES, but only if it was configured to do so. They can be set to any value your installation supports, like en_GB.UTF-8 (English in 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 with quote and escape characters that could otherwise be mistaken for the end of a string or an escape ๐Ÿ’€
  • LC_MESSAGES โ€” picks the language for diagnostic messages ๐Ÿ’ฌ
  • LC_ALL โ€” if this one is set, it overrides LC_CTYPE and LC_MESSAGES ๐Ÿ‘‘. If it isn't, those two default to whatever LANG says. And if none of these are set, GCC goes with traditional C English behaviour ๐Ÿ“

TMPDIR ๐Ÿ“

If TMPDIR is set, that's the directory GCC uses for temporary files. GCC stashes the output of one stage of compilation there so the next stage can use it as input. For example, the preprocessor's output is what the compiler proper takes in ๐Ÿงš

GCC_COMPARE_DEBUG ๐Ÿฆ‹

Setting GCC_COMPARE_DEBUG is nearly the same as passing -fcompare-debug to the compiler driver. Check that option's docs for the full scoop ๐Ÿ“–

GCC_EXEC_PREFIX ๐Ÿš€

If GCC_EXEC_PREFIX is set, it's a prefix stuck onto the names of the subprograms the compiler runs. No slash gets added when the prefix is combined with a subprogram name, so if you want one, end your prefix with a slash yourself ๐Ÿซถ

If it's not set, GCC tries to work out a sensible prefix based on the pathname it was invoked with ๐Ÿ”Ž

If GCC can't find a subprogram using that prefix, it checks the usual places instead ๐Ÿ 

The default value is prefix/lib/gcc/, where prefix is the prefix of the installed compiler. A lot of the time that's whatever "prefix" was set to when you ran the configure script ๐Ÿ› ๏ธ

Prefixes given with -B take precedence over this one โญ

This prefix is also used to find files like crt0.o that get used for linking ๐Ÿ”—

Now for the weird part ๐Ÿคฏ The prefix works differently when GCC is finding header directories. For each standard directory that normally begins with /usr/local/lib/gcc (or, more precisely, the value of GCC_INCLUDE_DIR), GCC swaps that beginning out for the specified prefix to make an alternate directory name. So with -Bfoo/, GCC searches foo/bar just before it searches the standard directory /usr/local/lib/bar. If a standard directory begins with the configured prefix, then the prefix gets replaced by GCC_EXEC_PREFIX when GCC looks for header files ๐Ÿ’–

COMPILER_PATH ๐Ÿ“‚

The value is a colon-separated list of directories, kinda like PATH โœจ GCC checks these when searching for subprograms, but only if it can't find them using GCC_EXEC_PREFIX first.

LIBRARY_PATH ๐Ÿ“š

Also a colon-separated list of directories, like PATH ๐ŸŒˆ When GCC is configured as a native compiler, it checks these for special linker files, again only if GCC_EXEC_PREFIX couldn't find them. Linking with GCC also searches these directories for ordinary libraries used with the -l option, but directories given with -L come first ๐Ÿฅ‡

LANG ๐Ÿ—ฃ๏ธ

This variable passes locale info to the compiler ๐ŸŒ One thing that info controls is which character set gets used when character literals, string literals and comments are parsed in C and C++. When the compiler is configured to allow multibyte characters, these values for LANG are recognised:

  • C-JIS โ€” recognise JIS characters.
  • C-SJIS โ€” recognise SJIS characters.
  • C-EUCJP โ€” recognise EUCJP characters.

If LANG isn't defined, or it has some other value, the compiler uses mblen and mbtowc as defined by the default locale to recognise and translate multibyte characters ๐Ÿซ 

Preprocessor vibes ๐Ÿงน

Some additional environment variables affect how the preprocessor behaves ๐Ÿ‘€

CPATH, C_INCLUDE_PATH, CPLUS_INCLUDE_PATH, OBJC_INCLUDE_PATH ๐Ÿ—‚๏ธ

Each of these holds a list of directories, separated by a special character (much like PATH), to look in for header files. That special character is PATH_SEPARATOR. It depends on the target and gets decided when GCC is built ๐Ÿ› ๏ธ For Microsoft Windows-based targets it's a semicolon, and for almost every other target it's a colon ๐ŸŒˆ

  • CPATH โ€” searched as if the directories were given with -I, but after any -I paths on the command line. This one gets used no matter which language is being preprocessed ๐Ÿ’…
  • C_INCLUDE_PATH, CPLUS_INCLUDE_PATH and OBJC_INCLUDE_PATH โ€” these only apply when preprocessing their particular language. Each one is searched as if the directories were given with -isystem, but after any -isystem paths on the command line ๐Ÿซถ

In all of these, an empty element tells the compiler to search its current working directory ๐Ÿ“ Empty elements can show up at the beginning or end of a path. For instance, if the value of CPATH is ":/special/include", that has the same effect 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 are ignored in the dependency output ๐Ÿ™…

The value can be just a file name. In that case the Make rules get written to that file, and the target name is guessed from the source file name ๐ŸŽฏ Or the value can look like file target, where the rules get written to file and target is used as the target name.

In other words, this variable is equivalent to combining -MM and -MF, with an optional -MT switch too ๐Ÿ’œ

SUNPRO_DEPENDENCIES ๐Ÿ™ˆ

This one's the same as DEPENDENCIES_OUTPUT, except system header files are not ignored, so it implies -M rather than -MM. The dependence on the main input file gets left out, though ๐Ÿ’€

SOURCE_DATE_EPOCH โฐ

If this variable is set, its value is a UNIX timestamp used instead of the current date and time in the __DATE__ and __TIME__ macros, so the embedded timestamps come out reproducible ๐Ÿ”

The value has to be a UNIX timestamp, meaning the number of seconds (leap seconds excluded) since 01 Jan 1970 00:00:00, written in ASCII. That's identical to the output of date +%s on GNU/Linux and other systems that support the %s extension in the date command ๐Ÿงฎ

It should be a known timestamp, like the last modification time of the source or package, and it should be set by the build process ๐Ÿ› ๏ธ


๐Ÿ› BUGS ๐Ÿ›

For instructions on reporting bugs, check out file:///usr/share/doc/gcc-10/README.Bugs ๐Ÿž

๐Ÿ“ FOOTNOTES ๐Ÿ“

  1. On some systems, gcc -shared needs to build supplementary stub code for constructors to work. On multi-libbed systems, gcc -shared must select the correct support libraries to link against. Failing to supply the correct flags may lead to subtle defects. Supplying them where they aren't necessary is innocuous ๐Ÿซง

๐Ÿ”— SEE ALSO ๐Ÿ”—

gpl(7), gfdl(7), fsf-funding(7), cpp(1), gcov(1), as(1), ld(1), gdb(1), dbx(1) and the Info entries for gcc, cpp, as, ld, binutils and gdb ๐Ÿ“š

๐Ÿ‘ฉโ€๐Ÿ’ป AUTHOR ๐Ÿ‘ฉโ€๐Ÿ’ป

See the Info entry for gcc, or http://gcc.gnu.org/onlinedocs/gcc/Contributors.html, for contributors to GCC ๐Ÿ’œ

Copyright (c) 1988-2020 Free Software Foundation, Inc. ๐ŸŒธ

Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.3 or any later version published by the Free Software Foundation; with the Invariant Sections being "GNU General Public License" and "Funding Free Software", the Front-Cover texts being (a) (see below), and with the Back-Cover Texts being (b) (see below). A copy of the license is included in the gfdl(7) man page ๐Ÿ“œ

  • (a) The FSF's Front-Cover Text is: "A GNU Manual"
  • (b) The FSF's Back-Cover Text is: "You have freedom to copy and modify this GNU Manual, like GNU software. Copies published by the Free Software Foundation raise funds for GNU development."

That's the whole page, bestie! ๐ŸŽ€ This one came from the gcc-10 source, version stamp 2023-07-07, and it's GCC(1) all the way through ๐Ÿ’– Stay iconic, stay compiling ๐Ÿฆ‹โœจ

๐Ÿ“ฆ where this page comes from