GCC(1)

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

๐ŸŽ€ GCC(1) ๐ŸŽ€

Hiii bestie, this is the manual for the GNU project's C and C++ compiler, gcc, and I am so ready to walk you through it ๐Ÿ’–โœจ

๐Ÿ’… NAME ๐Ÿ’…

gcc is the GNU project C and C++ compiler ๐Ÿ‘‘ It's giving compiler queen energy, no cap.

๐Ÿ“œ SYNOPSIS ๐Ÿ“œ

Here's the quick-glance way to call it ๐Ÿงš

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

Okay so this is just the highlights reel ๐ŸŽž๏ธ The rest of the options are down below ๐Ÿ‘‡ And g++ takes mostly the same options as gcc, so you're basically good to go ๐Ÿซถ

๐ŸŒธ DESCRIPTION ๐ŸŒธ

When you invoke GCC, it normally does preprocessing, compilation, assembly and linking. The "overall options" let you stop this whole process at an intermediate stage. For example, -c says don't run the linker, so the output is the object files the assembler spits out ๐Ÿฆ‹

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

Most of the command-line options you can use with GCC are meant for C programs. When an option is only useful with another language (usually C++), the explanation says so explicitly. 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 to run the executable called gcc, or machine-gcc when you're cross-compiling, or machine-gcc-version if you want one specific version of GCC. When you compile C++ programs, you should invoke GCC as g++ instead ๐Ÿ’–

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

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

Lots of options have long names that start with -f or with -W---for, like -fmove-loop-invariants or -Wformat and so on ๐Ÿง Most of these come in both positive and negative forms, and the negative form of -ffoo is -fno-foo. This manual only documents one of the two forms, whichever one isn't the default โญ

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

Arguments to options that set a size threshold of some sort can be arbitrarily large decimal or hexadecimal integers, followed by a byte size suffix for a multiple of bytes. So you've got kB and KiB for kilobyte and kibibyte, MB and MiB for megabyte and mebibyte, GB and GiB for gigabyte and gigibyte, and so on ๐Ÿ’œ Those arguments get called byte-size in the rest of the text. 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 the lowdown on all the options, grouped by type. The explanations live in the following sections ๐Ÿ’–

๐ŸŒท Overall Options

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

๐Ÿง C Language Options

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

๐Ÿ’œ C++ Language Options

-fabi-version=n  -fno-access-control -faligned-new=n
-fargs-in-order=n  -fchar8_t  -fcheck-new -fconstexpr-depth=n
-fconstexpr-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 -frepo  -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=n  -Wabi-tag  -Wconversion-null
-Wctor-dtor-privacy -Wdelete-non-virtual-dtor  -Wdeprecated-copy
-Wdeprecated-copy-dtor -Wliteral-suffix -Wmultiple-inheritance
-Wno-init-list-lifetime -Wnamespaces  -Wnarrowing -Wpessimizing-move
-Wredundant-move -Wnoexcept  -Wnoexcept-type  -Wclass-memaccess
-Wnon-virtual-dtor  -Wreorder  -Wregister -Weffc++
-Wstrict-null-sentinel  -Wtemplates -Wno-non-template-friend
-Wold-style-cast -Woverloaded-virtual  -Wno-pmf-conversions
-Wno-class-conversion  -Wno-terminate -Wsign-promo
-Wvirtual-inheritance

๐Ÿฆ„ 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-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-format=[text|json] -fno-diagnostics-show-option
-fno-diagnostics-show-caret -fno-diagnostics-show-labels
-fno-diagnostics-show-line-numbers
-fdiagnostics-minimum-margin-width=width
-fdiagnostics-parseable-fixits  -fdiagnostics-generate-patch
-fdiagnostics-show-template-tree  -fno-elide-type -fno-show-column

โœจ Warning Options โœจ

okay bestie, the warning options are a WHOLE buffet ๐Ÿ’… gcc gets super chatty with these, so here's the full menu, no cap ๐Ÿซถ

-fsyntax-only  -fmax-errors=n  -Wpedantic -pedantic-errors -w
-Wextra  -Wall  -Waddress  -Waddress-of-packed-member
-Waggregate-return  -Waligned-new -Walloc-zero
-Walloc-size-larger-than=byte-size -Walloca
-Walloca-larger-than=byte-size -Wno-aggressive-loop-optimizations
-Warray-bounds  -Warray-bounds=n -Wno-attributes
-Wattribute-alias=n -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 -Wcast-align
-Wcast-align=strict  -Wcast-function-type  -Wcast-qual
-Wchar-subscripts  -Wcatch-value  -Wcatch-value=n -Wclobbered
-Wcomment  -Wconditionally-supported -Wconversion
-Wcoverage-mismatch  -Wno-cpp  -Wdangling-else  -Wdate-time
-Wdelete-incomplete -Wno-attribute-warning -Wno-deprecated
-Wno-deprecated-declarations  -Wno-designated-init
-Wdisabled-optimization -Wno-discarded-qualifiers
-Wno-discarded-array-qualifiers -Wno-div-by-zero  -Wdouble-promotion
-Wduplicated-branches  -Wduplicated-cond -Wempty-body
-Wenum-compare  -Wno-endif-labels  -Wexpansion-to-defined -Werror
-Werror=*  -Wextra-semi  -Wfatal-errors -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 -Wjump-misses-init -Whsa  -Wif-not-aligned
-Wignored-qualifiers  -Wignored-attributes
-Wincompatible-pointer-types -Wimplicit  -Wimplicit-fallthrough
-Wimplicit-fallthrough=n -Wimplicit-function-declaration
-Wimplicit-int -Winit-self  -Winline  -Wno-int-conversion
-Wint-in-bool-context -Wno-int-to-pointer-cast
-Winvalid-memory-model  -Wno-invalid-offsetof -Winvalid-pch
-Wlarger-than=byte-size -Wlogical-op  -Wlogical-not-parentheses
-Wlong-long -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  -Wmissing-profile -Wno-multichar
-Wmultistatement-macros  -Wnonnull  -Wnonnull-compare
-Wnormalized=[none|id|nfc|nfkc] -Wnull-dereference  -Wodr
-Wno-overflow  -Wopenmp-simd -Woverride-init-side-effects
-Woverlength-strings -Wpacked  -Wpacked-bitfield-compat
-Wpacked-not-aligned  -Wpadded -Wparentheses
-Wno-pedantic-ms-format -Wplacement-new  -Wplacement-new=n
-Wpointer-arith  -Wpointer-compare  -Wno-pointer-to-int-cast
-Wno-pragmas  -Wno-prio-ctor-dtor  -Wredundant-decls -Wrestrict
-Wno-return-local-addr -Wreturn-type  -Wsequence-point  -Wshadow
-Wno-shadow-ivar -Wshadow=global,  -Wshadow=local,
-Wshadow=compatible-local -Wshift-overflow  -Wshift-overflow=n
-Wshift-count-negative  -Wshift-count-overflow
-Wshift-negative-value -Wsign-compare  -Wsign-conversion
-Wfloat-conversion -Wno-scalar-storage-order  -Wsizeof-pointer-div
-Wsizeof-pointer-memaccess  -Wsizeof-array-argument
-Wstack-protector  -Wstack-usage=byte-size  -Wstrict-aliasing
-Wstrict-aliasing=n  -Wstrict-overflow  -Wstrict-overflow=n
-Wstringop-overflow=n  -Wstringop-truncation  -Wsubobject-linkage
-Wsuggest-attribute=[pure|const|noreturn|format|malloc]
-Wsuggest-final-types   -Wsuggest-final-methods  -Wsuggest-override
-Wswitch  -Wswitch-bool  -Wswitch-default  -Wswitch-enum
-Wswitch-unreachable  -Wsync-nand -Wsystem-headers
-Wtautological-compare  -Wtrampolines  -Wtrigraphs -Wtype-limits
-Wundef -Wuninitialized  -Wunknown-pragmas
-Wunsuffixed-float-constants  -Wunused  -Wunused-function
-Wunused-label  -Wunused-local-typedefs  -Wunused-macros
-Wunused-parameter  -Wno-unused-result -Wunused-value
-Wunused-variable -Wunused-const-variable  -Wunused-const-variable=n
-Wunused-but-set-parameter  -Wunused-but-set-variable -Wuseless-cast
-Wvariadic-macros  -Wvector-operation-performance -Wvla
-Wvla-larger-than=byte-size  -Wvolatile-register-var -Wwrite-strings
-Wzero-as-null-pointer-constant

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

these ones are C and Objective-C only, so if you're not in those lanes, they're not your vibe ๐Ÿงš

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

ok debugging time ๐Ÿฆ‹ this is the lineup for when you wanna peek under the hood ๐Ÿ”

-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]
-feliminate-unused-debug-symbols  -femit-class-debug-always
-fno-merge-debug-strings  -fno-dwarf2-cfi-asm -fvar-tracking
-fvar-tracking-assignments

โœจ Optimization Options โœจ

and the optimization options ๐Ÿ”ฅ this list is so long it's giving marathon ๐Ÿ˜ญ here's everything, no skipping:

-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]]]] -fassociative-math  -fauto-profile
-fauto-profile[=path] -fauto-inc-dec  -fbranch-probabilities
-fbranch-target-load-optimize  -fbranch-target-load-optimize2
-fbtr-bb-exclusive  -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 -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-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  -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 ๐ŸŒธ

okay bestie, this is the instrumentation drip ๐Ÿ” these are the flags that poke at your program from the inside, and they are a lot ๐Ÿ˜ญ

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

๐Ÿงš Preprocessor Options ๐Ÿงš

the preprocessor squad is serving main character energy ๐Ÿ’– get ready for a lot of little flags

  • -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
  • -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 ๐Ÿฆ‹

only two of these, but they're iconic ๐Ÿซถ

  • -Wa,option
  • -Xassembler option

๐Ÿ”— Linker Options ๐Ÿ”—

the linking crew ๐Ÿ‘‘ this is where all your pieces get tied together

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

๐Ÿ“‚ Directory Options ๐Ÿ“‚

where the compiler goes looking for stuff ๐Ÿ—บ๏ธ it's giving scavenger hunt

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

๐Ÿ’… Code Generation Options ๐Ÿ’…

this is where the code gets its whole glow-up โœจ

  • -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
  • -fno-common
  • -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 developer zone ๐Ÿ”ฅ bestie if you're poking around under the hood, this is your playground

  • -dletters
  • -dumpspecs
  • -dumpmachine
  • -dumpversion
  • -dumpfullversion
  • -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 but not least, the target-specific flags ๐ŸŒˆ every chip gets its own little lineup, so let's go through them one by one ๐Ÿ’œ

๐Ÿ“ 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]|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 ๐Ÿ

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

๐ŸŒ™ AMD GCN Options ๐ŸŒ™

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

๐Ÿฆ„ ARC Options ๐Ÿฆ„

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

๐Ÿ› ๏ธ ARM Options ๐Ÿ› ๏ธ

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

โšก AVR Options โšก

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

๐Ÿซง Blackfin Options ๐Ÿซง

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

๐ŸŽฎ C6X Options ๐ŸŽฎ

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

๐Ÿ’ฟ CRIS Options ๐Ÿ’ฟ

  • -mcpu=cpu
  • -march=cpu
  • -mtune=cpu
  • -mmax-stack-frame=n
  • -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 ๐Ÿ•น๏ธ

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

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

  • -march=arch
  • -mcpu=cpu
  • -mbig-endian
  • -EB
  • -mlittle-endian
  • -EL
  • -mhard-float
  • -msoft-float
  • -mfpu=fpu
  • -mdouble-float
  • -mfdivdu
  • -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
The original page just lists these flags without explaining them, so I'm sharing the full lineup exactly as written. I haven't made up any behaviour ๐Ÿซถ

๐ŸŽ Darwin Options ๐ŸŽ

Okay bestie, the Darwin squad is HUGE ๐Ÿ’… Here's every single one:

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

Next up, the Alpha crew ๐Ÿ‘‘ Look at this lineup:

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

๐Ÿฆ‹ FR30 Options ๐Ÿฆ‹

Short and sweet ๐Ÿ“

  • -msmall-model
  • -mno-lsim

๐Ÿงš FT32 Options ๐Ÿงš

Six of these, bestie โœจ

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

๐Ÿ’œ FRV Options ๐Ÿ’œ

The FRV list is literally massive ๐Ÿ˜ญ Here's every single one:

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

๐Ÿค– GNU/Linux Options ๐Ÿค–

Penguin energy ๐Ÿง

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

๐ŸŽ€ H8/300 Options ๐ŸŽ€

Eight little guys ๐ŸŽ€

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

๐ŸŒˆ HPPA Options ๐ŸŒˆ

The HPPA list is a whole journey, bestie ๐ŸŒˆ

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

Okay this one is ENORMOUS, but we're still going ๐Ÿ’…

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

Five options, all vibes ๐ŸŒท

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

๐Ÿ”ฅ M32R/D Options ๐Ÿ”ฅ

This one's got a lot going on ๐Ÿ”ฅ

  • -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 ๐Ÿฆ„

Three little picks ๐Ÿฆ„

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

๐Ÿ‘‘ M680x0 Options ๐Ÿ‘‘

The M680x0 list is iconic, and it's long ๐Ÿ‘‘ Let's go:

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

Big list, bestie, but every one is a gem ๐Ÿงธ

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

The MeP crew is giving main character energy ๐ŸŒŠ

  • -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 ๐Ÿชจ

Rock solid lineup ๐Ÿชจ

  • -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 ๐Ÿ‰

MIPS is the biggest boss of them all ๐Ÿ‰ Buckle up, bestie ๐Ÿ’–

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

Sixteen pieces to this puzzle ๐Ÿงฉ

  • -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 ๐ŸŽ

Little wind chime energy ๐ŸŽ

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

Four to keep you company ๐ŸŒ™

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

โšก MSP430 Options โšก

Zappy list, bestie โšก

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

๐Ÿฆ• NDS32 Options ๐Ÿฆ•

Prehistoric-sized list, no cap ๐Ÿฆ•

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

This one's long and I'm obsessed with it ๐Ÿค

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

Four little options, very green ๐Ÿ’š

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

๐Ÿ› ๏ธ OpenRISC Options ๐Ÿ› ๏ธ

Tool-kit vibes ๐Ÿ› ๏ธ

  • -mboard=name
  • -mnewlib
  • -mhard-mul
  • -mhard-div
  • -msoft-mul
  • -msoft-div
  • -mcmov
  • -mror
  • -msext
  • -msfimm
  • -mshftimm

๐Ÿ•น๏ธ PDP-11 Options ๐Ÿ•น๏ธ

Retro era, serving classic energy ๐Ÿ•น๏ธ

  • -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 ๐Ÿž

Tiny but mighty ๐Ÿž

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

๐ŸŽ PowerPC Options ๐ŸŽ

And finally, the PowerPC one ๐Ÿ’– It's a cross-reference, not a list, so here's where to look:

See RS/6000 and PowerPC Options.

๐ŸŒธ RISC-V Options ๐ŸŒธ

okay bestie, the RISC-V squad is up first ๐Ÿ’– here are all the flags:

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

๐Ÿฆ‹ RL78 Options ๐Ÿฆ‹

next up, the RL78 crew, lowkey a smaller group but still iconic โœจ

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

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

this is the biggest list on the whole page and it is absolutely unhinged, no cap ๐Ÿ’€ it's giving a lot of flags, so get comfy ๐Ÿซถ

  • -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
  • -mmfpgpr
  • -mno-mfpgpr
  • -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

๐Ÿ’… RX Options ๐Ÿ’…

the RX group, short and sweet ๐ŸŒˆ

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

now the S/390 and zSeries era, lowkey a whole mood ๐Ÿ”ฎ

  • -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
  • -mfused-madd
  • -mno-fused-madd
  • -mwarn-framesize
  • -mwarn-dynamicstack
  • -mstack-size
  • -mstack-guard
  • -mhotpatch=halfwords,halfwords

๐ŸŒ™ Score Options ๐ŸŒ™

the Score bunch, small but mighty โญ

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

๐Ÿ“ SH Options ๐Ÿ“

the SH list is so long it needs its own snack break ๐Ÿ™ˆ

  • -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 โ˜€๏ธ

the Solaris 2 flags, quick and clean โœจ

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

๐Ÿซง SPARC Options ๐Ÿซง

SPARC is up next and it's giving very structured energy ๐Ÿ’…

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

๐ŸŽฎ SPU Options ๐ŸŽฎ

the SPU options, very gamer-coded, I'm obsessed ๐Ÿ”ฅ

  • -mwarn-reloc
  • -merror-reloc
  • -msafe-dma
  • -munsafe-dma
  • -mbranch-hints
  • -msmall-mem
  • -mlarge-mem
  • -mstdmain
  • -mfixed-range=register-range
  • -mea32
  • -mea64
  • -maddress-space-conversion
  • -mno-address-space-conversion
  • -mcache-size=cache-size
  • -matomic-updates
  • -mno-atomic-updates

๐ŸŽ€ System V Options ๐ŸŽ€

the System V crew, very old-school but still slay ๐Ÿ‘‘

  • -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 ๐Ÿฆ„

the V850 options are a whole lineup, no cap ๐Ÿซถ

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

๐Ÿ‚ VAX Options ๐Ÿ‚

  • -mg
  • -mgnu
  • -munix

๐Ÿ”ญ Visium Options ๐Ÿ”ญ

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

๐Ÿงธ VMS Options ๐Ÿงธ

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

๐Ÿš€ VxWorks Options ๐Ÿš€

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

๐Ÿ’œ x86 Options ๐Ÿ’œ

the x86 list is absolutely massive, bestie, this is the final boss of flags ๐Ÿ’€๐Ÿ”ฅ take a breath and let's go

  • -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
  • -mvpclmulqdq
  • -mavx512bitalg
  • -mmovdiri
  • -mmovdir64b
  • -mavx512vpopcntdq
  • -mavx5124fmaps
  • -mavx512vnni
  • -mavx5124vnniw
  • -mprfchw
  • -mrdpid
  • -mrdseed
  • -msgx
  • -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

๐ŸชŸ x86 Windows Options ๐ŸชŸ

okay the Windows-specific x86 flags, bestie, you've made it ๐Ÿฅน

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

๐ŸŒผ Xstormy16 Options ๐ŸŒผ

  • -msim

๐ŸŒบ Xtensa Options ๐ŸŒบ

the Xtensa lineup to close things out ๐Ÿ’–

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

  • zSeries Options see S/390 and zSeries Options. literally just go check that section ๐Ÿ’…

๐Ÿงš Options Controlling the Kind of Output ๐Ÿงš

okay so this bit is about the stages of compilation, and it's actually lowkey important ๐Ÿซถ there are up to four stages, and they always happen in this order: preprocessing, compilation proper, assembly, and linking.

GCC can preprocess and compile several files into several assembler input files, or squish them all into one assembler input file. Then each assembler input file makes an object file, and linking combines all the object files (the ones freshly compiled plus any you passed in as input) into one executable file โœจ

For any given input file, the file name suffix decides what kind of compilation happens. the way that it works is so simple, iykyk ๐Ÿ’–

  • file.c โ€” C source code that must be preprocessed.
  • file.i โ€” C source code that should not be preprocessed.
  • file.ii โ€” C++ source code that should not be preprocessed.
  • file.m โ€” Objective-C source code.
Heads up, bestie: you must link with the libobjc library to make an Objective-C program work. Don't skip this or it won't slay ๐Ÿ’€
  • file.mi โ€” Objective-C source code that should not be preprocessed.
  • file.mm, file.M โ€” Objective-C++ source code ๐Ÿ’… You have to link with the libobjc library or your Objective-C++ program won't work ๐Ÿ’€ And .M has to be a literal capital M, not lowercase.
  • file.mii โ€” Objective-C++ source code that should not be preprocessed ๐Ÿฆ‹
  • file.h โ€” A C, C++, Objective-C, or Objective-C++ header that gets turned into a precompiled header (that's the default โœจ), or a C or C++ header that gets turned into an Ada spec through 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 ๐Ÿ”ฅ In .cxx, the last two letters have to be literally lowercase x, and .C has to be 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 (yes, it's back again, no notes ๐Ÿ™ˆ)
  • file.hh, file.H, file.hp, file.hxx, file.hpp, file.HPP, file.h++, file.tcc โ€” C++ headers that get turned into a precompiled header or an Ada spec ๐Ÿงš
  • file.f, file.for, file.ftn โ€” Fixed form Fortran source code that should not be preprocessed ๐Ÿ“
  • file.F, file.FOR, file.fpp, file.FPP, file.FTN โ€” Fixed form Fortran source code that must be preprocessed, using the traditional preprocessor ๐Ÿ’œ
  • file.f90, file.f95, file.f03, file.f08 โ€” Free form Fortran source code that should not be preprocessed โœจ
  • file.F90, file.F95, file.F03, file.F08 โ€” Free form Fortran source code that must be preprocessed, using the traditional preprocessor ๐ŸŒธ
  • file.go โ€” Go source code ๐Ÿน
  • file.brig โ€” BRIG files, which are the binary representation of HSAIL ๐Ÿค“
  • file.d โ€” D source code ๐Ÿ‘‘
  • file.di โ€” D interface file ๐Ÿซถ
  • file.dd โ€” D documentation code, aka Ddoc ๐Ÿ“š
  • file.ads โ€” An Ada source file that holds a library unit declaration (a declaration of a package, subprogram, or generic, or a generic instantiation), or a library unit renaming declaration (a package, generic, or subprogram renaming declaration). These are also called specs ๐Ÿ’…
  • file.adb โ€” An Ada source file with a library unit body (a subprogram or package body). These are also called bodies ๐Ÿฆ‹
  • file.s โ€” Assembler code ๐Ÿ”ง
  • file.S, file.sx โ€” Assembler code that must be preprocessed ๐ŸŒˆ
  • other โ€” An object file that gets fed straight into linking. Any file name with no recognized suffix gets treated this way ๐Ÿซ 

You can specify the input language yourself with the -x option ๐Ÿ’–

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

If you only want some stages of compilation, use -x (or filename suffixes) to tell gcc where to start, and one of the options -c, -S, or -E to say where it should stop ๐ŸŽฏ > Heads up: some combinations, like -x cpp-output -E, instruct gcc to do absolutely nothing at all ๐Ÿ’€

  • -c โ€” Compile or assemble the source files, but don't link ๐Ÿ”— The linking stage just doesn't happen. The final output is an object file for each source file.

By default, the object file name for a source file is made by swapping the suffix .c, .i, .s, etc. for .o.

Unrecognized input files that don't need compiling or assembling get ignored.

  • -S โ€” Stop after the actual compilation stage and skip assembling โœจ The output is an assembler code file for each non-assembler input file you give it.

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

Input files that don't need compiling get ignored.

  • -E โ€” Stop after preprocessing and don't run the compiler proper ๐ŸŒธ The output is preprocessed source code, which gets sent to the standard output.

Input files that don't need preprocessing get ignored.

  • -o file โ€” Put the output in a file called file ๐Ÿ“ฆ This works for whatever you're making, whether it's an executable, an object file, an assembler file, or preprocessed C code.

If you don't use -o, the defaults are: an executable goes in a.out, the object file for source.suffix goes in source.o, its assembler file goes in source.s, a precompiled header file goes in source.suffix.gch, and all the preprocessed C source goes to standard output.

  • -v โ€” Print the commands executed for each stage of compilation to standard error output ๐Ÿ•ต๏ธ It also prints the version number of the compiler driver program, the preprocessor, and the compiler proper.
  • -### โ€” Like -v, except the commands don't actually run ๐Ÿ™… Arguments get quoted unless they only contain alphanumeric characters or "./-_". This is super useful for shell scripts that want to capture the command lines the driver generates ๐Ÿš
  • --help โ€” Prints a description of the command-line options gcc understands, straight to standard output ๐Ÿ“– If -v is also specified, --help gets passed along to the various processes gcc invokes, so they can show you the command-line options they accept. If -Wextra was specified (before the --help option), then command-line options with no documentation attached get displayed too ๐Ÿ‘€
  • --target-help โ€” Prints a description of the target-specific command-line options for each tool, to standard output ๐ŸŽฏ For some targets, extra target-specific info might get printed too.
  • --help={class|[^]qualifier}[,...] โ€” Prints a description of the command-line options the compiler understands that fit into all the classes and qualifiers you specify, to standard output ๐Ÿฐ These are the supported classes:
    • optimizers โ€” Shows all the optimization options the compiler supports โšก
    • warnings โ€” Shows all the options that control the warning messages the compiler produces โš ๏ธ
    • target โ€” Shows the target-specific options. Unlike --target-help, the target-specific options of the linker and assembler are not shown, because those tools don't support the extended --help= syntax yet ๐Ÿ™ƒ
    • params โ€” Shows the values the --param option recognizes ๐Ÿงพ
    • language โ€” Shows the options supported for language, where language is the name of one of the languages this version of GCC supports ๐Ÿ—ฃ๏ธ
    • common โ€” Shows the options common to all languages ๐ŸŒ

These are the supported qualifiers:

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

So if you want every undocumented target-specific switch the compiler supports, use:

--help=target,undocumented

You can flip a qualifier by putting a ^ 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 do have a description, use:

--help=warnings,^joined,^undocumented

The argument to --help= should not consist solely of inverted qualifiers ๐Ÿšซ

You can combine several classes, but that usually narrows the output down so much 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 use displays its requested class of options, skipping anything already shown ๐Ÿ” If --help is also specified anywhere on the command line, it takes precedence over any --help= option ๐Ÿ‘‘

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

Here's a truncated example from the ARM port of gcc:

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

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

-Q -O2 --help=optimizers

Or, if you want to figure out which binary optimizations are enabled by -O3, you can do:

gcc -c -Q -O3 --help=optimizers > /tmp/O3-opts
gcc -c -Q -O2 --help=optimizers > /tmp/O2-opts
diff /tmp/O2-opts /tmp/O3-opts | grep enabled
  • --version โ€” Displays the version number and copyrights of the GCC you invoked ๐ŸŒˆโœจ
  • -pass-exit-codes: okay so normally gcc exits with the code of 1 if any phase of the compiler returns a non-success return code ๐Ÿ˜ญ. But if you add -pass-exit-codes, it instead returns the numerically highest error from 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 stuff between the stages of compilation ๐Ÿฆ‹. Ngl this one can be sketchy on some systems where the assembler can't read from a pipe, but the GNU assembler has no trouble ๐Ÿซถ.
  • -specs=file: processes file after the compiler reads in the standard specs file, so it can 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: invokes all subcommands under a wrapper program ๐ŸŽ€. The wrapper's name and its parameters go in as a comma separated list.
gcc -c t.c -wrapper gdb,--args

This invokes all subprograms of gcc under gdb --args, so the invocation of cc1 is gdb --args cc1 .... ๐Ÿงš

  • -ffile-prefix-map=old=new: when compiling files that live in directory old, any references to them in the result of the compilation get recorded as if the files lived in directory new instead ๐Ÿ“. Specifying this is the same as specifying all the individual -f*-prefix-map options, and it can be used to make reproducible builds that are location independent ๐Ÿซง. See also -fmacro-prefix-map and -fdebug-prefix-map.
  • -fplugin=name.so: loads the plugin code in name.so, a shared object that the compiler dlopen's ๐Ÿ”Œ. The base name of the shared object file is used to identify the plugin for argument parsing (see -fplugin-arg-name-key=value below). Each plugin should define the callback functions specified in the Plugins API.
  • -fplugin-arg-name-key=value: defines an argument called key with a value of value for the plugin called name ๐Ÿงฉ.
  • -fdump-ada-spec[-slim]: for C and C++ source and include files, generates the matching Ada specs ๐Ÿ’œ.
  • -fada-spec-parent=unit: used together with -fdump-ada-spec[-slim] above, this generates Ada specs as child units of the parent unit ๐Ÿ‘‘.
  • -fdump-go-spec=file: for input files in any language, generates matching Go declarations in file ๐Ÿน. You get Go "const", "type", "var", and "func" declarations, which can be a useful way to start writing a Go interface to code written in some other language โœจ.
  • @file: reads command-line options from file ๐Ÿ“œ. The options it reads get inserted in place of the original @file option. If file doesn't exist or can't be read, then the option is treated literally and not removed ๐Ÿ™ˆ.

Options in file are separated by whitespace. A whitespace character can be included in an option by surrounding the entire option in either single or double quotes. Any character (including a backslash) can be included by prefixing the character you want to include with a backslash. The file may itself contain additional @file options, and any such options 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 ๐Ÿ˜ค. That's where g++ comes in. It's a program that calls GCC and automatically specifies linking against the C++ library ๐Ÿ‘‘. It treats .c, .h and .i files as C++ source files instead of C source files, unless -x is used. This program is also useful when precompiling a C header file with a .h extension for use in C++ compilations ๐Ÿซถ. On many systems, g++ is also installed with the name c++.

When you compile C++ programs, you can specify many of the same command-line options you use for programs in any language ๐ŸŽ€. You can also use command-line options meaningful for C and related languages, or options that are meaningful only for C++ programs โœจ.

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

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

  • -ansi: in C mode, this is the same as -std=c90. In C++ mode, it's the same as -std=c++98 ๐Ÿง.

This turns off certain features of GCC that aren't compatible with ISO C90 (when compiling C code), or with standard C++ (when compiling C++ code). That includes the asm and typeof keywords, and predefined macros such as 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 disables recognition of C++ style // comments as well as the inline keyword ๐Ÿฅ€.

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

The -ansi option doesn't cause non-ISO programs to be rejected gratuitously. For that, -Wpedantic is required in addition to -ansi ๐Ÿ”.

The macro __STRICT_ANSI__ is predefined when the -ansi option is used ๐ŸŽฏ. Some header files may notice this macro and refrain from declaring certain functions or defining certain macros that the ISO standard doesn't call for. This avoids interfering with any programs that might use those names for other things ๐Ÿซง.

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

  • -std=: determines the language standard ๐Ÿ“š. This option is currently only supported when compiling C or C++.

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

On the other hand, when a GNU dialect of a standard is specified, all features supported by the compiler are enabled, even when those features change the meaning of the base standard. As a result, some strict-conforming programs may be rejected ๐Ÿ˜ฌ. The particular standard is used by -Wpedantic to identify which features are GNU extensions, given that version of the standard. For example, -std=gnu90 -Wpedantic warns about C++ style // comments, while -std=gnu99 -Wpedantic does not ๐Ÿ”ฅ.

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

  • c90, c89, iso9899:1990: supports all ISO C90 programs (certain GNU extensions that conflict with ISO C90 are disabled). Same as -ansi for C code ๐ŸŽ€.
  • iso9899:199409: ISO C90 as modified in amendment 1 ๐ŸŒท.
  • c99, c9x, iso9899:1999, iso9899:199x: ISO C99. This standard is substantially completely supported, modulo bugs and floating-point issues (mainly but not entirely relating to optional C99 features from Annexes F and G). See <http://gcc.gnu.org/c99status.html> for more information. The names c9x and iso9899:199x are deprecated ๐Ÿฅ€.
  • c11, c1x, iso9899:2011: ISO C11, the 2011 revision of the ISO C standard. This standard is substantially completely supported, modulo bugs, floating-point issues (mainly but not entirely relating to optional C11 features from Annexes F and G), and the optional Annexes K (Bounds-checking interfaces) and L (Analyzability). The name c1x is deprecated ๐Ÿง.
  • c17, c18, iso9899:2017, iso9899:2018: ISO C17, the 2017 revision of the ISO C standard (published in 2018). This standard is the same as C11 except for corrections of defects (all of which are also applied with -std=c11) and a new value of __STDC_VERSION__, so it's supported to the same extent as C11 โœ….
  • c2x: the next version of the ISO C standard, still under development. Support for this version is experimental and incomplete ๐Ÿงช.
  • gnu90, gnu89: GNU dialect of ISO C90 (including some C99 features) ๐ŸŒ™.
  • gnu99, gnu9x: GNU dialect of ISO C99. The name gnu9x is deprecated ๐Ÿฆ„.
  • gnu11, gnu1x: GNU dialect of ISO C11. The name gnu1x is deprecated ๐ŸŒŸ.
  • gnu17, gnu18: GNU dialect of ISO C17. This is the default for C code ๐Ÿ‘‘๐Ÿ’–.
  • gnu2x: the next version of the ISO C standard, still under development, plus GNU extensions. Support for this version is experimental and incomplete ๐Ÿงชโœจ.
  • c++98, c++03: the 1998 ISO C++ standard plus the 2003 technical corrigendum and some additional defect reports. Same as -ansi for C++ code ๐Ÿ“.
  • gnu++98, gnu++03: GNU dialect of -std=c++98 ๐Ÿซถ.
  • c++11, c++0x: the 2011 ISO C++ standard plus amendments. The name c++0x is deprecated ๐ŸŒธ.
  • gnu++11, gnu++0x: GNU dialect of -std=c++11. The name gnu++0x is deprecated ๐Ÿ’….
  • c++14, c++1y: the 2014 ISO C++ standard plus amendments. The name c++1y is deprecated ๐Ÿฆ‹.
  • gnu++14, gnu++1y: GNU dialect of -std=c++14. This is the default for C++ code. The name gnu++1y is deprecated ๐Ÿงš.
  • c++17, c++1z: the 2017 ISO C++ standard plus amendments. The name c++1z is deprecated ๐ŸŽ€.
  • gnu++17, gnu++1z: GNU dialect of -std=c++17 ๐Ÿ’… The name gnu++1z is deprecated ๐Ÿ™ˆ
  • c++2a: the next revision of the ISO C++ standard, tentatively planned for 2020 ๐Ÿ”ฎ Support is highly experimental and will almost certainly change in incompatible ways in future releases ๐Ÿ’€
  • gnu++2a: the GNU dialect of -std=c++2a โœจ It's just as highly experimental, and it will almost certainly change in incompatible ways in future releases ๐Ÿ˜ญ
  • -fgnu89-inline: okay so this tells GCC to use the traditional GNU semantics for inline functions when you're in C99 mode ๐Ÿฆ‹ It's roughly the same as slapping the gnu_inline function attribute on every inline function, lowkey iconic ๐Ÿ‘‘
  • -fno-gnu89-inline: the opposite energy ๐Ÿ’… It tells GCC to use the C99 semantics for inline when you're in C99 or gnu99 mode, which is the default behaviour. This option is not supported in -std=c90 or -std=gnu90 mode ๐Ÿ™… You can check which semantics are active with the preprocessor macros __GNUC_GNU_INLINE__ and __GNUC_STDC_INLINE__ ๐Ÿ”
  • -fpermitted-flt-eval-methods=style: this one is a lot ๐Ÿค“ ISO/IEC TS 18661-3 adds brand new permissible values for FLT_EVAL_METHOD, saying that operations and constants with a semantic type that's an interchange or extended format should be evaluated to that type's precision and range ๐ŸŒˆ These new values are a superset of what C99/C11 allows, and C99/C11 doesn't specify what any other positive values mean, so C11 code might not have been written expecting them ๐Ÿ‘€
    • -fpermitted-flt-eval-methods decides whether the compiler allows only the values from C99/C11, or the extended set from ISO/IEC TS 18661-3 ๐ŸŽฏ
    • style is either c11 or ts-18661-3, as appropriate
    • In a standards-compliant mode (-std=c11 or similar), the default is -fpermitted-flt-eval-methods=c11 ๐Ÿ’–
    • In a GNU dialect (-std=gnu11 or similar), the default is -fpermitted-flt-eval-methods=ts-18661-3 โœจ
  • -aux-info filename: this dumps prototyped declarations for all functions declared and/or defined in a translation unit, including the ones in header files, into the given filename ๐Ÿ“ It's silently ignored in any language other than C ๐Ÿคซ
    • Besides the declarations, the file uses comments to show:
      • the origin of each declaration (source file and line)
      • whether the declaration was implicit, prototyped or unprototyped, shown by I, N (new) or O (old) in the first character after the line number and the colon
      • whether it came from a declaration or a definition, shown by C or F respectively in the character after that
    • For function definitions, a K&R-style list of arguments followed by their declarations also shows up inside comments, right after the declaration ๐Ÿงถ
  • -fallow-parameterless-variadic-functions: accepts variadic functions without any named parameters ๐ŸŒธ You can define one, but it's not super useful since you can't read the arguments ๐Ÿ™ƒ This is only supported for C, because C++ already allows this construct ๐Ÿ’œ
  • -fno-asm: stops asm, inline and typeof from being 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 only affects typeof, since asm and inline are standard keywords. You may want to use -fno-gnu-keywords instead, which has the same effect ๐ŸŽ€
    • In C99 mode (-std=c99 or -std=gnu99), it only affects asm and typeof, since inline is a standard keyword in ISO C99 ๐Ÿฆ‹
  • -fno-builtin, -fno-builtin-function: don't recognise the built-in functions that don't begin with the __builtin_ prefix ๐Ÿšซ
    • GCC normally generates special code to handle certain built-in functions more efficiently. For instance, calls to alloca may become single instructions that adjust the stack directly, and calls to memcpy may become inline copy loops ๐Ÿง‘โ€๐Ÿ”ง The result is often both smaller and faster ๐ŸŽ๏ธ
    • But since the function calls no longer appear as calls, you can't set a breakpoint on them, and you can't change what the functions do by linking with a different library ๐Ÿ˜ฉ
    • When a function is recognised as built-in, GCC may also use info about it to warn about problems with calls to it, or to generate more efficient code, even if the result still contains calls to that function ๐Ÿ”Ž For example, warnings are given with -Wformat for bad calls to printf when printf is built in and strlen is known not to modify global memory ๐Ÿ“ฃ
    • With -fno-builtin-function, only that one built-in function is disabled. function must not begin with __builtin_. If you name a function that isn't built-in in this version of GCC, the option is ignored ๐Ÿคท
    • There's no corresponding -fbuiltin-function option. If you want to enable built-in functions selectively when using -fno-builtin or -ffreestanding, you can define macros such as:
#define abs(n)          __builtin_abs ((n))
#define strcpy(d, s)    __builtin_strcpy ((d), (s))
  • -fgimple: enables parsing of function definitions marked with __GIMPLE ๐Ÿงช It's an experimental feature that allows unit testing of GIMPLE passes ๐Ÿง 
  • -fhosted: asserts that compilation targets a hosted environment, and this implies -fbuiltin ๐Ÿ  A hosted environment is one where the entire standard library is available, and main has a return type of int. Think nearly everything except a kernel ๐Ÿ’… This is equivalent to -fno-freestanding.
  • -ffreestanding: asserts that compilation targets a freestanding environment, and this implies -fno-builtin ๐Ÿ”ฅ A freestanding environment is one where the standard library may not exist, and program startup may not necessarily be at main ๐Ÿซ  The most obvious example is an OS kernel ๐Ÿ‘‘ This is equivalent to -fno-hosted.
  • -fopenacc: enables handling of OpenACC directives #pragma acc in C/C++ and !$acc in Fortran ๐Ÿš€ When you specify it, the compiler generates accelerated code according to the OpenACC Application Programming Interface v2.0 (https://www.openacc.org) ๐ŸŒŸ This option implies -pthread, so it's only supported on targets that support -pthread ๐Ÿงต
  • -fopenacc-dim=geom: sets default compute dimensions for parallel offload regions that don't explicitly specify their own ๐Ÿ“ geom is a triple of :-separated sizes, in the order gang, worker and vector. You can leave a size out to use a target-specific default value ๐ŸŒˆ
  • -fopenmp: enables handling of OpenMP directives #pragma omp in C/C++ and !$omp in Fortran ๐Ÿง‘โ€๐Ÿ’ป When you specify it, the compiler generates parallel code according to the OpenMP Application Program Interface v4.5 (https://www.openmp.org) ๐ŸŽ‰ This option implies -pthread, so it's only supported on targets that support -pthread. -fopenmp also implies -fopenmp-simd.
  • -fopenmp-simd: enables handling of OpenMP's SIMD directives with #pragma omp in C/C++ and !$omp in Fortran ๐Ÿ’– Other OpenMP directives are ignored ๐Ÿ™ˆ
  • -fgnu-tm: when you specify this, the compiler generates code for the Linux variant of Intel's current Transactional Memory ABI specification document (Revision 1.1, May 6 2009) ๐Ÿง  It's an experimental feature whose interface may change in future GCC versions as the official specification changes โš ๏ธ Please note that not all architectures are supported for this feature ๐Ÿ’€
    • For more information on GCC's support for transactional memory,
    • > Heads up, bestie: the transactional memory feature is not supported with non-call exceptions (-fnon-call-exceptions) ๐Ÿšจ
  • -fms-extensions: accepts some non-standard constructs used in Microsoft header files ๐Ÿ’… In C++ code, this lets member names in structures be similar to previous type declarations, like this:
typedef int UOW;
struct ABC {
  UOW UOW;
};

Some cases of unnamed fields in structures and unions are only accepted with this option ๐ŸŽ€

This option is off for all targets except x86 targets using ms-abi ๐Ÿšจ
  • -fplan9-extensions: accepts some non-standard constructs used in Plan 9 code ๐Ÿš This enables -fms-extensions, permits passing pointers to structures with anonymous fields to functions that expect pointers to elements of the type of the field, and permits referring to anonymous fields declared using a typedef ๐Ÿช„ This is only supported for C, not C++ ๐Ÿ™…
  • -fcond-mismatch: allows conditional expressions with mismatched types in the second and third arguments ๐Ÿ”€ The value of such an expression is void ๐Ÿ’ญ This option is not supported for C++ ๐Ÿ’€
  • -flax-vector-conversions: allows implicit conversions between vectors with differing numbers of elements and/or incompatible element types ๐Ÿซ 
This option should not be used for new code ๐Ÿ™…
  • -funsigned-char: lets the type char be unsigned, like unsigned char ๐ŸŒ™ Each kind of machine has a default for what char should be. It's either like unsigned char by default or like signed char by default ๐Ÿคท
    • Ideally, a portable program should always use signed char or unsigned char when it depends on the signedness of an object. But many programs were written to use plain char and expect it to be signed, or expect it to be unsigned, depending on the machines they were written for ๐Ÿฅฒ This option, and its inverse, lets you make such a program work with the opposite default ๐Ÿ”„
    • The type char is always a distinct type from each of signed char or unsigned char, even though its behaviour is always just like one of those two ๐Ÿงฉ
  • -fsigned-char: lets the type char be signed, like signed char ๐Ÿ’œ This is equivalent to -fno-unsigned-char, which is the negative form of -funsigned-char. Likewise, -fno-signed-char is equivalent to -funsigned-char โœจ

-fsigned-bitfields, -funsigned-bitfields, -fno-signed-bitfields, -fno-unsigned-bitfields** โ€” okay so these decide whether a <pink>bit-field</pink> is signed or unsigned, but only when the declaration doesn't already say signedorunsigned๐Ÿ’… By default it's **signed**, and honestly that's the consistent choice, because basic types likeint` are signed too ๐ŸŽ€

  • -fsso-struct=endianness โ€” this sets the default scalar storage order for structs and unions to whatever endianness you pick โœจ Your options are big-endian, little-endian, or native (the native endianness of your target, which is the default) ๐ŸŒˆ Heads up, this one isn't supported for C++ ๐Ÿ™ˆ
โš ๏ธ Bestie, be careful with -fsso-struct! If the endianness you pick isn't your target's native one, GCC generates code that is not binary compatible with code built without the flag ๐Ÿ˜ญ

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

This section is all about the command-line options that only matter for C++ programs ๐Ÿ’œ Good news though, you can use most GNU compiler options no matter what language your program is written in ๐Ÿฆ‹ For example, you could compile a file called firstClass.C like this:

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

In that example, only -fstrict-enums is meant just for C++ programs. The other options work with any language GCC supports ๐Ÿซถ

Some options that are mainly for C programs, like -std, are also relevant to C++ programs ๐Ÿ“

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

  • -fabi-version=n โ€” picks version n of the C++ ABI ๐Ÿ”ฅ The default is version 0.
    • Version 0 is the one that matches the C++ ABI spec the most closely, so the ABI you get from version 0 will keep changing across G++ versions as ABI bugs get squashed ๐Ÿ›
    • Version 1 first showed up in G++ 3.2 โœจ
    • Version 2 first showed up in G++ 3.4 and was the default all the way through G++ 4.9 ๐Ÿ’…
    • Version 3 fixes a mistake in mangling a constant address used as a template argument ๐ŸŽ€
    • Version 4 first showed up in G++ 4.5 and adds a standard mangling for vector types ๐Ÿฆ‹
    • Version 5 first showed up in G++ 4.6 and corrects the mangling of attribute const/volatile on function pointer types, decltype of a plain decl, and using a function parameter in the declaration of another parameter ๐ŸŒธ
    • Version 6 first showed up in G++ 4.7 and corrects the promotion behavior of C++11 scoped enums, plus the mangling of template argument packs, const/static_cast, prefix ++ and --, and a class scope function used as a template argument ๐Ÿ’–
    • Version 7 first showed up in G++ 4.8 and treats nullptr_t as a builtin type, and it also corrects the mangling of lambdas in default argument scope ๐Ÿงš
    • Version 8 first showed up in G++ 4.9 and corrects the substitution behavior of function types with function-cv-qualifiers โญ
    • Version 9 first showed up in G++ 5.2 and corrects the alignment of "nullptr_t" ๐ŸŒˆ
    • Version 10 first showed up in G++ 6.1 and adds mangling for attributes that affect type identity, like ia32 calling convention attributes (e.g. stdcall) ๐Ÿ’œ
    • Version 11 first showed up in G++ 7 and corrects the mangling of sizeof... expressions and operator names. For multiple entities with the same name within a function that are declared in different scopes, the mangling now changes starting with the twelfth occurrence. It also implies -fnew-inheriting-ctors ๐Ÿ‘‘
    • Version 12 first showed up in G++ 8 and corrects the calling conventions for empty classes on the x86_64 target and for classes with only deleted copy/move constructors. It accidentally changes the calling convention for classes with a deleted copy constructor and a trivial move constructor ๐Ÿ˜ญ
    • Version 13 first showed up in G++ 8.2 and fixes that accidental change from version 12 ๐Ÿซถ
    • See also -Wabi. ๐Ÿ”
  • -fabi-compat-version=n โ€” okay this one is a whole vibe ๐ŸŒธ On targets that support strong aliases, G++ dodges mangling changes by making an alias with the correct mangled name whenever it defines a symbol with an incorrect one. This switch picks which ABI version that alias uses ๐Ÿฆ‹

With -fabi-version=0 (the default), this defaults to 11 (GCC 7 compatibility). If you explicitly pick a different ABI version, it defaults to 0. If you want 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 (no version number), the version from this option is used for the warning โœจ

  • -fno-access-control โ€” turns off all access checking ๐Ÿ™ˆ It's mainly useful for working around bugs in the access control code, so it's not really a everyday flex ๐Ÿ’€
  • -faligned-new โ€” enables support for C++17 new of types that need more alignment than void* ::operator new(std::size_t) gives you ๐ŸŽ€ You can use a number like -faligned-new=32 to say how much alignment (in bytes) that function provides, but honestly few people 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 โ€” this turns on support for char8_t, as adopted for C++2a ๐Ÿงš It 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, updates the standard library, and adds the new "__cpp_char8_t" and "__cpp_lib_char8_t" feature test macros โœจ

With this on, functions can be overloaded for ordinary strings and UTF-8 strings, like this:

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

It also introduces new signatures for user-defined literals:

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

โš ๏ธ Heads up, bestie: changing the types of UTF-8 string and character literals breaks compatibility with ISO C++11 and later standards ๐Ÿ˜ญ For example, this code is fine under ISO C++11, but it's ill-formed 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
  • -fcheck-new โ€” this makes GCC check that the pointer returned by operator new is non-null before it touches the allocated storage ๐Ÿซถ Usually you don't need it, because the C++ standard says operator new only returns 0 if it's declared throw(), and in that case the compiler always checks the return value even without this option ๐Ÿ’– In every other case, when operator new has a non-empty exception specification, running out of memory gets signalled by throwing std::bad_alloc. See also new (nothrow). ๐Ÿ“
  • -fconcepts โ€” enables support for the C++ Extensions for Concepts Technical Specification, ISO 19217 (2015), so you can write code like this ๐Ÿฆ‹
        template <class T> concept bool Addable = requires (T t) { t + t; };
        template <Addable T> T add (T a, T b) { return a + b; }
  • -fconstexpr-depth=n โ€” sets the maximum nested evaluation depth for C++11 constexpr functions to n ๐ŸŒธ You need a limit so endless recursion can be caught during constant expression evaluation. The minimum the standard specifies is 512 โœจ
  • -fconstexpr-loop-limit=n โ€” sets the maximum number of iterations for a loop in C++14 constexpr functions to n ๐Ÿ”ฅ The limit is there to catch 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 ๐Ÿงš Even if a single loop's iterations are capped by the option above, you can still run into trouble. If you have several nested loops that each have lots of iterations (but are still under that limit), or if too many expressions need evaluating in a loop body or even outside a loop, the constexpr evaluation might take way too long ๐Ÿ˜ญ The default is 33554432 (1<<25) ๐Ÿ‘‘
  • -fdeduce-init-list โ€” enables deducing a template type parameter as std::initializer_list from a brace-enclosed initializer list ๐Ÿ’œ Check out this example:
        template <class T> auto forward(T t) -> decltype (realfn (t))
        {
          return realfn (t);
        }

        void f()
        {
          forward({1,2}); // call forward<std::initializer_list<int>>
        }

This deduction was an extension someone floated during the C++11 standard drafting, but it never made it into the final standard, so it's disabled by default ๐Ÿ™ˆ This option is deprecated and may be removed in a future version of G++ ๐Ÿ’€

  • -fno-elide-constructors โ€” the C++ standard lets an implementation skip creating a temporary that's only used to initialize another object of the same type ๐ŸŒˆ This option turns that optimization off and forces G++ to call the copy constructor in all cases โœจ It also makes G++ call trivial member functions that would otherwise be expanded inline ๐ŸŽ€

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

  • -fno-enforce-eh-specs โ€” okay bestie, this one's a bit spicy ๐ŸŒถ๏ธ It tells the compiler to skip generating the run-time checks for exception specifications. It goes against the C++ standard, but it can shrink code size in production builds, kinda like defining NDEBUG โœจ Also, this does NOT give your code permission to throw exceptions that break those specs. The compiler still optimizes based on the specs, so an unexpected throw leads to undefined behavior at run time ๐Ÿ’€
  • -fextern-tls-init, -fno-extern-tls-init โ€” so C++11 and OpenMP let thread_local and threadprivate variables do dynamic (runtime) initialization ๐Ÿงต To make that work, every use of one of these variables goes through a wrapper function that handles the setup. If the variable is used and defined in the same translation unit, the compiler can optimize that overhead away. But if the use is in a different translation unit, the overhead sticks around even when the variable doesn't actually need dynamic init ๐Ÿ˜ค If you're sure no use in a non-defining TU needs to trigger dynamic initialization (maybe it's statically initialized, or the defining TU runs a use before any other TU does), 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 do not support symbol aliases, the default is -fno-extern-tls-init.

  • -fno-gnu-keywords โ€” this tells GCC to stop treating typeof as a keyword, so you can use it as a normal identifier ๐ŸŽ€ If you still want the keyword version, use __typeof__ instead. This is automatically on for the strict ISO C++ dialects: -ansi, -std=c++98, -std=c++11, etc.
  • -fno-implicit-templates โ€” never emit code for non-inline templates that get instantiated implicitly (aka just by using them) ๐Ÿฆ‹ Only explicit instantiations get code. If you go this route, you need to structure your code so every explicit instantiation you need is there, or you'll get undefined symbols at link time ๐Ÿ™ˆ
  • -fno-implicit-inline-templates โ€” same vibe, but for inline templates. No code gets emitted for their implicit instantiations either ๐ŸŒธ By default, inlines are handled differently so that compiles with and without optimization need the same set of explicit instantiations, which is a whole mood honestly โœจ
  • -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 stuff used in MFC, like implicit int and getting a pointer to a member function via non-standard syntax ๐ŸŒˆ
  • -fnew-inheriting-ctors โ€” turns on the P0136 adjustment to C++11 constructor inheritance semantics ๐Ÿงš It's technically part of C++17, but it's also considered a Defect Report against C++11 and C++14. This flag is enabled by default unless -fabi-version=10 or lower is specified.
  • -fnew-ttp-matching โ€” enables the P0522 resolution to Core issue 150, which is about template template parameters and default arguments ๐Ÿ’œ It lets a template with default template arguments be used as an argument for a template template parameter that has fewer template parameters. This flag is enabled by default for -std=c++17.
  • -fno-nonansi-builtins โ€” disables built-in declarations for functions that aren't required by ANSI/ISO C ๐Ÿ™ƒ That includes ffs, alloca, _exit, index, bzero, conjf, and a bunch of other related functions.
  • -fnothrow-opt โ€” treats a throw() exception specification as if it were a noexcept specification, which can reduce or wipe out the text size overhead compared to a function with no exception spec โญ If the function has local variables with non-trivial destructors, the exception spec can actually make the function smaller, because the EH cleanups for those variables can get optimized away. The catch (literally ๐Ÿ’€): an exception thrown out of a function with this kind of spec leads to a call to terminate instead of unexpected.
  • -fno-operator-names โ€” stops treating the operator name keywords and, bitand, bitor, compl, not, or and xor as synonyms for keywords ๐Ÿ“
  • -fno-optional-diags โ€” disables diagnostics that the standard says a compiler doesn't have 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 with -fpermissive, some nonconforming code is allowed to compile. Use it wisely, bestie.
  • -fno-pretty-templates โ€” when an error mentions a specialization of a function template, GCC normally prints the template signature followed by the template arguments and any typedefs or typenames in the signature. For example, you'd get void f(T) [with T = int] instead of void f(int), so it's super clear which template is involved ๐Ÿ‘‘ When an error mentions a specialization of a class template, GCC leaves out any template arguments that match the template's default arguments. If either of those behaviors makes errors harder to read instead of easier, you can use -fno-pretty-templates to turn them off ๐Ÿ’…
  • -frepo โ€” enables automatic template instantiation at link time ๐Ÿฆ‹ This option also implies -fno-implicit-templates.
  • -fno-rtti โ€” disables generating run-time type information for every class with virtual functions. That info is used by the C++ run-time type identification features (dynamic_cast and typeid) ๐Ÿง  If you don't use those features, you can save some space with this flag. Note that exception handling uses the same info, but G++ only generates it as needed. The dynamic_cast operator still works for casts that don't need RTTI, i.e. casts to void * or to unambiguous base classes โœจ
Mixing code compiled with -frtti and code compiled with -fno-rtti may not work. For example, programs may fail to link if a class compiled with -fno-rtti is used as a base for a class compiled with -frtti. ๐Ÿ˜ฌ
  • -fsized-deallocation โ€” enables the built-in global declarations introduced in C++14 ๐ŸŒท
void operator delete (void *, std::size_t) noexcept;
void operator delete[] (void *, std::size_t) noexcept;

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

  • -fstrict-enums โ€” lets the compiler optimize based on the assumption that a value of an enumerated type can only be one of the enumeration's values (per the C++ standard, basically a value that fits in the minimum number of bits needed to represent all the enumerators) ๐ŸŽฏ This assumption may not hold if the program casts an arbitrary integer to the enumerated type, so be careful with that ๐Ÿ™ˆ
  • -fstrong-eval-order โ€” evaluates member access, array subscripting, and shift expressions left-to-right, and assignment right-to-left, as adopted for C++17 ๐Ÿ’– It's enabled by default with -std=c++17. -fstrong-eval-order=some only enables the ordering for member access and shift expressions, and it's the default without -std=c++17.
  • -ftemplate-backtrace-limit=n โ€” sets the maximum number of template instantiation notes shown for a single warning or error to n ๐Ÿ“ The default is 10.
  • -ftemplate-depth=n โ€” sets the maximum instantiation depth for template classes to n ๐ŸŒ€ A limit is needed to catch endless recursion during template class instantiation. ANSI/ISO C++ conforming programs must not rely on a maximum depth greater than 17 (which changed to 1024 in C++11). The default value is 900, because the compiler can run out of stack space before hitting 1024 in some situations ๐Ÿฅฒ
  • -fno-threadsafe-statics โ€” stops emitting the extra code that uses the routines from the C++ ABI for thread-safe initialization of local statics ๐Ÿงต You can use this to shave a bit off code size in code that doesn't need to be thread-safe.
  • -fuse-cxa-atexit โ€” registers destructors for objects with static storage duration using the __cxa_atexit function instead of atexit ๐Ÿฆข This is required for fully standards-compliant handling of static destructors, but it only works if your C library supports __cxa_atexit.
  • -fno-use-cxa-get-exception-ptr โ€” don't use the __cxa_get_exception_ptr runtime routine ๐Ÿšซ This makes std::uncaught_exception incorrect, but it's necessary if that runtime routine isn't available.
  • -fvisibility-inlines-hidden โ€” this switch tells GCC that you won't try to compare pointers to inline functions or methods when the two functions' addresses 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 inside that DSO ๐ŸŒˆ Turning this on can have a dramatic effect on load and link times for a DSO, because it massively shrinks the dynamic export table when the library uses lots of templates ๐Ÿš€

The behavior isn't quite the same as marking methods hidden directly, because it doesn't affect static variables local to the function, and it doesn't make the compiler deduce that the function is defined in only one shared object.

You can explicitly give a method a visibility to cancel out the switch for that method. For example, if you do want to compare pointers to a particular inline method, you might mark it with 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 โ€” okay bestie, this one is a whole vibe ๐Ÿฆ‹ It tries to use visibility settings to make GCC's C++ linkage model act like Microsoft Visual Studio's. โœจ

Here's what it changes in GCC's linkage model ๐ŸŽ€:

  1. It sets the default visibility to "hidden", same as -fvisibility=hidden.
  2. Types (but not their members) are not hidden by default.
  3. The One Definition Rule (ODR) is relaxed for types without explicit visibility specifications that are defined in more than one shared object. Those declarations are allowed if they'd be allowed without this option.

In new code, the move is to use -fvisibility=hidden and export only the classes you actually want visible externally ๐Ÿ’… Unfortunately, code might rely on the Visual Studio behavior, maybe even by accident ๐Ÿ™ˆ

Some of the fallout: static data members of the same type, with the same name, defined in different shared objects are different, so changing one won't change the other ๐Ÿ˜ญ Also, pointers to function members defined in different shared objects may not compare equal. With this flag on, defining types with the same name differently is an ODR violation ๐Ÿ’€

  • -fno-weak โ€” don't use weak symbol support, even if the linker provides it. By default, G++ uses weak symbols when they're available, but this option is strictly for testing ๐Ÿงช End users shouldn't touch it, since it gives inferior code and has no benefits. It might get removed in a future release of G++ ๐Ÿฅ€
  • -nostdinc++ โ€” skips the C++-specific standard directories when hunting for header files, but still searches the other standard directories ๐Ÿ“ (This is the option used when building the C++ library.)

Now for the extra goodies ๐ŸŒˆ These optimization, warning, and code generation options only mean something for C++ programs:

  • -Wabi (C, Objective-C, C++ and Objective-C++ only) โ€” warns when G++ generates code that's probably not compatible with the vendor-neutral C++ ABI ๐Ÿ‘‘ G++ now updates the ABI with every major release by default, so -Wabi normally only warns about an ABI issue that got a check added later in a release series, after the initial release was out. It'll warn about way more stuff if you pick an older ABI version with -fabi-version=n.

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

If you pass an explicit version number and don't specify -fabi-compat-version, the version number from this option gets used for compatibility aliases. If you don't pass a version number here but do specify -fabi-compat-version, that version number gets used for ABI warnings instead.

Real talk: an effort was made to warn about all these cases, but there are probably some incompatible cases that slip through anyway. There can also be false alarms where the warning fires even though the generated code is actually compatible โœจ

If you care about G++ output not being binary compatible with code from other compilers, you should rewrite your code to dodge these warnings ๐Ÿซถ

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

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

This was fixed in -fabi-version=3.

  • SIMD vector types declared using __attribute ((vector_size)) were mangled in a non-standard way that didn't allow overloading functions that take vectors of different sizes ๐Ÿ˜ค

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

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

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

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

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

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

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

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

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

It also warns 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. For example:
union U {
  long double ld;
  int i;
};

union U is always passed in memory.

  • -Wabi-tag (C++ and Objective-C++ only) โ€” warns when a type with an ABI tag gets used in a context that doesn't have that ABI tag ๐Ÿท๏ธ See C++ Attributes for more info about ABI tags.
  • -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 no friends or 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 ๐Ÿ’€ Deleting a derived class through a base class pointer is unsafe 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 when the class has a user-provided copy constructor or copy assignment operator, in C++11 and up ๐Ÿ“‹ This warning is enabled by -Wextra. With -Wdeprecated-copy-dtor, it also deprecates the implicit copy operations if the class has a user-provided destructor.
  • -Wno-init-list-lifetime (C++ and Objective-C++ only) โ€” stops warnings about uses of std::initializer_list that are likely to end up with dangling pointers ๐Ÿซ  The underlying array for an initializer_list is handled like a normal C++ temporary object, so it's super easy to accidentally keep a pointer to the array after its lifetime has ended. For example:
    • If a function returns a temporary initializer_list, or a local initializer_list variable, the array's lifetime ends at the end of the return statement, so the returned value has a dangling pointer.
    • If a new-expression creates an initializer_list, the array only lives until the end of the enclosing full-expression, so the initializer_list on the heap has a dangling pointer.
    • When an initializer_list variable is assigned from a brace-enclosed initializer list, the temporary array made for the right side of the assignment only lives until the end of the full-expression. So by 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, it 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.
  • -Wliteral-suffix (C++ and Objective-C++ only) โ€” warns 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 these suffixes as separate preprocessing tokens so that older code using formatting macros from <inttypes.h> keeps working. For example:
#define __STDC_FORMAT_MACROS
#include <inttypes.h>
#include <stdio.h>

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

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

This option also warns when a user-defined literal operator is declared with a literal suffix identifier that doesn't begin with an underscore. Literal suffix identifiers without a leading underscore are reserved for future standardization ๐Ÿ“š

This warning is enabled by default.

  • -Wlto-type-mismatch โ€” during link-time optimization, warns about type mismatches in global declarations from different compilation units ๐Ÿ”ฅ It requires -flto to be enabled. Enabled by default.
  • -Wno-narrowing (C++ and Objective-C++ only) โ€” okay so for C++11 and later, GCC flags narrowing conversions by default because the standard requires it ๐Ÿ™„๐Ÿ’…. A narrowing conversion from a constant is an error, and one from a non-constant is a warning. -Wno-narrowing shuts that whole diagnostic up ๐Ÿคซ. It doesn't change what well-formed code means โœจ, but narrowing is still ill-formed in SFINAE contexts ๐Ÿ’€. With -Wnarrowing in C++98, GCC 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 it calls a function without a non-throwing exception spec (throw() or noexcept), even though the compiler knows that function never throws ๐Ÿฆ‹.
  • -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:
template <class T> void f(T t) { t(); };
void g() noexcept;
void h() { f(g); }

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

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

The safe move is to initialize or clear these objects using the appropriate constructor or assignment operator, if one exists โœจ. -Wclass-memaccess is enabled by -Wall. Casting the pointer to the class object to void *, or to a type that can be safely accessed by the raw memory function, quiets the warning ๐Ÿซถ.

  • -Wnon-virtual-dtor (C++ and Objective-C++ only) โ€” warns when a class has virtual functions but its own destructor, or the destructor of an accessible polymorphic base class, isn't virtual ๐Ÿ“. Deleting a derived instance through a pointer to the base or class is possible but unsafe in that case. This warning is turned on automatically if -Weffc++ is specified.
  • -Wregister (C++ and Objective-C++ only) โ€” warns on uses of the register storage class specifier, unless it's part of the GNU Explicit Register Variables extension ๐Ÿงš. Using register as a storage class specifier was deprecated in C++11 and removed in C++17. It's enabled by default with -std=c++17.
  • -Wreorder (C++ and Objective-C++ only) โ€” warns when the order of member initializers in your code doesn't match the order they actually have to run in ๐Ÿ”ฅ. Here's the sneaky one:
struct A {
  int i;
  int j;
  A(): j (0), i (1) { }
};

The compiler quietly rearranges the initializers for i and j to match the declaration order of the members, and it warns you about it ๐Ÿ‘€. This warning is enabled by -Wall.

  • -Wno-pessimizing-move (C++ and Objective-C++ only) โ€” this one warns when a call to std::move stops copy elision from happening ๐Ÿ™ˆ. The classic copy-elision situation is returning from a function with a class return type, where the returned expression is the name of a non-volatile automatic object that isn't a function parameter and has the same type as the return type. Look at this:
struct T {
...
};
T fn()
{
  T t;
  ...
  return std::move (t);
}

In this example, the std::move call prevents copy elision ๐Ÿ’…. This warning is enabled by -Wall.

  • -Wno-redundant-move (C++ and Objective-C++ only) โ€” warns about redundant calls to std::move, meaning a move would have happened even without the std::move call ๐Ÿฆ‹. This happens because the compiler is forced to treat the 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 ๐Ÿ’€. G++ implements Core Issue 1579, so there's another example:

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

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

  • -fext-numeric-literals (C++ and Objective-C++ only) โ€” accepts imaginary, fixed-point, or machine-defined literal number suffixes as GNU extensions โœจ. When this option is turned off, those suffixes get treated as C++11 user-defined literal numeric suffixes. It's on by default for all pre-C++11 dialects and all GNU dialects: -std=c++98, -std=gnu++98, -std=gnu++11, -std=gnu++14. It's off by default for ISO C++11 onwards (-std=c++11, ...) ๐Ÿฉท.

The following -W... options are not affected by -Wall ๐Ÿšซ. Bestie, these need to be turned on by hand ๐Ÿซถ.

  • -Weffc++ (C++ and Objective-C++ only) โ€” warns about violations of the style guidelines from Scott Meyers' Effective C++ series of books ๐Ÿ“š. The guidelines it checks are:
    • Define a copy constructor and an assignment operator for classes with dynamically-allocated memory.
    • Prefer initialization to assignment in constructors.
    • Have operator= return a reference to *this.
    • Don't try to return a reference when you must return an object.
    • Distinguish between prefix and postfix forms of increment and decrement operators.
    • Never overload &&, ||, or ,.

This option also turns on -Wnon-virtual-dtor, which is one of the Effective C++ recommendations too ๐Ÿ’œ. The check is extended to warn about a missing virtual destructor in accessible non-polymorphic base classes as well. Heads up though: the standard library headers don't obey all of these guidelines, so if the warnings get noisy, use grep -v to filter them out ๐Ÿ™ˆ.

  • -Wstrict-null-sentinel (C++ and Objective-C++ only) โ€” warns about using an uncasted NULL as a sentinel ๐Ÿ“. When you're compiling only with GCC, this is a valid sentinel, since NULL is defined as __null. It's a null pointer constant rather than a null pointer, but it's guaranteed to be the same size as a pointer. Still, this usage isn't portable across different compilers ๐Ÿ˜ฌ.
  • -Wno-non-template-friend (C++ and Objective-C++ only) โ€” disables warnings when non-template friend functions are declared inside a template ๐ŸŒธ. In very old GCC versions that predate the ISO standard, declarations like friend int foo(int), where the friend's name is an unqualified-id, could be read as a particular specialization of a template function. This warning exists to diagnose those compatibility problems, and it's enabled by default.
  • -Wold-style-cast (C++ and Objective-C++ only) โ€” warns if an old-style (C-style) cast to a non-void type shows up in a C++ program ๐Ÿ™…โ€โ™€๏ธ. The new-style casts (dynamic_cast, static_cast, reinterpret_cast, and const_cast) are less vulnerable to unintended effects and way easier to search for โœจ.
  • -Woverloaded-virtual (C++ and Objective-C++ only) โ€” warns when a function declaration hides virtual functions from a base class ๐Ÿซ . For example:
struct A {
  virtual void f();
};

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

The A class version of f gets hidden in B, so code like this fails to compile:

B* b;
b->f();
  • -Wno-pmf-conversions (C++ and Objective-C++ only) โ€” disables the diagnostic for converting a bound pointer to a member function into a plain pointer ๐Ÿฆ‹.
  • -Wsign-promo (C++ and Objective-C++ only) โ€” warns when overload resolution picks a promotion from an unsigned or enumerated type to a signed type, instead of a conversion to an unsigned type of the same size ๐ŸŽ€. Older versions of G++ tried to preserve unsignedness, but the standard mandates the current behaviour, so this is the new normal ๐Ÿ’–.
  • -Wtemplates (C++ and Objective-C++ only) โ€” warns when a primary template declaration is encountered ๐Ÿงš. Some coding rules disallow templates, and this flag can help enforce that rule. The warning is inactive inside a system header file like the STL, so you can still use the STL ๐ŸŒˆ. You're also still allowed to instantiate or specialize templates.
  • -Wmultiple-inheritance (C++ and Objective-C++ only) โ€” warns when a class is defined with multiple direct base classes ๐Ÿ‘‘. Some coding rules ban multiple inheritance, and this can enforce that rule. The warning is inactive inside system headers like the STL, and you're still allowed to define classes that indirectly use multiple inheritance โœจ.
  • -Wvirtual-inheritance โ€” warns when a class is defined with a virtual direct base class ๐Ÿ’…. Some coding rules disallow multiple inheritance, and this can help enforce that rule. The warning is inactive inside a system header file like the STL, so the STL is still fair game ๐Ÿ’œ. You can also define classes that indirectly use virtual inheritance.

Okay bestie, this one's a warning flag ๐Ÿšจ - -Wnamespaces lets you know whenever a namespace definition gets opened. Some coding rules straight up ban namespaces, so this is how you enforce that rule ๐Ÿ’… It stays quiet inside system header files like the STL, so you can still use the STL ๐Ÿซถ Using directives and qualified names are still allowed too, just saying ๐Ÿ’โ€โ™€๏ธ

  • -Wno-terminate (C++ and Objective-C++ only) โ€” turns off the warning for a throw-expression that's going to immediately result in a call to "terminate" ๐Ÿ™ˆ
  • -Wno-class-conversion (C++ and Objective-C++ only) โ€” turns off the warning for 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 ๐Ÿ’€

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

(NOTE: this manual doesn't teach you the Objective-C and Objective-C++ languages themselves, so don't come here expecting a language tutorial ๐Ÿ“๐Ÿ™ƒ

This section covers the command-line options that only matter for Objective-C and Objective-C++ programs ๐ŸŒˆ You can still use most of the language-independent GNU compiler options too. For example, you might compile a file 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. You can use the other options with any language GCC supports ๐Ÿงš

Note that since Objective-C is an extension of the C language, Objective-C compilations can also use options specific to the C front-end (e.g., -Wtraditional). Similarly, Objective-C++ compilations can use C++-specific options (e.g., -Wabi) ๐Ÿ“

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

  • -fconstant-string-class=class-name โ€” picks the class that gets instantiated for each literal string written with the syntax "@".."". The default class name is "NXConstantString" if the GNU runtime is being used, and "NSConstantString" if the NeXT runtime is being used (see below). If -fconstant-cfstrings is also there, it overrides -fconstant-string-class and makes "@".."" literals get laid out as constant CoreFoundation strings โœจ
  • -fgnu-runtime โ€” generates object code 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". That lets more efficient entry points in the runtime get used ๐Ÿฆ‹ This option is only available 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, and here's the breakdown ๐Ÿงพ
    • Version 0 is the traditional (32-bit) ABI, with no support for properties or other Objective-C 2.0 additions
    • Version 1 is the traditional (32-bit) ABI, with 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, checks whether any of its instance variables is a C++ object with a non-trivial default constructor. If so, it synthesizes a special - (id) .cxx_construct instance method that runs those non-trivial default constructors on the instance variables, in order, and then returns self. It also checks whether any instance variable is a C++ object with a non-trivial destructor, and if so, synthesizes a special - (void) .cxx_destruct method that runs all of those default destructors in reverse order ๐Ÿ’…

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

โš ๏ธ Heads up: 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. Everyone else is out of luck for now ๐Ÿ˜ญ
  • -fobjc-direct-dispatch โ€” allows fast jumps to the message dispatcher. On Darwin this is accomplished via the comm page โšก
  • -fobjc-exceptions โ€” turns on syntactic support for structured exception handling in Objective-C, kinda like what C++ offers ๐Ÿ™Œ This option is required to use the Objective-C keywords @try, @throw, @catch, @finally and @synchronized. It works with both the GNU runtime and the NeXT runtime, but it's not available with the NeXT runtime on Mac OS X 10.2 and earlier ๐Ÿ™…โ€โ™€๏ธ
  • -fobjc-gc โ€” enables garbage collection (GC) in Objective-C and Objective-C++ programs. This is only available with the NeXT runtime. The GNU runtime has 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 one recognized by GCC 4.0. This only affects the Objective-C additions to the C/C++ language, and it doesn't change conformance to C/C++ standards, which is controlled by the separate C/C++ dialect option flags. When you use this with the Objective-C or Objective-C++ compiler, any Objective-C syntax that GCC 4.0 doesn't recognize gets rejected. It's super useful if you need to make sure your Objective-C code still compiles with older versions of GCC ๐Ÿ•ฐ๏ธ
  • -freplace-objc-classes โ€” emits a special marker that tells ld(1) not to statically link the resulting object file, and lets dyld(1) load it in at run time instead. This is used with the Fix-and-Continue debugging mode, where the object file might get recompiled and dynamically reloaded during program execution, without restarting the program itself. 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 stops that and keeps the calls to objc_getClass("..."). It's handy in Zero-Link debugging mode, since it lets you modify individual class implementations while the program is running. 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. That 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 and avoids those variable shadowing issues ๐Ÿ™ˆ
  • -fivar-visibility=[public|protected|private|package] โ€” sets the default instance variable visibility to the option you pick, so that instance variables declared outside the scope of any access modifier directive default to that visibility ๐Ÿ‘€
  • -gen-decls โ€” dumps the interface declarations for all classes seen in the source file into a file named sourcename.decl ๐Ÿ“œ
  • -Wassign-intercept (Objective-C and Objective-C++ only) โ€” warns whenever an Objective-C assignment is being intercepted by the garbage collector ๐Ÿšจ
  • -Wno-protocol (Objective-C and Objective-C++ only) โ€” if a class is declared to implement a protocol, a warning gets issued for every method in the 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. If you use -Wno-protocol, inherited methods count as implemented, so there's no warning for them ๐Ÿ™Œ
  • -Wselector (Objective-C and Objective-C++ only) โ€” warns if multiple methods of different types for the same selector are found during compilation. This check runs on the list of methods in the final stage of compilation. There's also a check for each selector that shows up in a "@selector(...)" expression, if a corresponding method for that selector was found during compilation. Since these checks only scan the method table at the very end, these warnings won't be produced if the final stage of compilation isn't reached, like when an error gets found during compilation or when -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 with that selector to a receiver of type "id" or "Class". When this flag is off (which is the default), the compiler skips these warnings if the differences are confined to types that share the same size and alignment ๐Ÿ’–
  • -Wundeclared-selector (Objective-C and Objective-C++ only) โ€” okay bestie, this one is a selector cop ๐Ÿ‘ฎโ€โ™€๏ธ๐Ÿ’… It warns you if a @selector(...) expression points at a selector that hasn't been declared yet. A selector counts as undeclared if no method with that name was declared before the @selector(...) expression, whether that's explicitly in an @interface or @protocol declaration, or implicitly in an @implementation section. This option checks the second it spots a @selector(...), whereas -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. Main character energy ๐Ÿ‘‘
  • -print-objc-runtime-info โ€” generates a C header describing the largest structure that gets passed by value, if there is one ๐Ÿงšโœจ

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

Okay so, traditionally, diagnostic messages were formatted without caring about the output device's aspect (e.g. its width, ...) ๐Ÿ™ˆ But you can use these options to control the formatting algorithm, like how many characters go on each line and how often source location info gets reported. Lowkey a game changer ๐Ÿฆ‹ Just note that some language front ends may not honor these options.

  • -fmessage-length=n โ€” tries to format error messages so they fit on lines of about n characters ๐Ÿ“ If n is zero, no line-wrapping happens and each error message sits on a single line. This is the default for all front ends.
Note - this option also affects the display of the #error and #warning pre-processor directives, and the deprecated function/type/variable attribute. It does not however affect the pragma GCC warning and pragma GCC error pragmas.
  • -fdiagnostics-show-location=once โ€” only meaningful in line-wrapping mode ๐ŸŒธ It tells the diagnostic reporter to emit source location info once. So if a message is too long and has to be wrapped, the location won't get slapped on as a prefix again and again on every continuation line. This is the default behavior, and honestly iconic.
  • -fdiagnostics-show-location=every-line โ€” also only meaningful in line-wrapping mode ๐Ÿ“ This one emits the same source location (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 โ€” uses color 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 also never if the GCC_COLORS environment variable isn't present in the environment, and auto otherwise. auto means color only shows up when standard error is a terminal. The forms -fdiagnostics-color and -fno-diagnostics-color are aliases for -fdiagnostics-color=always and -fdiagnostics-color=never, respectively.

The colors are controlled by the GCC_COLORS environment variable ๐ŸŽจ Its value is a colon-separated list of capabilities and Select Graphic Rendition (SGR) substrings. SGR commands get interpreted by the terminal or terminal emulator, so check the section in your text terminal's docs for permitted values and what they mean as character attributes. These substring values are integers in decimal form and can be concatenated with semicolons. The common ones are: 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:fixit-insert=32:fixit-delete=31:\
diff-filename=01:diff-hunk=32:diff-delete=31:diff-insert=32:\
type-diff=01;32

Here, 01;31 is bold red, 01;35 is bold magenta, 01;36 is bold cyan, 32 is green, 34 is blue, 01 is bold, and 31 is red. Setting GCC_COLORS to the empty string disables colors ๐Ÿ™…โ€โ™€๏ธ These are the supported capabilities:

  • error= โ€” SGR substring for error: markers.
  • warning= โ€” SGR substring for warning: markers.
  • note= โ€” SGR substring for note: markers.
  • range1= โ€” SGR substring for the first additional range.
  • range2= โ€” SGR substring for the second additional range.
  • locus= โ€” SGR substring for location info, like file:line or file:line:column etc.
  • quote= โ€” SGR substring for info printed within quotes.
  • fixit-insert= โ€” SGR substring for fix-it hints suggesting text to be inserted or replaced.
  • fixit-delete= โ€” SGR substring for fix-it hints suggesting text to be deleted.
  • diff-filename= โ€” SGR substring for filename headers within generated patches.
  • diff-hunk= โ€” SGR substring for the starts of hunks within generated patches.
  • diff-delete= โ€” SGR substring for deleted lines within generated patches.
  • diff-insert= โ€” SGR substring for inserted lines within generated patches.
  • type-diff= โ€” SGR substring for highlighting mismatching types within template arguments in the C++ frontend.
  • -fno-diagnostics-show-option โ€” by default, every diagnostic includes text pointing at the command-line option that directly controls it (if the diagnostic machinery knows about one) ๐Ÿ” Add -fno-diagnostics-show-option and that text gets suppressed.
  • -fno-diagnostics-show-caret โ€” by default, each diagnostic shows the original source line plus a caret ^ pointing at the column ๐ŸŽฏ This option hides all of that. If -fmessage-length=n is given, the source line gets truncated to n characters. When the output goes to the terminal, the width is capped at the value of the COLUMNS environment variable or, if that's not set, the terminal width.
  • -fno-diagnostics-show-labels โ€” when printing source code (via -fdiagnostics-show-caret), diagnostics can label ranges of source code with useful info, like the types of expressions ๐Ÿท๏ธ Something like this:
printf ("foo %s bar", long_i + long_j);
             ~^       ~~~~~~~~~~~~~~~
              |              |
              char *         long int

This option suppresses those labels, so the vertical bars and the "char *" and "long int" text in the example above disappear ๐Ÿซถ

  • -fno-diagnostics-show-line-numbers โ€” by default, when printing source code (via -fdiagnostics-show-caret), a left margin with line numbers gets printed ๐Ÿ”ข This option kills that left margin.
  • -fdiagnostics-minimum-margin-width=width โ€” controls the minimum width of the left margin printed by -fdiagnostics-show-line-numbers. It defaults to 6.
  • -fdiagnostics-parseable-fixits โ€” emits fix-it hints in a machine-parseable format, perfect for IDEs to read ๐Ÿค– For each fix-it, a line gets printed after the relevant diagnostic, starting with the string fix-it:. For example:
fix-it:"test.c":{45:3-45:21}:"gtk_widget_show_all"

The location is a half-open range, counted in bytes, starting at byte 1 for the initial column. In the example above, bytes 3 through 20 of line 45 of "test.c" get replaced with the given string:

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

The filename and replacement string escape backslash as "\\", tab as "\t", newline as "\n", double quotes as "\"", and non-printable characters as octal (e.g. vertical tab as "\013") ๐Ÿงฉ An empty replacement string means the given range gets removed. An empty range (e.g. "45:3-45:3") means the string gets inserted at the given position.

  • -fdiagnostics-generate-patch โ€” prints fix-it hints to stderr in unified diff format, after any diagnostics are printed ๐Ÿ“ For example:
--- test.c
+++ test.c
@ -42,5 +42,5 @

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

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

  • -fdiagnostics-show-template-tree โ€” in the C++ frontend, when printing diagnostics about mismatching template types, you'd normally see something like this ๐Ÿ˜ตโ€๐Ÿ’ซ
could not convert 'std::map<int, std::vector<double> >()'
  from 'map<[...],vector<double>>' to 'map<[...],vector<float>>

This flag turns on a tree-like structure showing the common and differing parts of the types, like:

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

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

  • -fno-elide-type โ€” by default, when the C++ frontend prints diagnostics showing mismatching template types, the common parts get printed as "[...]" to keep the error message short โœ‚๏ธ For example:
could not convert 'std::map<int, std::vector<double> >()'
  from 'map<[...],vector<double>>' to 'map<[...],vector<float>>

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

  • -fno-show-column โ€” does not print column numbers in diagnostics ๐Ÿ™…โ€โ™€๏ธ This might be necessary if diagnostics are being scanned by a program that doesn't understand column numbers, such as dejagnu.
  • -fdiagnostics-format=FORMAT โ€” selects a different format for printing diagnostics ๐Ÿ’– FORMAT is text or json. The default is text.

okay bestie, the json format is one big top-level JSON array ๐Ÿงš, and every item inside it is a JSON object describing one diagnostic ๐Ÿ’–. GCC prints it all on a single unformatted line ๐Ÿซถ, so the examples below are prettied up so your eyes can actually read them โœจ

Diagnostics can have little child diagnostics too ๐ŸŒธ For example, this error and note:

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

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

[
    {
        "kind": "warning",
        "locations": [
            {
                "caret": {
                    "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",
        "children": [
            {
                "kind": "note",
                "locations": [
                    {
                        "caret": {
                            "column": 5,
                            "file": "misleading-indentation.c",
                            "line": 17
                        }
                    }
                ],
                "message": "...this statement, but the latter is ..."
            }
        ]
    },
    ...
]

where the "note" is a child of the "warning" ๐ŸŽ€

A diagnostic has a "kind" ๐Ÿ’… If it's "warning", then there's an "option" key that tells you which command-line option is controlling that warning ๐Ÿ”ฅ

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

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

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

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

If a diagnostic has fix-it hints, it gets a "fixits" array ๐Ÿ“ That array is made of half-open intervals, kinda like what you get from -fdiagnostics-parseable-fixits. For example, this diagnostic with a replacement fix-it hint:

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

might be printed in JSON form as:

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

where the fix-it hint suggests replacing the text from "start" up to but not including "next" with the value of "string". Deletions are written with an empty value for "string", and insertions are written by having "start" equal "next" ๐ŸŒˆ


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

Warnings are diagnostic messages ๐Ÿ’€ They flag constructions that aren't inherently erroneous, but that are risky or might mean there was an error somewhere ๐Ÿ™ˆ

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

  • -fsyntax-only โ€” Checks your code for syntax errors and then stops right there, no extra stuff ๐Ÿ’…
  • -fmax-errors=n โ€” Caps the number of error messages at n, and when that limit is hit GCC bails out instead of trying to keep going ๐Ÿ›‘ If n is 0 (the default), there's no limit on how many error messages get printed. If -Wfatal-errors is also specified, then -Wfatal-errors takes precedence over this option ๐Ÿ‘‘
  • -w โ€” Inhibits all warning messages ๐Ÿคซ
  • -Werror โ€” Turns all warnings into errors ๐Ÿ˜ญ
  • -Werror= โ€” Turns one specific warning into an error. You append the warning's specifier, so for example -Werror=switch turns the warnings controlled by -Wswitch into errors ๐Ÿ”ฅ This one also has a negative form that undoes -Werror for specific warnings. For example, -Wno-error=switch makes -Wswitch warnings not be errors, even when -Werror is in effect ๐Ÿ™…โ€โ™€๏ธ

The warning message for each controllable warning includes the option that controls it ๐Ÿฆ‹ You can then use that option with -Werror= and -Wno-error=, as described above. (Printing of the option in the warning message can be turned off with the -fno-diagnostics-show-option flag ๐Ÿ™ˆ)

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

  • -Wfatal-errors โ€” Makes the compiler abort compilation on the first error it runs into, 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 beginning with -Wno- that turns the warnings off. For example, -Wno-implicit. This manual only lists one of the two forms, whichever one isn't the default ๐Ÿ“– For more language-specific options, also check out C++ Dialect Options and Objective-C and Objective-C++ Dialect Options ๐ŸŒธ

Some options, such as -Wall and -Wextra, turn on other options, like -Wunused, and those might turn on even more, 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 act as if they appeared at the end of the command-line ๐Ÿ”ฅ

When you request an unrecognized warning option (e.g., -Wunknown-warning), GCC emits a diagnostic saying the option isn't recognized ๐Ÿ™ˆ The -Wno- form is a little different though: no diagnostic is produced for -Wno-unknown-warning unless other diagnostics are being produced anyway ๐Ÿซถ 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 won'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 also 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 ๐Ÿ‘‘

Okay so, bestie, -Wpedantic is about to get real ๐Ÿ’… Valid ISO C and ISO C++ programs should compile fine with or without this option ๐Ÿซถ. A rare few do need -ansi or a -std option naming the exact ISO C version they want. Without this option, certain GNU extensions and traditional C and C++ features still work โœจ. With this option, they get rejected ๐Ÿšซ.

-Wpedantic won't warn about the alternate keywords whose names begin and end with __ ๐Ÿ™ˆ. Pedantic warnings are also turned off in the expression that follows __extension__. Real talk though: 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 find it doesn't quite do what they want. It finds some non-ISO practices, but not all. It only catches the ones where ISO C requires a diagnostic, plus a few others that got diagnostics added later ๐Ÿ’€.

A feature that reports any failure to conform to ISO C would be useful sometimes, but it would take a ton of extra work and would be totally different from -Wpedantic ๐Ÿ˜ญ. We don't have plans to support that in the near future, sorry bestie.

When the standard picked with -std is a GNU extended dialect of C, like gnu90 or gnu99, there's a matching base standard. That's the version of ISO C 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 chosen GNU dialect, because by definition the GNU dialects include every feature the compiler supports with that option, so there'd be nothing to warn about ๐Ÿคทโ€โ™€๏ธ.)


  • -pedantic-errors โ€” Okay, this one is the strict version ๐Ÿ˜ค. It gives an error whenever the base standard (see -Wpedantic) requires a diagnostic. That includes some cases with undefined behavior at compile-time, and some other cases that don't stop compilation of programs that are valid according to the standard. It is not the same as -Werror=pedantic, because there are errors this option turns on that the latter doesn't, and vice versa ๐Ÿ”ฅ.
  • -Wall โ€” This turns on all the warnings about constructions that some users consider questionable, and that are easy to avoid (or to modify so the warning goes away), 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 these bad boys: -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++) -Wformat -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

Note that some warning flags are not implied by -Wall ๐Ÿ™ƒ. Some of them warn about constructions that users generally don't consider questionable, but that you might occasionally want to check for. Others warn about constructions that are necessary or hard to avoid in some cases, with 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 turns on some extra warning flags that -Wall doesn't ๐ŸŒธ. (This option used to be called -W. The older name is still supported, but the newer name is more descriptive ๐Ÿ’œ.)

-Wextra turns on these: -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) -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 these 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.
  • -Wchar-subscripts โ€” Warns if an array subscript has type char ๐Ÿ™ˆ. This is a super common mistake, because programmers often forget this type is signed on some machines. This warning is enabled by -Wall.
  • -Wno-coverage-mismatch โ€” Warns if feedback profiles don't match when you use -fprofile-use ๐Ÿ“Š. If a source file changes between 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 treated as an error. -Wno-coverage-mismatch can disable the warning, and -Wno-error=coverage-mismatch can disable the error. Disabling the error for this warning can result in poorly optimized code, so it's only useful for very minor changes like bug fixes to an existing code-base. Completely disabling the warning is not recommended ๐Ÿšซ.
  • -Wno-cpp โ€” (C, Objective-C, C++, Objective-C++ and Fortran only) Suppresses warning messages emitted by #warning directives ๐Ÿคซ.
  • -Wdouble-promotion โ€” (C, C++, Objective-C and Objective-C++ only) Gives a warning when a value of type float is implicitly promoted to double ๐Ÿข. CPUs with a 32-bit single-precision floating-point unit implement float in hardware, but they emulate double in software. On a machine like that, doing computations with double values is way more expensive because of the overhead of software emulation.

It's super easy to accidentally do computations with double, because floating-point literals are implicitly of type double ๐Ÿ˜ญ. For example:

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

Yep, the compiler does the entire computation with double, because the floating-point literal is a double ๐Ÿ’€.

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

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

  • -Wformat=1, -Wformat โ€” -Wformat is equivalent to -Wformat=1, and -Wno-format is equivalent to -Wformat=0 ๐Ÿ“. Since -Wformat also checks for null format arguments for several functions, it also implies -Wnonnull. Some aspects of this level of format checking can be disabled with -Wno-format-contains-nul, -Wno-format-extra-args, and -Wno-format-zero-length. -Wformat is enabled by -Wall.
  • -Wno-format-contains-nul โ€” If -Wformat is specified, don't warn about format strings that contain NUL bytes ๐ŸŒ™.
  • -Wno-format-extra-args โ€” If -Wformat is specified, don't warn about excess arguments to a printf or scanf format function. The C standard says those arguments are ignored. Where the unused arguments lie between used arguments that are specified with $ operand number specifications, warnings are normally still given, since the implementation couldn't know what type to pass to va_arg to skip the unused arguments. However, for scanf formats, this option suppresses the warning if the unused arguments are all pointers, since the Single Unix Specification says such unused arguments are allowed ๐Ÿซถ.
  • -Wformat-overflow, -Wformat-overflow=level โ€” okay bestie, this one is a whole vibe ๐Ÿ’… It warns about calls to formatted input/output functions like sprintf and vsprintf that might overflow the destination buffer ๐Ÿ˜ญ When GCC can't figure out exactly how many bytes a format directive will write at compile time, it makes a guess using heuristics that depend on the level argument and on optimization. Turning optimization on usually makes the warning more accurate, but it can also give you false positives ๐Ÿ™ˆ
    • -Wformat-overflow, -Wformat-overflow=1 โ€” Level 1 gets switched on by -Wformat and it's the chill, conservative option โœจ It only warns about calls that most likely overflow the buffer. Numeric arguments with unknown values get treated as one, and strings of unknown length get treated as empty. Numeric arguments known to be bounded to a subrange of their type, or string arguments whose output is bounded by their directive's precision or by a finite set of string literals, get assumed to take on the value within that range that produces the most bytes on output. For example, the sprintf call below gets diagnosed because even with both a and b equal to zero, the terminating NUL character ('\0') that the function appends to the destination buffer still gets written past its end ๐Ÿ’€ Making the buffer one byte bigger is enough to dodge the warning, though it might not be enough to actually avoid the overflow ๐Ÿซถ
void f (int a, int b)
{
  char buf [13];
  sprintf (buf, "a = %i, b = %i\n", a, b);
}
  • -Wformat-overflow=2 โ€” Level 2 goes a step further and also warns about calls that might overflow the destination buffer given an argument of sufficient length or magnitude ๐Ÿ”ฅ At this level, 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 to be bounded by the directive's precision, by a finite set of string literals they may evaluate to, or by the character array they may point to, get assumed to be 1 character long. At level 2, the call in the example above gets diagnosed again, but this time it's because with a equal to a 32-bit INT_MIN, the first %i directive will write some of its digits beyond the end of the destination buffer. To make the call safe no matter what the two variables are, the destination buffer has to be at least 34 bytes. GCC includes that minimum buffer size in an informational note right after the warning ๐ŸŽ€

Instead of making the buffer bigger, you can also constrain the range of the formatted values โœจ The maximum length of string arguments can be bounded by specifying the precision in the format directive. When numeric arguments can be assumed to be bounded by less than the precision of their type, picking an appropriate length modifier for the format specifier will shrink the required buffer size. For example, if a and b in the example above can be assumed to be within the precision of the short int type, then using either the %hi format directive or casting the argument to short reduces the maximum required size of the buffer to 24 bytes ๐Ÿฆ‹

void f (int a, int b)
{
  char buf [23];
  sprintf (buf, "a = %hi, b = %i\n", a, (short)b);
}
  • -Wno-format-zero-length โ€” if -Wformat is specified, don't warn about zero-length formats. The C standard says zero-length formats are allowed, so this one is just being extra ๐ŸŒธ
  • -Wformat=2 โ€” enables -Wformat plus some additional format checks ๐Ÿ‘‘ Right now it's equivalent to -Wformat -Wformat-nonliteral -Wformat-security -Wformat-y2k.
  • -Wformat-nonliteral โ€” if -Wformat is specified, also warn if the format string isn't a string literal, since that means it can't be checked. The exception is when the format function takes its format arguments as a va_list.
  • -Wformat-security โ€” if -Wformat is specified, also warn about uses of format functions that could be a security problem ๐Ÿšจ Right now this 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);. That can be a security hole if the format string came from untrusted input and contains %n. (This is currently a subset of what -Wformat-nonliteral warns about, but future warnings may be added to -Wformat-security that aren't included in -Wformat-nonliteral.)
  • -Wformat-signedness โ€” if -Wformat is specified, also warn if the format string requires an unsigned argument and the argument is signed, and vice versa ๐Ÿงš
  • -Wformat-truncation, -Wformat-truncation=level โ€” warns about calls to formatted input/output functions like snprintf and vsnprintf that might result in output truncation โœ‚๏ธ Just like the overflow one, when the exact number of bytes a format directive writes can't be determined at compile time, it's estimated using heuristics that depend on the level argument and on optimization. Optimization usually makes it more accurate, but it can also cause false positives. Except where noted otherwise, this option uses the same logic as -Wformat-overflow.
    • -Wformat-truncation, -Wformat-truncation=1 โ€” Level 1 gets enabled by -Wformat and is the conservative one ๐Ÿซถ It only warns about calls to bounded functions whose return value is unused and that will most likely result in output truncation.
    • -Wformat-truncation=2 โ€” Level 2 also warns about calls to bounded functions whose return value is used and that might result in truncation, given an argument of sufficient length or magnitude ๐Ÿ’œ
  • -Wformat-y2k โ€” if -Wformat is specified, also warn about strftime formats that may only yield a two-digit year. Y2K is not the vibe ๐Ÿ’€

  • -Wnonnull โ€” warns about passing a null pointer for arguments marked as requiring a non-null value by the nonnull function attribute ๐Ÿ™…โ€โ™€๏ธ -Wnonnull is included in -Wall and -Wformat. It can be disabled with the -Wno-nonnull option.
  • -Wnonnull-compare โ€” warns when comparing an argument marked with the nonnull function attribute against null inside the function ๐Ÿ‘€ -Wnonnull-compare is included in -Wall. It can be disabled with the -Wno-nonnull-compare option.
  • -Wnull-dereference โ€” warns if the compiler detects paths that trigger erroneous or undefined behavior because of dereferencing a null pointer ๐Ÿ˜ญ This option is only active when -fdelete-null-pointer-checks is active, which is enabled by optimizations on most targets. The precision of the warnings depends on the optimization options you use.
  • -Winit-self (C, C++, Objective-C and Objective-C++ only) โ€” warns about uninitialized variables that get initialized with themselves ๐ŸŒ€ Note that this option can only be used together with -Wuninitialized. GCC warns about i being uninitialized in the snippet below only when -Winit-self has been specified:
int f()
{
  int i = i;
  return i;
}

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

  • -Wimplicit-int (C and Objective-C only) โ€” warns when a declaration doesn't specify a type. This warning is enabled by -Wall ๐ŸŒธ
  • -Wimplicit-function-declaration (C and Objective-C only) โ€” gives a warning whenever a function is used before it's declared ๐Ÿ™ˆ In C99 mode (-std=c99 or -std=gnu99), this warning is enabled by default, and it gets turned into an error by -pedantic-errors. This warning is also enabled by -Wall.
  • -Wimplicit (C and Objective-C only) โ€” same as -Wimplicit-int and -Wimplicit-function-declaration ๐Ÿ“ This warning is enabled by -Wall.
  • -Wimplicit-fallthrough โ€” is the same as -Wimplicit-fallthrough=3, and -Wno-implicit-fallthrough is the same as -Wimplicit-fallthrough=0 ๐Ÿฆ‹
  • -Wimplicit-fallthrough=n โ€” warns when a switch case falls through to the next one ๐Ÿ‘‘ Here's the tea:
switch (cond)
  {
  case 1:
    a = 1;
    break;
  case 2:
    a = 2;
  case 3:
    a = 3;
    break;
  }

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

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

Sometimes a switch case falling through is exactly what you want ๐Ÿซถ For those times, GCC provides an attribute, __attribute__ ((fallthrough)), that goes along with a null statement to suppress the warning that would normally happen:

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

C++17 gives us a standard way to shush -Wimplicit-fallthrough: [[fallthrough]]; ๐Ÿ’… No GNU-only attribute needed! If you're stuck on C++11 or C++14, you can use [[gnu::fallthrough]]; instead, which is a GNU extension ๐ŸŒˆ. Bestie, you can also skip attributes entirely and drop a fallthrough comment ๐Ÿซถ. The whole body of the C or C++ style comment has to match one of the regular expressions below, and the option argument n decides which kinds of comments count:

  • -Wimplicit-fallthrough=0 turns the warning off completely ๐Ÿ™ˆ.
  • -Wimplicit-fallthrough=1 uses the ".*" regular expression, so literally any comment counts as a fallthrough comment โœจ.
  • -Wimplicit-fallthrough=2 matches the ".*falls?[ \t-]*thr(ough|u).*" regular expression, and it doesn't care about capital letters ๐Ÿฆ‹.
  • -Wimplicit-fallthrough=3 is case sensitive and needs to match one of these 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 is also case sensitive and needs to match one of these:
    • "-fallthrough"
    • "@fallthrough@"
    • "lint -fallthrough[ \t]*"
    • "[ \t]*FALLTHR(OUGH|U)[ \t]*"
  • -Wimplicit-fallthrough=5 doesn't recognize any comments as fallthrough comments, so only attributes will shut the warning up ๐Ÿ”’.

The comment has to come right before a case or default keyword (optional whitespace and other comments are fine in between), or before a user label that sits in front of a case or default label ๐ŸŽ€.

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

๐Ÿ”ฅ -Wimplicit-fallthrough=3 is turned on by -Wextra, so you get it for free there.

๐ŸŒธ -Wif-not-aligned (C, C++, Objective-C and Objective-C++ only)

This controls whether the warning triggered by the warn_if_not_aligned attribute gets issued. It's on by default, but if it's annoying you, -Wno-if-not-aligned turns it off ๐Ÿ™…โ€โ™€๏ธ.

๐Ÿงš -Wignored-qualifiers (C and C++ only)

Warns if a function's return type has a type qualifier like "const". In ISO C that qualifier does nothing, because a function's return value isn't an lvalue ๐Ÿคทโ€โ™€๏ธ. In C++, the warning only shows up for scalar types or "void". ISO C doesn't allow qualified "void" return types on function definitions, so those always get a warning, even without this option.

This warning is also turned on by -Wextra.

๐Ÿฆ‹ -Wignored-attributes (C and C++ only)

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

๐Ÿ‘‘ -Wmain

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

๐Ÿ’œ -Wmisleading-indentation (C and C++ only)

Warns when the indentation doesn't match the actual block structure โš ๏ธ. Specifically, it fires for if, else, while, and for clauses that have a guarded statement without braces, followed by an unguarded statement with the same indentation.

In this example, the call to bar looks like it's guarded by the if, but it isn't:

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

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

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

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

It also won't warn after a #line directive. That usually means the code was autogenerated, and nobody can make assumptions about the layout of the file that the directive points to ๐Ÿค–.

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

๐ŸŒˆ -Wmissing-attributes

This one warns when a function declaration is missing one or more attributes that a related function is declared with, and where that missing attribute could hurt the correctness or efficiency of the generated code ๐Ÿง . For example, it fires for alias declarations that use attributes to set less restrictive requirements than their targets. That usually means there's a potential optimization opportunity. The opposite case is handled by -Wattribute-alias=2, which warns when the alias is more restrictive than the target, and that could lead to incorrect code generation ๐Ÿšจ.

The attributes it considers are alloc_align, alloc_size, cold, const, hot, leaf, malloc, nonnull, noreturn, nothrow, pure, returns_nonnull, and returns_twice.

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

You can use the copy attribute to apply the same set of attributes from one declaration to another, without having to list them all out ๐Ÿซถ. It works on declarations of functions, variables, or types.

-Wmissing-attributes is enabled by -Wall.

Here's an example. The primary function template below uses both malloc and alloc_size, so the explicit specialization gets flagged for missing one of them ๐Ÿ™ˆ:

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

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

๐ŸŽ€ -Wmissing-braces

Warns if an aggregate or union initializer isn't fully bracketed ๐Ÿงบ. In the example below, the initializer for a isn't fully bracketed, but the one for b is.

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

This warning is enabled by -Wall in C.

๐Ÿ“ -Wmissing-include-dirs (C, C++, Objective-C and Objective-C++ only)

Warns if a user-supplied include directory doesn't exist ๐Ÿ“‚.

๐ŸŒท -Wmissing-profile

Warns if feedback profiles are missing when you use -fprofile-use ๐Ÿ“‰. It catches the cases where a new function or a new file got added between compiling with -fprofile-generate and compiling with -fprofile-use, and you didn't regenerate the profiles. In those cases, the profile feedback data files don't have any feedback info for the new function or file. Also, if profile count data (.gcda) files get removed, GCC can't use any profile feedback information at all. In every one of these cases, you get a warning letting you know a profile generation step is due ๐Ÿ”.

-Wno-missing-profile can be used to disable the warning. Ignoring the warning can result in poorly optimized code.

โš ๏ธ Completely disabling this warning isn't recommended. Only do it when having no profile data at all is actually justified.

๐Ÿ’… -Wmultistatement-macros

Warns about unsafe multiple-statement macros that look like they're guarded by an if, else, for, switch, or while clause, when only the first statement is actually guarded once the macro expands ๐Ÿ˜ญ.

For example:

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

Here y gets incremented unconditionally, not only when c holds. You can usually fix this by wrapping the macro in a do-while loop:

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

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

๐Ÿ”ฎ -Wparentheses

Warns when parentheses are left out in certain spots, like an assignment where a truth value is expected, or nested operators whose precedence people often mix up ๐Ÿคฏ.

It also warns about a comparison like x<=y<=z. That's equivalent to (x<=y ? 1 : 0) <= z, which is a different meaning from regular math notation, so bestie, watch out ๐Ÿ‘€.

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

For C++, it also warns about some cases of unnecessary parentheses in declarations. Those can mean you were trying to make a function call instead of a declaration:

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

This warning is enabled by -Wall.

๐Ÿง -Wsequence-point

Warns about code that might have undefined semantics because it breaks the sequence point rules in the C and C++ standards ๐Ÿšซ.

Okay so sequence points are basically how the C and C++ standards say "this part finishes before that part starts" โœจ. They're only a partial ordering, so they lock in some of the order and leave the rest open ๐Ÿ™ˆ. They show up after a full expression (one that isn't stuck inside a bigger expression) ๐Ÿ’–, after the first operand of a &&, ||, ? : or , (comma) operator ๐Ÿฆ‹, and right before a function gets called, but only after its arguments and the expression naming the function are done. There are a few other spots too. Everywhere else, the order that subexpressions get evaluated in is not specified. Like, if two functions get called in one expression with no sequence point between them, the order they run in is up for grabs ๐Ÿ’…. The standards committee did rule that function calls don't overlap, though, so at least that's locked in ๐Ÿ”’.

It's also not specified when, between sequence points, changes to object values actually take effect ๐Ÿ˜ญ. Programs that depend 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 a program breaks those rules, the results on any given implementation are entirely unpredictable ๐Ÿ’€.

Examples of undefined behavior include a = a++;, a[n] = b[n++] and a[i++] = i; ๐Ÿ™ƒ. Some trickier cases won't get caught by this option, and it might occasionally throw a false positive ๐Ÿ™ˆ. But overall it's been found to be pretty effective at catching this kind of problem in programs ๐Ÿ‘‘.

The C++17 standard is going to define the order of evaluation for operands in more cases ๐ŸŒˆ. Specifically, 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 warning will still yell about them though, so people can avoid writing code that's undefined in C and earlier revisions of C++ ๐Ÿซถ.

The standard is worded kinda confusingly, so there's some debate about what the sequence point rules mean in subtle cases ๐Ÿค”. If you want to dig into the discussions, including proposed formal definitions, check 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 โ€” Chill, don't warn about returning a pointer (or a reference in C++) to a variable that goes out of scope once the function returns ๐ŸŒธ.
  • -Wreturn-type โ€” Warns whenever a function is defined with a return type that defaults to int ๐ŸŽ€. It also warns about any return statement with no return value in a function whose return type isn't void. Falling off the end of the function body counts as returning without a value, so yeah, that gets flagged too ๐Ÿ™ˆ.

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

Unlike C, 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 ๐Ÿ˜ญ. This warning is enabled by default in C++ and by -Wall otherwise ๐Ÿ’–.

  • -Wshift-count-negative โ€” Warns if the shift count is negative. This warning is enabled by default ๐Ÿ’….
  • -Wshift-count-overflow โ€” Warns if the shift count is >= the width of the type. This warning is enabled by default โœจ.
  • -Wshift-negative-value โ€” Warns if you're left shifting a negative value ๐Ÿฆ‹. This warning is enabled by -Wextra in C99 (and newer) and C++11 to C++17 modes.
  • -Wshift-overflow, -Wshift-overflow=n โ€” Warns about left shift overflows ๐Ÿ”ฅ. This warning is enabled by default in C99 and C++11 modes (and newer).
    • -Wshift-overflow=1 โ€” This is the warning level of -Wshift-overflow, and it's enabled by default in C99 and C++11 modes (and newer) ๐ŸŒˆ. This level doesn't warn about left-shifting 1 into the sign bit. (However, in C, that kind of overflow is still rejected in contexts where an integer constant expression is required.) No warning is emitted in C++2A mode (and newer), since signed left shifts always wrap ๐Ÿซถ.
    • -Wshift-overflow=2 โ€” This level also warns about left-shifting 1 into the sign bit, unless C++14 mode (or newer) is active ๐Ÿ‘‘.
  • -Wswitch โ€” Warns whenever a switch statement has an index of enumerated type and is missing a case for one or more of the named codes in that enumeration ๐ŸŽ€. (A default label stops this warning.) case labels outside the enumeration range also get warnings with this option, even if there's a default label. This warning is enabled by -Wall ๐Ÿ’–.
  • -Wswitch-default โ€” Warns whenever a switch statement doesn't have a default case ๐ŸŒธ.
  • -Wswitch-enum โ€” Same vibe as -Wswitch: warns when a switch on an enumerated type is missing a case for one or more of the named codes, and when case labels fall outside the enumeration range ๐Ÿฆ‹. The only difference is that this option warns about an omitted enumeration code even if there's a default label ๐Ÿ‘€.
  • -Wswitch-bool โ€” Warns whenever 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 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 โœจ.

  • -Wswitch-unreachable โ€” Warns whenever a switch statement has statements between the controlling expression and the first case label, since those will never be executed ๐Ÿ’€. For example:
switch (cond)
  {
   i = 15;
  ...
   case 5:
  ...
  }

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

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

This warning is enabled by default for C and C++ programs ๐Ÿซถ.

  • -Wsync-nand (C and C++ only) โ€” Warns when the __sync_fetch_and_nand and __sync_nand_and_fetch built-in functions are used ๐Ÿ”ฅ. These functions changed semantics in GCC 4.4 ๐Ÿ˜ญ.
  • -Wunused-but-set-parameter โ€” Warns whenever a function parameter gets assigned to but otherwise goes unused (aside from its declaration) ๐ŸŒˆ.

To suppress this warning, use the unused attribute ๐Ÿงš.

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

  • -Wunused-but-set-variable โ€” Warns whenever a local variable gets assigned to but otherwise goes unused (aside from its declaration) ๐Ÿ’…. This warning is enabled by -Wall.

To suppress this warning, use the unused attribute ๐Ÿ™ˆ.

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

  • -Wunused-function โ€” Warns whenever a static function is declared but not defined, or a non-inline static function is unused ๐Ÿฆ‹. This warning is enabled by -Wall.
  • -Wunused-label โ€” Warns whenever a label is declared but never used ๐Ÿท๏ธ. This warning is enabled by -Wall.

To suppress this warning, use the unused attribute ๐ŸŒธ.

  • -Wunused-local-typedefs (C, Objective-C, C++ and Objective-C++ only) โ€” Warns when a typedef defined locally inside a function isn't used ๐ŸŽ€. This warning is enabled by -Wall โœจ.
  • -Wunused-parameter โ€” Warns whenever a function parameter goes unused aside from its declaration ๐Ÿงš.

To suppress this warning, use the unused attribute ๐Ÿ’œ.

  • -Wno-unused-result โ€” Don't warn if a caller of a function marked with the attribute warn_unused_result doesn't use its return value ๐Ÿ™Œ. The default is -Wunused-result ๐Ÿ‘‘.
  • -Wunused-variable โ€” Warns whenever a local or static variable is unused aside from its declaration ๐Ÿซถ. This option implies -Wunused-const-variable=1 for C, but not for C++ ๐Ÿค”. This warning is enabled by -Wall ๐Ÿ’–.

To suppress this warning, use the unused attribute ๐Ÿ™ˆ.

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

To suppress this warning, use the unused attribute โœจ.

  • -Wunused-const-variable=1 โ€” This is the warning level that -Wunused-variable enables for C ๐Ÿ’…. It only warns about unused static const variables defined in the main compilation unit, not about static const variables declared in any header that gets included ๐Ÿฆ‹.
  • -Wunused-const-variable=2 โ€” This level also warns about unused constant static variables in headers (excluding system headers) ๐Ÿ‘€. It's the level of -Wunused-const-variable and has to be explicitly requested, since in C++ it isn't an error and in C it might be harder to clean up every header that's included ๐Ÿ™ƒ.
  • -Wunused-value โ€” Warns whenever a statement computes a result that's 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, x[i,j] causes a warning, while x[(void)i,j] does not ๐Ÿ’….

This warning is enabled by -Wall โœจ.

  • -Wunused โ€” All the above -Wunused options combined ๐Ÿ’–.

So, to get a warning about an unused function parameter, bestie, you gotta either specify -Wextra -Wunused (ngl -Wall already implies -Wunused ๐Ÿซถ), or separately specify -Wunused-parameter ๐ŸŽ€.

  • -Wuninitialized โ€” ๐Ÿฅบ Warns if an automatic variable gets used before it's ever initialized, or if a variable might get clobbered by a setjmp call. In C++, it also warns if a non-static reference or a non-static const member shows up in a class with no constructors.

If you want to catch code that uses a variable's uninitialized value inside its own initializer, that's what -Winit-self is for ๐Ÿ’….

These warnings show up for individual uninitialized or clobbered elements of structs, unions, or arrays, and also for variables that are uninitialized or clobbered as a whole. They do not show up for variables or elements declared volatile ๐Ÿ™ˆ. Since these depend on optimization, the exact variables or elements that get flagged depend on the precise optimization options and the GCC version you're using, so it's a whole vibe ๐ŸŒˆ.

Heads up: there may be no warning about a variable that's only used to compute a value that's never used, because data flow analysis can delete those computations before the warnings are printed ๐Ÿ’€.

  • -Winvalid-memory-model โ€” ๐Ÿ”ฅ Warns for invocations of __atomic builtins, __sync builtins, and the C11 atomic generic functions when the memory consistency argument is either invalid for the operation or outside the range of values in the memory_order enumeration. For example, __atomic_store and __atomic_store_n are only defined for the relaxed, release, and sequentially consistent memory orders, so the code below gets diagnosed:
void store (int *i)
{
  __atomic_store_n (i, 0, memory_order_consume);
}

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

  • -Wmaybe-uninitialized โ€” ๐Ÿงš For an automatic (aka local) variable, if there's a path from the function entry to a use of the variable that is initialized, but other paths exist where it isn't, the compiler emits a warning if it can't prove those uninitialized paths never run at runtime.

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

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

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

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

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

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

This warning is enabled by -Wall or -Wextra.

  • -Wunknown-pragmas โ€” ๐Ÿฆ‹ Warns when a #pragma directive shows up that GCC doesn't understand. If this command-line option is used, warnings get issued even for unknown pragmas in system header files. That's not the case if the warnings are only enabled by the -Wall command-line option.
  • -Wno-pragmas โ€” ๐ŸŒธ Turns off warnings about pragma misuses, like incorrect parameters, invalid syntax, or conflicts between pragmas. See also -Wunknown-pragmas.
  • -Wno-prio-ctor-dtor โ€” ๐Ÿ‘‘ Stops warnings if a priority from 0 to 100 is used for a constructor or destructor. Constructor and destructor attributes let you assign a priority to control their order of execution before main is called or after it returns. The priority values must be greater than 100, because the compiler reserves priority values between 0--100 for the implementation ๐Ÿ“.
  • -Wstrict-aliasing โ€” ๐Ÿ’… This option is only active when -fstrict-aliasing is active. It warns about code that might break the strict aliasing rules the compiler uses for optimization. It doesn't catch every case, but it does try to catch the more common pitfalls. It's included in -Wall. It's equivalent to -Wstrict-aliasing=3 โœจ.
  • -Wstrict-aliasing=n โ€” ๐ŸŽ€ Same deal: only active when -fstrict-aliasing is active, and it warns about code that might break the strict aliasing rules. Higher levels mean higher accuracy (fewer false positives), but also more effort, kinda like how -O works. -Wstrict-aliasing is equivalent to -Wstrict-aliasing=3.
    • Level 1 โ€” Most aggressive, quick, and least accurate ๐Ÿ˜ค. It's possibly useful when higher levels don't warn but -fstrict-aliasing still breaks the code, since it has very few false negatives. However, it has many false positives. It warns for all pointer conversions between possibly incompatible types, even if the pointer is never dereferenced. It runs in the front end only.
    • Level 2 โ€” Aggressive, quick, and not too precise ๐Ÿซ . It may still have many false positives (not as many as level 1 though), and few false negatives (but possibly more than level 1). Unlike level 1, it only warns when an address is taken. It warns about incomplete types. It runs in the front end only.
    • Level 3 (default for -Wstrict-aliasing) โ€” The main character ๐Ÿ‘‘. It should have very few false positives and few false negatives. It's slightly slower than levels 1 or 2 when optimization is enabled. It handles the common pun+dereference pattern in the front end, like *(int*)&some_float. If optimization is enabled, it also runs in the back end, where it deals with multiple statement cases using flow-sensitive points-to information. It only warns when the converted pointer is dereferenced. It does not warn about incomplete types.
  • -Wstrict-overflow, -Wstrict-overflow=n โ€” ๐ŸŒˆ This option is only active when signed overflow is undefined. It warns about cases where the compiler optimizes based on the assumption that signed overflow doesn't happen. It doesn't warn about every place the code might overflow, only where the compiler actually implements some optimization, so this warning depends on the optimization level ๐Ÿง.

An optimization that assumes signed overflow never happens is perfectly safe if the values involved are such that overflow never does happen. So this warning can easily give a false positive: a warning about code that isn't actually a problem. To help you focus on the important stuff, several warning levels are defined. No warnings are issued for the use of undefined signed overflow when estimating how many iterations a loop requires, especially when figuring out whether a loop will run at all ๐Ÿ”ฅ.

  • -Wstrict-overflow=1 โ€” Warns about cases that are both questionable and easy to avoid. For example, the compiler simplifies x + 1 > x to 1. This level is enabled by -Wall; higher levels aren't, and must be explicitly requested ๐Ÿ™…โ€โ™€๏ธ.
  • -Wstrict-overflow=2 โ€” Also warns about other cases where a comparison is simplified to a constant. For example: abs (x) >= 0. This can only be simplified when signed integer overflow is undefined, because abs (INT_MIN) overflows to INT_MIN, which is less than zero. -Wstrict-overflow (with no level) is the same as -Wstrict-overflow=2 ๐Ÿ’–.
  • -Wstrict-overflow=3 โ€” Also warns about other cases where a comparison is simplified. For example: x + 1 > 1 is simplified to x > 0.
  • -Wstrict-overflow=4 โ€” Also warns about other simplifications not covered by the cases above. For example: (x * 10) / 5 is simplified to x * 2.
  • -Wstrict-overflow=5 โ€” Also warns about cases where the compiler reduces the magnitude of a constant involved in a comparison. For example: x + 2 > y is simplified to x + 1 >= y. This is only reported at the highest warning level, because this simplification applies to many comparisons, so this level gives a very large number of false positives ๐Ÿ˜ตโ€๐Ÿ’ซ.
  • -Wstringop-overflow, -Wstringop-overflow=type โ€” ๐Ÿง Warns for calls to string manipulation functions like memcpy and strcpy that are determined to overflow the destination buffer. The optional type argument is one greater than the type of Object Size Checking to perform to determine the size of the destination ๐Ÿง .

That argument only matters for functions that operate on character arrays, not raw memory functions like memcpy, which always make use of Object Size type-0. This option also warns for calls that specify a size bigger than the largest possible object, or at most SIZE_MAX / 2 bytes ๐Ÿซถ.

It gives the best results with optimization enabled, but it can detect a small subset of simple buffer overflows even without optimization, in calls to GCC built-in functions like __builtin_memcpy that correspond to the standard functions. Either way, the option only warns about a subset of the buffer overflows that the corresponding overflow checking built-ins detect ๐Ÿฆ‹.

For example, this option will issue a warning for a strcpy call that copies at least 5 characters (the string "blue" including the terminating NUL) into a buffer of size 4 ๐Ÿ’€โœจ.

Check out the // warning here line, bestie, because that's where GCC is gonna scream ๐Ÿ“ฃ๐Ÿซถ

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
}

Quick tea โ˜•: the manual says -Wstringop-overflow=2 is enabled by default, and then the =1 entry below says =1 is the default setting. The page is having a whole identity crisis ๐Ÿ™ˆ so I'm just reporting both, no cap.

๐Ÿ’… -Wstringop-overflow

  • -Wstringop-overflow, -Wstringop-overflow=1 โ€” The main character of the family ๐Ÿ‘‘. It uses type-zero Object Size Checking to figure out how big destination objects are, and this is the default setting. At this level it won't yell about writes past the end of subobjects inside bigger objects reached through pointers, unless the size of the largest surrounding object is known. If the destination could be one of several objects, GCC assumes it's the largest one. On Linux systems, with optimization turned on at this level, it warns for the same code you'd get when the _FORTIFY_SOURCE macro is defined to a non-zero value ๐Ÿ›ก๏ธ.
  • -Wstringop-overflow=2 โ€” Uses type-one Object Size Checking ๐Ÿ”. It warns about overflows when writing to members of the largest complete objects whose exact size is known. It won't warn about excessive writes to the same members of unknown objects referenced by pointers, since those might point at arrays with an unknown number of elements ๐Ÿคทโ€โ™€๏ธ.
  • -Wstringop-overflow=3 โ€” Uses type-two Object Size Checking. It warns about overflowing the smallest object or data member. This is the strictest setting that can still flag safe code, so be ready for a few false alarms ๐Ÿฅฒ.
  • -Wstringop-overflow=4 โ€” Uses type-three Object Size Checking ๐Ÿ’€. It warns about overflowing any data members. When the destination is one of several objects, it uses the size of the largest one to decide whether to warn. Just like =3, this setting may flag totally benign code.

๐Ÿ’… -Wstringop-truncation

  • -Wstringop-truncation โ€” Warns for calls to bounded string functions like strncat, strncpy, and stpncpy that might either truncate the copied string or leave the destination unchanged โœ‚๏ธ.

Look at this strncat call. The bound is smaller than the length of the source string, so the copy gets chopped and the call gets diagnosed. To avoid the warning, use bufsize - strlen (buf) - 1) as the bound.

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

Next up, strncpy. This call copies only the characters before the terminating NUL, and it doesn't add the NUL to the end. Assuming the result is always NUL-terminated is a super common mistake, so this one gets flagged too ๐Ÿ™ƒ. If the result isn't expected to be NUL-terminated, call memcpy instead.

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

Last one! Here the bound is the size of the destination buffer. If the source length is equal to or greater than that size, the result won't be NUL-terminated, so it gets 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 ๐Ÿงต. Just know that those arrays aren't suitable for functions that expect NUL-terminated strings. To help catch accidental misuse, GCC still issues warnings unless it can prove the use is safe ๐Ÿง.

๐Ÿ’… -Wsuggest-attribute

  • -Wsuggest-attribute=[pure|const|noreturn|format|cold|malloc] โ€” Warns for cases where adding an attribute might be beneficial โœจ. The supported attributes are listed below.
  • -Wsuggest-attribute=pure, -Wsuggest-attribute=const, -Wsuggest-attribute=noreturn, -Wmissing-noreturn, -Wsuggest-attribute=malloc โ€” Flags functions that might be candidates for the pure, const, noreturn, or malloc attributes ๐ŸŒธ. GCC only warns about functions visible in other compilation units, or (for pure and const) if it can't prove the function returns normally. A function returns normally if it doesn't contain an infinite loop and doesn't return abnormally by throwing, calling abort, or trapping. This analysis requires option -fipa-pure-const, which is enabled by default at -O and higher. Higher optimization levels improve the accuracy of the analysis.
  • -Wsuggest-attribute=format, -Wmissing-format-attribute โ€” Flags function pointers that might be candidates for format attributes ๐Ÿ–จ๏ธ. These are only possible candidates, not absolute ones. GCC guesses that function pointers with format attributes used in assignment, initialization, parameter passing, or return statements should have a matching format attribute in the resulting type. So the left-hand side of the assignment or initialization, the type of the parameter variable, or the return type of the containing function should also have a format attribute to avoid the warning. GCC also warns about function definitions that might be candidates for format attributes, again only as possible candidates. It guesses format attributes might be appropriate for any function that calls a function like vprintf or vscanf, but that's not always the case, and some functions where format attributes are appropriate might not get detected.
  • -Wsuggest-attribute=cold โ€” Flags 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 of C++ throw or fatal error reporting functions that lead to abort.

๐Ÿ’… -Wsuggest-final-types

  • -Wsuggest-final-types โ€” Warns about types with virtual methods where code quality would improve if the type were declared with the C++11 final specifier or, if possible, declared in an anonymous namespace ๐Ÿน. This lets GCC devirtualize the 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

  • -Wsuggest-final-methods โ€” Warns about virtual methods where code quality would improve 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 ๐Ÿ’œ. It's more effective with link-time optimization, where the class hierarchy graph is more complete. It's recommended to first consider the suggestions from -Wsuggest-final-types and then rebuild with new annotations.

๐Ÿ’… -Wsuggest-override

  • -Wsuggest-override โ€” Warns about overriding virtual functions that aren't marked with the override keyword ๐ŸŽ€.

๐Ÿ’… -Walloc-zero

  • -Walloc-zero โ€” Warns about calls to allocation functions decorated with the alloc_size attribute that specify zero bytes ๐Ÿ™…โ€โ™€๏ธ. This includes the built-in forms of aligned_alloc, alloca, calloc, malloc, and realloc. The behavior of these functions with a zero size differs among implementations (and for realloc, that behavior has been deprecated), so relying on it can cause subtle portability bugs. Avoid it!

๐Ÿ’… -Walloc-size-larger-than

  • -Walloc-size-larger-than=byte-size โ€” Warns about calls to functions decorated with the alloc_size attribute that try to allocate objects larger than the specified number of bytes ๐Ÿ“. It also warns when the result of the size computation, done in an integer type with infinite precision, would exceed the value of PTRDIFF_MAX on the target. -Walloc-size-larger-than=PTRDIFF_MAX is enabled by default ๐Ÿฅณ. You can disable these warnings by specifying a byte-size of SIZE_MAX or more, or by using -Wno-alloc-size-larger-than.
  • -Wno-alloc-size-larger-than โ€” Disables the -Walloc-size-larger-than= warnings ๐Ÿ™…. It's equivalent to -Walloc-size-larger-than=SIZE_MAX or larger.

๐Ÿ’… -Walloca

  • -Walloca โ€” Warns on all uses of alloca in the source. Every single one ๐Ÿ‘€.

๐Ÿ’… -Walloca-larger-than

  • -Walloca-larger-than=byte-size โ€” This one warns on calls to alloca with an integer argument whose value is either zero, or that isn't bounded by a controlling predicate limiting its value to at most byte-size ๐Ÿช„. It also warns for calls to alloca where the bound value is unknown. Arguments of non-integer types count as unbounded, even if they look like they're constrained to the expected range.

For example, a bounded case of alloca could look like this:

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

In the example above, passing -Walloca-larger-than=1000 wouldn't 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 ๐Ÿšจ.

Okay so the alloca thing gets even spicier, bestie ๐Ÿ’… Unbounded uses are the ones with no controlling predicate keeping the integer argument in check. Like this:

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

If you pass -Walloca-larger-than=500, this one trips a warning too, but this time it's because there's zero bounds checking. Not a vibe ๐Ÿ˜ญ

Even code that looks totally fine with signed integers can get a warning ๐Ÿ™ˆ

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

Like, n could be negative, and then a way-too-big number gets implicitly cast into the alloca call. Plot twist, iykyk ๐Ÿซ 

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

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

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


  • -Wno-alloca-larger-than โ€” the big ol' off switch for -Walloca-larger-than= warnings ๐Ÿ™…โ€โ™€๏ธ It's the same as -Walloca-larger-than=SIZE_MAX or larger.
  • -Warray-bounds, -Warray-bounds=n โ€” this one only does its thing when -ftree-vrp is active (default for -O2 and above) ๐ŸŽ€ It warns about subscripts to arrays that are always out of bounds, and -Wall turns it on.
    • -Warray-bounds=1 โ€” this is the level -Warray-bounds runs at, and -Wall enables it. Higher levels aren't on with -Wall, so you have to ask for them explicitly ๐Ÿ™‹โ€โ™€๏ธ
    • -Warray-bounds=2 โ€” this level also catches out-of-bounds access for arrays at the end of a struct and arrays accessed through pointers ๐Ÿ‘€ It can throw a bigger pile of false positives, so it's deactivated by default ๐Ÿ’€
  • -Wattribute-alias=n, -Wno-attribute-alias โ€” warns about declarations using the alias attribute (and similar ones) whose target doesn't match the type of the alias ๐Ÿ“
    • -Wattribute-alias=1 โ€” this is the default level ๐Ÿ’– It flags mismatches between the type of the alias declaration and its target. Those are usually a sign of bugs, bestie.
    • -Wattribute-alias=2 โ€” now it also flags cases where the alias declaration is more restrictive than its target's attributes โš ๏ธ Those mismatches can lead to incorrect code generation! In other cases they're harmless and can be fixed by just adding the missing attribute to the target. For comparison, check out -Wmissing-attributes, which covers the opposite situation, where the alias is less restrictive than the target.

The attributes it considers are "alloc_align", "alloc_size", "cold", "const", "hot", "leaf", "malloc", "nonnull", "noreturn", "nothrow", "pure", "returns_nonnull", and "returns_twice" ๐Ÿงš

-Wattribute-alias is the same as -Wattribute-alias=1, and that's the default โœจ To turn these warnings off, use either -Wno-attribute-alias or -Wattribute-alias=0 ๐Ÿซถ

  • -Wbool-compare โ€” warns about a boolean expression being compared to an integer value that isn't true or false ๐Ÿง This comparison is always false:
int n = 5;
...
if ((n > 1) == 2) { ... }

It's enabled by -Wall ๐Ÿ’œ

  • -Wbool-operation โ€” flags sus operations on boolean expressions ๐Ÿšฉ Like, bitwise negation of a boolean is very likely a bug. For C, this also warns about incrementing or decrementing a boolean, which rarely makes sense. (In C++, decrementing a boolean is always invalid, and incrementing one is invalid in C++17 and deprecated otherwise ๐Ÿ’…) It's enabled by -Wall ๐ŸŒธ
  • -Wduplicated-branches โ€” warns when an if-else has identical branches ๐Ÿ‘ฏ Like this one:
if (p != NULL)
  return 0;
else
  return 0;

It doesn't warn when both branches contain just a null statement ๐Ÿ™ˆ It also warns for conditional operators, like:

int i = x ? *p : *p;
  • -Wduplicated-cond โ€” warns about duplicated conditions in an if-else-if chain ๐Ÿ” For example, it'll warn on this:
if (p->q != NULL) { ... }
else if (p->q != NULL) { ... }
  • -Wframe-address โ€” warns when __builtin_frame_address or __builtin_return_address gets called with an argument greater than 0 ๐Ÿ˜ฌ Those calls might return indeterminate values or crash the program. It's included in -Wall โœจ
  • -Wno-discarded-qualifiers (C and Objective-C only) โ€” doesn't warn when type qualifiers on pointers get dropped ๐Ÿ™…โ€โ™€๏ธ Normally the compiler complains if a const char * variable gets passed to a function that takes a char * parameter. This option quiets that one ๐Ÿคซ
  • -Wno-discarded-array-qualifiers (C and Objective-C only) โ€” same energy, but for arrays that are pointer targets. Normally it warns if a const int (*)[] variable gets passed to a function taking an int (*)[] parameter. This option suppresses that warning ๐ŸŒˆ
  • -Wno-incompatible-pointer-types (C and Objective-C only) โ€” doesn't warn when there's a conversion between pointers with incompatible types ๐Ÿฆ„ This one covers cases that -Wno-pointer-sign doesn't. That one handles pointer argument passing or assignment with different signedness.
  • -Wno-int-conversion (C and Objective-C only) โ€” doesn't warn about incompatible integer-to-pointer and pointer-to-integer conversions ๐Ÿ”ข This is about implicit conversions. For explicit ones, you can use -Wno-int-to-pointer-cast and -Wno-pointer-to-int-cast instead ๐Ÿซถ
  • -Wno-div-by-zero โ€” doesn't warn about compile-time integer division by zero ๐Ÿ™ƒ Floating-point division by zero isn't warned about either, since it can be a legit way to get infinities and NaNs ๐ŸŒŸ
  • -Wsystem-headers โ€” prints warning messages for constructs found in system header files ๐Ÿ“š Warnings from system headers are normally suppressed, on the assumption that they usually aren't real problems and would just make the compiler output harder to read. This option tells GCC to emit those warnings as if they came from user code ๐Ÿ‘‘
Heads up, bestie! Using -Wall together with this option does not warn about unknown pragmas in system headers. For that, you also need -Wunknown-pragmas ๐Ÿšจ
  • -Wtautological-compare โ€” warns if a self-comparison always evaluates to true or false ๐Ÿชž This catches mistakes like:
int i = 1;
...
if (i > i) { ... }

It also warns about bitwise comparisons that always evaluate to true or false. For instance, this one is always false:

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

It's enabled by -Wall ๐Ÿ’–

  • -Wtrampolines โ€” warns about trampolines generated for pointers to nested functions ๐ŸŽข A trampoline is a small piece of data or code created at run time on the stack when the address of a nested function is taken, and it's used to call the nested function indirectly. On some targets it's just data and needs no special treatment. But on most targets it's made of code, which means the stack has to be made executable for the program to work properly ๐Ÿ˜ณ
  • -Wfloat-equal โ€” warns if floating-point values are used in equality comparisons ๐Ÿงฎ The idea is that sometimes it's convenient to treat floating-point values as approximations of infinitely precise real numbers. If you're doing that, you need to figure out (by analyzing the code, or some other way) the maximum or likely maximum error the computation introduces, and allow for it when comparing (and when producing output, but that's a different problem ๐Ÿ™„). Instead of testing for equality, check whether the two values have ranges that overlap. That's done with the relational operators, so equality comparisons are probably a mistake ๐ŸŒธ
  • -Wtraditional (C and Objective-C only) โ€” warns about certain constructs that behave differently in traditional and ISO C ๐Ÿ•ฐ๏ธ It also warns about ISO C constructs with no traditional C equivalent, and about problematic constructs you should avoid. Here's what it flags:
    • Macro parameters that appear within string literals in the macro body. Traditional C does macro replacement inside string literals, but ISO C doesn't ๐Ÿงต
    • In traditional C, some preprocessor directives didn't exist. Traditional preprocessors only treated a line as a directive if the # was in column 1. So -Wtraditional warns about directives that traditional C understands but ignores because the # isn't the first character on the line. It also suggests hiding directives like #pragma, which traditional C doesn't understand, by indenting them. Some traditional implementations don't recognize #elif, so this option suggests avoiding it altogether ๐Ÿ™ˆ
    • A function-like macro that appears without arguments ๐Ÿค”
    • The unary plus operator โž•
    • The U integer constant suffix, or the F or L floating-point constant suffixes. (Traditional C does support the L suffix on integer constants.) These suffixes show up in macros defined in the system headers of most modern systems, like the _MIN/_MAX macros in <limits.h>. Using these macros in user code might normally lead to spurious warnings, but GCC's integrated preprocessor has enough context to avoid warning in these cases ๐Ÿซง
    • A function declared external in one block and then used after the end of that block ๐Ÿงฉ
    • A switch statement with an operand of type long ๐ŸŽ€
  • ๐Ÿ™…โ€โ™€๏ธ A non-static function declaration that shows up after a static one. Some traditional C compilers absolutely refuse this, so it's giving "nope" ๐Ÿ’€
  • ๐Ÿ”ข An integer constant whose ISO type has a different width or signedness than its traditional type. Lowkey important: this only fires when the constant's base is ten. I.e., hexadecimal or octal values, which usually represent bit patterns, are not warned about ๐Ÿซถ
  • ๐Ÿงต GCC clocks it whenever you use ISO string concatenation.
  • ๐Ÿ“ฆ Initializing automatic aggregates.
  • ๐Ÿท๏ธ An identifier that clashes with a label. Traditional C doesn't have a separate namespace for labels, so this one is a classic gotcha.
  • ๐Ÿซง Initializing unions! If the initializer is zero, GCC stays quiet. The thinking is that a zero initializer in user code usually sits behind a condition on e.g. __STDC__ so it doesn't set off missing initializer warnings, and that it relies on default initialization to zero in the traditional C case.
  • ๐Ÿ” Conversions by prototypes between fixed/floating-point values and vice versa. Without those prototypes, compiling with traditional C can cause serious problems. This is only a subset of the possible conversion warnings, so for the full set, use -Wtraditional-conversion.
  • ๐ŸŽ€ ISO C style function definitions! GCC intentionally skips this for prototype declarations and variadic functions, since those ISO C features sneak into your code when you use libiberty's traditional C compatibility macros, PARAMS and VPARAMS. It also skips nested functions, because those are already a GCC extension and aren't relevant to traditional C compatibility.

  • -Wtraditional-conversion (C and Objective-C only) โ€” Heads up if a prototype causes a type conversion that's different from what would happen to the same argument without a prototype. This covers fixed-point to floating-point conversions and vice versa, plus conversions that change the width or signedness of a fixed-point argument, unless 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 one's borrowed from C++, was introduced with ISO C99, and is allowed by default in GCC. 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. Quick note: in C++, the compiler warns if a local variable shadows an explicit typedef, but not if it shadows a struct/class/enum. This is the 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. Chill ๐Ÿง˜โ€โ™€๏ธ
  • -Wshadow=global โ€” The default for -Wshadow. Warns for any (global) shadowing.
  • -Wshadow=local โ€” Warns when a local variable shadows another local variable or parameter. This warning gets turned on by -Wshadow=global.
  • -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" here means the shadowing variable's type can be converted to the shadowed variable's type. This flag exists (alongside -Wshadow=local) because when a local variable shadows one of an incompatible type, it's most likely on purpose and not a bug or typo. Check out this example ๐Ÿ‘‡
for (SomeIterator i = SomeObj.begin(); i != SomeObj.end(); ++i)
{
  for (int i = 0; i < N; ++i)
  {
    ...
  }
  ...
}

Since the two i variables in that example have incompatible types, turning on only -Wshadow=compatible-local won't emit a warning. And because their types are incompatible, if a programmer accidentally uses one in place of the other, type checking will catch it and emit an error or warning. So skipping the shadowing warning here won't lead to undetected bugs. Using this flag instead of -Wshadow=local can cut down on the number of warnings triggered by intentional shadowing. โœจ

This warning gets turned on by -Wshadow=local.

  • -Wlarger-than=_byte-size_ โ€” Warns whenever an object is defined whose size exceeds byte-size. -Wlarger-than=PTRDIFF_MAX is on by default. You can switch these warnings off by specifying a byte-size of SIZE_MAX or more, or by using -Wno-larger-than ๐Ÿ“
  • -Wno-larger-than โ€” Disables -Wlarger-than= warnings. This is equivalent to -Wlarger-than=SIZE_MAX or larger.
  • -Wframe-larger-than=_byte-size_ โ€” Warns if the size of a function frame exceeds byte-size. Heads up: the math used to figure out the stack frame size is approximate and not conservative. The real requirements might be somewhat bigger than byte-size even if you don't get a warning. Also, any space allocated via alloca, variable-length arrays, or related constructs isn't counted by the compiler when it decides whether to warn. -Wframe-larger-than=PTRDIFF_MAX is on by default. You can disable these warnings by specifying a byte-size of SIZE_MAX or more, or by using -Wno-frame-larger-than ๐Ÿชœ
  • -Wno-frame-larger-than โ€” Disables -Wframe-larger-than= warnings. This is equivalent to -Wframe-larger-than=SIZE_MAX or larger.
  • -Wno-free-nonheap-object โ€” Don't warn when you try to free an object that wasn't allocated on the heap. ๐Ÿ—‘๏ธ
  • -Wstack-usage=_byte-size_ โ€” Warns if the stack usage of a function might exceed byte-size. This one's more careful: the math is conservative, and any space allocated via alloca, variable-length arrays, or related constructs is included when the compiler decides whether to warn. The message matches the output of -fstack-usage. Here's what you'll see:
    • If the stack usage is fully static but goes over the specified amount, it's: warning: stack usage is 1120 bytes
    • If the stack usage is (partly) dynamic but bounded, it's: warning: stack usage might be 1648 bytes
    • If the stack usage is (partly) dynamic and not bounded, it's: warning: stack usage might be unbounded

-Wstack-usage=PTRDIFF_MAX is on by default. You can switch these warnings off by specifying a byte-size of SIZE_MAX or more, or by using -Wno-stack-usage ๐Ÿฅž

  • -Wno-stack-usage โ€” Disables -Wstack-usage= warnings. This is equivalent to -Wstack-usage=SIZE_MAX or larger.
  • -Wunsafe-loop-optimizations โ€” Warns if a loop can't be optimized because the compiler can't assume anything about the bounds of the loop indices. With -funsafe-loop-optimizations, it warns if the compiler makes those assumptions instead ๐Ÿ”„
  • -Wno-pedantic-ms-format (MinGW targets only) โ€” When you combine it with -Wformat and -pedantic (without GNU extensions), this turns off the warnings about non-ISO printf / scanf format width specifiers I32, I64, and I used on Windows targets. Those depend on the MS runtime, so they're kind of a Windows-only moment ๐ŸชŸ
  • -Waligned-new โ€” Warns about a new-expression of a type that needs greater alignment than alignof(std::max_align_t), but uses an allocation function without an explicit alignment parameter. This option is enabled by -Wall. Normally it only warns about global allocation functions, but -Waligned-new=all also warns about class member allocation functions. ๐Ÿงฑ
  • -Wplacement-new, -Wplacement-new=n โ€” Warns about placement new expressions with undefined behavior, like constructing an object in a buffer that's smaller than the object's type. For example, the placement new expression below gets flagged, because it tries to construct an array of 64 integers in a buffer that's only 64 bytes large ๐Ÿ’€
char buf [64];
new (buf) int[64];

This warning is enabled by default.

  • -Wplacement-new=1 โ€” This is the default warning level for -Wplacement-new. At this level, the warning isn't issued for some strictly undefined constructs that GCC allows as extensions for compatibility with legacy code. For example, the following new expression isn't diagnosed at this level, even though it has undefined behavior according to the C++ standard, because it writes past the end of the one-element array.
struct S { int n, a[1]; };
S *s = (S *)malloc (sizeof *s + 31 * sizeof s->a[0]);
new (s->a)int [32]();
  • -Wplacement-new=2 โ€” At this level, GCC diagnoses all the same constructs as level 1, plus placement new expressions that construct an object in the last member of a structure, where that member is an array of a single element and the object being constructed is bigger than it. The previous example would get diagnosed here, but the following construct uses the flexible member array extension to avoid the warning at level 2 ๐ŸŒธ
struct S { int n, a[]; };
S *s = (S *)malloc (sizeof *s + 32 * sizeof s->a[0]);
new (s->a)int [32]();
  • -Wpointer-arith โ€” Warns about anything that depends on the "size of" a function type or of void. GNU C gives these types a size of 1, for convenience in calculations with void * pointers and pointers to functions. In C++, it also warns when an arithmetic operation involves NULL. This warning is also enabled by -Wpedantic ๐Ÿงฎ
  • -Wpointer-compare โ€” Warns if a pointer is compared with a zero character constant. This usually means the pointer was meant to be dereferenced. Like this:
const char *p = foo ();
if (p == '\0')
  return 42;
Note that the code above is invalid in C++11. ๐Ÿšซ

This warning is enabled by default. ๐Ÿ’–

  • -Wtype-limits ๐Ÿ’… โ€” okay so this one warns when a comparison is always true or always false because of the limited range of the data type. Constant expressions don't get flagged, though. For example, it warns if an unsigned variable is compared against zero with < or >=. It's also turned on by -Wextra. ๐Ÿงš
  • -Wabsolute-value (C and Objective-C only) โ€” bestie, this one catches you calling a standard absolute-value function when there's a better one for the job ๐Ÿ˜ญ. Calling abs(3.14) triggers it, since fabs is the right call for a double. It also warns when the argument to one of these functions has an unsigned type. You can shut it up with an explicit type cast, and it's enabled by -Wextra too. ๐ŸŽ€
  • -Wcomment, -Wcomments โ€” this one is a whole vibe check on comments ๐Ÿซถ. It warns when a /* start sequence shows up inside a /* comment, or when a backslash-newline shows up inside a // comment. It's enabled by -Wall. ๐ŸŒธ
  • -Wtrigraphs โ€” warns if any trigraphs pop up that could change what the program means ๐Ÿ‘€. Trigraphs inside comments don't get flagged, except the ones that would form escaped newlines. This option is implied by -Wall. If you don't pass -Wall, it's still on unless trigraphs are enabled. Want trigraph conversion without the warnings but still all the other -Wall warnings? Use -trigraphs -Wall -Wno-trigraphs. The main character move ๐Ÿ‘‘.
  • -Wundef โ€” warns if an undefined identifier gets evaluated in an #if directive. Those identifiers get replaced with zero, so keep an eye out ๐Ÿฆ‹.
  • -Wexpansion-to-defined โ€” warns whenever defined shows up in the expansion of a macro, including when the macro gets expanded by an #if directive. That usage isn't portable, so this one is giving caution ๐Ÿ’€. It's also enabled by -Wpedantic and -Wextra.
  • -Wunused-macros โ€” warns about macros defined in the main file that never get used ๐Ÿงน. A macro counts as used if it's expanded or tested for existence at least once. The preprocessor also warns if the macro hasn't been used by the time it 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 used, but only inside skipped conditional blocks, the preprocessor still reports it as unused ๐Ÿ˜ญ. To dodge the warning in that case, you might improve the scope of the macro's definition, for example by moving it into the first skipped block. Or you could give it a dummy use with something like this:
#if defined the_macro_causing_the_warning
#endif
  • -Wno-endif-labels โ€” this one turns off the warning for when an #else or an #endif has text after it ๐Ÿ™ˆ. It 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, so this is an old-school situation. The warning is on by default. ๐Ÿ“

  • -Wbad-function-cast (C and Objective-C only) โ€” warns when a function call gets cast to a type it doesn't match. For example, it warns if a call to a function returning an integer type gets cast to a pointer type ๐Ÿ™ƒ.
  • -Wc90-c99-compat (C and Objective-C only) โ€” warns about features that exist in ISO C99 but not in ISO C90 โœจ. Think variable length arrays, the long long type, the bool type, compound literals, designated initializers, and so on. This option doesn't care what standards mode you're in. 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 ๐ŸŒˆ. Examples are 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. Also independent of the standards mode, and warnings are disabled in the expression that follows __extension__.
  • -Wc11-c2x-compat (C and Objective-C only) โ€” warns about features in ISO C2X that aren't in ISO C11 ๐Ÿ”ฅ. For instance, it warns about leaving out the string in _Static_assert. Independent of the standards mode, and warnings are disabled in the expression that follows __extension__.
  • -Wc++-compat (C and Objective-C only) โ€” warns about ISO C constructs that live outside the common subset of ISO C and ISO C++ ๐Ÿง. One example is asking for an implicit conversion from void * to a pointer to a non-void type.
  • -Wc++11-compat (C++ and Objective-C++ only) โ€” warns about C++ constructs whose meaning changed between ISO C++ 1998 and ISO C++ 2011 ๐Ÿ’œ. For example, identifiers that were fine in ISO C++ 1998 but are keywords in ISO C++ 2011. This warning turns on -Wnarrowing and is enabled by -Wall.
  • -Wc++14-compat (C++ and Objective-C++ only) โ€” same idea, but for changes between ISO C++ 2011 and ISO C++ 2014 ๐ŸŽ€. It's enabled by -Wall.
  • -Wc++17-compat (C++ and Objective-C++ only) โ€” warns about C++ constructs that changed between ISO C++ 2014 and ISO C++ 2017 ๐Ÿฆ‹. It's enabled by -Wall.
  • -Wcast-qual โ€” warns whenever a pointer gets cast in a way that drops a type qualifier from the target type ๐Ÿซฃ. For example, it warns if a const char * gets cast to a plain char *. It also warns when a cast adds a type qualifier in an unsafe way. Casting char ** to const char ** is unsafe, as you can see here:
/* p is char ** value.  */
const char **q = (const char **) p;
/* Assignment of readonly string to const char * is OK.  */
*q = "string";
/* Now char** pointer points to read-only memory.  */
**p = 'b';
  • -Wcast-align โ€” warns whenever a pointer gets cast so the required alignment of the target goes up ๐Ÿ“. For example, it warns if a char * gets cast to an int * on machines where integers can only be accessed at two- or four-byte boundaries.
  • -Wcast-align=strict โ€” same warning as above, but stricter ๐Ÿ˜ค. It warns whenever a pointer gets cast so the target's required alignment increases, for example a char * cast to an int *, regardless of the target machine.
  • -Wcast-function-type โ€” warns when a function pointer gets cast to an incompatible function pointer type ๐Ÿงฉ. 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 get ignored, like int vs. long on ILP32 targets. Type qualifiers are ignored too. The function type void (*) (void) is special and matches everything, so you can use it to suppress this warning. For casts involving pointer to member types, the warning fires whenever the cast changes the pointer to member type. It's enabled by -Wextra. ๐Ÿ’…
  • -Wwrite-strings โ€” when you're 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 can catch code that tries to write into a string constant at compile time, but only if you've been super careful with const in your declarations and prototypes. Otherwise it's just a nuisance, which is why -Wall doesn't ask for these warnings. When you're compiling C++, it warns about the deprecated conversion from string literals to char *. This warning is enabled by default for C++ programs. ๐Ÿ“
  • -Wcatch-value, -Wcatch-value=n (C++ and Objective-C++ only) โ€” warns about catch handlers that don't catch via reference ๐Ÿ™Œ. With -Wcatch-value=1 (or just -Wcatch-value), it warns about polymorphic class types that get caught by value. With -Wcatch-value=2, it warns about all class types caught by value. With -Wcatch-value=3, it warns about all types that aren't caught by reference. -Wcatch-value is enabled by -Wall.
  • -Wclobbered โ€” warns about variables that might get changed by longjmp or vfork ๐Ÿ˜ต. It's also enabled by -Wextra.
  • -Wconditionally-supported (C++ and Objective-C++ only) โ€” warns about conditionally-supported constructs, as defined in C++11 [intro.defs] โœจ.
  • -Wconversion โ€” warns about implicit conversions that might change a value ๐Ÿ”. That includes conversions between real and integer types, like abs (x) when x is a double. It also covers conversions between signed and unsigned, like unsigned ui = -1, and conversions to smaller types, like sqrtf (M_PI). It won't warn about explicit casts like abs ((int) x) or ui = (unsigned) -1, or about cases where the conversion doesn't change the value, like abs (2.0). You can turn off the warnings about signed/unsigned conversions with -Wno-sign-conversion.

For C++, it also warns about confusing overload resolution for user-defined conversions. It warns about conversions that never use a type conversion operator too: conversions to void, to the same type, to a base class, or to a reference to any of those. In C++, warnings about conversions between signed and unsigned integers are disabled by default unless -Wsign-conversion is explicitly enabled. ๐ŸŒธ

  • -Wno-conversion-null (C++ and Objective-C++ only) โ€” don't warn about conversions between NULL and non-pointer types ๐Ÿ™…. -Wconversion-null is enabled by default.
  • -Wzero-as-null-pointer-constant (C++ and Objective-C++ only) โ€” warns when a literal 0 is used as a null pointer constant ๐Ÿงผ. This can help when you're converting to nullptr in C++11.
  • -Wsubobject-linkage (C++ and Objective-C++ only) โ€” warns if a class type has a base or a field whose type uses the anonymous namespace or depends on a type with no linkage ๐Ÿง . If a type A depends on a type B with no linkage or internal linkage, defining it in multiple translation units would be an ODR violation, because the meaning of B is different in each translation unit. If A only shows up in one translation unit, the best way to silence the warning is to give it internal linkage by putting it in an anonymous namespace too. The compiler doesn't give this warning for types defined in the main .C file, since those are unlikely to have multiple definitions. -Wsubobject-linkage is enabled by default. ๐Ÿ‘‘
  • -Wdangling-else โ€” okay bestie, this one is all about "else" drama ๐Ÿ™ˆ It warns you about code where it's unclear which "if" an "else" branch actually belongs to. Check this out:
{
  if (a)
    if (b)
      foo ();
  else
    bar ();
}

In C/C++, every "else" belongs to the innermost possible "if", which here is if (b) ๐Ÿ’€. That's usually NOT what the programmer meant, even though the indentation says otherwise. When this kind of confusion is possible, GCC warns you as long as this flag is on. To make the warning disappear, add explicit braces around the innermost "if" so the "else" can't possibly belong to the outer one โœจ. It looks like this:

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

This warning gets switched on by -Wparentheses ๐ŸŽ€.

  • -Wdate-time โ€” warn me when __TIME__, __DATE__ or __TIMESTAMP__ show up, because they can stop your builds from being bit-wise-identical and reproducible ๐Ÿ•ฐ๏ธ
  • -Wdelete-incomplete (C++ and Objective-C++ only) โ€” warns when you delete a pointer to an incomplete type, which can cause undefined behavior at runtime ๐Ÿ˜ฌ This one is enabled by default, so you get it for free ๐Ÿ’–
  • -Wuseless-cast (C++ and Objective-C++ only) โ€” warns when you cast an expression to its own type. Literally pointless, no cap ๐Ÿ™„
  • -Wempty-body โ€” warns if there's an empty body in an "if", "else" or "do while" statement. This one is also turned on by -Wextra ๐Ÿงน
  • -Wenum-compare โ€” warns about comparing values from different enumerated types. In C++, enum mismatches in conditional expressions get flagged too, and the warning is on by default there. In C, it's turned on by -Wall ๐Ÿ‘‘
  • -Wextra-semi (C++, Objective-C++ only) โ€” warns about a redundant semicolon after an in-class function definition. Tiny little extra semicolon, big energy ๐Ÿ˜ญ
  • -Wjump-misses-init (C, Objective-C only) โ€” warns if a goto or a switch jumps forward across the initialization of a variable, or jumps backward to a label after that variable has already been initialized ๐Ÿฆ‹ It only cares about variables that get initialized when they're declared. This warning is only supported for C and Objective-C. In C++, this kind of branch is an error anyway, so it doesn't matter there ๐Ÿ™…โ€โ™€๏ธ

-Wjump-misses-init is included in -Wc++-compat. You can turn it off with the -Wno-jump-misses-init option ๐ŸŒธ

  • -Wsign-compare โ€” warns when comparing signed and unsigned values could give you a wrong answer, because the signed value gets converted to unsigned. In C++, this is also enabled by -Wall. In C, it's also enabled by -Wextra ๐Ÿงš
  • -Wsign-conversion โ€” warns about implicit conversions that might flip the sign of an integer, like assigning a signed integer expression to an unsigned integer variable. An explicit cast quiets the warning ๐Ÿคซ In C, this option is also enabled by -Wconversion.
  • -Wfloat-conversion โ€” warns about implicit conversions that drop the precision of a real value. That includes real-to-integer conversions, and conversions from higher precision real values to lower precision ones ๐Ÿ“‰ This option is also enabled by -Wconversion.
  • -Wno-scalar-storage-order โ€” nah, don't warn me about sketchy constructs involving reverse scalar storage order ๐Ÿ™…โ€โ™€๏ธ
  • -Wsized-deallocation (C++ and Objective-C++ only) โ€” warns about defining an unsized deallocation function like this:
void operator delete (void *) noexcept;
void operator delete[] (void *) noexcept;

โ€ฆwithout also defining the matching sized deallocation function, like this:

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

Or the other way around, too ๐Ÿ” This one gets enabled by -Wextra along with -fsized-deallocation ๐Ÿ’…

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

It also warns about calls to bounded string copy functions like strncat or strncpy that use a sizeof expression of the source array as their bound. In the example below, the strncat call uses the size of the source string as its bound. That's almost certainly a mistake, so the call gets flagged ๐Ÿšฉ

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

This warning is enabled by -Wall โœจ

  • -Wsizeof-array-argument โ€” warns when the sizeof operator gets applied to a parameter that's declared as an array in a function definition. This one is enabled by default for C and C++ programs ๐Ÿซถ
  • -Wmemset-elt-size โ€” warns about suspicious calls to the memset built-in function. It triggers when the first argument references an array, and the third argument is a number equal to the number of elements but not equal to the array's size in memory. That usually means you forgot to multiply by the element size ๐Ÿ™ˆ This warning is enabled by -Wall.
  • -Wmemset-transposed-args โ€” warns about suspicious calls to memset where the second argument is not zero and the third argument is zero. For example, memset (buf, sizeof buf, 0) gets diagnosed, because memset (buf, 0, sizeof buf) was what you meant ๐Ÿ”„ The diagnostic only fires if the third argument is a literal zero. If it's an expression that folds to zero, or a cast of zero to some type, the arguments are far less likely to be mixed up by mistake, so no warning is emitted ๐Ÿคทโ€โ™€๏ธ This warning is enabled by -Wall.
  • -Waddress โ€” warns about suspicious uses of memory addresses ๐Ÿ‘€ That includes using a function's address in a conditional expression, like void func(void); if (func), and comparing against the memory address of a string literal, like if (x == "abc"). These typically mean a programmer error. A function's address always evaluates to true, so using it in a conditional usually means you forgot the parentheses in a function call. Comparing against string literals gives unspecified behavior and isn't portable in C, so the programmer probably meant to use strcmp ๐Ÿ’… This warning is enabled by -Wall.
  • -Waddress-of-packed-member โ€” warns when you take the address of a packed member of a struct or union, which usually results in an unaligned pointer value ๐Ÿ“ฆ This is enabled by default.
  • -Wlogical-op โ€” warns about suspicious uses of logical operators in expressions. That includes using logical operators where a bit-wise operator is probably what you wanted ๐Ÿค” It also warns when both operands of a logical operator are the same:
extern int a;
if (a < 0 && a < 0) { ... }
  • -Wlogical-not-parentheses โ€” warns about a logical not used on the left-hand side operand of a comparison. It won't warn if the right operand is considered a boolean expression. Its whole purpose is to catch sus code like this:
int a;
...
if (!a > 1) { ... }

You can suppress the warning by wrapping the left-hand side in parentheses:

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

This warning is enabled by -Wall ๐ŸŽ€

  • -Waggregate-return โ€” warns if any functions that return structures or unions are defined or called. (In languages where you can return an array, this also triggers a warning ๐Ÿ“š)
  • -Wno-aggressive-loop-optimizations โ€” warns if, inside a loop with a constant number of iterations, the compiler detects undefined behavior in some statement during one or more of the iterations ๐Ÿ”
  • -Wno-attributes โ€” don't warn if an unexpected __attribute__ gets used, like unrecognized attributes, function attributes applied to variables, etc. This does NOT stop errors for incorrect use of supported attributes, so don't get it twisted ๐Ÿ’€
  • -Wno-builtin-declaration-mismatch โ€” warns if a built-in function is declared with an incompatible signature or as a non-function. It also warns when a built-in function declared with a type that doesn't include a prototype gets called with arguments whose promoted types don't match what the function expects ๐Ÿงฉ When -Wextra is specified, it also warns when a built-in function that takes arguments is declared without a prototype. The -Wno-builtin-declaration-mismatch warning is enabled by default. To avoid it, include the appropriate header so the prototypes of built-in functions are in scope ๐Ÿซง

For example, the memset call 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 too:

extern void* memset ();
void f (void *d)
{
  memset (d, '\0', 32);
}
  • -Wno-builtin-macro-redefined โ€” don't warn if certain built-in macros get redefined. This quiets warnings for redefining __TIMESTAMP__, __TIME__, __DATE__, __FILE__, and __BASE_FILE__ ๐ŸŒท
  • -Wstrict-prototypes (C and Objective-C only) โ€” warns if a function is declared or defined without specifying its argument types ๐Ÿ“ An old-style function definition is allowed without a warning if it's preceded by a declaration that specifies the argument types โœจ
  • -Wold-style-declaration (C and Objective-C only) โ€” okay so this one is the obsolete-syntax police ๐Ÿ‘ฎโ€โ™€๏ธโœจ. It warns about declarations that the C Standard considers outdated, like when storage-class specifiers such as 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) โ€” warns if you write an old-style function definition ๐Ÿ™ˆ. And it still warns even when there's already a previous prototype, so no sneaking past it ๐Ÿ’….
  • -Wmissing-parameter-type (C and Objective-C only) โ€” catches a function parameter that's declared with no type in K&R-style functions. Like this:
void foo(bar) { }

It's also enabled by -Wextra ๐ŸŽ€.

  • -Wmissing-prototypes (C and Objective-C only) โ€” warns if a global function gets defined without a previous prototype declaration ๐Ÿฆ‹. This happens even if the definition itself has a prototype. Use it to find 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 gives a prototype, and a non-matching one just makes an overload instead of clashing with an earlier declaration. For missing declarations in C++, use -Wmissing-declarations instead.
  • -Wmissing-declarations โ€” warns if a global function gets defined without a previous declaration, even when the definition itself provides a prototype ๐ŸŒˆ. This is your go-to for spotting global functions that aren't declared in header files. In C, you won't get warnings for functions that have previous non-prototype declarations, so use -Wmissing-prototypes to catch those missing prototypes. In C++, there are no warnings for function templates, inline functions, or functions in anonymous namespaces ๐Ÿงš.
  • -Wmissing-field-initializers โ€” warns if a struct's initializer is missing some fields ๐Ÿ“. In this example, x.h is implicitly zero, so you'll get a warning:
struct s { int f, g, h; };
struct s x = { 3, 4 };

Designated initializers are exempt though ๐Ÿซถ, so this one won't trigger a warning:

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

In C, the universal zero initializer { 0 } is also safe from this warning:

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

And in C++, the empty { } initializer doesn't get flagged either, for example:

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 โ€” stops the warning for multicharacter constants like 'FOOF' ๐Ÿ™…โ€โ™€๏ธ. Those usually mean there's a typo in your code, since their values are implementation-defined and they shouldn't show up in portable code.
  • -Wnormalized=[none|id|nfc|nfkc] โ€” okay this one is a whole vibe ๐ŸŒธ. In ISO C and ISO C++, two identifiers are different if their character sequences are different. But when you use characters outside basic ASCII, two different sequences can 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 when your identifiers haven't been normalized. This option controls that warning.

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

Unfortunately, some characters that ISO C and ISO C++ allow in identifiers aren't allowed once they're converted to NFC. So there's no way to use those symbols in portable ISO C or C++ and still have every identifier in NFC ๐Ÿ˜ญ. -Wnormalized=id suppresses the warning for those characters. The hope is that future versions of the standards fix this, which is why it isn't the default ๐Ÿ™.

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

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

  • -Wno-attribute-warning โ€” don't warn about using functions declared with the "warning" attribute ๐Ÿ™Œ. This warning is enabled by default. You can 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 using deprecated features ๐Ÿ•ฐ๏ธ.
  • -Wno-deprecated-declarations โ€” don't warn about uses of functions, variables, and types marked as deprecated with the "deprecated" attribute ๐Ÿฅฑ.
  • -Wno-overflow โ€” don't warn about compile-time overflow in constant expressions ๐Ÿ”ข.
  • -Wno-odr โ€” this one warns about One Definition Rule violations during link-time optimization ๐Ÿ“ฆ. It requires -flto-odr-type-merging to be enabled, and it's on by default.
  • -Wopenmp-simd โ€” warns if the vectorizer cost model overrides the OpenMP simd directive you set ๐ŸŽ๏ธ. If you want to loosen the cost model, you can use -fsimd-cost-model=unlimited.
  • -Woverride-init (C and Objective-C only) โ€” warns if an initialized field without side effects gets overridden when you use designated initializers ๐Ÿ”. This warning is included in -Wextra. To get the other -Wextra warnings without this one, use -Wextra -Wno-override-init.
  • -Woverride-init-side-effects (C and Objective-C only) โ€” same deal, but for an initialized field with side effects that gets overridden by designated initializers ๐Ÿ’ฅ. This warning is enabled by default.
  • -Wpacked โ€” warns if a structure has the packed attribute but that attribute doesn't change the layout or size of the structure ๐Ÿคทโ€โ™€๏ธ. Those structures can end up misaligned for very little benefit. In this code, the variable f.x in struct bar is misaligned, even though struct bar doesn't have the packed attribute itself:
struct foo {
  int x;
  char a, b, c, d;
} __attribute__((packed));
struct bar {
  char z;
  struct foo f;
};
  • -Wpacked-bitfield-compat โ€” the 4.1, 4.2, and 4.3 series of GCC ignore the packed attribute on bit-fields of type char ๐Ÿ˜ฌ. That got fixed in GCC 4.4, but the change can lead to differences in structure layout. GCC tells you when the offset of such a field has changed in GCC 4.4. For example, there's no longer a 4-bit padding between fields a and b in this structure:
struct foo
{
  char a:4;
  char b:8;
} __attribute__ ((packed));

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

  • -Wpacked-not-aligned (C, C++, Objective-C and Objective-C++ only) โ€” warns if a structure field with explicitly specified alignment inside a packed struct or union is misaligned ๐Ÿ“. In this code, you'll get a warning on struct S that looks 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 โ€” warns if padding gets added to a structure, either to align one of its elements or to align the whole structure ๐Ÿงฉ. Sometimes you can rearrange the fields to reduce the padding, which makes the structure smaller.
  • -Wredundant-decls โ€” warns if anything gets declared more than once in the same scope ๐Ÿ”‚. This happens even when multiple declarations are valid and don't change anything.
  • -Wno-restrict โ€” this is about restrict-qualified parameters (or __restrict-qualified ones in C++) ๐Ÿšง. It warns when the object a parameter points to is aliased by another argument, or when copies between those objects overlap. In the example below, strcpy tries to truncate the string by replacing its first characters with the last four. But because the call writes the terminating NUL into a[4], the copies overlap, and the call gets flagged:
void foo (void)
{
  char a[] = "abcd1234";
  strcpy (a, a + 4);
  ...
}

The -Wrestrict option can catch some simple overlaps even without optimization, but it works best at -O2 and above. It's included in -Wall ๐Ÿ’œ.

  • -Wnested-externs (C and Objective-C only) โ€” warns if an extern declaration shows up inside a function ๐Ÿ•ต๏ธโ€โ™€๏ธ.
  • -Wno-inherited-variadic-ctor โ€” silences warnings about using C++11 inheriting constructors when the base class you're inheriting from has a C variadic constructor ๐Ÿ™Š. The warning is on by default, since the ellipsis doesn't get inherited.
  • -Winline โ€” warns if a function declared as inline can't actually be inlined ๐Ÿฆข. Even with this option on, the compiler won't warn about failures to inline functions declared in system headers.

okay so the compiler is out here using a whole pile of heuristics to decide whether it's gonna inline a function ๐Ÿง โœจ it looks at how big the function being inlined is and how much inlining has already happened in the current function. so yeah, seemingly tiny changes in your source can make the -Winline warnings pop up or vanish ๐Ÿ˜ญ not you, the compiler is just being dramatic ๐Ÿ’…

  • -Wno-invalid-offsetof (C++ and Objective-C++ only) โ€” ๐Ÿ™ˆ this one shuts up warnings for using the offsetof macro on a non-POD type. heads up, the 2014 ISO C++ standard says using offsetof on a non-standard-layout type is undefined. but in existing C++ implementations, offsetof usually gives meaningful results anyway. this flag is for the users who know they're writing nonportable code and have deliberately chosen to ignore the warning. the restrictions on offsetof might get relaxed in a future version of the C++ standard, so keep an eye on that ๐Ÿ‘€
  • -Wint-in-bool-context โ€” โš ๏ธ warns about sus integer values showing up where booleans are expected. for example, ?: conditionals using non-boolean integer constants in a boolean context, like if (a <= b ? 2 : 3). or left shifting signed integers in a boolean context, like for (a = 0; 1 << a; a++);. same goes for all kinds of multiplications, no matter the data type. this one is enabled by -Wall ๐Ÿ”ฅ
  • -Wno-int-to-pointer-cast โ€” ๐Ÿงš suppresses warnings about casts to a pointer type from an integer of a different size. in C++, casting to a pointer type of smaller size is an error, not just a warning. Wint-to-pointer-cast is enabled by default.
  • -Wno-pointer-to-int-cast (C and Objective-C only) โ€” ๐Ÿฆ‹ mutes warnings about casts from a pointer to an integer type of a different size.
  • -Winvalid-pch โ€” ๐ŸŒธ warns if a precompiled header is found in the search path but can't actually be used.
  • -Wlong-long โ€” ๐Ÿ’œ warns if the long long type is used. this is enabled by either -Wpedantic or -Wtraditional in ISO C90 and C++98 modes. if you want those warning messages gone, use -Wno-long-long.
  • -Wvariadic-macros โ€” ๐ŸŽ€ warns if variadic macros are used in ISO C90 mode, or if the GNU alternate syntax is used in ISO C99 mode. enabled by either -Wpedantic or -Wtraditional. to inhibit the messages, use -Wno-variadic-macros.
  • -Wvarargs โ€” ๐Ÿ‘‘ warns upon questionable usage of the macros that handle variable arguments, like va_start. this one is on by default. to silence it, use -Wno-varargs.
  • -Wvector-operation-performance โ€” ๐Ÿ”ฅ warns if a vector operation isn't implemented using the SIMD capabilities of the architecture. honestly mostly useful for performance tuning. a vector operation can be implemented in three ways:
    • "piecewise", which means the scalar operation is performed on every vector element
    • "in parallel", which means the vector operation is implemented using scalars of a wider type, which normally is more performance efficient
    • "as a single scalar", which means the vector fits into a scalar type
  • -Wno-virtual-move-assign โ€” ๐Ÿ’… suppresses warnings about inheriting from a virtual base with 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, then this warning is safe to disable.
  • -Wvla โ€” ๐ŸŒˆ warns if a variable-length array is used in the code. -Wno-vla prevents the -Wpedantic warning about the variable-length array.
  • -Wvla-larger-than=byte-size โ€” ๐Ÿงฎ if you use this, the compiler warns for declarations of variable-length arrays whose size is either unbounded, or bounded by an argument that lets the array size exceed byte-size bytes. it's kinda like how -Walloca-larger-than=byte-size works, just for variable-length arrays instead.

โœจ note that GCC may optimize small variable-length arrays of a known value into plain arrays, so this warning may not trigger for those.

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

see also -Walloca-larger-than=byte-size.

  • -Wno-vla-larger-than โ€” ๐Ÿ™… disables -Wvla-larger-than= warnings. this is equivalent to -Wvla-larger-than=SIZE_MAX or larger.
  • -Wvolatile-register-var โ€” ๐Ÿซถ warns if a register variable is declared volatile. the volatile modifier doesn't stop every optimization that might eliminate reads and/or writes to register variables. enabled by -Wall.
  • -Wdisabled-optimization โ€” ๐Ÿข warns if a requested optimization pass is disabled. this doesn't usually mean anything is wrong with your code, it just means GCC's optimizers can't handle the code effectively. often the problem is that your code is too big or too complex, and GCC refuses to optimize programs when the optimization is likely to take inordinate amounts of time.
  • -Wpointer-sign (C and Objective-C only) โ€” ๐Ÿงท warns for pointer argument passing or assignment with different signedness. this is only supported for C and Objective-C. it's implied by -Wall and by -Wpedantic, and you can turn it off with -Wno-pointer-sign.
  • -Wstack-protector โ€” ๐Ÿ›ก๏ธ only active when -fstack-protector is active. it warns about functions that are not protected against stack smashing.
  • -Woverlength-strings โ€” ๐Ÿ“ warns about string constants that are longer than the "minimum maximum" length specified in the C standard. modern compilers are generally chill with string constants way longer than that minimum, but very portable programs should avoid longer strings.

the limit applies after string constant concatenation, and it doesn't count the trailing NUL. in C90 the limit was 509 characters, and in C99 it got raised to 4095. C++98 doesn't specify a normative minimum maximum, so overlength strings aren't diagnosed in C++. this option is implied by -Wpedantic, and you can disable it with -Wno-overlength-strings.

  • -Wunsuffixed-float-constants (C and Objective-C only) โ€” ๐Ÿ”ข issues a warning for any floating constant that doesn't have a suffix. when you use it together with -Wsystem-headers, it also warns about those constants in system header files. this can be useful when you're prepping code to use with the FLOAT_CONST_DECIMAL64 pragma from the decimal floating-point extension to C99.
  • -Wno-designated-init (C and Objective-C only) โ€” ๐ŸŽ€ suppresses warnings when a positional initializer is used to initialize a structure that has been marked with the designated_init attribute.
  • -Whsa โ€” ๐Ÿงต issues a warning when HSAIL can't be emitted for the compiled function or OpenMP construct.

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

okay this section is giving main character energy ๐Ÿงš to tell GCC to emit extra info for a debugger, you pretty much only need to add -g to your other options in almost all cases.

GCC lets you use -g with -O. ngl the shortcuts taken by optimized code can be 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 get 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. but it's still possible to debug optimized output! which makes it reasonable to use the optimizer for programs that might have bugs ๐Ÿ’–

if you aren't using some other optimization option, consider using -Og with -g. with no -O option at all, some compiler passes that collect information useful for debugging don't run, so -Og may give you a better debugging experience โœจ

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

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

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

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

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

๐Ÿšซ GCC no longer supports DWARF Version 1, which is substantially different from Version 2 and later. for historical reasons, some other DWARF-related options such as -fno-dwarf2-cfi-asm) still have a reference to DWARF Version 2 in their names, but they apply to all currently-supported versions of DWARF.
  • -gstabs โ€” ๐Ÿ“ produces debugging information in stabs format (if that's supported), without GDB extensions. this is the format DBX uses on most BSD systems. on MIPS, Alpha and System V Release 4 systems, this option produces stabs debugging output that DBX doesn't understand. on System V Release 4 systems this option requires the GNU assembler.
  • -gstabs+ โ€” ๐Ÿง produces debugging information in stabs format (if that's supported), using GNU extensions that only the GNU debugger (GDB) understands. using these extensions is likely to make other debuggers crash or refuse to read the program.
  • -gxcoff โ€” ๐Ÿ–ฅ๏ธ produces debugging information in XCOFF format (if that's supported). this is the format the DBX debugger uses on IBM RS/6000 systems.
  • -gxcoff+ โ€” okay bestie, this one spits out debug info in XCOFF format (if your setup supports it ๐Ÿ’…) using GNU extensions that ONLY the GNU debugger (GDB) understands ๐Ÿ™ˆ. Heads up though: other debuggers might crash or straight up refuse to read your program ๐Ÿ’€, and assemblers that aren't the GNU assembler (GAS) could throw an error at you.
  • -gvms โ€” produces debug info in the Alpha/VMS debug format (if it's supported) ๐Ÿฆ‹. This is the format DEBUG uses on Alpha/VMS systems, so it's very much their thing โœจ.
  • -glevel, -ggdblevel, -gstabslevel, -gxcofflevel, -gvmslevel โ€” requests debug info AND lets you pick how much you want ๐ŸŽ€. The default level is 2 ๐Ÿ’–.
    • Level 0 gives you zero debug info, so -g0 cancels out -g ๐Ÿ™…โ€โ™€๏ธ.
    • Level 1 is the minimal, lowkey version ๐ŸŒธ. It's enough to make backtraces in the parts you're not planning to debug. You get descriptions of functions and external variables plus line number tables, but NO info about local variables.
    • Level 3 goes extra ๐Ÿงš, including stuff like all the macro definitions present in the program. Some debuggers can even do macro expansion when you use -g3 ๐Ÿ”ฅ.
    • If you stack up multiple -g options, with or without level numbers, the LAST one is the one that counts ๐Ÿ‘‘.
    • > Quick heads up: -gdwarf won't accept a concatenated debug level, so nobody gets confused with -gdwarf-level. Instead, add an extra -glevel option to change the debug level for DWARF ๐Ÿซถ.
  • -feliminate-unused-debug-symbols โ€” produces debug info in stabs format (if that's supported), but ONLY for symbols that are actually used ๐Ÿงน.
  • -femit-class-debug-always โ€” instead of putting the debug info for a C++ class in just one object file, this emits it in every object file that uses the class ๐Ÿ“ฆ. Only use this with debuggers that can't handle how GCC normally does it ๐Ÿ™ƒ. It's a big ask, too: it can make the debug info up to a factor of two bigger ๐Ÿ˜ญ.
  • -fno-merge-debug-strings โ€” tells the linker NOT to merge together strings in the debug info that are identical across different object files ๐Ÿงต. Not every assembler or linker supports merging anyway. Merging shrinks the debug info in your output file, but the tradeoff is slower link time โณ. Merging is on by default, btw ๐Ÿ’….
  • -fdebug-prefix-map=old=new โ€” when you compile files living in directory old, the debug info describes them as if they lived in directory new instead ๐Ÿ—บ๏ธ. This is perfect for swapping a build-time path for an install-time path. You can also turn an absolute path into a relative one by using . for new ๐ŸŒฟ. It can give you more reproducible builds that don't depend on location ๐Ÿ”, 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 ๐Ÿ•ต๏ธโ€โ™€๏ธ. It figures out where variables are stored at each position in the code, so the debug info can be better (if your debug info format supports that). It's turned on by default when you compile with optimization (-Os, -O, -O2, ...), debug info (-g), and a format that supports it ๐ŸŽฏ.
  • -fvar-tracking-assignments โ€” annotates assignments to user variables early in compilation, then tries to carry those annotations all the way to the end ๐Ÿ. The goal is better debug info while optimizing โœจ. Using -gdwarf-4 alongside it is recommended ๐Ÿ’œ. It can be enabled even when var-tracking is disabled, in which case the annotations get created and maintained but tossed at the end ๐Ÿ—‘๏ธ. By default this flag rides along 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 .dwo extension ๐Ÿ“‚. This lets your build system skip linking files that have debug info, which is so helpful ๐Ÿ™Œ. To be useful though, you need a debugger that can read .dwo files ๐Ÿ”ง.
  • -gdescribe-dies โ€” adds description attributes to some DWARF DIEs that don't have a name attribute ๐Ÿท๏ธ. Examples are 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 ready to be converted into a GDB index ๐Ÿ—‚๏ธ. This is only useful with a linker that can produce GDB index version 7 ๐Ÿง .
  • -fdebug-types-section โ€” when you're using DWARF Version 4 or higher, type DIEs can get their own ".debug_types" section instead of living inside ".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 it makes the debug info bigger instead of smaller ๐Ÿ˜ฌ.
  • -grecord-gcc-switches, -gno-record-gcc-switches โ€” this one tacks the command-line options that might affect code generation onto the DW_AT_producer attribute in the DWARF debug info ๐Ÿ“. The options are joined with spaces, separating them from each other and from the compiler version ๐ŸŽ€. It's enabled by default. See also -frecord-gcc-switches for another way of storing compiler options in the object file ๐Ÿ’….
  • -gstrict-dwarf โ€” no cap, this one disallows using extensions from a later DWARF standard version than the one you picked with -gdwarf-version ๐Ÿšซ. On most targets, using non-conflicting DWARF extensions from later standard versions is allowed anyway ๐ŸŒˆ.
  • -gno-strict-dwarf โ€” the opposite energy ๐Ÿฆ‹: it 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 can then use them so the assembler generates DWARF2+ line number tables for you ๐Ÿ“. This is usually the move, because assembler-generated line number tables are a LOT more compact than the ones the compiler can make itself ๐ŸคŒ. This option gets turned on 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 they're going to be generated at all ๐Ÿ› ๏ธ.
  • gas-locview-support โ€” tells the compiler the assembler supports "view" assignment and reset assertion checking in ".loc" directives ๐Ÿ‘€. This is enabled by default if the assembler was found to support them at GCC configure time ๐ŸŒŸ.
  • gno-as-locview-support โ€” forces GCC to assign view numbers internally, but only if -gvariable-location-views has been explicitly requested ๐Ÿซ .
  • -gcolumn-info, -gno-column-info โ€” emits location column information into the DWARF debug info, not just the file and line ๐Ÿ“. It's enabled by default ๐Ÿ’–.
  • -gstatement-frontiers, -gno-statement-frontiers โ€” this makes GCC drop markers into the internal representation at the beginning of statements ๐Ÿ“. It keeps them roughly in place all through compilation, and uses them to guide the output of "is_stmt" markers in the line number table ๐Ÿงญ. This is enabled by default when you compile with optimization (-Os, -O, -O2, ...) AND output DWARF 2 debug info at the normal level ๐ŸŽฏ.
  • -gvariable-location-views, -gvariable-location-views=incompat5, -gno-variable-location-views โ€” this one augments variable location lists with progressive view numbers, implied from the line number table ๐Ÿ”ข. The payoff is that debug info consumers can inspect state at certain points in the program, even when no instructions linked to those source locations exist there ๐Ÿ”โœจ. If the assembler doesn't support view numbers in line number tables, the compiler ends up emitting the line number table itself, which makes them somewhat less compact ๐Ÿ“‰. The augmented line number tables and location lists are fully backward-compatible, so consumers that don't know about these augmentations can still read them, they just won't get any benefit 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. Without assembler support it may still be enabled, but it forces GCC to output internal line number tables. And if -ginternal-reset-location-views isn't enabled, that will most certainly lead to silently mismatching location views ๐Ÿ’€.

Careful with -gvariable-location-views=incompat5! It's a proposed representation for view numbers that is NOT backward compatible with the location list format introduced in DWARF 5 โš ๏ธ. It may be removed in the future and is only provided as a reference implementation of the proposed representation ๐Ÿงช. Debug info consumers aren't expected to support this extended format, and they'd be unable to decode location lists that use it ๐Ÿ˜ญ.
  • -ginternal-reset-location-views, -gno-internal-reset-location-views โ€” this attempts to figure out which location views can be left out of location view lists ๐Ÿง. It requires the compiler to have very accurate instruction length estimates, which isn't always the case ๐Ÿ™ˆ. When using an assembler that doesn't support location view lists, it may silently generate incorrect view lists ๐Ÿ˜ฑ. The GNU assembler will flag any such error as a "view number mismatch". This is only enabled on ports that define a reliable estimation function ๐ŸŽ€.
  • -ginline-points, -gno-inline-points โ€” generates extended debug info for inlined functions โœจ. Location view tracking markers are inserted at inlined entry points, so address and view numbers can be computed and output in the debug info ๐Ÿ“. This can be enabled independently of location views, in which case the view numbers won't be output. It can ONLY be enabled along with statement frontiers, and it's only enabled by default if location views are enabled ๐Ÿฆ‹.
  • -gz[=type] โ€” okay so this one makes 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 โ€” bestie, this one only emits debug info for struct-like types when the base name of the compilation source file matches the base name of the file where the struct is defined ๐ŸŽ€ It substantially shrinks the debug info, but there's significant potential loss in type information for the debugger ๐Ÿ’€ See -femit-struct-debug-reduced for a less aggressive option, and -femit-struct-debug-detailed for more detailed control. This option works only with DWARF debug output.
  • -femit-struct-debug-reduced โ€” a middle-ground vibe โœจ It emits debug info for struct-like types only when the base name of the compilation source file matches the base name of the file where the type is defined, unless the struct is a template or defined in a system header. It significantly shrinks the debug info, with some potential loss in type information to the debugger. See -femit-struct-debug-baseonly for a more aggressive option, and -femit-struct-debug-detailed for more detailed control. This option works only with DWARF debug output.

-femit-struct-debug-detailed[=spec-list]

okay this is the detailed, customizable one ๐Ÿฆ‹ It lets you pick exactly which struct-like types get debug info. The whole point is to cut down on duplicate struct debug info between different object files in the same program ๐Ÿ’… It's a detailed version of -femit-struct-debug-reduced and -femit-struct-debug-baseonly, and it covers most needs.

A specification has the syntax:

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

The optional first word limits the spec to structs that are used directly (dir:) or used indirectly (ind:). A struct type is used directly when it's the type of a variable or member. Indirect uses come through pointers to structs. In other words, when using an incomplete struct is valid, the use is indirect. For example:

struct one direct;
struct two * indirect;

The optional second word limits the spec to ordinary structs (ord:) or generic structs (gen:). Generic structs are a bit tricky to explain ๐Ÿ™ˆ For C++, these are non-explicit specializations of template classes, or non-template classes within the above. Other programming languages have generics, but -femit-struct-debug-detailed does not yet implement them.

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

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

The default is -femit-struct-debug-detailed=all. This option 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 symbol output for types that are nowhere used in the source file being compiled ๐Ÿงน Sometimes you actually want debug info for every type declared in 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 โœจ

these options control various sorts of optimizations ๐Ÿ’–

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

Turning on optimization flags makes the compiler attempt to improve performance and/or code size, at the expense of compilation time and possibly your ability to debug the program ๐Ÿซถ

The compiler performs optimization based on what it knows about the program. Compiling multiple files at once to a single output file mode lets the compiler use info gathered from all the files when compiling each of them โœจ

Not all optimizations are controlled directly by a flag. Only optimizations that have a flag are listed in this section.

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

Depending on the target and how GCC was configured, a slightly different set of optimizations may be enabled at each -O level than the ones listed here. You can invoke GCC with -Q --help=optimizers to find out the exact set enabled at each level ๐Ÿ”

-O, -O1

Optimize ๐ŸŒธ Optimizing compilation takes somewhat more time, and a lot more memory for a large function.

With -O, the compiler tries to reduce code size and execution time, without performing any optimizations that take a great deal of compilation time.

-O turns on the following optimization flags:

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

-O2

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

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

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

-O3

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

-fgcse-after-reload -finline-functions -fipa-cp-clone
-floop-interchange -floop-unroll-and-jam -fpeel-loops
-fpredictive-commoning -fsplit-paths -ftree-loop-distribute-patterns
-ftree-loop-distribution -ftree-loop-vectorize -ftree-partial-pre
-ftree-slp-vectorize -funswitch-loops -fvect-cost-model
-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 the ones that often increase code size:

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

It also enables -finline-functions, causes the compiler to tune for code size rather than execution speed, and performs further optimizations designed to reduce code size ๐Ÿงธ

-Ofast

Disregard strict standards compliance ๐Ÿ‘‘ -Ofast enables all -O3 optimizations. It also enables optimizations that are not valid for all standard-compliant programs. It turns on -ffast-math and the Fortran-specific -fstack-arrays, unless -fmax-stack-var-size is specified, and -fno-protect-parens.

Heads up bestie โš ๏ธ -Ofast enables optimizations that are not valid for all standard-compliant programs, so only reach for it when you know your code can handle that ๐Ÿ˜ญ

-Og

Optimize debugging experience ๐Ÿฆ‹ -Og should be the optimization level of choice for the standard edit-compile-debug cycle. It offers a reasonable level of optimization while keeping compilation fast and the debugging experience good โœจ It's a better choice than -O0 for producing debuggable code, because some compiler passes that collect debug information are disabled at -O0.

Okay so -Og is lowkey the debugging girlie option ๐Ÿฆ‹ Like -O0, it completely turns off a bunch of optimization passes, so the individual options that control those passes do literally nothing ๐Ÿ’€ Otherwise -Og switches on every -O1 optimization flag EXCEPT the ones that could interfere with debugging ๐Ÿ” Those are:

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

Bestie, if you stack up multiple -O options, with or without level numbers, only the last one is the one that slays โœจ Everything before it gets ignored ๐Ÿ™ˆ

Options of the form -fflag are machine-independent flags ๐Ÿ’œ Most of them have a positive and a negative form, and the negative form of -ffoo is -fno-foo. In the list below, only one form is shown, the one you'll usually reach for. You can figure out the other one just by removing no- or adding it ๐Ÿซถ

These options control specific optimizations. They're either switched on by -O options or they're related to ones that are ๐ŸŒธ Only pull out these "fine-tuning" flags in the rare cases where you actually want to tweak which optimizations get performed ๐ŸŽ€

  • -fno-defer-pop โ€” On machines that have to pop arguments after a function call, this makes the compiler pop them the second each function returns. At -O1 and higher, -fdefer-pop is already the default, which lets arguments pile up on the stack across several function calls and get popped all at once ๐Ÿงน
  • -fforward-propagate โ€” Runs a forward propagation pass on RTL ๐Ÿ” It tries to combine two instructions and then checks whether the result can be simplified. If loop unrolling is active, two passes get performed, and the second one is scheduled after loop unrolling. This option is enabled by default at optimization levels -O, -O2, -O3, -Os.
  • -ffp-contract=style โ€” -ffp-contract=off disables floating-point expression contraction ๐Ÿšซ -ffp-contract=fast turns contraction on, like forming fused multiply-add operations if the target natively supports them ๐Ÿ”ฅ -ffp-contract=on turns contraction on only if the language standard allows it. Heads up, this one is currently not implemented and gets 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, skipping the instructions that save, set up and restore it โœ‚๏ธ On many targets this also frees up an extra register ๐Ÿ‘‘ On some targets this flag does nothing, because the standard calling sequence always uses a frame pointer, so it can't be omitted. Also, -fno-omit-frame-pointer doesn't guarantee the frame pointer gets used in all functions, since several targets always omit it in leaf functions. Enabled by default at -O and higher.
  • -foptimize-sibling-calls โ€” Optimizes sibling and tail recursive calls ๐Ÿฆ‹ Enabled at levels -O2, -O3, -Os.
  • -foptimize-strlen โ€” Optimizes various standard C string functions (e.g. strlen, strchr or strcpy) and their _FORTIFY_SOURCE counterparts into faster alternatives ๐ŸŽ๏ธ Enabled at levels -O2, -O3.
  • -fno-inline โ€” Doesn't expand any functions inline, except the ones marked with the always_inline attribute ๐Ÿ™…โ€โ™€๏ธ This is the default when you're not optimizing. If you want to exempt a single function from inlining, mark it with the noinline attribute.
  • -finline-small-functions โ€” Integrates functions into their callers when their body is smaller than the expected function call code, so the overall program size gets smaller ๐Ÿ“‰ The compiler heuristically decides which functions are simple enough to be worth it. This applies to ALL functions, even ones not declared inline. Enabled at levels -O2, -O3, -Os.
  • -findirect-inlining โ€” Inlines indirect calls that are discovered to be known at compile time, thanks to previous inlining ๐Ÿง  This option only has an effect when inlining itself is turned on by the -finline-functions or -finline-small-functions options. Enabled at levels -O2, -O3, -Os.
  • -finline-functions โ€” Considers all functions for inlining, even if they aren't declared inline ๐ŸŒˆ The compiler heuristically decides which ones are worth integrating. If all calls to a given function get integrated and the function is declared static, then it's normally not output as assembler code in its own right. Enabled at levels -O3, -Os. Also enabled by -fprofile-use and -fauto-profile.
  • -finline-functions-called-once โ€” Considers all static functions that get called once for inlining into their caller, even if they aren't marked inline ๐Ÿ’… If a call to a given function gets integrated, the function isn't output as assembler code on its own. Enabled at levels -O1, -O2, -O3 and -Os, but NOT -Og.
  • -fearly-inlining โ€” Inlines functions marked by always_inline, plus functions whose body seems smaller than the function call overhead, early on. This happens before the -fprofile-generate instrumentation and the real inlining pass โฉ Doing it this way makes profiling significantly cheaper and usually makes inlining faster on programs with big 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. The -finline-limit=n option sets some of them for you, like so:
    • max-inline-insns-single is set to n/2.
    • max-inline-insns-auto is set to n/2.

Check out the docs for the individual inlining parameters below for their defaults ๐Ÿ‘€

Note: there may be NO value of -finline-limit that gives you default behavior ๐Ÿ’€

Note: a "pseudo instruction" here is just an abstract measurement of a function's size ๐Ÿซ  It is in NO way 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, and it only applies to functions declared with the dllexport attribute or declspec ๐Ÿงš
  • -fkeep-inline-functions โ€” In C, emits static functions that are declared inline into the object file, even if they've been inlined into all of their callers ๐Ÿ“ฆ This switch doesn't affect functions using the extern inline extension in GNU C90. In C++, it emits any and all inline functions into the object file.
  • -fkeep-static-functions โ€” Emits static functions into the object file, even if they're never used ๐Ÿ—‚๏ธ
  • -fkeep-static-consts โ€” Emits variables declared static const when optimization isn't turned on, even if they aren't referenced ๐Ÿ‘€ GCC enables this option by default. If you want the compiler to check whether a variable is referenced no matter what optimization is on, use -fno-keep-static-consts.
  • -fmerge-constants โ€” Attempts to merge identical constants (string constants and floating-point constants) across compilation units ๐Ÿงฉ This is the default for optimized compilation if the assembler and linker support it. Use -fno-merge-constants to stop this from happening. Enabled at levels -O, -O2, -O3, -Os.
  • -fmerge-all-constants โ€” Attempts to merge identical constants AND identical variables ๐Ÿซฃ This option implies -fmerge-constants. On top of that, it also considers things like constant initialized arrays, or initialized constant variables with integral or floating-point types.
Big warning, bestie โš ๏ธ 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 it for standards-compliant code ๐Ÿšจ
  • -fmodulo-sched โ€” Performs swing modulo scheduling right before the first scheduling pass ๐ŸŒ€ It looks at innermost loops and reorders their instructions by overlapping different iterations.
  • -fmodulo-sched-allow-regmoves โ€” Performs more aggressive SMS-based modulo scheduling with register moves allowed ๐Ÿƒโ€โ™€๏ธ Setting this flag deletes certain anti-dependence edges, which triggers the generation of reg-moves based on life-range analysis. This option is only effective when -fmodulo-sched is enabled.
  • -fno-branch-count-reg โ€” Disables the optimization pass that hunts for chances to use "decrement and branch" instructions on a count register. The alternative is instruction sequences that decrement a register, compare it against zero, and then branch based on the result ๐Ÿ”ข This option only means something on architectures that support such instructions, which include x86, PowerPC, IA-64 and S/390. Note that -fno-branch-count-reg doesn't remove the decrement and branch instructions introduced by other optimization passes ๐Ÿ™ƒ The default is -fbranch-count-reg at -O1 and higher, except for -Og.
  • -fno-function-cse โ€” Doesn't put function addresses in registers. Instead, each instruction that calls a constant function contains the function's address explicitly ๐Ÿ“ This makes the code less efficient, but some strange hacks that alter the assembler output might get confused by the optimizations that happen when this option isn't used ๐Ÿงช The default is -ffunction-cse
  • -fno-zero-initialized-in-bss โ€” When the target supports a BSS section, GCC by default puts variables that are initialized to zero into BSS, which can save space in the resulting code ๐Ÿ’พ This option turns that behavior OFF, because some programs explicitly rely on variables going into the data section ๐Ÿงธ For example, the executable might want to find the beginning of that section and/or make assumptions based on it. The default is -fzero-initialized-in-bss.
  • -fthread-jumps

Okay so this one is about jump threading, bestie ๐Ÿงตโœจ. The compiler checks whether a jump lands somewhere that another comparison (one the first comparison already covers) gets tested. If it does, the first branch gets redirected either to the destination of the second branch or to the spot right after it, depending on whether the condition is known to be true or false. Main character optimization energy ๐Ÿ‘‘๐Ÿ’….

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

  • -fsplit-wide-types

Bestie, this one is for types that take up multiple registers, like long long on a 32-bit system ๐Ÿซถ. The registers get split apart and allocated independently. This usually gives better code for those types, but it can make debugging more difficult ๐Ÿ˜ญ. Lowkey a tradeoff, but the code is usually fire ๐Ÿ”ฅ.

Enabled at levels -O, -O2, -O3, -Os. ๐Ÿฆ‹

  • -fcse-follow-jumps

Common subexpression elimination (CSE) is giving detective ๐Ÿ•ต๏ธโ€โ™€๏ธ. When it runs into jump instructions, it scans through them as long as the jump's target isn't reached by any other path. Like, when CSE hits an if statement with an else clause, it follows the jump when the condition tested is false. It's giving efficiency, no cap ๐Ÿ’–.

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

  • -fcse-skip-blocks

This is basically the cousin of -fcse-follow-jumps ๐Ÿงš, but it targets jumps that conditionally skip over blocks. When CSE sees a simple if statement with no else clause, -fcse-skip-blocks tells it to follow the jump around the body of the if. Iconic behavior ๐Ÿ’….

Enabled at levels -O2, -O3, -Os. ๐ŸŽ€

  • -frerun-cse-after-loop

Okay, this one just runs common subexpression elimination again once the loop optimizations are done ๐Ÿ”๐ŸŒˆ. Second glow-up, bestie โœจ.

Enabled at levels -O2, -O3, -Os. ๐Ÿ“

  • -fgcse

This turns on a global common subexpression elimination pass ๐ŸŒ. It also handles global constant and copy propagation, so it's doing a lot of work behind the scenes ๐Ÿ’œ.

Heads up: if you're compiling a program that uses computed gotos (a GCC extension ๐Ÿ™ˆ), you might get better run-time performance by disabling this pass with -fno-gcse on the command line. Just something to keep in mind, fr fr ๐Ÿ’€.

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

  • -fgcse-lm

When -fgcse-lm is on, global common subexpression elimination tries to move loads that only get killed by stores into themselves ๐Ÿงฒ. This lets a loop with a load/store sequence become a load outside the loop and a copy/store inside it. Lowkey genius ๐Ÿซถ.

Enabled by default when -fgcse is enabled. ๐ŸŒธ

  • -fgcse-sm

When -fgcse-sm is enabled, a store motion pass runs after global common subexpression elimination โœจ. It tries to move stores out of loops. When it's used together with -fgcse-lm, loops containing a load/store sequence can become a load before the loop and a store after it. Store motion, but make it aesthetic ๐ŸŽ€.

Not enabled at any optimization level. ๐Ÿฅ€

  • -fgcse-las

When -fgcse-las is enabled, the global common subexpression elimination pass gets rid of redundant loads that come after stores to the same memory location ๐Ÿงน. That covers both partial and full redundancies. Decluttering era ๐ŸŒท.

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. Spring cleaning but for registers ๐ŸŒธ๐Ÿงผ.

Enabled by -fprofile-use and -fauto-profile. ๐Ÿฆ‹

  • -faggressive-loop-optimizations

This one tells the loop optimizer to use language constraints to figure out bounds for how many times a loop iterates ๐Ÿ”ข. It assumes that loop code does not invoke undefined behavior, like causing signed integer overflows or out-of-bound array accesses ๐Ÿšซ. Those bounds then guide loop unrolling, loop peeling, and loop exit test optimizations. This option is enabled by default, so you're already getting the glow-up ๐Ÿ‘‘โœจ.

  • -funconstrained-commons

This tells the compiler that variables declared in common blocks (for example, Fortran) might later get overridden with longer trailing arrays ๐Ÿ“. It stops certain optimizations that depend on knowing the array bounds, so it's a bit of a trade-off ๐Ÿ™ˆ.

  • -fcrossjumping

This performs the cross-jumping transformation ๐Ÿงฉ. It unifies equivalent code and saves code size, which is very low-key iconic ๐Ÿ’…. The resulting code may or may not perform better than without cross-jumping, so it's not a guaranteed win ngl ๐Ÿคทโ€โ™€๏ธ.

Enabled at levels -O2, -O3, -Os. ๐ŸŽ€

  • -fauto-inc-dec

This combines increments or decrements of addresses with memory accesses โž•๐Ÿง . The pass is always skipped on architectures that don't have instructions to support it. It's enabled by default at -O and higher on architectures that do support it ๐ŸŒˆ.

  • -fdce

This performs dead code elimination (DCE) on RTL ๐Ÿ—‘๏ธ. It's enabled by default at -O and higher, so it's basically on the reg ๐Ÿ’–.

  • -fdse

This performs dead store elimination (DSE) on RTL ๐Ÿงฝ. It's enabled by default at -O and higher. Clean girl energy, fr ๐Ÿซง.

  • -fif-conversion

This tries to transform conditional jumps into branch-less equivalents ๐ŸŒ€. That includes conditional moves, min, max, set flags, abs instructions, and some tricks you can do with standard arithmetic. Whether conditional execution gets used on chips that support it is controlled by -fif-conversion2 ๐Ÿ”—.

Enabled at levels -O, -O2, -O3, -Os, but not with -Og. ๐Ÿšซ๐Ÿฆ‹

  • -fif-conversion2

This uses conditional execution (where the hardware has it) to transform conditional jumps into branch-less equivalents ๐Ÿงšโ€โ™€๏ธ.

Enabled at levels -O, -O2, -O3, -Os, but not with -Og. ๐Ÿšซ๐ŸŒธ

  • -fdeclone-ctor-dtor

Okay, C++ ABI moment ๐Ÿค“. The 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 same function ๐Ÿ‘ฏโ€โ™€๏ธ. With this option, those base and complete variants become thunks that call a common implementation, so you're not stuck with duplicate copies. Smaller code, bestie ๐Ÿ’œ.

Enabled by -Os. ๐ŸŒท

  • -fdelete-null-pointer-checks

This assumes that programs cannot safely dereference null pointers, and that no code or data element lives at address zero ๐Ÿ™…โ€โ™€๏ธ. It enables simple constant folding optimizations at all optimization levels. Other GCC passes also use this flag to control global dataflow analyses that eliminate useless null pointer checks ๐Ÿงน. These assume that a memory access to address zero always results in a trap, so if a pointer gets checked after it's already been dereferenced, it can't be null ๐Ÿคฏ.

Note however that in some environments this assumption is not true. If your program depends on that behavior, use -fno-delete-null-pointer-checks to disable this optimization ๐Ÿšจ.

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

This tries to convert calls to virtual functions into direct calls ๐Ÿ“ž. It does this both within a procedure and interprocedurally, as part of indirect inlining (-findirect-inlining) and interprocedural constant propagation (-fipa-cp) ๐Ÿ”ฎ. Enabled at levels -O2, -O3, -Os. ๐Ÿฆ‹

  • -fdevirtualize-speculatively

This tries to convert 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 that set is small (ideally size 1), the call becomes a conditional that picks between a direct call and an indirect one ๐Ÿ”€. The speculative calls enable more optimizations, like inlining ๐Ÿ’–. If they seem useless after further optimization, they get converted back to their original form ๐Ÿ”™.

  • -fdevirtualize-at-ltrans

This streams extra information needed for aggressive devirtualization when the link-time optimizer runs in local transformation mode ๐Ÿ“ก. It enables more devirtualization, but it significantly increases the size of the streamed data ๐Ÿ“ˆ. Because of that, it's disabled by default ๐Ÿ˜ญ.

  • -fexpensive-optimizations

This performs a bunch of minor optimizations that are relatively expensive โณ. Enabled at levels -O2, -O3, -Os. ๐ŸŽ€

  • -free

This attempts to remove redundant extension instructions โœ‚๏ธ. It's especially helpful for the x86-64 architecture, which implicitly zero-extends 64-bit registers after writing to their lower 32-bit half ๐Ÿง .

Enabled for Alpha, AArch64 and x86 at levels -O2, -O3, -Os. ๐ŸŒˆ

  • -fno-lifetime-dse

In C++, an object's value is only affected by changes within its lifetime ๐Ÿ’ญ. When the constructor begins, the object has an indeterminate value, and any changes made during its lifetime are dead once the object is destroyed ๐Ÿ’€. Normally dead store elimination takes advantage of this. If your code relies on the value of the object storage sticking around after the object's lifetime ends, you can use this flag to turn the optimization off ๐Ÿ›‘. To keep stores made before the constructor starts (for example, 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

This attempts to decrease register pressure through register live range shrinkage ๐Ÿง˜โ€โ™€๏ธ. It's helpful for fast processors with small or moderate-sized register sets ๐ŸŽ๏ธ.

  • -fira-algorithm=algorithm

This picks the coloring algorithm used by the integrated register allocator ๐ŸŽจ. The algorithm argument can be priority, which specifies Chow's priority coloring, or CB, which specifies Chaitin-Briggs coloring ๐Ÿ–Œ๏ธ. Chaitin-Briggs coloring isn't implemented for every architecture, but for targets that do support it, it's the default because it generates better code ๐Ÿ‘‘.

  • -fira-region=region

This picks which regions the integrated register allocator uses ๐Ÿ—บ๏ธ. The region argument should be one of the following:

  • all โ€” Uses all loops as register allocation regions. This can give the best results for machines with a small and/or irregular register set ๐Ÿงฉ.
  • mixed โ€” Uses all loops except for loops with small register pressure as the regions. This value usually gives the best results in most cases and for most architectures, and it's enabled by default when compiling with optimization for speed (-O, -O2, ...) ๐Ÿ’–.
  • one โ€” Uses all functions as a single region. This typically results in the smallest code size, and it's enabled by default for -Os or -O0 ๐ŸŒธ.
  • -fira-hoist-pressure โ€” okay so this one tells IRA to check register pressure during the code hoisting pass when it's deciding whether to hoist expressions ๐Ÿง  It usually gives you smaller code, but the compiler can slow down because of it ๐Ÿข Enabled at level -Os for all targets ๐Ÿ’…
  • -fira-loop-pressure โ€” this one has IRA look at register pressure inside loops when it's deciding whether to move loop invariants ๐Ÿ” It usually gives faster and smaller code on machines with large register files (>= 32 registers), but the compiler can slow down ๐ŸŒ Enabled at level -O3 for some targets ๐Ÿฆ‹
  • -fno-ira-share-save-slots โ€” the bestie-unfriendly option ๐Ÿ™ˆ It turns OFF sharing of stack slots used for saving 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 โ€” same energy, different slots ๐Ÿ’œ This disables sharing of stack slots for pseudo-registers. Every pseudo-register that doesn't get a hard register gets its own stack slot, and yep, the stack frames get bigger too ๐Ÿ˜ญ
  • -flra-remat โ€” this one is giving CFG-sensitive rematerialization inside LRA โœจ Instead of loading values of spilled pseudos, LRA tries to rematerialize (recalculate) them if it's profitable. Enabled at levels -O2, -O3, -Os ๐ŸŒธ
  • -fdelayed-branch โ€” if the target machine supports it, the compiler will try to reorder instructions so they fill the instruction slots available after delayed branch instructions ๐Ÿงš Enabled at levels -O, -O2, -O3, -Os, but not at -Og ๐Ÿšซ

  • -fschedule-insns โ€” if the target supports it, the compiler reorders instructions to get rid of execution stalls caused by required data not being ready yet ๐Ÿ”ฅ This is a lifesaver for machines with slow floating point or memory load instructions, because other instructions can get issued while the load or floating-point result is still cooking ๐Ÿณ Enabled at levels -O2, -O3 ๐Ÿ‘‘
  • -fschedule-insns2 โ€” basically the sequel to -fschedule-insns ๐ŸŽ€ It asks for an additional pass of instruction scheduling after register allocation is done. It's especially iconic on machines with a relatively small number of registers where memory load instructions take more than one cycle โญ Enabled at levels -O2, -O3, -Os ๐Ÿ’–
  • -fno-sched-interblock โ€” disables instruction scheduling across basic blocks. Normally this is on when scheduling happens before register allocation, which means with -fschedule-insns or at -O2 or higher ๐Ÿ™…โ€โ™€๏ธ
  • -fno-sched-spec โ€” disables speculative motion of non-load instructions. Normally this is enabled 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 scheduling before register allocation is enabled, 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 going above the number of available hard registers, which would otherwise mean spills during register allocation ๐Ÿง˜โ€โ™€๏ธ
  • -fsched-spec-load โ€” allows speculative motion of some load instructions ๐Ÿ‘€ This only makes sense when scheduling before register allocation, i.e. with -fschedule-insns or at -O2 or higher ๐ŸŒˆ
  • -fsched-spec-load-dangerous โ€” allows speculative motion of more load instructions ๐Ÿ˜ฌ Same deal: it only makes sense when scheduling before register allocation, i.e. with -fschedule-insns or at -O2 or higher ๐Ÿ’€
  • -fsched-stalled-insns, -fsched-stalled-insns=n โ€” this sets how many insns (if any) can get moved early from the queue of stalled insns into the ready list during the second scheduling pass ๐Ÿš€ -fno-sched-stalled-insns means no insns get moved early. -fsched-stalled-insns=0 means there's no limit on how many queued insns 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 โ€” this defines how many insn groups (cycles) get checked for a dependency on a stalled insn that's a candidate for being moved early ๐Ÿ” It only has an effect during the second scheduling pass, and only if -fsched-stalled-insns is used. -fno-sched-stalled-insns-dep is the same as -fsched-stalled-insns-dep=0. -fsched-stalled-insns-dep without a value is the same as -fsched-stalled-insns-dep=1 ๐Ÿฆ‹
  • -fsched2-use-superblocks โ€” when scheduling after register allocation, this uses superblock scheduling ๐Ÿงƒ That lets motion happen across basic block boundaries, which can give you faster schedules. โš ๏ธ This option is experimental, because not all machine descriptions used by GCC model the CPU closely enough to avoid unreliable results from the algorithm ๐Ÿ™ƒ
โš ๏ธ Heads up bestie: -fsched2-use-superblocks is experimental, and some machine descriptions don't model the CPU closely enough, so the results can be unreliable. Use with caution ๐Ÿ’€

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 ๐Ÿ‘ฏ It favors the instruction that belongs to a schedule group. This is enabled 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 ๐Ÿ›ฃ๏ธ It favors instructions that sit on the critical path. This is enabled 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 ๐ŸŽฒ It favors speculative instructions with greater dependency weakness. This is enabled by default when scheduling is enabled, i.e. with -fschedule-insns or -fschedule-insns2 or at -O2 or higher ๐ŸŒธ
  • -fsched-rank-heuristic โ€” enables the rank heuristic in the scheduler ๐Ÿ“Š It favors the instruction belonging to a basic block with greater size or frequency. This is enabled 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 ๐ŸŽฏ It favors the instruction that is less dependent on the last instruction scheduled. This is enabled 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 ๐Ÿงฎ It favors the instruction that has more instructions depending on it. This is enabled 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. Use this option to 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 too ๐Ÿช„ This time it runs instead of the second scheduler pass ๐Ÿ’ซ
  • -fsel-sched-pipelining โ€” enables software pipelining of innermost loops during selective scheduling ๐Ÿฅ This has no effect unless -fselective-scheduling or -fselective-scheduling2 is turned on ๐Ÿ™„
  • -fsel-sched-pipelining-outer-loops โ€” when pipelining loops during selective scheduling, this also pipelines the outer loops too ๐Ÿช† It 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 for symbols exported from the DSO, the compiler can't do interprocedural propagation, inlining, and other optimizations, because the function or variable might get swapped out for something else ๐Ÿ”€ It's useful, like if you want to rewrite memory allocation functions with a debugging implementation, but it's expensive when it comes to code quality ๐Ÿ’ธ With -fno-semantic-interposition, the compiler assumes that if interposition happens for functions, the overwriting function will have precisely the same semantics (and side effects). Similarly, if interposition happens for variables, the constructor of the variable will be the same ๐Ÿค The flag has no effect for functions explicitly declared inline (where it's never allowed for interposition 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 top of the function ๐ŸŽ This flag is enabled by default at -O and higher ๐Ÿฅฐ
  • -fshrink-wrap-separate โ€” shrink-wraps separate parts of the prologue and epilogue separately, so those parts only run when they're needed ๐Ÿงผ This option is on by default, but it has no effect unless -fshrink-wrap is also turned on and the target supports this ๐ŸŒ€
  • -fcaller-saves โ€” enables allocation of values to registers that get clobbered by function calls ๐Ÿ’… It does this by emitting extra instructions to save and restore the registers around those calls. This allocation only happens when it seems to result in better code ๐Ÿฅ‡ This option is always enabled by default on certain machines, usually the ones with no call-preserved registers to use instead ๐ŸŒˆ Enabled at levels -O2, -O3, -Os ๐ŸŽ€
  • -fcombine-stack-adjustments โ€” tracks stack adjustments (pushes and pops) and stack memory references, then tries to find ways to combine them ๐Ÿงบ Enabled by default at -O1 and higher ๐Ÿ’–
  • -fipa-ra โ€” uses caller save registers for allocation if those registers aren't used by any called function ๐Ÿง‘โ€๐Ÿคโ€๐Ÿง‘ That means they don't need to be saved and restored around calls. This is only possible if the called functions are part of the same compilation unit as the current function and they're compiled before it ๐Ÿ“š Enabled at levels -O2, -O3, -Os, however the option is disabled if the generated code will be instrumented for profiling (-p, or -pg), or if the callee's register usage can't be known exactly (this happens on targets that don't expose prologues and epilogues in RTL) ๐Ÿ˜ญโœจ

-fconserve-stack Okay so this one is for when you want the compiler to be stingy with stack space ๐Ÿฅบ๐Ÿงš It tries to use less stack, even if your program ends up running a little slower. This option also sets 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 Okay bestie, code hoisting is so iconic ๐Ÿ‘‘ It tries to move the evaluation of expressions that run on every path to the function exit as early as possible. It's especially useful as a code size optimization, but it often helps code speed too. Enabled by default at -O2 and higher. ๐Ÿฆ‹

-ftree-pre Performs partial redundancy elimination (PRE) on trees. Enabled by default at -O2 and -O3. ๐Ÿ’–

-ftree-partial-pre Makes partial redundancy elimination (PRE) more aggressive. Enabled by default at -O3. ๐Ÿ”ฅ

-ftree-forwprop Performs forward propagation on trees. Enabled by default at -O and higher. ๐ŸŒธ

-ftree-fre Performs full redundancy elimination (FRE) on trees. The difference between FRE and PRE is that FRE only considers expressions that are computed on all paths leading to the redundant computation. FRE 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 if the loads come from adjacent locations in the same structure and the target architecture has a conditional move instruction. Enabled by default at -O2 and higher. ๐Ÿ™ˆ

-ftree-copy-prop Performs copy propagation on trees. This pass gets rid of unnecessary copy operations. Enabled by default at -O and higher. ๐Ÿงš

-fipa-pure-const Discovers which functions are pure or constant. Enabled by default at -O and higher. ๐Ÿ’œ

-fipa-reference Discovers which static variables do not 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 if possible. Enabled by default. ๐Ÿ’…

-fipa-pta Performs interprocedural pointer analysis and interprocedural modification and reference analysis. Warning, bestie ๐Ÿ’€ This option can cause excessive memory and compile-time usage on large compilation units. It is not enabled by default at any optimization level. ๐Ÿ˜ญ

-fipa-profile Performs interprocedural profile propagation. Functions called only from cold functions are marked as cold, and functions executed once (such as "cold", "noreturn", static constructors or destructors) are 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 optimization figures 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. 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 externally visible functions that can be called with constant arguments. Because this can create multiple copies of functions, it may significantly increase code size (see --param ipcp-unit-growth=value). 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. Enabled by default at -O2 and by -fprofile-use and -fauto-profile. It requires that -fipa-cp is enabled. ๐Ÿงš

-fipa-vrp When enabled, performs interprocedural propagation of value ranges. Enabled by default at -O2. It requires that -fipa-cp is enabled. ๐Ÿ“

-fipa-icf Performs Identical Code Folding for functions and read-only variables. The optimization reduces code size and may disturb unwind stacks by replacing a function with an equivalent one that has a different name. It works more effectively with link-time optimization enabled. ๐Ÿซถ

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

Enabled by default at -O2 and -Os. ๐Ÿ’–

-flive-patching=level Controls GCC's optimizations so the output is suitable for live-patching. ๐Ÿฆ‹

If the compiler's optimization uses a function's body, or information pulled from its body, to optimize or change another function, the latter is called an impacted function of the former. If a function is patched, its impacted functions should be patched too. ๐ŸŒˆ

The impacted functions are decided by the compiler's interprocedural optimizations. For example, a caller is impacted when a function is 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 information is extracted to optimize its direct or indirect callers, and so on. ๐Ÿ’…

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

The level argument should be one of the following: โœจ

  • inline-clone โ€” Only enables inlining and cloning optimizations, which includes inlining, cloning, interprocedural scalar replacement of aggregates and partial inlining. As a result, when patching a function, all its callers and its clones' callers are impacted, so they need to be patched as well. -flive-patching=inline-clone disables the following optimization flags: -fwhole-program -fipa-pta -fipa-reference -fipa-ra -fipa-icf -fipa-icf-functions -fipa-icf-variables -fipa-bit-cp -fipa-vrp -fipa-pure-const -fipa-reference-addressable -fipa-stack-alignment ๐ŸŽ€
  • inline-only-static โ€” Only enables inlining of static functions. As a result, when patching a static function, all its callers are impacted and so they need to be patched as well. In addition to all the flags that -flive-patching=inline-clone disables, -flive-patching=inline-only-static disables the following additional optimization flags: -fipa-cp-clone -fipa-sra -fpartial-inlining -fipa-cp ๐Ÿงš

When -flive-patching is specified without any value, the default value is inline-clone. ๐Ÿ“

This flag is disabled by default. ๐Ÿ’€

Note, bestie: -flive-patching is not supported with link-time optimization (-flto). ๐Ÿ˜ญ

-fisolate-erroneous-paths-dereference Detects paths that trigger erroneous or undefined behavior due to dereferencing a null pointer. It isolates those paths from the main control flow and turns the statement with erroneous or undefined behavior into a trap. 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 due to a null value being 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 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 in order to simplify the definitions. For example, this pass strips sign operations if the sign of a value never matters. Enabled by default at -O and higher. ๐Ÿฆ‹

-fssa-phiopt Performs pattern matching on SSA PHI nodes to optimize conditional code. This pass is enabled by default at -O1 and higher, except for -Og. ๐Ÿ’…

-ftree-switch-conversion Performs conversion of simple initializations in a switch to initializations from a scalar array. Enabled by default at -O2 and higher. ๐ŸŽ€

-ftree-tail-merge Looks for identical code sequences. When found, replaces one with a jump to the other. This optimization is known as tail merging or cross jumping. Enabled by default at -O2 and higher. The compilation time in this pass can be limited using the max-tail-merge-comparisons parameter and the max-tail-merge-iterations parameter. ๐ŸŒธ

-ftree-dce Performs dead code elimination (DCE) on trees. Enabled by default at -O and higher. ๐Ÿซถ

-ftree-builtin-call-dce Performs conditional dead code elimination (DCE) for calls to built-in functions that may set errno but are otherwise free of side effects. Enabled by default at -O2 and higher if -Os is not also specified. ๐Ÿ’–

  • -ftree-dominator-opts โ€” okay bestie, this one is a whole vibe ๐Ÿ’… It does a bunch of simple scalar cleanups (constant/copy propagation, redundancy elimination, range propagation and expression simplification) by walking a dominator tree โœจ It also does jump threading, which cuts down on jumps that just lead to other jumps ๐Ÿฆ‹ Enabled 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 another store overwrites later, with no loads in between. In that case the earlier store can be deleted ๐Ÿ’€ Enabled by default at -O and higher.
  • -ftree-ch โ€” loop header copying on trees ๐ŸŒธ It's super beneficial because it makes code motion optimizations way more effective, and it also saves one jump ๐Ÿซถ Enabled by default at -O and higher. It's not enabled for -Os, since it usually bloats code size ๐Ÿ˜ญ
  • -ftree-loop-optimize โ€” loop optimizations on trees ๐Ÿ” Enabled by default at -O and higher.
  • -ftree-loop-linear, -floop-strip-mine, -floop-block โ€” loop nest optimizations, same as -floop-nest-optimize ๐Ÿงฑ To use this transformation, GCC has to be configured with --with-isl so the Graphite loop transformation infrastructure gets switched on โš™๏ธ
  • -fgraphite-identity โ€” the identity transformation for graphite ๐Ÿชž For every SCoP, GCC generates the polyhedral representation and then transforms it back to GIMPLE. With this you can check the costs or benefits of the GIMPLE -> GRAPHITE -> GIMPLE round trip ๐Ÿ” Some minimal optimizations also happen in the isl code generator, like index splitting and dead code elimination in loops ๐Ÿงน
  • -floop-nest-optimize โ€” the isl-based loop nest optimizer ๐Ÿง  It's a generic one based on the Pluto optimization algorithms, and it calculates a loop structure optimized for data locality and parallelism ๐ŸŒˆ This option is experimental ๐Ÿงช
  • -floop-parallelize-all โ€” uses Graphite data dependence analysis to find loops that can be parallelized ๐Ÿงต It parallelizes all the loops that can be analyzed to not contain loop carried dependences, without checking whether parallelizing them is actually profitable ๐Ÿซ 
  • -ftree-coalesce-vars โ€” when transforming the program out of SSA representation, it tries to reduce copying by coalescing versions of different user-defined variables, not just compiler temporaries โœจ
Heads up: this may severely limit your ability to debug an optimized program compiled with -fno-var-tracking-assignments ๐Ÿ˜ญ

In the negated form, this flag prevents SSA coalescing of user variables. It's enabled by default if optimization is enabled, and it does very little otherwise ๐Ÿ’ค

  • -ftree-loop-if-convert โ€” 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 ๐Ÿฆ‹ Enabled by default if vectorization is enabled.
  • -ftree-loop-distribution โ€” performs loop distribution ๐Ÿฐ It can improve cache performance on big loop bodies and lets further loop optimizations, like parallelization or vectorization, take place. For example, this loop:
DO I = 1, N
  A(I) = B(I) + C
  D(I) = E(I) * F
ENDDO

gets split into this:

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 -O3, and by -fprofile-use and -fauto-profile ๐Ÿ’–

This pass distributes the initialization loops and generates a call to memset zero. For example, this loop:

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

gets split into this:

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

and the initialization loop gets turned into a call to memset zero ๐Ÿงน This flag is enabled by default at -O3. It's also enabled by -fprofile-use and -fauto-profile ๐ŸŒธ

  • -floop-interchange โ€” loop interchange outside of graphite ๐Ÿ”„ This flag can improve cache performance on loop nests and let further loop optimizations, like vectorization, take place. For example, this nest:
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];

gets swapped into this:

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, it unrolls the outer loop by some factor and fuses the resulting multiple inner loops together. Enabled by default at -O3. It's also enabled by -fprofile-use and -fauto-profile ๐Ÿ”ฅ
  • -ftree-loop-im โ€” loop invariant motion on trees ๐Ÿšš This pass only moves the invariants that are hard to handle at the RTL level (function calls, operations that expand to nontrivial sequences of insns) ๐Ÿง With -funswitch-loops it also moves operands of conditions that are invariant out of the loop, so 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 out the iteration count takes complicated analysis ๐Ÿ”ข Later optimizations can then determine the number easily. It's especially useful together 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, as long as it's sufficiently cheap โœจ This reduces data dependencies and may allow further simplifications. Enabled by default at -O and higher.
  • -fivopts โ€” 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. The optimization is only profitable on multiprocessor machines, and only for CPU-intensive loops rather than ones constrained by things like memory bandwidth ๐Ÿ’ช This option implies -pthread, so it's only supported on targets that have support for -pthread ๐Ÿงต
  • -ftree-pta โ€” function-local points-to analysis on trees ๐ŸŽฏ Enabled by default at -O1 and higher, except for -Og ๐Ÿ’–
  • -ftree-sra โ€” scalar replacement of aggregates ๐Ÿงฉ This pass swaps structure references out for scalars so structures don't get committed to memory too early ๐Ÿง  Enabled by default at -O1 and higher, except for -Og ๐Ÿ’…
  • -fstore-merging โ€” merges narrow stores to consecutive memory addresses ๐Ÿซง It combines contiguous stores of immediate values that are narrower than a word into fewer, wider stores, which cuts down on the number of instructions ๐Ÿ“‰ Enabled by default at -O2 and higher, as well as -Os ๐ŸŒธ
  • -ftree-ter โ€” temporary expression replacement during the SSA->normal phase ๐Ÿชƒ Single use/single def temporaries get replaced at their use location with their defining expression. This results in non-GIMPLE code, but it gives the expanders much more complex trees to work on, which leads to better RTL generation ๐ŸคŒ Enabled by default at -O and higher.
  • -ftree-slsr โ€” straight-line strength reduction on trees ๐Ÿ“ It recognizes related expressions involving multiplications and replaces them with cheaper calculations when possible โœจ Enabled by default at -O and higher.
  • -ftree-vectorize โ€” vectorization on trees ๐Ÿš€ This flag enables -ftree-loop-vectorize and -ftree-slp-vectorize if they aren't explicitly specified ๐Ÿซถ
  • -ftree-loop-vectorize โ€” loop vectorization on trees ๐ŸŽ€ Enabled by default at -O3, and by -ftree-vectorize, -fprofile-use, and -fauto-profile ๐Ÿ‘‘
  • -ftree-slp-vectorize โ€” basic block vectorization on trees ๐ŸŒˆ Enabled by default at -O3, and by -ftree-vectorize, -fprofile-use, and -fauto-profile โญ
  • -fvect-cost-model=model โ€” alters the cost model used for vectorization ๐Ÿ’ฐ The model argument should be one of the following:
    • unlimited โ€” the vectorized code path is assumed to be profitable ๐Ÿš€
    • dynamic โ€” a runtime check guards the vectorized code path, so it only gets enabled for iteration counts that will likely run faster than the original scalar loop ๐Ÿง 
    • cheap โ€” disables vectorization of loops where doing so would be cost-prohibitive, for example because of required runtime checks for data dependence or alignment. Otherwise it's equal to dynamic ๐Ÿซง

The default cost model depends on other optimization flags and is either dynamic or cheap ๐Ÿคทโ€โ™€๏ธ

  • -fsimd-cost-model=model โ€” alters the cost model used for vectorization of loops marked with the OpenMP simd directive ๐Ÿ’œ The model argument should be one of unlimited, dynamic, or cheap. All values of model have the same meaning as described in -fvect-cost-model, and by default a cost model defined with -fvect-cost-model is used ๐Ÿฆ‹
  • -ftree-vrp: okay so this one does Value Range Propagation on trees ๐ŸŒณ๐Ÿ’– It's giving constant propagation vibes, except instead of tracking single values, it tracks whole ranges of values ๐Ÿฆ‹ That lets the optimizers delete unnecessary range checks like array bound checks and null pointer checks ๐Ÿ™ˆ It's on by default at -O2 and higher โœจ

Heads up tho: null pointer check elimination only happens if -fdelete-null-pointer-checks is enabled ๐Ÿ‘€

  • -fsplit-paths: this one splits the paths leading to loop backedges ๐Ÿ›ค๏ธ It can level up dead code elimination and common subexpression elimination ๐Ÿงน It's enabled by default at -O3 and above ๐Ÿ‘‘
  • -fsplit-ivs-in-unroller: this lets the compiler express the values of induction variables in later iterations of an unrolled loop using the value from the first iteration ๐Ÿง  That breaks up long dependency chains, which makes the scheduling passes more efficient ๐Ÿš€

Using -fweb and CSE together is often enough to get the same effect ๐Ÿซถ But that's not reliable when the loop body is more complicated than a single basic block ๐Ÿ’€ It also 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: with this on, the compiler makes multiple copies of some local variables when it unrolls a loop, and that can lead to superior code ๐ŸŒˆ
  • -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: this performs predictive commoning, which means reusing computations (especially memory loads and stores) from previous iterations of loops ๐Ÿ”๐Ÿ’œ

It's enabled at level -O3, and it's also enabled by -fprofile-use and -fauto-profile ๐Ÿ”ฅ

  • -fprefetch-loop-arrays: if the target machine supports it, the compiler generates instructions to prefetch memory, which can boost loops that access large arrays ๐Ÿƒโ€โ™€๏ธ

Fair warning: this might produce better code 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: okay this one is kinda wild ๐Ÿคฏ It stops GCC from substituting constants for the known return value of formatted output functions like sprintf, snprintf, vsprintf, and vsnprintf (but not printf or fprintf) ๐Ÿšซ

The transformation is what lets GCC optimize or even eliminate branches based on the known return value of these functions, as long as the arguments are either constant or have values known to be in a range that makes the exact return value figurable out ๐Ÿ”ฎ For example, when -fprintf-return-value is in effect, both the branch and the body of the if statement (but not the call to snprint) can be optimized away when i is a 32-bit or smaller integer, because the return value is guaranteed to be at most 8 ๐Ÿ’…

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

The -fprintf-return-value option relies on other optimizations and gives the best results with -O2 and above ๐Ÿ† It works in tandem with -Wformat-overflow and -Wformat-truncation ๐Ÿซถ The -fprintf-return-value option is enabled by default ๐Ÿ’–

  • -fno-peephole, -fno-peephole2: these disable any machine-specific peephole optimizations ๐Ÿ™…โ€โ™€๏ธ The difference between -fno-peephole and -fno-peephole2 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: do not guess branch probabilities using heuristics ๐Ÿง ๐Ÿšซ

GCC uses heuristics to guess branch probabilities when they aren't provided by profiling feedback (-fprofile-arcs) ๐Ÿ” These heuristics are based on the control flow graph ๐Ÿ—บ๏ธ If some branch probabilities are specified by __builtin_expect, the heuristics guess the rest of the control flow graph while taking the __builtin_expect info into account ๐ŸŽฏ The interactions between the heuristics and __builtin_expect can get messy ๐Ÿ˜ตโ€๐Ÿ’ซ so in some cases it's useful to turn the heuristics off, so the effects of __builtin_expect are easier to understand ๐Ÿซถ

You can also specify the expected probability of an expression with the __builtin_expect_with_probability built-in function ๐Ÿ”ฎ

The default is -fguess-branch-probability at levels -O, -O2, -O3, -Os ๐Ÿ’…

  • -freorder-blocks: reorders basic blocks in the compiled function to reduce the number of taken branches and improve code locality ๐Ÿงบ

Enabled at levels -O, -O2, -O3, -Os โœจ

  • -freorder-blocks-algorithm=algorithm: picks the algorithm used for basic block reordering ๐Ÿงฉ The algorithm argument can be simple, which doesn't increase code size (except sometimes because of secondary effects like alignment) ๐Ÿง˜โ€โ™€๏ธ or stc, the "software trace cache" algorithm ๐ŸŒŸ That one puts all the often-executed code together and minimizes the number of branches executed by making extra copies of code ๐Ÿ’ฅ

The default is simple at levels -O, -Os, and stc at levels -O2, -O3 ๐Ÿ‘‘

  • -freorder-blocks-and-partition: on top of reordering basic blocks to cut down on taken branches, this one partitions hot and cold basic blocks into separate sections of the assembly and .o files ๐Ÿ”ฅ๐ŸงŠ That helps paging and cache locality performance ๐Ÿš€

This optimization is automatically turned off when there's exception handling or unwind tables (on targets using setjump/longjump or a target specific scheme), for linkonce sections, for functions with a user-defined section attribute, and on any architecture that doesn't support named sections ๐Ÿ™…โ€โ™€๏ธ When -fsplit-stack is used, this option isn't enabled by default (to avoid linker errors), but you can enable it explicitly if you're using a working linker ๐Ÿ”ง

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

  • -freorder-functions: reorders functions in the object file to improve code locality ๐Ÿ—‚๏ธ This is done with special subsections, .text.hot for the most frequently executed functions and .text.unlikely for unlikely executed ones ๐ŸŒก๏ธ The reordering is done by the linker, so the object file format must support named sections and the linker must place them in a reasonable way ๐Ÿซถ

This option isn't effective unless you either provide profile feedback (see -fprofile-arcs for details) or manually annotate functions with hot or cold attributes ๐ŸŽ€

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

  • -fstrict-aliasing: this lets the compiler assume the strictest aliasing rules that apply to the language being compiled ๐Ÿง For C (and C++), it turns on optimizations based on the type of expressions ๐Ÿง  An object of one type is assumed never to live at the same address as an object of a different type, unless the types are almost the same ๐Ÿ™ƒ For example, an unsigned int can alias an int, but not a void* or a double ๐Ÿšซ A character type may alias any other type ๐ŸŒˆ

Pay special attention to code like this ๐Ÿ‘€

union a_union {
  int i;
  double d;
};

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

Reading from a different union member than the one most recently written to (called "type-punning") is super common ๐Ÿซ  Even with -fstrict-aliasing, type-punning is allowed, as long as the memory is accessed through the union type ๐Ÿ™Œ So the code above works as expected ๐Ÿ’… However, this code might not ๐Ÿ˜ฌ

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

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

int f() {
  double d = 3.0;
  return ((union a_union *) &d)->i;
}

The -fstrict-aliasing option is enabled at levels -O2, -O3, -Os ๐ŸŽ€

  • -falign-functions, -falign-functions=n, -falign-functions=n:m, -falign-functions=n:m:n2, -falign-functions=n:m:n2:m2: this aligns the start of functions to the next power-of-two greater than n, skipping up to m-1 bytes ๐Ÿ“ That 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, and -falign-functions=32:7 aligns to the next 32-byte boundary only if this can be done by skipping 6 bytes or less ๐Ÿงฎ

The second pair of n2:m2 values lets you specify a secondary alignment: -falign-functions=64:7:32:3 aligns to the next 64-byte boundary if this can be done by skipping 6 bytes or less, otherwise it aligns to the next 32-byte boundary if this can be done by skipping 2 bytes or less ๐Ÿช„ If m2 isn't specified, it defaults to n2 ๐Ÿ’–

Some assemblers only support this flag when n is a power of two; in that case, it gets rounded up ๐Ÿ”ผ

-fno-align-functions and -falign-functions=1 are equivalent and mean that functions are not aligned ๐Ÿ™…โ€โ™€๏ธ

If n isn't specified or is zero, the compiler uses a machine-dependent default ๐Ÿ–ฅ๏ธ The maximum allowed n value is 65536 ๐Ÿ’ฏ

Enabled at levels -O2, -O3 โœจ

  • -flimit-function-alignment: when this is enabled, the compiler tries to avoid unnecessarily overaligning functions ๐Ÿ™…โ€โ™€๏ธ It attempts to instruct the assembler to align by the amount specified by -falign-functions, but it won't skip more bytes than the size of the function ๐Ÿ“ not overdoing it, iconic ๐Ÿ’œ
  • -falign-labels, -falign-labels=n, -falign-labels=n:m, -falign-labels=n:m:n2, -falign-labels=n:m:n2:m2: this aligns all branch targets to a power-of-two boundary ๐ŸŽฏ

The parameters of this option are analogous to the -falign-functions option ๐Ÿชž -fno-align-labels and -falign-labels=1 are equivalent and mean that labels are not aligned ๐Ÿ™ˆ

If -falign-loops or -falign-jumps apply and their values are greater than this one, then those get used instead, bestie ๐Ÿ’…

If n is not specified or is zero, the machine picks its own default, which is very likely 1 (aka no alignment at all) ๐Ÿ™ˆ The maximum allowed n option value is 65536 โœจ

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


-falign-loops

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

Okay so this one aligns loops to a power-of-two boundary ๐Ÿฆ‹ If the loops run a ton of times, the dummy padding instructions are totally worth it, because the speedup makes up for them ๐Ÿ”ฅ

The parameters work exactly like the ones for -falign-functions, so it's giving dรฉjร  vu ๐Ÿ’œ -fno-align-loops and -falign-loops=1 are equivalent and mean that loops are not aligned. The maximum allowed n option value is 65536.

If n is not specified or is zero, the machine-dependent default takes over ๐Ÿงš

Enabled at levels -O2, -O3 โœจ


-falign-jumps

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

This one aligns branch targets to a power-of-two boundary ๐ŸŒˆ It's specifically for branch targets that can only be reached by jumping. Since they're only reached by jumping, no dummy operations need to run, which is so efficient ๐Ÿ˜ญ

Again, 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 is not specified or is zero, the machine-dependent default is used. The maximum allowed n option value is 65536.

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


-funit-at-a-time

This one is kept around purely for compatibility reasons, so it's basically a legacy icon ๐Ÿ‘‘ -funit-at-a-time has no effect ๐Ÿ™ƒ Meanwhile, -fno-unit-at-a-time implies -fno-toplevel-reorder and -fno-section-anchors.

Enabled by default ๐Ÿ’…


-fno-toplevel-reorder

Do not reorder top-level functions, variables, and asm statements. Everything comes out in the same order it appeared in the input file ๐Ÿ“œ When this is used, unreferenced static variables are not removed.

This one exists to support existing code that relies on a specific ordering. For new code, it's better to use attributes when possible ๐Ÿฆ‹

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


-fweb

This constructs webs, which are commonly used for register allocation purposes, and assigns each web its own individual pseudo register ๐Ÿง  That lets the register allocation pass operate on pseudos directly, and it also strengthens several other optimization passes, like CSE, the loop optimizer, and the trivial dead code remover โญ

It can, however, make debugging impossible, since variables no longer stay in a "home register" ๐Ÿ’€

Enabled by default with -funroll-loops ๐ŸŒธ


-fwhole-program

Okay this one assumes that the current compilation unit is the whole program being compiled ๐ŸŒ All public functions and variables, except main and those merged by the attribute externally_visible, become static functions. Because of that, the interprocedural optimizers can go way harder on them ๐Ÿ”ฅ

This option should not be used in combination with -flto. Instead, relying on a linker plugin should provide safer and more precise information ๐Ÿšจ

-flto[=n]

This runs the standard link-time optimizer, and it's honestly iconic ๐Ÿ‘‘ When you invoke it with source code, it generates GIMPLE (one of GCC's internal representations) and writes it to special ELF sections in the object file. When the object files get linked together, all the function bodies are read from those ELF sections and instantiated as if they had been part of the same translation unit ๐Ÿงš

To use the link-time optimizer, -flto and optimization options should be specified at compile time and during the final link. It's recommended that you compile all the files participating in the same link with the same options, and also specify those options at link time. For example:

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

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

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

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

This generates bytecode for foo.c and bar.c, merges them together into a single GIMPLE representation, and optimizes them as usual to produce myprog โœจ

The important thing to keep in mind is that to enable link-time optimizations, you need to use the GCC driver to perform the link step. GCC automatically performs link-time optimization if any of the objects involved were compiled with the -flto command-line option. You can always override the automatic decision to do link-time optimization by passing -fno-lto to the link command ๐Ÿซถ

To make whole program optimization effective, it's necessary to make certain whole program assumptions. The compiler needs to know what functions and variables can be accessed by libraries and runtime outside of the link-time optimized unit. When the linker supports it, the linker plugin (see -fuse-linker-plugin) passes information to the compiler about used and externally visible symbols. When the linker plugin isn't available, -fwhole-program should be used so the compiler can make these assumptions, which leads to more aggressive optimization decisions ๐Ÿ”ฅ

When a file is compiled with -flto without -fuse-linker-plugin, the generated object file is larger than a regular object file, 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, no interprocedural optimizations are applied. Note that when -fno-fat-lto-objects is enabled, the compile stage is faster, but you cannot perform a regular, non-LTO link on them ๐Ÿ˜ญ

When producing the final binary, GCC only applies link-time optimizations to those files that contain bytecode. So you can mix and match object files and libraries with GIMPLE bytecodes and final object code. GCC automatically selects which files to optimize in LTO mode and which files to link without further processing ๐Ÿฆ‹

Generally, options specified at link time override those specified at compile time, although in some cases GCC attempts to infer link-time options from the settings used to compile the input files.

If you do not specify an optimization level option -O at link time, GCC uses the highest optimization level used when compiling the object files. Note that it's generally ineffective to specify an optimization level option only at link time and not at compile time, for two reasons. First, compiling without optimization suppresses the compiler passes that gather information 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 are required to match in all compilation units. Trying to override this at link time with a conflicting value is ignored. This includes options such as -freg-struct-return and -fpcc-struct-return ๐Ÿšซ

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

When you need to pass options to the assembler via -Wa or -Xassembler, make sure to either compile such translation units with -fno-lto, or consistently use the same assembler options on all translation units. You can alternatively also specify assembler options at LTO link time ๐Ÿงฉ

To enable debug info generation, you need to supply -g at compile time. If any of the input files at link time were built with debug info generation enabled, the link will enable debug info generation as well. Any elaborate debug info settings, like the DWARF level -gdwarf-5, need to be explicitly repeated on the linker command line, and mixing different settings in different translation units is discouraged ๐Ÿ›

If LTO encounters objects with C linkage declared with incompatible types in separate translation units to be linked together, that's undefined behavior according to ISO C99 6.2.7. A non-fatal diagnostic may be issued, but the behavior is still undefined at run time. Similar diagnostics may be raised for other languages ๐Ÿ’€

Undefined behavior means the program can do literally anything, so please don't mix incompatible C linkage declarations and expect it to be fine ๐Ÿ˜ญ

Another feature of LTO is that it's possible to apply interprocedural optimizations on files written in different languages:

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

Notice that the final link is done with g++ to get the C++ runtime libraries, and -lgfortran is added to get the Fortran runtime libraries. In general, when mixing languages in LTO mode, you should use the same link command options as when mixing languages in a regular (non-LTO) compilation ๐ŸŒธ

Okay so, if you've got object files holding GIMPLE bytecode stashed in a library archive (say libfoo.a), you can totally pull them out for an LTO link, as long as your linker has plugin support ๐Ÿ’…. To make static libraries that vibe with LTO, use gcc-ar and gcc-ranlib instead of ar and ranlib. If you wanna peek at the symbols in object files with GIMPLE bytecode, gcc-nm is your bestie ๐Ÿ”. Those tools need ar, ranlib and nm to be built with plugin support too, or it's a no-go ๐Ÿ’€. When you link, slap on -fuse-linker-plugin so the library actually joins the LTO party ๐Ÿฆ‹:

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

With the linker plugin on, the linker grabs the GIMPLE files it needs out of libfoo.a and hands them to the running GCC, so they become part of the big combined GIMPLE image that gets optimized โœจ.

If you're not using a linker with plugin support, or you just didn't turn the linker plugin on, no drama ๐Ÿฅฒ. The objects inside libfoo.a still get extracted and linked like normal, they just don't join the LTO optimization process. If you want a static library that works for both LTO and regular linking, compile its object files with -flto -ffat-lto-objects ๐Ÿซถ.

LTO doesn't need the whole program to be present to work ๐ŸŒ. If your program doesn't need any symbols exported, you can combine -flto and -fwhole-program. That lets the interprocedural optimizers make more aggressive assumptions, which may lead to improved optimization opportunities ๐Ÿ”ฅ. You don't need -fwhole-program when the linker plugin is active (see -fuse-linker-plugin) ๐Ÿ‘‘.

The current LTO implementation makes no attempt to generate bytecode that's portable between different types of hosts ๐Ÿ™…โ€โ™€๏ธ. The bytecode files are versioned with a strict version check, so bytecode generated by one GCC version won't work with an older or newer GCC. Not a vibe ๐Ÿ˜ญ.

Link-time optimization doesn't play nice with debugging information on systems other than those using a combo 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, with an installed make program doing the heavy lifting ๐Ÿƒโ€โ™€๏ธ. The environment variable MAKE can be used to override which program gets used.

You can also specify -flto=jobserver to use GNU make's job server mode to figure out how many parallel jobs to run. 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.

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 โ€” This picks the partitioning algorithm the link-time optimizer uses. The value is either 1to1, which mirrors the original source files, or balanced, which splits things into equally sized chunks whenever possible, or max, which makes a new partition for every symbol where possible. Specifying none as the algorithm turns partitioning and streaming off completely. The default is balanced. 1to1 can be used as a workaround for various code ordering issues, but max partitioning is intended for internal testing only ๐Ÿงช. The value one means exactly one partition gets used, while none skips partitioning and runs the link-time optimization step straight from the WPA phase.
  • -flto-odr-type-merging โ€” Turns on streaming of the mangled type names of C++ types, plus their unification at link time. It makes LTO object files bigger, but you get diagnostics about One Definition Rule violations in return ๐Ÿ”.
  • -flto-compression-level=n โ€” This sets how much compression is used for the intermediate language written to LTO object files. It only matters with LTO mode (-flto). Valid values are 0 (no compression) to 9 (maximum compression). Values outside that range get clamped to either 0 or 9. If you don't give the option, a default balanced compression setting is used ๐Ÿ—œ๏ธ.
  • -fuse-linker-plugin โ€” Enables a linker plugin during link-time optimization. This relies on plugin support in the linker, which is available in gold or in GNU ld 2.21 or newer. It also enables extracting object files with GIMPLE bytecode out of library archives, which improves optimization quality by exposing more code to the link-time optimizer ๐Ÿฆ‹. The plugin tells the optimizer which symbols can be accessed externally (by non-LTO objects or during dynamic linking). The code quality gains on binaries (and on shared libraries that use hidden visibility) are similar to -fwhole-program. See -flto for a description of what this flag does and how to use it.

This option is enabled by default when LTO support in GCC is turned on and GCC was configured for 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 works when you're compiling with -flto, and it gets ignored at link time.

-fno-fat-lto-objects speeds up compilation compared to plain LTO, but the whole toolchain has to be LTO-aware. It needs a linker with linker plugin support for basic functionality ๐Ÿ™ƒ. On top of that, nm, ar and ranlib need to support linker plugins so you get a full-featured build environment (one that can build static libraries and all that). GCC provides the gcc-ar, gcc-nm and gcc-ranlib wrappers to pass the right options to these tools. With non-fat LTO, makefiles need to be modified to use them.

Modern binutils has a plugin auto-load mechanism ๐Ÿคฏ. Installing the linker plugin into $libdir/bfd-plugins has the same effect as using the command wrappers (gcc-ar, gcc-nm and gcc-ranlib).

The default is -fno-fat-lto-objects on targets with linker plugin support ๐Ÿ’….

  • -fcompare-elim โ€” After register allocation and post-register allocation instruction splitting, this finds arithmetic instructions that compute processor flags similar to a comparison operation based on that arithmetic. If possible, it eliminates the explicit comparison operation ๐Ÿงผ. This pass only applies to certain targets that can't explicitly represent the comparison operation before register allocation is complete.

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

  • -fcprop-registers โ€” After register allocation and post-register allocation instruction splitting, this does 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 from an instrumented binary for multi-threaded programs can be inconsistent because some counter updates get missed. When you specify this option, GCC uses heuristics to correct or smooth out those inconsistencies ๐Ÿฉน. By default, GCC emits an error message when it detects an inconsistent profile.

This option is enabled by -fauto-profile.

  • -fprofile-use, -fprofile-use=path โ€” Enables profile feedback-directed optimizations, plus the following optimizations, many of which are only really profitable when profile feedback is available:

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

Before you can use this option, you must first generate profiling information ๐Ÿ“Š.

By default, GCC emits an error message if the feedback profiles don't match the source code. You can turn that error into a warning with -Wno-error=coverage-mismatch. Just know this may result in poorly optimized code ๐Ÿ˜ฌ. Also by default, GCC emits a warning message if the feedback profiles don't exist (see -Wmissing-profile).

If path is specified, GCC looks at that path to find the profile feedback data files. See -fprofile-dir.

  • -fauto-profile, -fauto-profile=path โ€” Enables sampling-based feedback-directed optimizations, plus the following optimizations, many of which are only really profitable when profile feedback is available: ๐ŸŒˆ

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

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

Producing 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

Then use the create_gcov tool to convert the raw profile data into a format GCC can use. You also have to supply the unstripped binary for your program to this tool. See https://github.com/google/autofdo ๐Ÿ› ๏ธ.

E.g.

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

The following options control compiler behavior regarding floating-point arithmetic ๐Ÿงฎ. They trade off between speed and correctness, so think about which one you want. All of them must be specifically enabled.

  • -ffloat-store โ€” Don't store floating-point variables in registers, and inhibit other options that might change whether a floating-point value gets taken from a register or from memory. ๐Ÿ™ˆ

Okay so, this one's about -ffloat-store ๐Ÿงš It stops the sneaky extra precision on machines like the 68000, where the floating registers (on the 68881) hold more precision than a double is supposed to have. x86 has the same issue ๐Ÿ’… For most programs that extra precision is a total win, but some programs rely on the exact IEEE floating-point definition. Those programs can use -ffloat-store, but first you have to edit them so every pertinent intermediate computation gets stored into a variable ๐Ÿซถ


  • -fexcess-precision=style โ€” Okay, this is the more precise control panel for excess precision ๐ŸŽ€ It applies to machines where floating-point operations happen in a format with more precision or range than the IEEE standard and interchange floating-point types. By default, -fexcess-precision=fast is in effect โœจ That means operations can run in a wider precision than the source types if it makes the code faster, and it's unpredictable when rounding to the source types actually happens.
    • When you compile C with -fexcess-precision=standard, excess precision follows the ISO C99 rules ๐Ÿ“œ Casts and assignments both cause values to be rounded to their semantic types. (Compare that to -ffloat-store, which only affects assignments.) This option is enabled by default for C if a strict conformance option like -std=c99 is used.
    • -ffast-math turns on -fexcess-precision=fast by default, no matter whether a strict conformance option is used ๐Ÿš€
    • -fexcess-precision=standard is not implemented for languages other than C. On the x86, it does nothing if -mfpmath=sse or -mfpmath=sse+387 is specified. With the former, IEEE semantics apply without excess precision. With the latter, rounding is unpredictable ๐Ÿ™ˆ
  • -ffast-math โ€” This one is a whole vibe ๐ŸŽ๏ธ It 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 ๐Ÿ’–
    • Only -Ofast turns this on. No other -O option does ๐Ÿ’€
This can result in incorrect output for programs that depend on an exact implementation of IEEE or ISO rules and specifications for math functions. It may, however, yield faster code for programs that don't need the guarantees of those specifications.
  • -fno-math-errno โ€” Don't set errno after calling math functions that run in a single instruction, like sqrt ๐Ÿฆ‹ A program that handles math errors through IEEE exceptions might want this for speed while still keeping IEEE arithmetic compatibility ๐ŸŒธ
    • Not turned on by any -O option, because it can give incorrect output for programs that depend on an exact implementation of IEEE or ISO rules and specifications for math functions. It may, however, be faster for programs that don't need those guarantees.
    • The default is -fmath-errno.
    • On Darwin systems, the math library never sets errno. So the compiler has no reason to consider that it might, and -fno-math-errno is the default there โœจ
  • -funsafe-math-optimizations โ€” Allows floating-point optimizations that (a) assume arguments and results are valid and (b) may violate IEEE or ANSI standards ๐Ÿ”ฅ When used at link time, it may pull in libraries or startup files that change the default FPU control word or do other similar optimizations.
    • Not turned on by any -O option, same reason as before: incorrect output is possible for programs that depend on exact IEEE or ISO math rules. It may still be faster for programs that don't need those guarantees.
    • Enables -fno-signed-zeros, -fno-trapping-math, -fassociative-math and -freciprocal-math.
    • The default is -fno-unsafe-math-optimizations.
  • -fassociative-math โ€” Allows re-association of operands in a series of floating-point operations ๐ŸŒˆ This violates the ISO C and C++ standard because it can change the computation result.
NOTE: Re-ordering may change the sign of zero, ignore NaNs, and inhibit or create underflow or overflow. That means it can't be used on code that relies on rounding behavior like (x + 2**52) - 2**52. It may also reorder floating-point comparisons, so don't use it where ordered comparisons are required ๐Ÿ˜ญ
  • This option requires that both -fno-signed-zeros and -fno-trapping-math be in effect.
  • 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 โ€” Lets the reciprocal of a value be used instead of dividing by that value, if it enables optimizations ๐Ÿ“ For example, x / y can be replaced with x * (1/y), which is handy when (1/y) is subject to common subexpression elimination. Heads up: this loses precision and increases the number of flops operating on the value.
    • The default is -fno-reciprocal-math.
  • -ffinite-math-only โ€” Allows optimizations that assume arguments and results are never NaNs or +-Infs ๐Ÿซง
    • Not turned on by any -O option, because it can give incorrect output for programs that depend on an exact implementation of IEEE or ISO rules and specifications for math functions. It may still be faster for programs that don't need those guarantees.
    • The default is -fno-finite-math-only.
  • -fno-signed-zeros โ€” Allows optimizations that ignore the signedness of zero ๐ŸงŠ IEEE arithmetic gives distinct +0.0 and -0.0 values with their own behavior, and that blocks simplifications of expressions like x+0.0 or 0.0*x (even with -ffinite-math-only). This option says the sign of a zero result doesn't matter.
    • The default is -fsigned-zeros.
  • -fno-trapping-math โ€” Compiles code assuming floating-point operations can't generate user-visible traps ๐Ÿ™Œ Those traps include division by zero, overflow, underflow, inexact result and invalid operation. This option requires that -fno-signaling-nans be in effect. Turning it on 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 and specifications for math functions.
  • The default is -ftrapping-math.
  • -frounding-math โ€” Turns off transformations and optimizations that assume the default floating-point rounding behavior ๐ŸŒ That default is round-to-zero for all floating-point to integer conversions, and round-to-nearest for all other arithmetic truncations. Use this for programs that change the FP rounding mode dynamically, or that might run with a non-default rounding mode ๐ŸŽ€ It also disables compile-time constant folding of floating-point expressions (which rounding mode can affect), plus arithmetic transformations that are unsafe with sign-dependent rounding modes.
    • The default is -fno-rounding-math.
    • This option is experimental, and it doesn't currently guarantee that every GCC optimization affected by rounding mode gets disabled ๐Ÿงช
    • Future GCC versions may offer finer control using C99's FENV_ACCESS pragma. This command-line option will be used to set the default state for FENV_ACCESS.
  • -fsignaling-nans โ€” Compiles code assuming IEEE signaling NaNs may generate user-visible traps during floating-point operations ๐Ÿ‘‘ Turning this on disables optimizations that might change the number of exceptions visible with signaling NaNs. It implies -ftrapping-math.
    • This option causes the preprocessor macro __SUPPORT_SNAN__ to be defined.
    • The default is -fno-signaling-nans.
    • This option is experimental and doesn't currently guarantee that every GCC optimization affecting signaling NaN behavior gets disabled.
  • -fno-fp-int-builtin-inexact โ€” Stops the built-in functions ceil, floor, round and trunc (plus their float and long double variants) from generating code that raises the inexact floating-point exception for noninteger arguments ๐Ÿ’… ISO C99 and C11 let these functions raise inexact, but ISO/IEC TS 18661-1:2014, the C bindings to IEEE 754-2008, does not.
    • The default is -ffp-int-builtin-inexact, which allows the exception to be raised.
    • This option does nothing unless -ftrapping-math is in effect.
    • Even with -fno-fp-int-builtin-inexact, if these functions end up calling a library function, the inexact exception may still be raised if the library implementation doesn't follow TS 18661.
  • -fsingle-precision-constant โ€” Treats floating-point constants as single precision, instead of implicitly converting them to double-precision constants ๐Ÿฆ„
  • -fcx-limited-range โ€” When enabled, this says a range reduction step isn't needed for complex division ๐Ÿง It also means there's no check on whether a complex multiplication or division result is NaN + I*NaN, so no attempt to rescue that situation.
    • The default is -fno-cx-limited-range, but -ffast-math enables it.
    • This option controls the default setting of the ISO C99 CX_LIMITED_RANGE pragma. Even so, it applies to all languages ๐ŸŒท
  • -fcx-fortran-rules โ€” Complex multiplication and division follow Fortran rules ๐Ÿ“š Range reduction is done as part of complex division, but there's no check on whether the result is NaN + I*NaN, and no attempt to rescue it in that case.
    • The default is -fno-cx-fortran-rules.

The following options control optimizations that may improve performance, but none of them are enabled by any -O option. This section also includes experimental options that may produce broken code ๐Ÿ’€๐Ÿซถ

  • -fbranch-probabilities โ€” ๐Ÿฆ‹ okay so, after you run a program built with -fprofile-arcs, you compile it again with -fbranch-probabilities and the optimizer gets smarter about which branches actually get taken. When that profiled program exits, it saves arc execution counts to a file called sourcename.gcda for each source file. That data is super dependent on the structure of the generated code, so you must use the same source code and the same optimization options for both compiles, bestie. With this flag, GCC attaches a REG_BR_PROB note to each JUMP_INSN and CALL_INSN. Right now those notes only get used in one spot, reorg.c, where instead of guessing the likely path, GCC uses the REG_BR_PROB values to know exactly which path gets taken more often. โœจ Enabled by -fprofile-use and -fauto-profile.
  • -fprofile-values โ€” ๐Ÿ’… when you combine this with -fprofile-arcs, the compiler adds code that gathers data about the values of expressions in your program. Add -fbranch-probabilities and it reads that data back and uses it for optimizations. โœจ Enabled by -fprofile-generate, -fprofile-use, and -fauto-profile.
  • -fprofile-reorder-functions โ€” ๐Ÿงš function reordering based on profile instrumentation records the first time each function runs, then sorts the functions in ascending order. โœจ Enabled with -fprofile-use.
  • -fvpt โ€” ๐Ÿ”ฅ with -fprofile-arcs, this tells the compiler to add code that collects info about expression values. Then with -fbranch-probabilities, it reads that info back and actually does the optimizing. Right now that includes specializing division operations based on what the denominator's value is, which is so clever. โœจ Enabled with -fprofile-use and -fauto-profile.
  • -frename-registers โ€” ๐ŸŒธ this tries to dodge false dependencies in scheduled code by using registers that get left over after register allocation. It's most helpful on processors with lots of registers. > Heads up: depending on the debug information format your target uses, this can make debugging impossible, because variables no longer stay in a "home register." โœจ Enabled by default with -funroll-loops.
  • -fschedule-fusion โ€” ๐Ÿ“ a target-dependent pass over the instruction stream that groups instructions of the same type together, since some machines run them more efficiently when they're sitting next to each other. โœจ Enabled at levels -O2, -O3, -Os.
  • -ftracer โ€” ๐ŸŽ€ this does tail duplication to enlarge superblock size. It simplifies the function's control flow so other optimizations can do a better job. โœจ Enabled by -fprofile-use and -fauto-profile.
  • -funroll-loops โ€” ๐Ÿซถ unrolls loops whose number of iterations can be figured out at compile time or when the loop is entered. It implies -frerun-cse-after-loop, -fweb and -frename-registers, and it also turns on complete loop peeling (fully removing loops with a small constant number of iterations). โš ๏ธ This makes your code bigger, and it may or may not make it run faster, so it's not a guarantee, babe. โœจ Enabled by -fprofile-use and -fauto-profile.
  • -funroll-all-loops โ€” ๐Ÿ’€ unrolls every loop, even if the iteration count is uncertain when the loop is entered. > Warning: this usually makes programs run more slowly. It implies the same options as -funroll-loops.
  • -fpeel-loops โ€” ๐Ÿ‘‘ peels loops that the compiler has enough info about to know they won't roll much (from profile feedback or static analysis). It also turns on complete loop peeling, which fully removes loops with a small constant number of iterations. โœจ Enabled by -O3, -fprofile-use, and -fauto-profile.
  • -fmove-loop-invariants โ€” ๐ŸŒˆ turns on the loop invariant motion pass in the RTL loop optimizer, which moves stuff that doesn't change inside a loop out of it. โœจ Enabled at level -O1 and higher, except for -Og.
  • -fsplit-loops โ€” ๐Ÿฆ‹ splits a loop into two if it has a condition that's always true for one side of the iteration space and always false for the other. โœจ Enabled by -fprofile-use and -fauto-profile.
  • -funswitch-loops โ€” ๐Ÿ’œ moves branches with loop-invariant conditions out of the loop. You get duplicate copies of the loop on both branches, each modified according to what the condition came out to be. โœจ Enabled by -fprofile-use and -fauto-profile.
  • -fversion-loops-for-strides โ€” ๐Ÿงšโ€โ™€๏ธ if a loop walks through an array with a variable stride, the compiler makes a second version of the loop that assumes the stride is always one. Here's the vibe:
for (int i = 0; i < n; ++i)
  x[i * stride] = ...;

becomes:

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

This is especially clutch for assumed-shape arrays in Fortran, since it lets the compiler vectorize better by assuming the accesses are contiguous. ๐Ÿ˜ญ This flag is enabled by default at -O3, and it's also enabled by -fprofile-use and -fauto-profile.

  • -ffunction-sections, -fdata-sections โ€” ๐ŸŒธ these put each function or data item into its own section in the output file, if the target supports arbitrary sections. The function's name or the data item's name decides the section's name in the output file. Use these on systems where the linker can optimize locality of reference in the instruction space. Most systems using the ELF object format have linkers like that. On AIX, the linker rearranges sections (CSECTs) based on the call graph. The performance impact varies, fr. Together with linker garbage collection (the linker --gc-sections option), these may lead to smaller statically-linked executables (after stripping). On ELF/DWARF systems, these options don't degrade the quality of the debug information. There could be issues with other object file or debug info formats, though. โš ๏ธ Only use these when there are significant benefits, because when you turn them on, the assembler and linker make larger object and executable files and everything gets slower. They also affect code generation: they stop the compiler and assembler from using relative locations inside a translation unit, since those locations aren't known until link time. An example of an optimization that gets blocked is relaxing calls to short call instructions.
  • -fbranch-target-load-optimize โ€” ๐ŸŽ€ performs branch target register load optimization before prologue/epilogue threading. The use of target registers usually only shows up during reload, so hoisting loads out of loops and doing inter-block scheduling needs its own separate optimization pass.
  • -fbranch-target-load-optimize2 โ€” ๐Ÿ“ performs that same branch target register load optimization, but after prologue/epilogue threading.
  • -fbtr-bb-exclusive โ€” ๐Ÿ™ˆ when doing branch target register load optimization, this stops the compiler from reusing branch target registers within any basic block.
  • -fstdarg-opt โ€” ๐Ÿ’… optimizes the prologue of variadic argument functions based on how those arguments actually get 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 cut down on symbolic address calculations by using shared "anchor" symbols to address nearby objects. On some targets this can reduce the number of GOT entries and GOT accesses. For example, say you have this function foo:
static int a, b, c;
int foo (void) { return a + b + c; }

Normally it calculates the addresses of all three variables, but if you compile it with -fsection-anchors, it accesses the variables from a common anchor point instead. The effect is similar to this pseudocode (which isn't valid C):

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

๐Ÿ™ˆ Not all targets support this option.

  • --param name=value โ€” ๐ŸŒˆ GCC uses various constants to decide how much optimization to do. For example, it won't inline functions that contain more than a certain number of instructions. You can tweak some of these constants on the command line with --param. โš ๏ธ The names of specific parameters, and what the values mean, are tied to the compiler's internals and can change without notice in future releases. To find the minimal, maximal, and default value of a parameter, use --help=param -Q. In every case, the value is an integer. The allowable choices for name are:
    • 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 parameter sets the maximum number of instructions in a block that should be considered for if-conversion. The compiler also uses other heuristics to decide whether if-conversion is likely to be profitable.
    • max-rtl-if-conversion-predictable-cost, max-rtl-if-conversion-unpredictable-cost โ€” ๐Ÿง RTL if-conversion will try to remove conditional branches around a block and replace them with conditionally executed instructions. These parameters give the maximum permissible cost for the sequence that would be generated by if-conversion, depending on whether the branch is statically determined to be predictable or not. The units are the same as the GCC internal seq_cost metric. The compiler will try to provide a reasonable default for this parameter using the BRANCH_COST target macro.
  • max-crossjump-edges โ€” okay so this is the max number of incoming edges cross-jumping will consider ๐Ÿ‘€ -fcrossjumping is O(N^2) in the edges coming into each block, so cranking this up means more aggressive optimization, longer compile times, and probably only a small shrink in executable size ๐Ÿ’€
  • min-crossjump-insns โ€” the minimum number of instructions that have to match at the end of two blocks before cross-jumping happens on them ๐Ÿฆ‹ This one gets ignored if every instruction in the block being cross-jumped from already matches โœจ
  • max-grow-copy-bb-insns โ€” the max code size expansion factor when copying basic blocks instead of jumping ๐ŸŒธ The expansion is measured relative to a jump instruction ๐Ÿ’…
  • max-goto-duplication-insns โ€” the max number of instructions that can be duplicated into a block that jumps to a computed goto ๐Ÿงš GCC factors computed gotos early to dodge O(N^2) behavior in a bunch of passes, then unfactors them as late as possible ๐Ÿ’– Only computed jumps at the end of a basic block with no more than max-goto-duplication-insns instructions get unfactored ๐Ÿซถ
  • max-delay-slot-insn-search โ€” the max number of instructions to look at while hunting for something to fill a delay slot ๐Ÿ” Once you've searched past this arbitrary number, the time saved by filling the slot is basically nothing, so GCC just stops ๐Ÿ›‘ Bigger values mean more aggressive optimization, longer compile times, and probably a small win in execution time ๐ŸŒˆ
  • max-delay-slot-live-search โ€” when filling delay slots, this is the max number of instructions to check while looking for a block with valid live register information โœจ Raising this arbitrarily chosen value means more aggressive optimization and more compile time ๐Ÿ˜ญ This parameter should be removed once the delay slot code gets rewritten to maintain the control-flow graph ๐Ÿ’€
  • max-gcse-memory โ€” the approximate max memory that can be allocated for global common subexpression elimination ๐Ÿง  If the optimization needs more than this, it just doesn't happen ๐Ÿ™ˆ
  • max-gcse-insertion-ratio โ€” if the ratio of expression insertions to deletions is bigger than this for any expression, RTL PRE inserts or removes the expression instead ๐Ÿฆ‹ That means it leaves partially redundant computations sitting in the instruction stream, which is giving messy ๐Ÿซ 
  • max-pending-list-length โ€” the max number of pending dependencies scheduling allows before it flushes the current state and starts over ๐Ÿ“ Big functions with few branches or calls can build up way too-large lists that waste memory and resources, so this keeps things in check ๐Ÿ’œ
  • max-modulo-backtrack-attempts โ€” the max number of backtrack attempts the scheduler makes when modulo scheduling a loop ๐Ÿ” Bigger values can exponentially increase compilation time so don't go wild ๐Ÿ’€
  • max-inline-insns-single โ€” several parameters control the tree inliner, and this one is the max number of instructions (counted in GCC's internal representation) in a single function that the tree inliner will consider for inlining ๐Ÿ‘‘ It only affects functions declared inline and methods implemented in a class declaration (C++) ๐Ÿ’…
  • max-inline-insns-auto โ€” when you use -finline-functions (which is included in -O3), a whole lot of functions that would normally get skipped for inlining get investigated ๐Ÿ•ต๏ธโ€โ™€๏ธ For those, a different and more restrictive limit applies than the one for functions declared inline ๐ŸŒธ
  • max-inline-insns-small โ€” this bound applies to calls that count as relevant with -finline-small-functions ๐ŸŽ€
  • max-inline-insns-size โ€” this bound applies to calls that get optimized for size ๐Ÿ“ A little growth can be desirable here, since it helps anticipate optimization opportunities that inlining exposes โœจ
  • uninlined-function-insns โ€” the number of instructions the inliner counts as function overhead, like the function prologue and epilogue ๐Ÿงš
  • uninlined-function-time โ€” the extra time the inliner counts as function overhead, like the time it takes to run the function's prologue and epilogue โฑ๏ธ
  • uninlined-thunk-insns, uninlined-thunk-time โ€” same thing as --param uninlined-function-insns and --param uninlined-function-time, but these apply to function thunks ๐Ÿฆ‹
  • inline-min-speedup โ€” when the estimated performance improvement of caller + callee runtime goes over this threshold (in percent), the function can be inlined no matter what the limits on --param max-inline-insns-single and --param max-inline-insns-auto say ๐Ÿš€ Main character moment ๐Ÿ‘‘
  • large-function-insns โ€” the limit that defines really large functions ๐Ÿ˜ For functions bigger than this after inlining, inlining gets constrained by --param large-function-growth ๐Ÿ”’ It's mainly there to avoid extreme compile times caused by the non-linear algorithms the back end uses ๐Ÿซ 
  • large-function-growth โ€” the max growth of a large function caused by inlining, in percent ๐Ÿ“ˆ For example, a value of 100 limits large function growth to 2.0 times the original size ๐Ÿ’–
  • large-unit-insns โ€” the limit that defines a large translation unit ๐Ÿ“ฆ Growth from inlining units bigger than this is limited by --param inline-unit-growth, and for small units that might be way too tight ๐Ÿฅฒ Picture a unit with function A that's inline and function B that just calls A three times ๐ŸŽ€ If B is small compared to A, the unit's growth is 300% and yet that inlining is totally sane โœจ But for really big units made of tiny inlineable functions, the overall unit growth limit is needed to stop an exponential explosion of code size ๐Ÿ’€ So for smaller units, the size gets bumped up to --param large-unit-insns before --param inline-unit-growth is applied ๐Ÿง 
  • inline-unit-growth โ€” the max overall growth of the compilation unit caused by inlining ๐ŸŒˆ For example, a value of 20 limits unit growth to 1.2 times the original size ๐Ÿ“ Cold functions (marked cold with an attribute or by profile feedback) don't count toward the unit size ๐ŸงŠ
  • ipcp-unit-growth โ€” the max overall growth of the compilation unit caused by interprocedural constant propagation ๐Ÿ”ฎ For example, a value of 10 limits unit growth to 1.1 times the original size ๐Ÿซถ
  • 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 max growth of large stack frames caused by inlining, in percent ๐Ÿ“š For example, a value of 1000 limits large stack frame growth to 11 times the original size ๐Ÿคฏ
  • max-inline-insns-recursive, max-inline-insns-recursive-auto โ€” the max number of instructions an out-of-line copy of a self-recursive inline function can grow into by doing recursive inlining ๐Ÿ” --param max-inline-insns-recursive applies to functions declared inline ๐Ÿ’… For functions not declared inline, recursive inlining only happens when -finline-functions (included in -O3) is enabled, and --param max-inline-insns-recursive-auto applies instead ๐Ÿฆ‹
  • max-inline-recursive-depth, max-inline-recursive-depth-auto โ€” the max recursion depth used for recursive inlining ๐ŸŒ€ --param max-inline-recursive-depth applies to functions declared inline ๐ŸŽ€ For functions not declared inline, recursive inlining only happens when -finline-functions (included in -O3) is enabled, and --param max-inline-recursive-depth-auto applies instead โœจ
  • min-inline-recursive-probability โ€” recursive inlining is only worth it for functions that recurse deeply on average ๐ŸŒŠ For functions with a little recursion depth, it can hurt by bloating the prologue size or making the function body more complicated for other optimizers ๐Ÿ˜ฌ

When profile feedback is available (see -fprofile-generate), the actual recursion depth can be guessed from the probability that a function recurses via a given call expression ๐Ÿ”ฎ This parameter limits inlining to only those call expressions whose probability goes over the threshold (in percent) ๐ŸŽฏ

  • early-inlining-insns โ€” the growth the early inliner is allowed to make ๐Ÿฃ Basically, it boosts the amount of inlining for code that has a large abstraction penalty ๐Ÿ’œ
  • max-early-inliner-iterations โ€” the limit on iterations of the early inliner ๐Ÿ” This roughly bounds how many nested indirect calls the early inliner can resolve ๐Ÿ•ธ๏ธ Deeper chains still get handled by late inlining ๐Ÿซถ
  • comdat-sharing-probability โ€” the probability (in percent) that C++ inline functions with comdat visibility get shared across multiple compilation units ๐Ÿค
  • profile-func-internal-id โ€” a parameter that controls whether the function's internal id gets used in the profile database lookup ๐Ÿ—‚๏ธ If the value is 0, the compiler uses an id based on the function's assembler name and filename, which makes old profile data more forgiving of source changes, like function reordering ๐Ÿฆ‹
  • min-vect-loop-bound โ€” the min number of iterations under which loops won't get vectorized when -ftree-vectorize is used ๐ŸŽ€ The number of iterations after vectorization has to be greater than the value set by this option for vectorization to happen ๐Ÿ’…๐Ÿ”ฅ
  • gcse-cost-distance-ratio: okay so this is the scaling factor for how far GCSE is allowed to shove an expression around ๐Ÿฆ‹ It only works in the code hoisting pass, ngl. The bigger the ratio, the more aggressive the hoisting gets for simple expressions (the ones costing less than gcse-unrestricted-cost). Set it to 0 and simple expressions stop getting hoisted entirely ๐Ÿ™ˆ
  • gcse-unrestricted-cost: this is the cost, roughly one typical machine instruction, where GCSE stops putting a leash on how far an expression can travel ๐Ÿ’… Also only in the code hoisting pass. The lesser the cost, the more aggressive the hoisting. Set it to 0 and every expression gets to roam free, no limits โœจ
  • max-hoist-depth: how deep the search goes into the dominator tree when hunting for expressions to hoist ๐ŸŒณ It exists to keep the hoisting algorithm from going quadratic. A value of 0 means there's no limit on the search, but it may slow down compiling huge functions ๐Ÿ˜ญ
  • max-tail-merge-comparisons: the max number of similar basic blocks (bbs) a block gets compared against. It keeps tree tail merging from going quadratic ๐ŸŽ€
  • max-tail-merge-iterations: the max number of passes over the function. It's there to cap compile time during tree tail merging โฑ๏ธ
  • store-merging-allow-unaligned: lets the store merging pass sneak in unaligned stores, but only when that's legal ๐Ÿฆ‹
  • max-stores-to-merge: the max number of stores the store merging pass will try to squish into wider stores ๐Ÿ’œ
  • max-unrolled-insns: the max number of instructions a loop can have and still get unrolled ๐Ÿ” If it does get unrolled, this same number also decides how many times the loop code gets unrolled.
  • max-average-unrolled-insns: the max number of instructions, weighted by how likely they are to execute, that a loop can have and still get unrolled ๐Ÿ“Š Same deal as above: this also sets how many times the loop code gets unrolled.
  • max-unroll-times: the max number of unrollings for a single loop ๐ŸŒ€
  • max-peeled-insns: the max number of instructions a loop can have and still get peeled ๐ŸŠ If it does get peeled, this value also decides how many times the loop code gets peeled.
  • max-peel-times: the max number of peelings for a single loop ๐Ÿ“
  • max-peel-branches: the max number of branches on the hot path through the peeled sequence ๐Ÿ”ฅ
  • max-completely-peeled-insns: the max number of insns in a completely peeled loop ๐Ÿงš
  • max-completely-peel-times: the max number of loop iterations for a loop to still be a good candidate for complete peeling ๐Ÿ’–
  • max-completely-peel-loop-nest-depth: the max depth of a loop nest that's suitable for complete peeling ๐Ÿช†
  • max-unswitch-insns: the max number of insns in an unswitched loop ๐ŸŒธ
  • max-unswitch-level: the max number of branches that can get unswitched in a single loop ๐ŸŒˆ
  • lim-expensive: the minimum cost for an expression to count as "expensive" during loop invariant motion ๐Ÿ’…
  • iv-consider-all-candidates-bound: a bound on how many candidates there are for induction variables. Below this number, every candidate gets considered for each use in the induction variable optimizations. Above it, only the most relevant ones get considered, so things don't go quadratic on time complexity ๐Ÿงฎ
  • iv-max-considered-uses: the induction variable optimizations give up on any loop that has more induction variable uses than this โœ‹
  • iv-always-prune-cand-set-bound: if the candidate set is smaller than this value, GCC 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 max size, in bytes, of objects that dead store elimination tracks bytewise ๐Ÿ“ฆ Bigger values may mean bigger compile times.
  • dse-max-alias-queries-per-store: the max number of queries into the alias oracle per store ๐Ÿ” Bigger values mean longer compile times, but may also remove more dead stores.
  • scev-max-expr-size: a bound on the size of expressions used in the scalar evolutions (SCEV) analyzer. Big expressions slow the analyzer down ๐Ÿข
  • scev-max-expr-complexity: a bound on how complex the expressions in the SCEV analyzer can get. Complicated expressions slow it down too ๐ŸŒ€
  • max-tree-if-conversion-phi-args: the max number of arguments in a PHI that tree if conversion supports, unless the loop is marked with the simd pragma ๐ŸŽฏ
  • vect-max-version-for-alignment-checks: the max number of run-time checks allowed when the vectorizer does loop versioning for alignment ๐Ÿ“
  • vect-max-version-for-alias-checks: the max number of run-time checks allowed when the vectorizer does loop versioning for alias ๐Ÿชž
  • vect-max-peeling-for-alignment: the max number of loop peels the vectorizer can do to improve access alignment. A value of -1 means no limit ๐Ÿซถ
  • max-iterations-to-track: the max number of loop iterations the brute-force algorithm tries to evaluate when it's figuring out how many iterations a loop does ๐Ÿ•ต๏ธโ€โ™€๏ธ
  • hot-bb-count-ws-permille: a basic block's profile count counts as "hot" if it contributes to the given permillage (0...1000) of the entire profiled execution ๐Ÿ”ฅ
  • hot-bb-frequency-fraction: the fraction of the entry block's execution frequency a basic block in the function needs to hit to be considered hot ๐ŸŒก๏ธ
  • max-predicted-iterations: the max number of loop iterations GCC predicts statically. This matters when a function has one loop with a known bound and another with an unknown one. The known count gets predicted correctly, but the unknown count averages out to roughly 10, which makes the unbounded loop look artificially cold next to the other one ๐Ÿฅถ
  • builtin-expect-probability: controls how likely the expression is to have the specified value. It takes a percentage (0 ... 100) as input ๐ŸŽฒ
  • builtin-string-cmp-inline-length: the max length of a constant string for a builtin string cmp call to be eligible for inlining ๐Ÿงต
  • align-threshold: the fraction of the maximal execution frequency of a basic block in a function that's needed before GCC aligns that block ๐Ÿ“
  • align-loop-iterations: a loop that's expected to iterate at least this many times gets aligned ๐Ÿงญ
  • tracer-dynamic-coverage, tracer-dynamic-coverage-feedback: these limit superblock formation once the given percentage of executed instructions is covered, which keeps code size from ballooning ๐ŸŽˆ The -feedback version is only used when profile feedback is available. Real profiles are way less balanced than the estimated ones, so the threshold can be set to a larger value ๐Ÿง
  • tracer-max-code-growth: stops tail duplication once code growth reaches the given percentage. Honestly it's a pretty artificial limit, since most of the duplicates get cleaned up later in cross jumping, so it can be set way higher than the code growth you actually want ๐ŸŒฑ
  • tracer-min-branch-ratio: stops reverse growth when the reverse probability of the best edge drops below this threshold (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. Like tracer-dynamic-coverage, there are two versions. tracer-min-branch-probability-feedback is for compiling with profile feedback, and tracer-min-branch-probability is for compiling without it. The feedback value needs to be more conservative (higher) to make the tracer effective ๐Ÿ’…
  • stack-clash-protection-guard-size: sets the size of the operating system's stack guard as 2 raised to num bytes ๐Ÿ›ก๏ธ Higher values may reduce the number of explicit probes. But if the value is bigger than the operating system's guard, your code is left open to stack clash style attacks ๐Ÿšจ
  • stack-clash-protection-probe-interval: stack clash protection probes stack space as it gets allocated. This param sets the max distance between those probes as 2 raised to num bytes ๐Ÿ“ก Higher values may cut down on explicit probes, but a value bigger than the operating system's guard leaves the code open to stack clash style attacks ๐Ÿ˜ฌ
  • max-cse-path-length: the max number of basic blocks on a path that CSE considers ๐Ÿ›ค๏ธ
  • max-cse-insns: the max number of instructions CSE processes before it flushes ๐Ÿšฝ
  • ggc-min-expand: GCC uses a garbage collector to manage its own memory allocation ๐Ÿงน This param sets the minimum percentage the garbage collector's heap is allowed to expand between collections. Tuning it may improve compilation speed, but it has no effect on code generation ๐Ÿš€

The default is 30% + 70% * (RAM/1GB), with an upper bound of 100% when RAM is >= 1GB ๐Ÿงฎ If getrlimit is available, "RAM" means the smallest of actual RAM and RLIMIT_DATA or RLIMIT_AS. If GCC can't calculate RAM on a particular platform, the lower bound of 30% is used ๐Ÿฅน Setting this param and ggc-min-heapsize to zero causes a full collection to happen at every opportunity. It's extremely slow, but it can be useful for debugging ๐ŸŒ๐Ÿ”

  • ggc-min-heapsize โ€” okay so this is the minimum size the garbage collector's heap has to reach before it even bothers collecting garbage ๐Ÿ—‘๏ธโœจ The first collection happens once the heap grows by ggc-min-expand% beyond ggc-min-heapsize. Tuning this can speed up compilation, but it has zero effect on code generation ๐Ÿ’…
    • Default: the smaller of RAM/8, RLIMIT_RSS, or a limit that tries to make sure RLIMIT_DATA or RLIMIT_AS don't get exceeded, but with a lower bound of 4096 (four megabytes) and an upper bound of 131072 (128 megabytes) ๐ŸŽ€
    • If GCC can't figure out the RAM on a platform, the lower bound is used ๐Ÿคท
    • Setting this super large effectively turns garbage collection off ๐Ÿ™ˆ
    • Setting this and ggc-min-expand to zero makes a full collection happen at every opportunity ๐Ÿ’€
  • max-reload-search-insns โ€” how far back reload is allowed to look for an equivalent register ๐Ÿ” Bigger numbers mean more aggressive optimization, which makes compilation take longer for probably slightly better performance โณ
  • max-cselib-memory-locations โ€” the max number of memory locations cselib will keep in mind ๐Ÿง  Same deal: higher means more aggressive optimization and longer compile times, for probably slightly better performance ๐Ÿฆ‹
  • max-sched-ready-insns โ€” the max number of instructions ready to be issued that the scheduler will look at any one time during the first scheduling pass ๐Ÿ“‹ Higher values mean more thorough searches, so compilation time goes up for probably very little benefit ๐Ÿ˜ญ
  • max-sched-region-blocks โ€” the max number of blocks in a region that can be considered for interblock scheduling ๐Ÿงฉ
  • max-pipeline-region-blocks โ€” the max number of blocks in a region that can be considered for pipelining in the selective scheduler ๐ŸŒธ
  • max-sched-region-insns โ€” the max number of insns in a region that can be considered for interblock scheduling ๐Ÿงฉ
  • max-pipeline-region-insns โ€” the max number of insns in a region that can 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 max number of trips through the CFG when extending regions โœจ A value of 0 turns region extensions off ๐Ÿšซ
  • max-sched-insn-conflict-delay โ€” the max conflict delay an insn can have and still be considered for speculative motion ๐Ÿƒโ€โ™€๏ธ
  • sched-spec-prob-cutoff โ€” the minimal probability of speculation success (in percents) needed before speculative insns actually get scheduled ๐Ÿ’…
  • sched-state-edge-prob-cutoff โ€” the minimum probability an edge needs before the scheduler saves its state across it ๐Ÿ›ค๏ธ
  • sched-mem-true-dep-cost โ€” the minimal distance (in CPU cycles) between a store and a load that target the same memory locations โฑ๏ธ
  • selsched-max-lookahead โ€” the max size of the lookahead window for selective scheduling ๐Ÿ‘€ It's basically how deep the search for available instructions goes ๐ŸŒŠ
  • selsched-max-sched-times โ€” the max number of times an instruction gets scheduled during selective scheduling ๐Ÿ” This is the cap on how many iterations the instruction is allowed to be pipelined through ๐Ÿซถ
  • selsched-insns-to-rename โ€” the max number of best instructions on the ready list that get considered for renaming in the selective scheduler โœ๏ธ
  • sms-min-sc โ€” the minimum stage count that the swing modulo scheduler will generate ๐Ÿฆข
  • max-last-value-rtl โ€” the max size, counted in RTLs, that the combiner can record in an expression as the last known value of a pseudo register ๐Ÿงพ
  • max-combine-insns โ€” the max number of instructions the RTL combiner tries to combine together ๐Ÿงƒ
  • integer-share-limit โ€” small integer constants can use a shared data structure, which saves memory and speeds things up ๐Ÿ™Œ This sets the biggest value a shared integer constant can have ๐Ÿ’–

  • ssp-buffer-size โ€” the minimum size of buffers (aka arrays) that get stack smashing protection when -fstack-protection is used ๐Ÿ›ก๏ธ
    • Before Ubuntu 10.10 this default was "8" ๐Ÿ•ฐ๏ธ Right now it's "4", so more functions get protected by the stack protector ๐Ÿ’œ
  • min-size-for-stack-sharing โ€” the minimum size of variables that take part in stack slot sharing when you're not optimizing ๐Ÿ“ฆ
  • max-jump-thread-duplication-stmts โ€” the max number of statements allowed in a block that has to be duplicated when threading jumps ๐Ÿงต
  • max-fields-for-field-sensitive โ€” the max number of fields in a structure that get treated in a field sensitive manner during pointer analysis ๐Ÿ”ฌ
  • prefetch-latency โ€” an estimate of how many instructions, on average, run before a prefetch finishes โณ The distance prefetched ahead scales with this number ๐Ÿ“ Increasing it might also mean fewer streams get prefetched (see simultaneous-prefetches) ๐ŸŒ€
  • simultaneous-prefetches โ€” the max number of prefetches that can run at the same time ๐Ÿƒโ€โ™€๏ธ๐Ÿ’จ
  • l1-cache-line-size โ€” the size of a cache line in the L1 data cache, in bytes ๐ŸงŠ
  • l1-cache-size โ€” the size of the L1 data cache, in kilobytes ๐Ÿ“
  • l2-cache-size โ€” the size of the L2 data cache, in kilobytes ๐Ÿ“
  • prefetch-dynamic-strides โ€” whether the loop array prefetch pass should issue software prefetch hints for strides that aren't constant ๐Ÿฆ‹ This can be beneficial, but a non-constant stride can make it really hard to tell when the hints will clearly help ๐Ÿค”
    • Set to 1 if prefetch hints should be issued for non-constant strides โœ…
    • Set to 0 if prefetch hints should only be issued for strides that are known to be constant and below prefetch-minimum-stride โœ…
  • prefetch-minimum-stride โ€” the minimum constant stride, in bytes, before prefetch hints kick in ๐ŸŒท If the stride is below this threshold, no prefetch hints get issued ๐Ÿ™…โ€โ™€๏ธ
    • This is super handy for processors with hardware prefetchers ๐Ÿ–ฅ๏ธ Those and the software prefetchers can step on each other's toes, so if the hardware prefetchers have a maximum stride they can handle, that number belongs here to get the software prefetchers working well ๐Ÿซถ
    • A value of -1 means there's no threshold, so prefetch hints can be issued for any constant stride โ™พ๏ธ
    • This only matters for strides that are known and constant ๐Ÿ“
  • loop-interchange-max-num-stmts โ€” the max number of stmts in a loop that can be interchanged ๐Ÿ”„
  • loop-interchange-stride-ratio โ€” the minimum ratio between the strides of two loops for interchange to be profitable ๐Ÿ’œ
  • min-insn-to-prefetch-ratio โ€” the minimum ratio between the number of instructions and the number of prefetches needed to enable prefetching in a loop ๐Ÿงฎ
  • prefetch-min-insn-to-mem-ratio โ€” the minimum ratio between the number of instructions and the number of memory references needed to enable prefetching in a loop ๐Ÿงฎ
  • use-canonical-types โ€” whether the compiler uses the "canonical" type system ๐Ÿ‘‘ It should always be 1, since that uses a more efficient internal mechanism for comparing types in C++ and Objective-C++ ๐Ÿ’… But if bugs in the canonical type system are causing compilation failures, set 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 you're optimizing at -O3 and up ๐ŸŒช๏ธ For some source code, the enhanced partial redundancy elimination can run away and eat all the memory on the host machine ๐Ÿ˜ฑ This parameter caps the length of those sets to stop the runaway behavior ๐Ÿ›‘ Setting it to 0 allows an unlimited set length ๐ŸŒˆ
  • rpo-vn-max-loop-depth โ€” the max loop depth that gets value-numbered optimistically ๐Ÿง  When the limit is hit, the innermost rpo-vn-max-loop-depth loops and the outermost loop in the loop nest get value-numbered optimistically, and the remaining ones don't ๐Ÿซ 
  • 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 isn't considered redundant โŒ The number of queries is algorithmically limited to the number of stores on all paths from the load to the function entry ๐Ÿ“
  • ira-max-loops-num โ€” IRA uses regional register allocation by default ๐Ÿงฉ If a function has more loops than this parameter's number, only that many of the most frequently executed loops form regions for regional register allocation ๐Ÿ”
  • ira-max-conflict-table-size โ€” IRA uses a sophisticated algorithm to compress the conflict table, but for huge functions the table can still eat excessive memory ๐Ÿ˜ฉ If a function's conflict table could be bigger than the size in MB given by this parameter, the register allocator switches to a faster, simpler, lower-quality algorithm that doesn't need to build a pseudo-register conflict table ๐Ÿƒโ€โ™€๏ธ๐Ÿ’จ
  • ira-loop-reserved-regs โ€” okay so IRA can give a more accurate read on register pressure inside loops, which helps it decide whether to move loop invariants out (see -O3) ๐ŸŽ€. This parameter sets how many available registers get saved aside for other purposes. The default is the best value from a ton of experiments, so trust it bestie ๐Ÿ’….
  • lra-inheritance-ebb-probability-cutoff โ€” LRA tries to reuse values it already reloaded into registers in the insns that come after, and this trick is called inheritance ๐Ÿฆ‹. The EBB is the region it uses for this. The parameter is the minimum fall-through edge probability, as a percentage, needed before a BB gets added to the inheritance EBB in LRA. The default was picked from numerous runs of SPEC2000 on x86-64, so it's been tested to death ๐Ÿ”ฅ.
  • loop-invariant-max-bbs-in-loop โ€” loop invariant motion can be super expensive in compile time and in how much compile-time memory it eats, especially with really huge loops ๐Ÿ’€. Any loop with more basic blocks than this parameter just won't get loop invariant motion applied to it ๐Ÿ™ˆ.
  • loop-max-datarefs-for-datadeps โ€” building data dependencies gets pricey for very large loops ๐Ÿ˜ญ. This parameter caps how many data references in a loop get considered for data dependence analysis. The really big loops don't get handled by the optimizations that rely on loop data dependencies, so they just get skipped ๐ŸŒธ.
  • max-vartrack-size โ€” this sets the max number of hash table slots that can be used during variable tracking dataflow analysis for any function ๐Ÿงš. If you go over the limit while variable tracking at assignments is turned on, the analysis gets retried without it, after all the debug insns are removed from the function. If it's still over the limit even without debug insns, var tracking analysis is totally disabled for that function ๐Ÿ˜ญ. Setting it to zero makes it unlimited โœจ.
  • max-vartrack-expr-depth โ€” the max number of recursion levels when the compiler tries to map variable names or debug temporaries to value expressions ๐ŸŒˆ. It's basically trading compile time for more complete debug info. If you set it too low, value expressions that could be in the debug info might not get used at all ๐Ÿ™ƒ. Setting it higher lets the compiler find fancier debug expressions, but compile time and memory use can grow ๐Ÿ’œ.
  • max-debug-marker-count โ€” a cap on the number of debug markers (like begin stmt markers) so things don't get too complicated during inlining or expanding to RTL ๐Ÿ“. If a function has more of these 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 value are used for nondebug insns โญ. The range below it is reserved exclusively for debug insns created by -fvar-tracking-assignments. But debug insns can still get (non-overlapping) uids above it if that reserved range runs out ๐Ÿซถ.
  • ipa-sra-ptr-growth-factor โ€” IPA-SRA only swaps a pointer to an aggregate out for 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 ๐Ÿฆ‹.
  • sra-max-scalarization-size-Ospeed and sra-max-scalarization-size-Osize โ€” the two Scalar Reduction of Aggregates passes (SRA and IPA-SRA) are all about swapping the scalar parts of aggregates for uses of independent scalar variables ๐Ÿ‘‘. These two params set the max size, in storage units, of an aggregate that's even considered for replacement. sra-max-scalarization-size-Ospeed is for when you're compiling for speed, and sra-max-scalarization-size-Osize is for when you're compiling for size ๐Ÿ”ฅ.
  • sra-max-propagations โ€” the max number of artificial accesses that SRA will track for one local variable so it can do copy propagation ๐ŸŽ€.
  • tm-max-aggregate-size โ€” when copying thread-local variables inside a transaction, this sets the size in bytes after which variables get saved with the logging functions instead of the save/restore code sequence pairs ๐ŸŒธ. This option only applies when you're using -fgnu-tm ๐Ÿงš.
  • graphite-max-nb-scop-params โ€” to avoid exponential chaos in the Graphite loop transforms, the number of parameters in a Static Control Part (SCoP) is capped ๐Ÿ™ƒ. A value of zero lifts the cap. A variable whose value isn't known at compile time and is defined outside a SCoP counts as a parameter of the SCoP โœจ.
  • loop-block-tile-size โ€” loop blocking or strip mining (turned on with -floop-block or -floop-strip-mine) strip mines each loop in the loop nest by a set number of iterations ๐Ÿ“. You can change the strip length with this parameter ๐Ÿ’–.
  • ipa-cp-value-list-size โ€” IPA-CP tries to track every possible value and type passed to a function's parameter so it can propagate them and do devirtualization ๐Ÿง . This is the max number of values and types it stores for each formal parameter of a function ๐Ÿ’œ.
  • ipa-cp-eval-threshold โ€” IPA-CP calculates its own score for how profitable cloning is, and it goes ahead and does the cloning for any opportunity whose score is above ipa-cp-eval-threshold ๐Ÿ”ฅ.
  • ipa-cp-recursion-penalty โ€” the percentage penalty that recursive functions get when they're being evaluated for cloning ๐Ÿ™ˆ.
  • ipa-cp-single-call-penalty โ€” the percentage penalty that functions with a single call to another function get when they're being evaluated for cloning ๐ŸŒˆ.
  • ipa-max-agg-items โ€” IPA-CP can also propagate a bunch of scalar values passed inside an aggregate ๐Ÿซถ. This controls the max number of those values for each parameter ๐Ÿ’….
  • ipa-cp-loop-hint-bonus โ€” if IPA-CP figures out that a cloning candidate would make a loop's iteration count known, it adds a bonus of ipa-cp-loop-hint-bonus to that candidate's profitability score โญ.
  • ipa-cp-array-index-hint-bonus โ€” same vibe as the loop one! If a cloning candidate would make the index of an array access known, IPA-CP adds a bonus of ipa-cp-array-index-hint-bonus to the candidate's profitability score ๐Ÿฆ‹.
  • ipa-max-aa-steps โ€” while it analyzes function bodies, IPA-CP uses alias analysis to track values pointed to by function parameters ๐Ÿงš. So it doesn't spend forever on huge functions, it gives up and considers all memory clobbered after examining ipa-max-aa-steps statements that modify memory ๐Ÿ˜ญ.
  • lto-partitions โ€” the desired number of partitions made during WHOPR compilation ๐Ÿ‘‘. It should be more than the number of CPUs used for compilation ๐Ÿ’–.
  • lto-min-partition โ€” the size of the smallest partition for WHOPR (in estimated instructions) ๐ŸŒธ. This stops tiny programs from being chopped into way too many partitions ๐Ÿ™ƒ.
  • lto-max-partition โ€” the size of the biggest partition for WHOPR (in estimated instructions) ๐ŸŽ€. It gives an upper bound on how big any single partition can be โœจ. It's only meant to be used with balanced partitioning ๐Ÿซถ.
  • lto-max-streaming-parallelism โ€” the max number of parallel processes used for LTO streaming ๐Ÿ”ฅ.
  • cxx-max-namespaces-for-diagnostic-help โ€” the max number of namespaces the compiler checks for suggestions when a C++ name lookup fails for an identifier ๐Ÿง .
  • sink-frequency-threshold โ€” the max relative execution frequency (in percent) of the target block, compared to the statement's original block, that still allows statement sinking ๐Ÿ“. Bigger numbers mean more aggressive statement sinking ๐Ÿ’œ. A small positive adjustment gets applied to statements with memory operands, since those are even more profitable to sink ๐Ÿ’….
  • max-stores-to-sink โ€” the max number of conditional store pairs that can be sunk ๐ŸŒˆ. Set it to 0 if either vectorization (-ftree-vectorize) or if-conversion (-ftree-loop-if-convert) is disabled ๐Ÿ™ˆ.
  • allow-store-data-races โ€” lets optimizers introduce new data races on stores โš ๏ธ. Set it to 1 to allow that, or 0 to not ๐Ÿฆ‹. (Be careful with this one, bestie, because races can be a total disaster ๐Ÿ’€.)
  • case-values-threshold โ€” the smallest number of different values where a jump-table is better than a tree of conditional branches ๐Ÿงš. If the value is 0, the default for the machine gets used โœจ.
  • tree-reassoc-width โ€” sets the max number of instructions that run in parallel in a reassociated tree ๐Ÿ”ฅ. If it's set to a non-zero value, it overrides the target-dependent heuristics that would be used by default ๐Ÿ‘‘.
  • sched-pressure-algorithm โ€” lets you choose between the two implementations of -fsched-pressure ๐ŸŽ€. Algorithm 1 is the original, and it's more likely to stop instructions from getting reordered ๐Ÿ™ƒ. Algorithm 2 was designed as a compromise between the pretty conservative approach of algorithm 1 and the aggressive approach of the default scheduler ๐ŸŒธ. It leans harder on having a regular register file and accurate register pressure classes ๐Ÿซถ. See haifa-sched.c in the GCC sources for more details ๐Ÿ“–. The default depends on the target ๐Ÿงš.
  • max-slsr-cand-scan โ€” sets the max number of existing candidates that get 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 object protection, use --param asan-globals=0 ๐Ÿ™ˆ.
  • asan-stack โ€” turns on buffer overflow detection for stack objects ๐ŸŒˆ. This protection is also on by default when using -fsanitize=address. To turn off stack protection, use --param asan-stack=0 option ๐Ÿ’….
  • asan-instrument-reads โ€” okay so this one turns on buffer overflow detection for memory reads ๐Ÿ‘€ It's already on by default when you use -fsanitize=address. If you want to turn reads protection off, use --param asan-instrument-reads=0.
  • asan-instrument-writes โ€” same energy, but for memory writes โœ๏ธ Also on by default with -fsanitize=address. To disable writes protection, use --param asan-instrument-writes=0 option.
  • asan-memintrin โ€” detection for built-in functions ๐Ÿงฉ This is on by default with -fsanitize=address. To turn built-in functions protection off, use --param asan-memintrin=0.
  • asan-use-after-return โ€” detects use-after-return ๐Ÿ•ฐ๏ธ It's on by default when you use the -fsanitize=address option. To disable it, use --param asan-use-after-return=0.
Note: By default the check is disabled at run time ๐Ÿ™ˆ To turn it on, add "detect_stack_use_after_return=1" to the environment variable ASAN_OPTIONS.
  • asan-instrumentation-with-call-threshold โ€” if the number of memory accesses in the function being instrumented is greater or equal to this number, GCC uses callbacks instead of inline checks ๐Ÿง  E.g. to skip the inline code entirely, use --param asan-instrumentation-with-call-threshold=0.
  • use-after-scope-direct-emission-threshold โ€” if a local variable's size in bytes is smaller or equal to this number, shadow memory gets poisoned (or unpoisoned) directly, instead of going through run-time callbacks โšก
  • max-fsm-thread-path-insns โ€” the max number of instructions to copy when duplicating blocks on a finite state automaton jump thread path ๐Ÿงต
  • max-fsm-thread-length โ€” the max number of basic blocks on a finite state automaton jump thread path ๐Ÿงต
  • max-fsm-thread-paths โ€” the max number of new jump thread paths to create for a finite state automaton ๐Ÿงต
  • parloops-chunk-size โ€” the chunk size of the omp schedule for loops parallelized by parloops ๐ŸŒธ
  • parloops-schedule โ€” the schedule type of the omp schedule for loops parallelized by parloops ๐ŸŒธ Pick from static, dynamic, guided, auto, or runtime.
  • parloops-min-per-thread โ€” this is the minimum number of iterations per thread of an innermost parallelized loop where the parallel version is preferred over the single threaded one ๐Ÿ’… Heads up: for a parallelized loop nest, the minimum number of iterations of the outermost loop per thread is two.
  • 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 we analyze while hunting for a must-def that tells us the dynamic type of an object making a virtual call we might be able to speculatively devirtualize ๐Ÿ”Ž
  • max-vrp-switch-assertions โ€” the max number of assertions to add along the default edge of a switch statement during VRP ๐ŸŽ€
  • unroll-jam-min-percent โ€” the minimum percentage of memory references that must 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 permissible cost for the sequence the RTL if-conversion pass would generate for a branch that's considered unpredictable ๐ŸŽฒ
  • max-variable-expansions-in-unroller โ€” if -fvariable-expansion-in-unroller is used, this is the max number of times one individual variable gets expanded during loop unrolling ๐ŸŒ€
  • tracer-min-branch-probability-feedback โ€” stop forward growth if the probability of the best edge is less than this threshold (in percent) ๐Ÿ“‰ This one is used when profile feedback is available.
  • partial-inlining-entry-probability โ€” the max probability of the entry BB of a split region (in percent, relative to the entry BB of the function) that still lets partial inlining happen ๐Ÿงฉ
  • max-tracked-strlens โ€” the max number of strings the strlen optimization pass will track string lengths for ๐Ÿงถ
  • gcse-after-reload-partial-fraction โ€” the threshold ratio for performing partial redundancy elimination after reload ๐Ÿ’ซ
  • gcse-after-reload-critical-fraction โ€” the threshold ratio of critical edges' execution count that allows redundancy elimination after reload โœจ
  • max-loop-header-insns โ€” the max number of insns in a loop header duplicated by the copy loop headers pass ๐Ÿซถ
  • vect-epilogues-nomask โ€” enables loop epilogue vectorization using a smaller vector size ๐Ÿฆ‹
  • slp-max-insns-in-bb โ€” the max number of instructions in a basic block that gets considered for SLP vectorization ๐ŸŒˆ
  • avoid-fma-max-bits โ€” the max number of bits for which we avoid creating FMAs ๐Ÿ™…โ€โ™€๏ธ
  • sms-loop-average-count-threshold โ€” a threshold on the average loop count that the swing modulo scheduler considers ๐Ÿ”„
  • sms-dfa-history โ€” the number of cycles the swing modulo scheduler looks at when checking for conflicts using DFA ๐Ÿ•ฐ๏ธ
  • hot-bb-count-fraction โ€” the fraction of the max count of repetitions of a basic block in the program that a given basic block needs to hit to be considered hot ๐Ÿ”ฅ This one is used in non-LTO mode.
  • max-inline-insns-recursive-auto โ€” the max number of instructions a non-inline function can grow to via recursive inlining ๐Ÿ“ˆ
  • graphite-allow-codegen-errors โ€” decides whether codegen errors should be ICEs when -fchecking is on ๐Ÿงช
  • sms-max-ii-factor โ€” a factor for tuning the upper bound the swing modulo scheduler uses when scheduling a loop ๐ŸŽš๏ธ
  • lra-max-considered-reload-pseudos โ€” the max number of reload pseudos considered while spilling a non-reload pseudo ๐ŸŒท
  • max-pow-sqrt-depth โ€” the max depth of sqrt chains to use 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 โ€” enables asan allocas/VLAs protection ๐Ÿ›ก๏ธ
  • max-iterations-computation-cost โ€” the bound on the cost of an expression used to compute the number of iterations ๐Ÿงฎ
  • max-isl-operations โ€” the max number of isl operations, 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 ๐Ÿงท
  • unlikely-bb-count-fraction โ€” the minimum fraction of profile runs a given basic block's execution count has to be in order to not be considered unlikely ๐ŸŒ™
  • tracer-dynamic-coverage-feedback โ€” the percentage of a function, weighted by execution frequency, that trace formation must cover ๐Ÿ“Š 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 comparing against 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 to search for control dependencies during uninitialized variable analysis ๐Ÿ”
  • indir-call-topn-profile โ€” tracks the top N target addresses in the indirect-call profile ๐Ÿ‘‘
  • max-once-peeled-insns โ€” the max number of insns in a peeled loop that only rolls once ๐ŸŽข
  • sra-max-scalarization-size-Osize โ€” the max size, in storage units, of an aggregate that gets 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 comparing against the number of (scaled) statements ๐ŸŒป
  • sched-autopref-queue-depth โ€” a hardware autoprefetcher scheduler model control flag ๐Ÿง  It sets the number of lookahead cycles the model looks into. At ' ', only the instruction sorting heuristic gets enabled.
  • loop-versioning-max-inner-insns โ€” the max number of instructions an inner loop can have before the loop versioning pass decides it's too big to copy ๐Ÿ“š
  • loop-versioning-max-outer-insns โ€” the max number of instructions an outer loop can have before the loop versioning pass decides it's too big to copy, not counting any instructions in inner loops that directly benefit from versioning ๐Ÿ“š
  • 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.

โœจ Program Instrumentation Options โœจ

GCC supports a bunch of command-line options that control adding run-time instrumentation to the code it normally generates ๐ŸŽ€ For example, one purpose of instrumentation is collecting profiling statistics for finding program hot spots, doing code coverage analysis, or running profile-guided optimizations ๐Ÿ“Š Another kind of instrumentation adds run-time checking to catch programming errors like invalid pointer dereferences or out-of-bounds array accesses, plus deliberately hostile attacks like stack smashing or C++ vtable hijacking ๐Ÿ›ก๏ธ There's also a general hook that can be used to build other forms of tracing or function-level instrumentation for debug or program analysis purposes ๐Ÿฆ‹

  • -p, -pg โ€” okay bestie, these two make GCC sneak extra profiling code into your program ๐Ÿ“Š -p is for the prof analysis tool and -pg is for gprof. You have to pass the option when you compile the source files you want stats on, and when you link, no skipping ๐Ÿ™… You can also slap the function attribute no_instrument_function on a specific function to stop it from being profiled when you compile with these options ๐Ÿฆ‹
  • -fprofile-arcs โ€” this one instruments the program flow arcs โœจ While your program runs, it keeps count of how many times each branch and call happens, and how many times each one is taken or returns. On targets that support constructors with priority, profiling handles constructors, destructors, and C++ constructors (and destructors) of classes used as the type of a global variable properly ๐Ÿ’–

When the compiled program exits, it saves that data to a file called auxname.gcda for each source file. The data can be used for profile-directed optimizations (-fbranch-probabilities) or for test coverage analysis (-ftest-coverage). Each object file's auxname comes from the output file's name if you explicitly specified one and it isn't the final executable. Otherwise it's the basename of the source file. Either way, any suffix gets chopped off (so you get foo.gcda for input dir/foo.c, or dir/foo.gcda for output specified as -o dir/foo.o) ๐ŸŒธ

  • --coverage โ€” the ultimate combo ๐ŸŒˆ It's a synonym for -fprofile-arcs -ftest-coverage when compiling, and for -lgcov when linking. Check the docs for those options for more details. Here's the whole glow-up:
    • Compile the source files with -fprofile-arcs plus optimization and code generation options. For test coverage analysis, add the extra -ftest-coverage option. You don't need to profile every single source file in a program ๐Ÿ’…
    • Compile the source files additionally with -fprofile-abs-path to create absolute path names in the .gcno files. This lets gcov find the correct sources in projects where compilations happen with different working directories ๐Ÿ—บ๏ธ
    • Link your object files with -lgcov or -fprofile-arcs. The latter implies the former ๐Ÿ”—
    • Run the program on a representative workload to generate the arc profile information. You can repeat this as many times as you want ๐Ÿ” You can even 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 are 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. Refer to the gcov documentation for further info ๐Ÿ“–

With -fprofile-arcs, GCC builds a program flow graph for each function in your program, then finds a spanning tree for that graph. Only the arcs that aren't on the spanning tree need instrumenting. The compiler adds code to count how many times those arcs run. When an arc is the only exit or the only entrance to a block, the instrumentation code can go right into that block. Otherwise, a new basic block has to be created to hold it ๐Ÿง 

  • -ftest-coverage โ€” this makes a notes file that the gcov code-coverage utility uses to show your program's coverage ๐ŸŽ€ Each source file's notes file is called auxname.gcno. Check out the -fprofile-arcs entry above for what auxname means and how to generate test coverage data. Heads up: coverage data matches your source more closely if you don't optimize ๐Ÿ‘€
  • -fprofile-abs-path โ€” this automatically converts relative source file names into absolute path names in the .gcno files. That way gcov can find the right sources in projects where compilations happen with different working directories ๐Ÿฆ‹
  • -fprofile-dir=path โ€” sets the directory where the profile data files get searched for, to path ๐Ÿ“ This only affects profile data generated by -fprofile-generate, -ftest-coverage, and -fprofile-arcs, and used by -fprofile-use and -fbranch-probabilities and its related options. Absolute and relative paths both work. By default GCC uses the current directory, so the profile data file lands in the same directory as the object file. To avoid file name clashes, if the object file name isn't an absolute path, GCC mangles the absolute path of the sourcename.gcda file and uses that as the name of the .gcda file ๐Ÿงฉ

When an executable runs in a massively parallel environment, it's recommended to save profiles to different folders. You can do that with variables in path that get exported at run-time:

  • %p โ€” process ID ๐Ÿ†”
  • %q{VAR} โ€” value of environment variable VAR ๐ŸŒฟ
  • -fprofile-generate, -fprofile-generate=path โ€” turns on the options that instrument your app so it produces a profile for later recompilation with profile feedback based optimization ๐Ÿ”ฎ You must use -fprofile-generate both when compiling and when linking. The following options get enabled: -fprofile-arcs, -fprofile-values, -finline-functions, and -fipa-bit-cp ๐Ÿ’œ If path is specified, GCC looks there for the profile feedback data files. See -fprofile-dir. To optimize the program based on the collected profile information, use -fprofile-use ๐Ÿ†
  • -fprofile-update=method โ€” changes the update method for an app instrumented for profile feedback based optimization โš™๏ธ The method argument should be one of single, atomic or prefer-atomic. The first one is useful for single-threaded apps, and the second one prevents profile corruption by emitting thread-safe code ๐Ÿงต
โš ๏ธ Warning: if an application doesn't properly join all of its threads (or creates a detached thread), a profile file can still get corrupted. Be careful, bestie ๐Ÿ™ˆ

Using prefer-atomic gets transformed either to atomic, when a target supports it, or to single otherwise. The GCC driver automatically selects prefer-atomic when -pthread is present on the command line โœจ

  • -fprofile-filter-files=regex โ€” only instruments functions from files whose names match any regular expression (separated by a semicolon) ๐ŸŽฏ For example, -fprofile-filter-files=main.c;module.*.c will instrument only main.c and all C files starting with module ๐Ÿ“
  • -fprofile-exclude-files=regex โ€” 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/* prevents instrumentation of every file located in the /usr/ folder ๐Ÿ™…โ€โ™€๏ธ

  • -fsanitize=address โ€” enables AddressSanitizer, a fast memory error detector ๐Ÿงผ Memory access instructions get instrumented to catch out-of-bounds and use-after-free bugs. This option also enables -fsanitize-address-use-after-scope. More details live at https://github.com/google/sanitizers/wiki/AddressSanitizer. The run-time behavior can be influenced with the ASAN_OPTIONS environment variable. When it's set to "help=1", the available options get shown at startup of the instrumented program. You can find the supported options at 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 ๐Ÿง More details at https://github.com/google/kasan/wiki.
  • -fsanitize=pointer-compare โ€” instruments comparison operations (<, <=, >, >=) with pointer operands ๐Ÿ” This option must be combined with either -fsanitize=kernel-address or -fsanitize=address. It cannot be combined with -fsanitize=thread. Note: by default the check is disabled at run time. To turn it on, add "detect_invalid_pointer_pairs=2" to the ASAN_OPTIONS environment variable. Using "detect_invalid_pointer_pairs=1" only detects invalid operations when both pointers are non-null ๐Ÿซถ
  • -fsanitize=pointer-subtract โ€” instruments subtraction with pointer operands ๐Ÿงฎ This option must be combined with either -fsanitize=kernel-address or -fsanitize=address. It cannot be combined with -fsanitize=thread. Note: by default the check is disabled at run time. To enable it, add "detect_invalid_pointer_pairs=2" to the ASAN_OPTIONS environment variable. Using "detect_invalid_pointer_pairs=1" detects invalid operations only when both pointers are non-null ๐Ÿ’…
  • -fsanitize=thread โ€” enables ThreadSanitizer, a fast data race detector ๐Ÿงต Memory access instructions get instrumented to catch data race bugs. More details at https://github.com/google/sanitizers/wiki#threadsanitizer. The run-time behavior can be influenced with the TSAN_OPTIONS environment variable. See https://github.com/google/sanitizers/wiki/ThreadSanitizerFlags for a list of supported options. This option cannot be combined with -fsanitize=address or -fsanitize=leak โŒ

Heads up: sanitized atomic builtins can't throw exceptions when operating on invalid memory addresses with non-call exceptions (-fnon-call-exceptions) ๐Ÿ’€

  • -fsanitize=leak โ€” enables LeakSanitizer, a memory leak detector ๐Ÿ’ง This option only matters for linking executables, and the executable has to be linked against a library that overrides malloc and other allocator functions. More details at 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. See https://clang.llvm.org/docs/UndefinedBehaviorSanitizer.html for more details. The run-time behavior can be influenced with the UBSAN_OPTIONS environment variable. The current suboptions are:
  • -fsanitize=shift โ€” ๐Ÿ“ okay so this one checks that the result of a shift operation isn't undefined. Ngl, what counts as undefined is slightly different between C and C++, and between ISO C90 and C99, etc. It has two suboptions: -fsanitize=shift-base and -fsanitize=shift-exponent. ๐Ÿ’…
  • -fsanitize=shift-exponent โ€” ๐Ÿฆ‹ checks that the second argument of a shift is not negative and is smaller than the precision of the promoted first argument. Literally the bouncer for shifts. ๐Ÿšช
  • -fsanitize=shift-base โ€” ๐Ÿ’œ if the second argument of a shift is within range, this checks that the result of the shift is not undefined. Same vibe as above: the rules for what's undefined differ a bit between C and C++, and between ISO C90 and C99, etc. ๐ŸŒธ
  • -fsanitize=integer-divide-by-zero โ€” โœจ detects integer division by zero, plus INT_MIN / -1 division. ๐Ÿ’€
  • -fsanitize=unreachable โ€” ๐Ÿ”ฅ with this on, the compiler turns the __builtin_unreachable call into a diagnostics message call instead. When you actually reach __builtin_unreachable, the behavior is undefined. ๐Ÿ™ˆ
  • -fsanitize=vla-bound โ€” ๐ŸŽ€ makes the compiler check that the size of a variable length array is positive.
  • -fsanitize=null โ€” ๐Ÿซถ pointer checking! An app built with this will issue an error message when it tries to dereference a NULL pointer, when a reference (possibly an rvalue reference) gets bound to a NULL pointer, or when a method is invoked on an object pointed to by a NULL pointer. โ›”
  • -fsanitize=return โ€” ๐Ÿ‘‘ return statement checking. Programs built with this will issue an error message when the end of a non-void function is reached without actually returning a value. This one works in C++ only. ๐ŸŒˆ
  • -fsanitize=signed-integer-overflow โ€” ๐Ÿ’– checks signed integer overflow. We check that the result of +, *, and both unary and binary - doesn't overflow in signed arithmetic. Integer promotion rules totally count here! Like, this one is not an overflow:
signed char a = SCHAR_MAX;
a++;
  • -fsanitize=bounds โ€” ๐Ÿงš turns on array bounds instrumentation, so various out of bounds accesses get detected. Flexible array members, flexible array member-like arrays, and initializers of variables with static storage are not instrumented. ๐Ÿ™…
  • -fsanitize=bounds-strict โ€” ๐Ÿ’… the stricter array bounds check! Most out of bounds accesses get caught, 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 whenever pointers get dereferenced, when a reference is bound to an insufficiently aligned target, or when a method or constructor is invoked on an insufficiently aligned object. ๐Ÿ“
  • -fsanitize=object-size โ€” ๐ŸŒธ instruments memory references using the __builtin_object_size function. Various out of bounds pointer accesses get detected. ๐Ÿ‘€
  • -fsanitize=float-divide-by-zero โ€” โญ detects floating-point division by zero. Unlike other similar options, this one is not enabled by -fsanitize=undefined, since floating-point division by zero can be a totally legit way to get infinities and NaNs. ๐Ÿซถ
  • -fsanitize=float-cast-overflow โ€” ๐Ÿ“ enables floating-point to integer conversion checking. We check that the result of the conversion doesn't overflow. Unlike other similar options, this is not enabled by -fsanitize=undefined. Also, it does not work well with FE_INVALID exceptions enabled. ๐Ÿ˜ญ
  • -fsanitize=nonnull-attribute โ€” ๐ŸŽ€ instruments calls, checking 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 it can detect null values being returned from those functions. ๐Ÿ•ต๏ธ
  • -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 โ€” ๐Ÿ‘‘ instruments C++ member function calls, member accesses, and some conversions between pointers to base and derived classes, to verify the referenced object has the correct dynamic type. ๐Ÿ›๏ธ
  • -fsanitize=pointer-overflow โ€” ๐Ÿ”ฅ instruments pointer arithmetic. If the pointer arithmetic overflows, a run-time error is issued. ๐Ÿ’ฅ
  • -fsanitize=builtin โ€” โœจ instruments arguments to selected builtin functions. If an invalid value is 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 gets 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. ๐Ÿ™…โ€โ™€๏ธ
  • -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] โ€” ๐Ÿ›Ÿ -fsanitize-recover= controls the error recovery mode for the sanitizers listed in the comma-separated list of opts. Turn it on for a sanitizer and it tries to keep the program running as if no error happened. That means multiple runtime errors can be reported in a single run, and the exit code might say success even when errors were reported. ๐Ÿคท

The -fno-sanitize-recover= option changes this: only the first detected error is reported, and then the program exits with a non-zero exit code. ๐Ÿ›‘

Right now this feature only works for -fsanitize=undefined (and its suboptions, except -fsanitize=unreachable and -fsanitize=return), -fsanitize=float-cast-overflow, -fsanitize=float-divide-by-zero, -fsanitize=bounds-strict, -fsanitize=kernel-address and -fsanitize=address. For these sanitizers, error recovery is turned on by default, except -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 at the compiler side, it also needs to be enabled on the runtime library side, otherwise the failures are still fatal. ๐Ÿ’€ The runtime library defaults to halt_on_error=0 for ThreadSanitizer and UndefinedBehaviorSanitizer, while the default value for AddressSanitizer is halt_on_error=1. 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 is that the libubsan library is not needed and is not linked in, so this is usable even in freestanding environments. ๐ŸŒฟ
  • -fsanitize-coverage=trace-pc โ€” ๐Ÿ•ต๏ธ enables coverage-guided fuzzing code instrumentation. Inserts a call to __sanitizer_cov_trace_pc into every basic block. ๐Ÿงญ
  • -fsanitize-coverage=trace-cmp โ€” ๐Ÿ”Ž enables dataflow guided fuzzing code instrumentation. Inserts 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, or __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, and __sanitizer_cov_trace_switch for switch statements. ๐Ÿงฉ
  • -fcf-protection=[full|branch|return|none|check] โ€” ๐Ÿ›ก๏ธ enables code instrumentation of control-flow transfers to boost program security by checking that target addresses of control-flow transfer instructions (such as indirect function calls, function returns, and indirect jumps) are valid. This prevents diverting the flow of control to an unexpected target. It's intended to protect against threats like Return-oriented Programming (ROP), and similarly call/jmp-oriented programming (COP/JOP). ๐Ÿ”โœจ

Okay so the value branch tells the compiler to check that control-flow transfers are valid at indirect branch instructions (aka call/jmp instructions) ๐Ÿ’…. The value return checks validity when a function returns ๐Ÿ”™. full is an alias for specifying both branch and return โœจ, and none turns off the instrumentation entirely ๐Ÿ™…โ€โ™€๏ธ.

The value check is for the final link with link-time optimization (LTO) ๐Ÿ”—. An error gets issued if LTO object files were compiled with different -fcf-protection values ๐Ÿšจ. And check is ignored at compile time ๐Ÿ™ˆ.

The macro __CET__ gets defined whenever -fcf-protection is used ๐Ÿงš. Its first bit is set to 1 for the value branch, and its second bit is set to 1 for return ๐Ÿ’œ.

You can also use the nocf_check attribute to pick out which functions and calls should be skipped from instrumentation ๐ŸŽ€.

Currently the x86 GNU/Linux target has an implementation based on Intel Control-flow Enforcement Technology (CET), which works for i686 processors or newer ๐ŸŒˆ.

๐Ÿ“ฃ NOTE: In Ubuntu 19.10 and later versions, -fcf-protection is enabled by default for C, C++, ObjC, ObjC++, if none of -fno-cf-protection nor -fcf-protection=* are found. ๐Ÿ’€

  • -fstack-protector โ€” Emit extra code to check for buffer overflows ๐Ÿ›ก๏ธ, like stack smashing attacks ๐Ÿ’ฅ. It adds a guard variable to functions with vulnerable objects, which includes functions that call alloca and functions with buffers larger than 8 bytes ๐Ÿงธ. The guards get initialized when a function is entered and then checked when it exits ๐Ÿ”. If a guard check fails, an error message is printed and the program exits ๐Ÿ˜ญ.
  • -fstack-protector-all โ€” Same energy as -fstack-protector, except that every single function gets protected ๐Ÿ‘‘.
  • -fstack-protector-strong โ€” Like -fstack-protector but with extra functions added to the protected list ๐Ÿ’ช: those that have local array definitions, or have references to local frame addresses ๐Ÿงฉ.
  • -fstack-protector-explicit โ€” Like -fstack-protector but only protects the functions that have the stack_protect attribute ๐ŸŽฏ.
  • -fstack-check โ€” Generates code to verify that you don't go beyond the boundary of the stack ๐Ÿงฑ. You should specify this if you're running in an environment with multiple threads ๐Ÿงต, but you only rarely need it in a single-threaded environment, since stack overflow is automatically detected on nearly all systems when there's only one stack ๐Ÿ™Œ.

Quick heads up, though: this switch doesn't do the checking itself ๐Ÿ™…. The operating system or the language runtime has to do that. The switch just makes the code that ensures they see the stack being extended ๐Ÿซง.

You can also give it a string parameter: no means no checking, generic forces the old-style checking, and specific uses the best checking method and is equivalent to bare -fstack-check ๐ŸŽ€.

Old-style checking is a generic mechanism that needs no specific target support in the compiler, but it comes with these drawbacks ๐Ÿ˜ฌ:

  1. Modified allocation strategy for large objects: they're always allocated dynamically if their size exceeds a fixed threshold. Note this may change the semantics of some code.
  2. Fixed limit on the size of the static frame of functions: when it's topped by a particular function, stack checking isn't reliable and the compiler issues a warning.
  3. Inefficiency: because of both the modified allocation strategy and the generic implementation, code performance gets hampered.

Old-style stack checking is also the fallback method for specific if no target support has been added in the compiler ๐Ÿ”.

-fstack-check= is designed for Ada's needs to detect infinite recursion and stack overflows ๐Ÿ‘ธ. specific is an excellent choice when compiling Ada code ๐Ÿ’–. It's not generally sufficient to protect against stack-clash attacks, though. To protect against those, you want -fstack-clash-protection ๐Ÿ›ก๏ธ.

  • -fstack-clash-protection โ€” Generates code to prevent stack clash style attacks ๐Ÿ•ณ๏ธ. With this on, the compiler only allocates one page of stack space at a time, and each page is accessed right after allocation ๐Ÿ“„. That way, allocations can't jump over any stack guard page the operating system provides ๐Ÿšง.

Most targets don't fully support stack clash protection ๐Ÿ˜…. On those targets, -fstack-clash-protection protects dynamic stack allocations ๐Ÿ’ช. It may also give limited protection for static stack allocations if the target supports -fstack-check=specific ๐Ÿง .

๐Ÿ“ฃ NOTE: In Ubuntu 19.10 and later versions, -fstack-clash-protection is enabled by default for C, C++, ObjC, ObjC++, unless -fno-stack-clash-protection is found ๐ŸŒธ.
  • -fstack-limit-register=reg, -fstack-limit-symbol=sym, -fno-stack-limit โ€” Generates code to make sure the stack doesn't grow beyond a certain value ๐Ÿšฆ, either the value of a register or the address of a symbol. If a bigger stack is needed, a signal gets raised at run time โšก. For most targets, the signal is raised before the stack overruns the boundary, so you can catch it without taking special precautions ๐Ÿฅท.

For instance, if the stack starts at absolute address 0x80000000 and grows downwards, you can use the flags -fstack-limit-symbol=__stack_limit and -Wl,--defsym,__stack_limit=0x7ffe0000 to enforce a stack limit of 128KB ๐Ÿ“. Note that this may only work with the GNU linker ๐Ÿƒ.

You can locally override stack limit checking by using the no_stack_limit function attribute ๐Ÿ”“.

  • -fsplit-stack โ€” Generates code to automatically split the stack before it overflows โœ‚๏ธ. The resulting program has a discontiguous stack, which can only overflow if the program is unable to allocate any more memory ๐Ÿงฉ. This is most useful with threaded programs, since you no longer have to calculate a good stack size for each thread ๐Ÿงต. It's currently only implemented for the x86 targets running GNU/Linux ๐Ÿง.

When code compiled with -fsplit-stack calls code compiled without it, there may not be much stack space available for the latter code to run ๐Ÿ˜ฌ. If compiling all code, including library code, with -fsplit-stack isn't an option, the linker can fix up these calls so that code compiled without -fsplit-stack always has a large stack ๐Ÿ”ง. Support for this is implemented in the gold linker in GNU binutils release 2.21 and later ๐Ÿ“.


  • -fvtable-verify=[std|preinit|none] โ€” This is only available when compiling C++ code ๐Ÿ’œ. It turns on (or off, if you use -fvtable-verify=none) the security feature that checks at run time, for every virtual call, that the vtable pointer used for the call is valid for the object's type and hasn't been corrupted or overwritten ๐Ÿ•ต๏ธ. If an invalid vtable pointer is detected at run time, an error is reported and execution of the program is immediately halted ๐Ÿ›‘.

This option builds run-time data structures at program startup, and those are used to verify the vtable pointers ๐Ÿ—๏ธ. The options std and preinit control when these data structures get built โฐ. In both cases, they're built before execution reaches main ๐Ÿšช. -fvtable-verify=std builds them after shared libraries have been loaded and initialized ๐Ÿ“š, while -fvtable-verify=preinit builds them before shared libraries have been loaded and initialized ๐Ÿฃ.

If this option appears multiple times on the command line with different values specified, none takes highest priority over both std and preinit, and preinit takes priority over std ๐Ÿ‘‘.

  • -fvtv-debug โ€” When used with -fvtable-verify=std or -fvtable-verify=preinit, it causes debug versions of the runtime functions for the vtable verification feature to be called ๐Ÿ›. It also makes the compiler log which vtable pointers it finds for each class ๐Ÿ“. That info is written to a file named vtv_set_ptr_data.log in the directory named by the environment variable VTV_LOGS_DIR if that is defined, or the current working directory otherwise ๐Ÿ“‚.
Note: This feature appends data to the log file. If you want a fresh log file, be sure to delete any existing one ๐Ÿ—‘๏ธ.
  • -fvtv-counts โ€” This is a debugging flag ๐Ÿ”Ž. When used 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 it inserts, and logs that info for each compilation unit ๐Ÿ“Š. The compiler writes this to a file named vtv_count_data.log in the directory named by the environment variable VTV_LOGS_DIR if that is defined, or the current working directory otherwise ๐Ÿ—‚๏ธ. It also counts the size of the vtable pointer sets for each class and writes that to vtv_class_set_sizes.log in the same directory ๐Ÿ“.
Note: This feature appends data to the log files. To get fresh log files, be sure to delete any existing ones ๐Ÿงน.
  • -finstrument-functions โ€” Generates instrumentation calls for function entry and exit ๐Ÿ“. Just after function entry and just before function exit, the following profiling functions are called with the address of the current function and its call site ๐Ÿ”ญ. (On some platforms, __builtin_return_address doesn't work beyond the current function, so the call site information may not be available to the profiling functions otherwise ๐Ÿ™ˆ.)
void __cyg_profile_func_enter (void *this_fn,
                               void *call_site);
void __cyg_profile_func_exit  (void *this_fn,
                               void *call_site);

The first argument is the address of the start of the current function ๐Ÿ“, which may be looked up exactly in the symbol table ๐Ÿ”.

This instrumentation also happens for functions that get expanded inline inside other functions ๐Ÿ’… The profiling calls basically mark where the inline function is conceptually entered and exited, so addressable versions of those functions have to exist ๐Ÿฅบ If all your uses of a function get expanded inline, that can mean extra code size ๐Ÿ’€ And if you use extern inline in your C code, you have to provide an addressable version of the function ๐ŸŽ€ (This is normally the case anyway, but if you get lucky and the optimizer always expands the function inline, you might have gotten away without providing static copies ๐Ÿ™ˆ)

A function can be given the attribute no_instrument_function, and then this instrumentation just isn't done ๐Ÿ™…โ€โ™€๏ธ That's super handy for things like the profiling functions listed above ๐Ÿ“ˆ, high-priority interrupt routines โšก, and any functions the profiling functions can't safely be called from ๐Ÿ˜ฌ (think signal handlers, if the profiling routines generate output or allocate memory ๐Ÿซ ).

  • -finstrument-functions-exclude-file-list=file,file,... โ€” okay this one is a filter, and it's giving precision ๐Ÿ•ต๏ธโ€โ™€๏ธ It sets the list of functions that get excluded from instrumentation (see -finstrument-functions for the deets). If the file that contains a function definition matches one of the file entries, that function is not instrumented. The match is done on substrings, so if your file parameter is a substring of the file name, it counts as a match ๐ŸŽฏ

For example:

-finstrument-functions-exclude-file-list=/bits/stl,include/sys

That excludes any inline function defined in files whose pathnames contain /bits/stl or include/sys ๐Ÿงน

If, for some reason, you want to include the letter , in one of sym, write ,,. For example, -finstrument-functions-exclude-file-list=',,tmp' (note the single quote surrounding the option) โœจ

  • -finstrument-functions-exclude-function-list=sym,sym,... โ€” this is basically the same energy as the file list, except this one takes function names instead ๐Ÿฆ‹ The name that gets matched is the user-visible one, like vector<int> blah(const vector<int> &), NOT the internal mangled name (e.g., _Z4blahRSt6vectorIiSaIiEE) ๐Ÿ™ƒ Matching is substring-based too: if sym 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] โ€” okay this one is so cool ๐Ÿงš It generates N NOPs right at the beginning of each function, with the function entry point sitting before the Mth NOP. If M is omitted, it defaults to 0, so the entry point lands right at the first NOP ๐Ÿ“ Those NOPs reserve extra space you can use to patch in any instrumentation you want at run time, provided the code segment is writable ๐Ÿ”ฅ You control the amount of space indirectly, through 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 the 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 runs on each C source file before the actual compilation ๐Ÿงผ

If you use the -E option, nothing is done except preprocessing ๐Ÿ‘€ Some of these options only make sense together with -E, because they make the preprocessor output unsuitable for actual compilation ๐Ÿ™ƒ

In addition to the options listed here, there are a bunch 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 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 ๐Ÿง  In particular, the definition gets truncated by 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 shell syntax ๐Ÿš

If you wish to define a function-like macro on the command line, write its argument list with surrounding parentheses before the equals sign (if any). Parentheses are meaningful to most shells, so you should quote the option. With sh and csh, -D'name(args...)=definition' works ๐Ÿ’…

-D and -U options are processed in the order they are 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, either built in or provided with a -D option ๐Ÿงน
  • -include file โ€” processes file as if #include "file" appeared as the first line of the primary source file ๐Ÿ“‚ The 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's searched for in the remainder of the #include "..." search chain as normal ๐Ÿ”

If multiple -include options are given, the files are included in the order they appear on the command line ๐Ÿงพ

  • -imacros file โ€” exactly like -include, except any output produced by scanning file is thrown away ๐Ÿ—‘๏ธ The macros it defines stay defined, which 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 โ€” defines additional macros required for using the POSIX threads library ๐Ÿงต You should use this option consistently for both compilation and linking ๐Ÿ”— It's supported on GNU/Linux targets, most other Unix derivatives, and also on x86 Cygwin and MinGW targets ๐ŸŒˆ
  • -M โ€” main character energy ๐Ÿ’… Instead of outputting the result of preprocessing, it outputs a rule suitable for make that describes the dependencies of the main source file ๐Ÿ“œ The preprocessor outputs one make rule containing the object file name for that source file, a colon, and the names of all the included files, including those coming from -include or -imacros command-line options ๐Ÿงฉ

Unless you specify it explicitly (with -MT or -MQ), the object file name is the name of the source file with any suffix replaced by the object file suffix, and with any leading directory parts removed ๐Ÿ—‘๏ธ If there are many included files, the rule 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 tells CPP to add a phony target for each dependency other than the main file, causing each one to depend on nothing ๐Ÿ‘ป These dummy rules work around the errors make gives if you remove header files without updating the Makefile to match ๐Ÿฉน

This is typical output:

test.o: test.c test.h

test.h:
  • -MT target โ€” changes the target of the rule emitted by dependency generation ๐ŸŽฏ By default, CPP takes the name of the main input file, deletes any directory components and any file suffix such as .c, and appends the platform's usual object suffix. 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 ๐Ÿ’œ

Okay bestie, let's talk about the -MD flag ๐ŸŽ€ It's giving dependency-file energy ๐Ÿ’…

  • -MD โ€” basically -M -MF file with a glow-up, except it does not imply -E โœจ The driver figures out the file name like this:
    • If you've got an -o option, the driver takes that name and tacks on a .d suffix ๐Ÿฆ‹
    • If there's no -o, it grabs the input file's name, strips off any directory components and the suffix, then adds .d ๐ŸŒธ

Lowkey the most iconic part: if you use -MD together with -E, any -o switch is understood to specify the dependency output file ๐Ÿซถ But if you use it without -E, each -o is understood to specify a target object file instead ๐Ÿ’œ

Since -E isn't implied, -MD can make a dependency output file as a side effect of the compilation process. Main character behavior, no cap ๐Ÿ‘‘

  • -MMD โ€” same vibe as -MD, but it only mentions user header files and skips system header files ๐Ÿงš
  • -fpreprocessed โ€” tells the preprocessor that the input file is already preprocessed ๐Ÿ’– It skips macro expansion, trigraph conversion, escaped newline splicing, and processing of most directives, so it's all "already done, don't redo" ๐Ÿ™ˆ The preprocessor still recognizes and removes comments, so you can pass a file preprocessed with -C to the compiler without problems ๐Ÿ˜ญ In this mode the integrated preprocessor is little more than a tokenizer for the front ends ๐Ÿ’…
    • -fpreprocessed is implicit if the input file has one of the extensions .i, .ii or .mi ๐Ÿ“ Those are the extensions GCC uses for preprocessed files created by -save-temps.
  • -fdirectives-only โ€” when preprocessing, handle directives but don't expand macros ๐ŸŽ€ How it acts depends on -E and -fpreprocessed:
    • With -E, preprocessing is limited to directives like "#define", "#ifdef", and "#error". Other stuff like macro expansion and trigraph conversion doesn't happen. Also, -dD gets implicitly enabled ๐ŸŒˆ
    • With -fpreprocessed, predefinition of command line and most builtin macros is disabled. Contextual macros like "__LINE__" are handled normally, which lets you compile files previously preprocessed with "-E -fdirectives-only" ๐Ÿ’œ
    • With both -E and -fpreprocessed, the -fpreprocessed rules take precedence ๐Ÿ‘‘ That lets you fully preprocess files that were previously preprocessed with "-E -fdirectives-only" โœจ
  • -fdollars-in-identifiers โ€” accept $ in identifiers ๐Ÿ’ฒ
  • -fextended-identifiers โ€” accept universal character names in identifiers ๐ŸŒ This is enabled by default for C99 (and later C standard versions) and C++ ๐Ÿซถ
  • -fno-canonical-system-headers โ€” when preprocessing, don't shorten system header paths with canonicalization ๐Ÿ™…
  • -ftabstop=width โ€” sets the distance between tab stops ๐Ÿ“ This helps the preprocessor report correct column numbers in warnings or errors, even if tabs show up on the line. If the value is less than 1 or greater than 100, the option is ignored. The default is 8.
  • -ftrack-macro-expansion[=level] โ€” tracks token locations across macro expansions, so the compiler can show the current macro expansion stack when an error happens inside a macro ๐Ÿ” Heads up: using it makes the preprocessor and the compiler consume more memory ๐Ÿ’€ The level parameter lets you pick how precise the tracking is, so you can dial down the memory use if you need to:
    • 0 deactivates this option.
    • 1 tracks token locations in a degraded mode for minimal memory overhead. In this mode, all tokens resulting from expanding an argument of a function-like macro share the same location.
    • 2 tracks token locations completely. This is the most memory hungry one ๐Ÿ”
    • If you give it no argument, the default parameter value is 2.

Note that -ftrack-macro-expansion=2 is activated by default ๐Ÿฅน

  • -fmacro-prefix-map=old=new โ€” when preprocessing files residing in directory old, expands the "__FILE__" and "__BASE_FILE__" macros as if the files lived in directory new instead ๐Ÿ—บ๏ธ You can use this to turn an absolute path into a relative one by using . for new, which can give you more reproducible, location-independent builds โœจ This option also affects __builtin_FILE() during compilation. See also -ffile-prefix-map.
  • -fexec-charset=charset โ€” sets the execution character set, used for string and character constants ๐Ÿ’ฌ The default is UTF-8. charset can be any encoding supported by the system's iconv library routine ๐ŸŒธ
  • -fwide-exec-charset=charset โ€” sets the wide execution character set, used for wide string and character constants ๐ŸŒ The default is UTF-32 or UTF-16, whichever matches the width of wchar_t. Just like -fexec-charset, charset can be any encoding the system's iconv routine supports, but you'll have problems with encodings that don't fit exactly in wchar_t ๐Ÿ˜ฌ
  • -finput-charset=charset โ€” sets the input character set, which is used for translating from the input file's charset to the source character set GCC uses ๐Ÿ“ฅ If the locale doesn't specify it, 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, but right now the command-line option wins if there's a conflict. charset can be any encoding supported by the system's iconv library routine ๐Ÿฆ‹
  • -fpch-deps โ€” when you're using precompiled headers, this makes the dependency-output flags also list the files from the precompiled header's dependencies ๐Ÿง  If you don't specify it, only the precompiled header gets listed, not the files used to create it, because those files aren't consulted when a precompiled header is used.
  • -fpch-preprocess โ€” lets you use a precompiled header together with -E ๐ŸŽ€ It inserts a special #pragma, #pragma GCC pch_preprocess "filename", into the output to mark the spot where the precompiled header was found, plus its filename. When -fpreprocessed is in use, GCC recognizes this #pragma and loads the PCH ๐Ÿ’–
    • This option is off by default, since the resulting preprocessed output is only really suitable as input to GCC. It gets switched on by -save-temps.
    • You should never write this #pragma in your own code ๐Ÿ™… But it's safe to edit the filename if the PCH file is available in a different location. The filename may be absolute, or it may be relative to GCC's current directory.
  • -fworking-directory โ€” enables generation of linemarkers in the preprocessor output that let the compiler know the current working directory at the time of preprocessing ๐Ÿ“‚ With this on, the preprocessor emits, after the initial linemarker, a second linemarker with the current working directory followed by two slashes. GCC uses that directory, when it's present in the preprocessed input, as the directory emitted as the current working directory in some debugging information formats ๐Ÿ”ง This is implicitly enabled if debugging information is enabled, but you can inhibit it with the negated form -fno-working-directory. If the -P flag is in the command line, this option has no effect, since no #line directives are emitted whatsoever ๐Ÿ™ƒ
  • -A predicate=answer โ€” makes an assertion with the predicate predicate and answer answer ๐Ÿ”ฎ This form is preferred over the older -A predicate(answer) form, which is still supported, because it doesn't use shell special characters ๐Ÿš
  • -A -predicate=answer โ€” cancels an assertion with the predicate predicate and answer answer ๐Ÿšซ
  • -C โ€” don't discard comments ๐Ÿ’ฌ All comments are passed through to the output file, except for comments in processed directives, which get deleted along with the directive.
    • You should be prepared for side effects when using -C ๐Ÿ˜… It makes the preprocessor treat comments as tokens in their own right. For example, comments at the start of what would be a directive line turn that line into an ordinary source line, since the first token on the line is no longer a #.
  • -CC โ€” don't discard comments, including during macro expansion โœจ This is like -C, except comments contained within macros also get passed through to the output file where the macro is expanded.
    • Besides the side effects of -C, -CC converts all C++-style comments inside a macro into C-style comments ๐Ÿ›ก๏ธ This stops later uses of that macro from accidentally commenting out the rest of the source line.
    • -CC is generally used to support lint comments ๐Ÿงน
  • -P โ€” inhibits generation of linemarkers in the output from the preprocessor ๐Ÿ™Š This might be useful when you're running the preprocessor on something that isn't C code and will be sent to a program that might get confused by the linemarkers.
  • -traditional, -traditional-cpp โ€” try to imitate the behavior of pre-standard C preprocessors, as opposed to ISO C preprocessors ๐Ÿ•ฐ๏ธ See the GNU CPP manual for details.
    • Note that GCC doesn't otherwise attempt to emulate a pre-standard C compiler, and these options are only supported with the -E switch, or when invoking CPP explicitly.
  • -trigraphs โ€” supports ISO C trigraphs ๐ŸŒ™ These are three-character sequences, all starting with ??, that ISO C defines to stand for single characters. For example, ??/ stands for \, so '??/n' is a character constant for a newline.

The nine trigraphs and their replacements are:

Trigraph:       ??(  ??)  ??<  ??>  ??=  ??/  ??'  ??!  ??-
Replacement:      [    ]    {    }    #    \    ^    |    ~

By default, GCC ignores trigraphs, but in standard-conforming modes it converts them. See the -std and -ansi options.

  • -remap โ€” enables special code to work around file systems that only permit very short file names, such as MS-DOS ๐Ÿ’พ
  • -H โ€” prints the name of each header file used, in addition to other normal activities ๐Ÿ“œ Each name is indented to show how deep it is in the #include stack. Precompiled header files are also printed, even if they're found to be invalid. An invalid precompiled header file is printed with ...x, and a valid one with ...!.

โœจ OPTIONS โœจ

  • -dletters โ€” okay so this one lets you ask for debug dumps while compiling, and the letters you pass decide what gets dumped ๐Ÿ’…. These letters are for the preprocessor. Anything else is handled by the compiler proper or saved for future GCC versions, so it gets quietly ignored ๐Ÿซฅ. If you mix letters that clash, the result is undefined, so... don't do that bestie ๐Ÿ˜ญ.
  • -dM โ€” instead of the usual output, you get a list of #define directives for every macro defined while the preprocessor runs, predefined ones included ๐Ÿ”ฎ. It's the best way to see what your version of the preprocessor already has baked in โœจ. If you don't have a file called foo.h, this command shows all the predefined macros:
touch foo.h; cpp -dM foo.h

If you use -dM without -E, it's treated as a synonym for -fdump-rtl-mach ๐Ÿค“.

  • -dD โ€” basically -dM, but with two twists ๐Ÿฆ‹. It skips the predefined macros, and it outputs both the #define directives and the preprocessed result. Both go to the standard output file ๐Ÿ“„.
  • -dN โ€” like -dD, but only the macro names show up, not their expansions ๐ŸŒธ.
  • -dI โ€” adds #include directives to the preprocessed result ๐Ÿงš.
  • -dU โ€” like -dD, but only macros that get expanded, or whose definedness gets tested in preprocessor directives, make the cut ๐Ÿ’œ. The output is delayed until that macro is used or tested, and #undef directives also show up for macros that were tested but were undefined at that moment ๐Ÿซถ.
  • -fdebug-cpp โ€” this one is only useful if you're debugging GCC itself, so it's a niche moment ๐Ÿ™ˆ. When it's used from CPP or with -E, it dumps debugging info about location maps, and every token in the output gets the dump of the map its location belongs to ๐Ÿ—บ๏ธ. Used from GCC without -E, it does absolutely nothing ๐Ÿ’€.
  • -Wp,option โ€” this lets you skip the compiler driver and pass option straight through to the preprocessor ๐Ÿš€. If option has commas, it gets split into multiple options at each comma. Here's the tea though: lots of options get modified, translated, or interpreted by the driver first, and -Wp forcibly skips that step โš ๏ธ. The preprocessor's direct interface is undocumented and can change, so whenever possible, let the driver handle your options instead ๐Ÿซ .
  • -Xpreprocessor option โ€” passes option along to the preprocessor ๐ŸŽ€. Use this for system-specific preprocessor options that GCC doesn't recognize.

If the option you're passing needs an argument, you have to use -Xpreprocessor twice: once for the option and once for the argument ๐Ÿ™Œ.

  • -no-integrated-cpp โ€” normally GCC preprocesses as part of tokenizing and parsing the input, which is the integrated way ๐Ÿงฉ. With this flag, preprocessing becomes its own separate pass before compilation. The right language front end (cc1 for C, cc1plus for C++, or cc1obj for Objective-C) gets invoked twice: once for preprocessing only, and once for compiling the preprocessed input ๐Ÿ”. This can come in handy with the -B or -wrapper options if you want an alternate preprocessor, or extra processing of the source between preprocessing and compilation ๐Ÿ’–.

โœจ Passing Options to the Assembler โœจ

You can pass options to the assembler ๐Ÿงต.

  • -Wa,option โ€” passes option to the assembler ๐Ÿ’…. If option has commas, it gets split into multiple options at each comma.
  • -Xassembler option โ€” also passes option to the assembler ๐Ÿซถ. Use it for system-specific assembler options that GCC doesn't recognize.

If the option needs an argument, 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 โ€” any file name that doesn't end in a special recognized suffix is treated as an object file or library ๐Ÿ“ฆ. (The linker tells object files and libraries apart by checking the file contents.) If linking happens, these object files get fed into the linker as input.
  • -c, -S, -E โ€” if you use any of these, the linker doesn't run, so don't pass object file names as arguments ๐Ÿšซ.
  • -flinker-output=type โ€” this controls the code generation of the link time optimizer โšก. By default, the linker plugin picks the linker output automatically ๐Ÿค–. If you're debugging the compiler, or you want incremental linking to a non-LTO object file, it can be useful to set the type yourself ๐Ÿ› ๏ธ.
    • exec โ€” generates a static binary, and both -fpic and -fpie get disabled ๐ŸงŠ.
    • dyn โ€” generates a shared library. -fpic or -fPIC gets preserved, but not turned on automatically ๐Ÿฆ‹. This lets you build shared libraries without position independent code on architectures where that's possible, like x86.
    • pie โ€” generates a -fpie executable ๐Ÿ‘‘. You get similar optimizations as exec, except -fpie isn't disabled if you specified it at compile time.
    • rel โ€” assumes incremental linking is happening ๐Ÿงฉ. The sections holding intermediate LTO code get merged, pre-optimized, and written to the resulting object file. If you also pass -ffat-lto-objects, binary code gets produced for future non-LTO linking ๐Ÿซง. The object file from an incremental link ends up smaller than a static library made from the same object files, and at link time it loads faster for the compiler than a static library, as long as most of the library's objects are used ๐Ÿƒโ€โ™€๏ธ.
    • nolto-rel โ€” configures the compiler for incremental linking where code generation is forced ๐Ÿ’ช. A final binary gets produced, and the intermediate code for later LTO gets stripped out ๐Ÿ—‘๏ธ. When several object files are linked together, the code comes out better optimized than with LTO disabled (cross-module inlining will happen, for example), but most of the whole program optimization benefits are lost ๐Ÿ˜ค.

During an incremental link (with -r), the linker plugin defaults to rel ๐ŸŒˆ. Right now, GNU Binutils doesn't let you incrementally link LTO objects and non-LTO objects into a single mixed object file ๐Ÿ™…. If any object in an incremental link can't be used for link-time optimization, the linker plugin prints a warning and uses nolto-rel โš ๏ธ. To keep whole program optimization, it's recommended to link those objects into a static library instead ๐Ÿ“š. Or you can use H.J. Lu's binutils, which supports mixed objects ๐Ÿ’œ.

  • -fuse-ld=bfd โ€” uses the bfd linker instead of the default one ๐Ÿ”ง.
  • -fuse-ld=gold โ€” uses the gold linker instead of the default one ๐Ÿช™.
  • -fuse-ld=lld โ€” uses the LLVM lld linker instead of the default one ๐ŸŒ€.
  • -llibrary, -l library โ€” searches the library named library when linking ๐Ÿ”. (The second form, with the library as a separate argument, is only there for POSIX compliance, and it's not recommended ๐Ÿ™ˆ.)

GCC passes -l straight to the linker, so check your linker's docs for the exact details ๐Ÿ“–. The general description below applies to the GNU linker.

The linker searches a standard list of directories for the library ๐Ÿ—‚๏ธ. That list includes several standard system directories, plus any you add with -L.

Static libraries are archives of object files, with names like liblibrary.a. Some targets also support shared libraries, which usually have names like liblibrary.so ๐Ÿฆ‹. If the linker finds both kinds, it prefers the shared library unless you use the -static option ๐Ÿ’….

Where you put this option in the command matters ๐Ÿ“. The linker processes libraries and object files in the order you specify them. So foo.o -lz bar.o searches library z after foo.o but before bar.o. If bar.o calls functions in z, those functions might not get loaded ๐Ÿ˜ญ.

  • -lobjc โ€” you need this special case of -l to link an Objective-C or Objective-C++ program ๐ŸŽ.
  • -nostartfiles โ€” skips the standard system startup files when linking ๐Ÿšช. The standard system libraries still get used normally, unless -nostdlib, -nolibc, or -nodefaultlibs is used.
  • -nodefaultlibs โ€” skips the standard system libraries when linking ๐Ÿ™…โ€โ™€๏ธ. Only the libraries you name get passed to the linker, and options that set linkage for system libraries, like -static-libgcc or -shared-libgcc, get ignored. The standard startup files still get used normally, unless -nostartfiles is used.
The compiler may generate calls to "memcmp", "memset", "memcpy" and "memmove". These are usually resolved by entries in libc. When you use this option, you have to supply those entry points some other way ๐Ÿšจ.
  • -nolibc โ€” skips the C library and the system libraries that are tightly coupled with it ๐ŸงŠ. It still links the startup files, libgcc, and toolchain-provided language support libraries like libgnat, libgfortran, or libstdc++, unless other options stop their inclusion too ๐Ÿ’–. This usually removes -lc from the link command line, along with system libraries that normally go with it and stop making sense without a C library, like -lpthread or -lm in some configurations ๐Ÿซง. It's meant for bare-board targets where there's genuinely no C library available ๐Ÿค–.
  • -nostdlib โ€” skips the standard system startup files and libraries when linking ๐ŸŒ™. No startup files get used, and only the libraries you name get passed to the linker. Options that set linkage for system libraries, like -static-libgcc or -shared-libgcc, get ignored too ๐Ÿฅน.

okay so the compiler is lowkey going to make calls to memcmp, memset, memcpy and memmove on its own ๐Ÿซถ Usually libc has those covered, but when you use this option, those entry points need to be supplied some other way ๐Ÿ˜ญ

One of the standard libraries that -nostdlib and -nodefaultlibs bypass is libgcc.a ๐Ÿงš It's a library of internal subroutines that GCC uses to work around quirks of particular machines or special needs for some languages.

In most cases you still need libgcc.a even when you want to skip the other standard libraries, so when you pass -nostdlib or -nodefaultlibs, you should usually pass -lgcc as well โœจ That way you don't end up with unresolved references to internal GCC library subroutines. (An example is __main, which makes sure C++ constructors get called ๐Ÿ’…)


  • -e entry, --entry=entry โ€” Sets the program entry point to entry. The linker is the one that reads this value, and the GNU linker will take either a symbol name or an address ๐Ÿฆ‹
  • -pie โ€” Makes a dynamically linked position independent executable on targets that support it ๐Ÿ’– For predictable results, you also need to use the same set of options you used for compilation (-fpie, -fPIE, or model suboptions) when you pass this linker option.
  • -no-pie โ€” Don't make a dynamically linked position independent executable. Not me skipping the PIE ๐Ÿ™ˆ
  • -static-pie โ€” Makes a static position independent executable on targets that support it ๐ŸŒธ It's basically like a static executable, except it can be loaded at any address without a dynamic linker. Same deal as -pie: for predictable results, match your compile options (-fpie, -fPIE, or model suboptions) when you use this linker option.
  • -pthread โ€” Links with the POSIX threads library ๐Ÿงต This works on GNU/Linux targets, most other Unix derivatives, and also on x86 Cygwin and MinGW targets. On some targets it also sets flags for the preprocessor, so you should use it consistently for both compiling and linking.
  • -r โ€” Produces a relocatable object as the output. This is also called 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 ones that get used, to the dynamic symbol table. It's needed for some uses of dlopen, or if you want backtraces from inside a program.
  • -s โ€” Removes all symbol table and relocation information from the executable ๐Ÿซง
  • -static โ€” On systems that support dynamic linking, this overrides -pie and stops linking with the shared libraries. On other systems it does absolutely nothing ๐Ÿ’€
  • -shared โ€” Produces a shared object that can be linked with other objects to form an executable. Not every system supports this one. For predictable results, you also need to use the same set of options you used for compilation (-fpic, -fPIC, or model suboptions) when you pass this linker option.[1]
  • -shared-libgcc, -static-libgcc โ€” On systems that provide libgcc as a shared library, these force the use of the shared or static version, respectively ๐ŸŒˆ If no shared version of libgcc was built when the compiler was configured, these options do nothing.

There are a few situations where an application should use the shared libgcc instead of the static version. 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 application itself should use the shared libgcc.

So the G++ driver automatically adds -shared-libgcc whenever you build a shared library or a main executable ๐Ÿ’œ C++ programs usually use exceptions, so this is the right thing to do.

If you use the GCC driver to create shared libraries instead, you might notice they don't always get linked with the shared libgcc ๐Ÿง If GCC finds, at configuration time, that you have a non-GNU linker, or a GNU linker that doesn't support the option --eh-frame-hdr, it links the shared version of libgcc into shared libraries by default. Otherwise, it takes advantage of the linker and optimizes away the linking with the shared version of libgcc, so it links with the static version by default. This lets exceptions propagate through those shared libraries without adding relocation costs at library load time โœจ

However, if a library or main executable is supposed to throw or catch exceptions, you must link it using the G++ driver, or use the option -shared-libgcc, so that it's linked with the shared libgcc. Don't skip this 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 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 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 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 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 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 you override that with the link editor option -Xlinker -z -Xlinker defs). Only a few systems support this one.
  • -T script โ€” Uses script as the linker script ๐Ÿ“œ Most systems using the GNU linker support this. On some targets, like bare-board targets without an operating system, you may need -T when linking to avoid references to undefined symbols.
  • -Xlinker option โ€” Passes option to the linker ๐Ÿ”ง Use this to supply system-specific linker options that GCC doesn't recognize.

If you want to pass an option that takes a separate argument, you have to use -Xlinker twice: once for the option and once for the argument. For example, to pass -assert definitions, you write -Xlinker -assert -Xlinker definitions. Writing -Xlinker "-assert definitions" does NOT work, because that passes the whole string as a single argument, which isn't what the linker expects ๐Ÿ™…โ€โ™€๏ธ

When you're using the GNU linker, it's usually way more convenient to pass arguments with the option=value syntax instead of as separate arguments ๐Ÿ’– For example, you can write -Xlinker -Map=output.map instead of -Xlinker -Map -Xlinker output.map. Other linkers might not support this syntax for command-line options.

  • -Wl,option โ€” Passes option to the linker ๐Ÿช„ If option contains commas, it gets split into multiple options at those commas. You can use this syntax to pass an argument to the option. For example, -Wl,-Map,output.map passes -Map output.map to the linker. When you're using the GNU linker, you can get the same effect with -Wl,-Map=output.map.
NOTE: In Ubuntu 8.10 and later versions, for LDFLAGS, the option -Wl,-z,relro is used. To disable it, use -Wl,-z,norelro.
  • -u symbol โ€” Pretends the symbol symbol is undefined, which forces the 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 to the linker along with the keyword. Check the documentation for your linker to see the permitted values and what they mean ๐Ÿ“š

These options tell GCC which directories to search for header files, libraries, and 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 that = or $SYSROOT gets 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 the lookup for both #include "file" and #include <file> directives ๐Ÿซถ

You can specify any number or combination of these options on the command line to search for header files in several directories at once ๐ŸŽ€ 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 (#include "file"), the -iquote directories get searched left-to-right, in the exact order they show up on the command line. ๐ŸŽ€
  3. Next up are the -I directories, also scanned left-to-right. ๐ŸŒธ
  4. Then the -isystem directories, scanned left-to-right too. ๐Ÿ’…
  5. Now the standard system directories get their turn. ๐Ÿ›๏ธ
  6. Last but not least, the -idirafter directories, scanned left-to-right. ๐Ÿฆ‹

Want to swap out a system header for your own version? -I is your girl, since those directories get searched before the standard system header directories. BUT bestie, ๐Ÿšจ don't use -I to add directories full of vendor-supplied system headers. Use -isystem for that. ๐Ÿซถ

Both -isystem and -idirafter also tag their directory as a system directory, so it gets the same VIP treatment as the standard system ones. โœจ

Heads up: if a standard system include directory (or one you gave to -isystem) also shows up as a -I, the -I gets ignored ๐Ÿ™ˆ. That directory still gets searched, just as a system directory in its normal spot in the system include chain. The whole point is so GCC's procedure for fixing buggy system headers and the ordering for the "#include_next" directive don't get messed up by accident. If you truly need to shuffle the search order for system directories, reach for -nostdinc and/or -isystem. ๐Ÿ‘‘

  • -I- โ€” Splits the include path. This one is deprecated, so please don't be attached ๐Ÿ’€
    • Swap to -iquote for any -I directories that come before -I-, then delete the -I- entirely.
    • -I directories placed before -I- only get searched for #include "file". They are NOT searched for #include <file>.
    • -I directories placed after -I- get searched for every #include directive.
    • Also, -I- stops the current file's directory from being the first place searched for #include "file". There's no way to undo that effect of -I-. ๐Ÿ˜ญ
  • -iprefix prefix โ€” Sets prefix as the prefix for later -iwithprefix options. If the prefix is a directory, make sure you include the final /. ๐Ÿ“
  • -iwithprefix dir, -iwithprefixbefore dir โ€” Tacks dir onto the prefix you set with -iprefix, then adds the result to the include search path. -iwithprefixbefore puts it in the same spot -I would, while -iwithprefix puts it where -idirafter would. ๐Ÿงš
  • -isysroot dir โ€” This is basically --sysroot, but it only applies to header files (except on Darwin targets, where it covers both headers and libraries). Check out --sysroot for the full scoop. ๐ŸŒˆ
  • -imultilib dir โ€” Uses dir as a subdirectory of the directory that holds the target-specific C++ headers. ๐Ÿ“
  • -nostdinc โ€” Skips the standard system directories when hunting for headers. Only the directories you explicitly give through -I, -iquote, -isystem, and/or -idirafter get searched, plus the current file's directory if that's appropriate. ๐Ÿ™…โ€โ™€๏ธ
  • -nostdinc++ โ€” Skips the C++-specific standard directories but still searches the other standard ones. (This one is used when building the C++ library, so it's pretty niche. ๐Ÿค“)
  • -iplugindir=dir โ€” Sets the directory to search for plugins that get passed with -fplugin=name instead of -fplugin=path/name.so. This is NOT meant for you to use directly. Only the driver should pass it. ๐Ÿšซ
  • -Ldir โ€” Adds dir to the list of directories searched for -l. ๐Ÿ”
  • -Bprefix โ€” This is where you tell the compiler to find its own executables, libraries, include files, and data files. โœจ
    • The compiler driver runs one or more of the subprograms cpp, cc1, as and ld. It tries prefix as a prefix for each program it attempts to run, both with and without machine/version/ for the corresponding target machine and compiler version.
    • For each subprogram, the driver tries the -B prefix first (if you gave one). If that name isn't found, or if -B wasn't specified, it tries two standard prefixes: /usr/lib/gcc/ and /usr/local/lib/gcc/. If neither of those turns up a file, the unmodified program name gets searched for in the directories listed in your PATH environment variable.
    • The compiler checks whether the path given by -B is a directory, and if needed, it adds a directory separator character at the end of the path.
    • -B prefixes that effectively specify directory names also apply to libraries in the linker, because the compiler translates these options into -L options for the linker. They also apply to include files in the preprocessor, because the compiler translates these options into -isystem options for the preprocessor. In that case, the compiler appends include to the prefix.
    • The runtime support file libgcc.a can also be searched for using the -B prefix, if needed. If it isn't found there, the two standard prefixes above get tried, and that's it. The file is left out of the link if those means don't find it.
    • Another way to specify a prefix, much like the -B prefix, is 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 helps with boot-strapping the compiler. ๐Ÿฅพ
  • -no-canonical-prefixes โ€” Don't expand any symbolic links, resolve references to /../ or /./, or make the path absolute when generating a relative prefix. ๐Ÿ™…
  • --sysroot=dir โ€” Uses dir as the logical root directory for headers and libraries. For example, if the compiler normally searches for headers in /usr/include and libraries in /usr/lib, it will instead search dir/usr/include and dir/usr/lib. ๐Ÿ‘‘
    • If you use both this option and -isysroot, then --sysroot applies to libraries, but -isysroot applies to header files.
    • The GNU linker (beginning with version 2.16) has the necessary support for this option. If your linker doesn't support it, the header file part of --sysroot still works, but the library part does not. ๐Ÿฅฒ
  • --no-sysroot-suffix โ€” For some targets, a suffix gets added to the root directory you specify with --sysroot, depending on the other options you used. That means headers might be found in dir/suffix/usr/include instead of dir/usr/include. This option turns off that suffix. ๐Ÿ™ˆ

๐ŸŽ€ Options for Code Generation Conventions ๐ŸŽ€

These machine-independent options control the interface conventions used in code generation. ๐Ÿ’–

Most of them come in both positive and negative forms. The negative form of -ffoo is -fno-foo. Below, only one of the forms is listed, the one that is not the default. You can figure out the other form by 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 that have names, and none disables stack reuse completely. The default value is all. This option is needed when the program extends the lifetime of a scoped local variable or a compiler-generated temporary beyond the end point defined by the language. When a variable's lifetime ends and it lives in memory, the optimizing compiler has the freedom to reuse its stack space with other temporaries or scoped local variables whose live range doesn't overlap with it. Legacy code that extends local lifetime is likely to break with stack reuse optimization. ๐Ÿ’€

For example,

int *p;
{
  int local1;

  p = &local1;
  local1 = 10;
  ....
}
{
   int local2;
   local2 = 20;
   ...
}

if (*p == 10)  // out of scope use of local1
  {

  }

Another example:

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

A *ap;

void foo(const A& ar)
{
   ap = &ar;
}

void bar()
{
   foo(A(10)); // temp object's lifetime ends when foo returns

   {
     A a(20);
     ....
   }
   ap->i+= 10;  // ap references out of scope temp whose space
                // is reused with a. What is the value of ap->i?
}

The lifetime of a compiler-generated temporary is well defined by the C++ standard. When a temporary's lifetime ends and it lives in memory, the optimizing compiler has the freedom to reuse its stack space with other temporaries or scoped local variables whose live range doesn't overlap with it. However, some legacy code relies on the behavior of older compilers, where temporaries' stack space wasn't reused, so aggressive stack reuse can lead to runtime errors. This option is used to control the temporary stack reuse optimization. ๐Ÿงฏ

-ftrapv

This option generates traps for signed overflow on addition, subtraction, and multiplication operations. -ftrapv and -fwrapv override each other, so using -ftrapv -fwrapv on the command-line results in -fwrapv being effective. Only active options override, though, so using -ftrapv -fwrapv -fno-wrapv on the command-line results in -ftrapv being effective. โšก

  • -fwrapv โ€” okay so this one tells the compiler to assume signed arithmetic overflow from addition, subtraction, and multiplication just wraps around, using twos-complement representation ๐Ÿ”„. It turns some optimizations on and others off, so it's a whole vibe โœจ. -ftrapv and -fwrapv override each other, so -ftrapv -fwrapv on the command line means -fwrapv is the one that's effective ๐Ÿ‘‘. Only active options override, though, so -ftrapv -fwrapv -fno-wrapv means -ftrapv wins ๐Ÿ’….
  • -fwrapv-pointer โ€” same energy, but for pointers ๐Ÿฆ‹. This tells the compiler to assume pointer arithmetic overflow on addition and subtraction wraps around using twos-complement representation. It also switches off some optimizations that assume pointer overflow is invalid ๐Ÿ™ˆ.
  • -fstrict-overflow โ€” this one flips the switch the other way ๐Ÿ”€. It implies -fno-wrapv -fno-wrapv-pointer, and when negated it implies -fwrapv -fwrapv-pointer ๐Ÿซถ.
  • -fexceptions โ€” enable exception handling ๐ŸŽ€. GCC generates the extra code needed to propagate exceptions. On some targets this also means GCC generates frame unwind information for all functions, which can cause significant data size overhead, but it doesn't affect execution, so no panic ๐ŸŒธ. If you don't specify this option, GCC turns it on by default for languages like C++ that normally need exception handling, and turns it off for languages like C that don't. You may still need to enable it when compiling C code that has to interoperate properly with exception handlers written in C++ ๐Ÿงš. You might also want to disable it if you're compiling older C++ programs that don't use exception handling ๐Ÿ’€.
  • -fnon-call-exceptions โ€” generates code that lets trapping instructions throw exceptions โšก. Heads up, this needs platform-specific runtime support that doesn't exist everywhere ๐Ÿ˜ญ. It only lets trapping instructions throw exceptions, meaning memory references or floating-point instructions. It does not let exceptions get thrown from arbitrary signal handlers such as "SIGALRM" ๐Ÿ™…โ€โ™€๏ธ.
  • -fdelete-dead-exceptions โ€” instructions that might throw exceptions but don't otherwise contribute to the program's execution can be optimized away ๐Ÿ—‘๏ธ. This is enabled by default for the Ada front end, as the Ada language specification permits. Optimization passes that remove dead exceptions are enabled independently at different optimization levels ๐Ÿ“.
  • -funwind-tables โ€” similar to -fexceptions, except it only generates any needed static data and doesn't touch the generated code in any other way ๐Ÿ“ฆ. You normally don't need to turn this on yourself, because a language processor that needs this handling enables it on your behalf ๐Ÿซถ.
  • -fasynchronous-unwind-tables โ€” generates an unwind table in DWARF format, if the target machine supports it ๐ŸŒˆ. The table is exact at each instruction boundary, so it can be used for stack unwinding from asynchronous events, like a debugger or a garbage collector ๐Ÿ”.
  • -fno-gnu-unique โ€” okay this one is a little deep ๐Ÿค“. With a recent GNU assembler and C library, the C++ compiler uses the "STB_GNU_UNIQUE" binding so that template static data members and static local variables in inline functions stay unique, even with "RTLD_LOCAL". That's needed to avoid problems where a library used by two different "RTLD_LOCAL" plugins depends on a definition in one of them and then disagrees with the other about the binding of the symbol. The catch is that this makes dlclose get ignored for affected DSOs. So if your program relies on reinitializing a DSO via dlclose and dlopen, you can use -fno-gnu-unique ๐Ÿ”„.
  • -fpcc-struct-return โ€” returns "short" "struct" and "union" values in memory, just like the longer ones, instead of in registers ๐Ÿงบ. It's less efficient, but it lets GCC-compiled files play nicely with files compiled by other compilers, especially the Portable C Compiler (pcc) ๐Ÿค.

The exact convention for returning structures in memory depends on the target configuration macros ๐ŸŽฏ.

Short structures and unions are the ones whose size and alignment match that of some integer type ๐Ÿ“.

๐Ÿšจ Warning: code compiled with the -fpcc-struct-return switch is not binary compatible with code compiled with the -freg-struct-return switch. Only use it to conform to a non-default application binary interface.
  • -freg-struct-return โ€” returns "struct" and "union" values in registers when possible ๐Ÿƒโ€โ™€๏ธ. This is more efficient for small structures than -fpcc-struct-return โšก.

If you specify neither -fpcc-struct-return nor -freg-struct-return, GCC defaults to whichever convention is standard for the target ๐ŸŽ€. If there's no standard convention, GCC defaults to -fpcc-struct-return, except on targets where GCC is the principal compiler. In those cases, GCC gets to choose the standard, and it picked the more efficient register return alternative ๐Ÿ‘‘.

๐Ÿšจ Warning: code compiled with the -freg-struct-return switch is not binary compatible with code compiled with the -fpcc-struct-return switch. Only use it to conform to a non-default application binary interface.
  • -fshort-enums โ€” allocates to an "enum" type only as many bytes as it needs for the declared range of possible values ๐Ÿ”ข. The "enum" type ends up equivalent to the smallest integer type that has enough room ๐Ÿงธ.
๐Ÿšจ Warning: the -fshort-enums switch causes GCC to generate code that is not binary compatible with code generated without that switch. Only use it to conform to a non-default application binary interface.
  • -fshort-wchar โ€” overrides the underlying type for "wchar_t" to be "short unsigned int" instead of the target's default ๐ŸชŸ. This one is super useful for building programs that run under WINE ๐Ÿท.
๐Ÿšจ Warning: the -fshort-wchar switch causes GCC to generate code that is not binary compatible with code generated without that switch. Only use it to conform to a non-default application binary interface.
  • -fno-common โ€” in C code, this option controls where global variables defined without an initializer get placed. These are called tentative definitions in the C standard ๐Ÿ“. Tentative definitions are different from declarations of a variable with the "extern" keyword, which don't allocate any storage ๐Ÿซง.

Unix C compilers have traditionally put storage for uninitialized global variables in a common block ๐Ÿงฑ. That lets the linker resolve all the tentative definitions of the same variable across different compilation units into the same object, or into a non-tentative definition ๐Ÿ”—. This is the behavior -fcommon specifies, and it's the default for GCC on most targets ๐Ÿ’œ. It isn't required by ISO C though, and on some targets it can carry a speed or code size penalty on variable references ๐ŸŒ.

-fno-common tells the compiler to put uninitialized global variables in the BSS section of the object file instead ๐Ÿ—‚๏ธ. This stops the linker from merging tentative definitions, so you'll get a multiple-definition error if the same variable is defined in more than one compilation unit ๐Ÿšซ. Compiling with -fno-common is useful on targets where it gives better performance, or if you want to check that your program will work on other systems that always treat uninitialized variable definitions this way ๐Ÿ”.

  • -fno-ident โ€” ignores the "#ident" directive ๐Ÿ™ˆ.
  • -finhibit-size-directive โ€” don't output a .size assembler directive, or anything else that would cause trouble if the function gets split in the middle and the two halves end up placed far apart in memory ๐Ÿงฉ. This is used when compiling crtstuff.c, so you shouldn't need it for anything else ๐Ÿ™…โ€โ™€๏ธ.
  • -fverbose-asm โ€” puts extra commentary into the generated assembly code to make it more readable ๐Ÿ“. This is mostly for people who actually need to read the generated assembly, like when debugging the compiler itself ๐Ÿง‘โ€๐Ÿ’ป.

-fno-verbose-asm, which is the default, leaves out the extra info. That's handy when you want to compare two assembler files ๐Ÿ”Ž.

The added comments include:

  • information on the compiler version and command-line options,
  • the source code lines associated with the assembly instructions, in the form FILENAME:LINENUMBER:CONTENT OF LINE,
  • hints on which high-level expressions correspond to the various assembly instruction operands.

For example, here's a C source file:

int test (int n)
{
  int i;
  int total = 0;

  for (i = 0; i < n; i++)
    total += i * i;

  return total;
}

If you compile it to (x86_64) assembly via -S and emit the result straight to stdout via -o -:

gcc -S test.c -fverbose-asm -Os -o -

you'll get 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...]

Okay so, we're picking up right where the -fverbose-asm stuff left off, and this is what the assembly looks like with all the comments in it ๐Ÿ‘€โœจ

        .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, not machines, bestie, so the exact format of those comments can change whenever. Don't build your whole life around them ๐Ÿซถ


๐ŸŽ€ -frecord-gcc-switches

This switch makes GCC record the command line you used to invoke the compiler into the object file it's creating. ๐Ÿ’… It's only implemented on some targets, and the exact format of the recording depends on both the target and the binary file format, but it usually shows up as a section full of ASCII text. It's related to -fverbose-asm, except that one only drops info into the assembler output as comments, so it never actually makes it into the object file. If you want another way to stash compiler options in the object file, check out -grecord-gcc-switches. ๐Ÿงš

๐Ÿฆ‹ -fpic

Generate position-independent code (PIC), which is perfect for a shared library, as long as your target machine supports it. ๐ŸŒˆ This code reaches every constant address through a global offset table (GOT). The dynamic loader fills in the GOT entries when the program starts up. (The dynamic loader isn't part of GCC, it's part of the operating system, so no, GCC isn't doing that part, bestie ๐Ÿ’€)

If the GOT size for your linked executable goes over a machine-specific maximum, the linker will throw an error saying that -fpic doesn't work. When that happens, just recompile with -fPIC instead. ๐Ÿ˜ญ The maximums are 8k on the SPARC, 28k on AArch64, and 32k on the m68k and RS/6000. The x86 has no such limit, so it's giving freedom ๐Ÿฆ‹

Position-independent code needs special support, so it only works on certain machines. For 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 it avoids any limit on the size of the global offset table. This option makes a difference on AArch64, m68k, PowerPC, and SPARC. ๐Ÿ”ฅ

Same as before, this needs special support, so it only works on certain machines.

When this flag is set, the macros __pic__ and __PIC__ are defined to 2. Note the 2, not the 1 from -fpic ๐Ÿ‘€

๐Ÿงš -fpie, -fPIE

These are basically cousins of -fpic and -fPIC, but the position-independent code they generate can only be linked into executables, not shared libraries. ๐Ÿ™ˆ You'll usually use them when compiling code that's getting linked with the -pie GCC option.

Both -fpie and -fPIE define the macros __pie__ and __PIE__. The macros have the value 1 for -fpie and 2 for -fPIE. ๐Ÿ’–

๐Ÿ“ -fno-plt

Do not use the PLT for external function calls in position-independent code. Instead, load the callee address at call sites from the GOT and branch to it. โœจ This is more efficient code because it gets rid of PLT stubs and exposes GOT loads to optimizations. On architectures like 32-bit x86, where PLT stubs expect the GOT pointer in a specific register, this gives the compiler more register allocation freedom, which is so iconic. ๐Ÿ‘‘

Lazy binding needs the PLT. With -fno-plt, all external symbols get resolved at load time, so no lazy binding for you, babe ๐Ÿ˜ญ

Alternatively, the function attribute noplt can be used to avoid calls through the PLT for specific external functions. Very targeted, very cute ๐ŸŽฏ

In position-dependent code, a few targets also convert calls to functions marked to not use the PLT so they use the GOT instead. ๐ŸŒˆ

๐Ÿซง -fno-jump-tables

Don't use jump tables for switch statements, even where they'd be more efficient than other code generation strategies. ๐Ÿ™ƒ This one is useful alongside -fpic or -fPIC when you're building code that's part of a dynamic linker and can't reference the address of a jump table. On some targets, jump tables don't 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 has to be the name of a register. The accepted register names are machine-specific, and they're defined in the REGISTER_NAMES macro in the machine description macro file. ๐Ÿง 

This flag doesn't have a negative form, because it's a three-way choice. ๐Ÿฆ‹

๐Ÿ’œ -fcall-used-reg

Treat the register named reg as an allocable register that gets clobbered by function calls. It can be allocated for temporaries or variables that don't live across a call. Functions compiled this way do not save and restore the register reg. ๐ŸŒธ

It is an error to use this flag with the frame pointer or stack pointer. Using this flag on other registers with fixed, pervasive roles in the machine's execution model produces disastrous results. ๐Ÿ’€ Not the vibe.

This flag doesn't have a negative form, because it's 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 the register reg if they use it. ๐Ÿซถ

It is an error to use this flag with the frame pointer or stack pointer. Using it on other registers with fixed, pervasive roles in the machine's execution model produces disastrous results. ๐Ÿ˜ญ

A different kind of disaster happens if you use this flag on a register where function values may be returned. ๐Ÿ”ฅ Please don't.

This flag doesn't have a negative form, because it's a three-way choice. ๐Ÿฆ‹

๐Ÿ‘ -fpack-struct[=n]

Without a value, this packs all structure members together with no holes. ๐Ÿงฉ When you give it a value, which has to be a small power of two, structure members get packed according to that value, which is treated as the maximum alignment. Objects with default alignment requirements larger than this are output potentially unaligned at the next fitting location. ๐Ÿ“

Warning: the -fpack-struct switch makes GCC generate code that is not binary compatible with code generated without that switch. It also makes the code suboptimal. Only use it to conform to a non-default application binary interface. โš ๏ธ

๐ŸŒˆ -fleading-underscore

This option, and its counterpart -fno-leading-underscore, forcibly change how C symbols are represented in the object file. One use is to help link with legacy assembly code. ๐Ÿ•ฐ๏ธ

Warning: the -fleading-underscore switch makes GCC generate code that is not binary compatible with code generated without that switch. Only use it to conform to a non-default application binary interface. Not all targets provide complete support for this switch. ๐Ÿšจ

๐Ÿงต -ftls-model=model

This alters the thread-local storage model. The model argument should be one of global-dynamic, local-dynamic, initial-exec, or local-exec. โœจ Heads up, the choice is subject to optimization. The compiler might use a more efficient model for symbols that aren't visible outside of the translation unit, or if -fpic isn't given on the command line. ๐Ÿง 

The default without -fpic is initial-exec. With -fpic, the default is global-dynamic ๐Ÿ’–

๐Ÿช„ -ftrampolines

For targets that normally need trampolines for nested functions, this always generates them instead of using descriptors. For targets that don't need them, like HP-PA or IA-64, it does nothing. ๐Ÿ™Œ

A trampoline is a small piece of code created at run time on the stack when the address of a nested function is taken. It's used to call the nested function indirectly. Because of that, the stack has to be made executable for the program to work properly. ๐Ÿ˜ณ

-fno-trampolines is enabled by default on a language-by-language basis, so the compiler can skip generating trampolines when it figures out that's safe, and replace them with descriptors instead. Descriptors are made up of data only, but the generated code has to be prepared to deal with them. As of this writing, -fno-trampolines is enabled by default only for Ada. ๐Ÿ’…

Code compiled with -ftrampolines and code compiled with -fno-trampolines are not binary compatible if nested functions are present. So this option must be used on a program-wide basis and handled with extreme care ๐ŸŒˆ

๐Ÿ‘‘ -fvisibility=[default|internal|hidden|protected]

This sets the default ELF image symbol visibility to the option you specify. All symbols get marked with this unless they're overridden within the code. ๐Ÿ’œ Using this feature can massively improve linking and load times for shared object libraries, produce more optimized code, give you near-perfect API export, and prevent symbol clashes. It's strongly recommended that you use it in any shared objects you distribute. ๐Ÿซถ

Despite the name, default always means public, meaning it's available to be linked against from outside the shared object. protected and internal are pretty useless in real-world usage, so the only other commonly used option is hidden. โœจ If -fvisibility isn't specified, the default is default, which makes every symbol public. ๐Ÿฆ‹

A good explanation of why ELF symbols should have the correct visibility is "How To Write Shared Libraries" by Ulrich Drepper ๐Ÿ“š (you can find it at https://www.akkadia.org/drepper/). But the real main character move this option unlocks is making the default hidden and marking the stuff you want public ๐Ÿ‘‘ That's the norm with DLLs on Windows. With -fvisibility=hidden and __attribute__ ((visibility("default"))) instead of __declspec(dllexport), you get almost identical semantics with identical syntax ๐Ÿซถ This is a total boon for cross-platform projects ๐ŸŒˆ

For those adding visibility support to existing code, #pragma GCC visibility is giving ๐Ÿงš You wrap the declarations you want to set visibility for with, for example, #pragma GCC visibility push(hidden) and #pragma GCC visibility pop. Bear in mind that symbol visibility should be treated as part of the API interface contract, so all new code should always specify visibility when it isn't the default ๐Ÿ’… That means declarations only used inside the local DSO should always be marked explicitly as hidden, so you avoid PLT indirection overheads. Making this super clear also helps readability and self-documentation, bestie ๐Ÿ“

Note that, due to ISO C++ specification requirements, operator new and operator delete must always be of default visibility. No exceptions, no cap ๐Ÿ™…โ€โ™€๏ธ

Be aware that headers from outside your project, especially system headers and headers from any other library you use, may not be expecting to be compiled with visibility other than the default ๐Ÿ‘€ You may need to explicitly say #pragma GCC visibility push(default) before including any of those headers.

extern declarations are not affected by -fvisibility, so a lot of code can be recompiled with -fvisibility=hidden with zero modifications โœจ However, calls to extern functions with no explicit visibility go through the PLT, so it's more effective to use __attribute ((visibility)) and/or #pragma GCC visibility to tell the compiler which extern declarations should be treated as hidden ๐Ÿฆ‹

Note that -fvisibility does affect C++ vague linkage entities. This means, for instance, that an exception class to be thrown between DSOs must be explicitly marked with default visibility, so the type_info nodes get unified between the DSOs ๐ŸŽ€

An overview of these techniques, their benefits, and how to use them lives at http://gcc.gnu.org/wiki/Visibility ๐ŸŒธ

โœจ -fstrict-volatile-bitfields โœจ

This option should be used if accesses to volatile bit-fields (or other structure fields, although the compiler usually honors those types anyway) should use a single access of the width of the field's type, aligned to a natural alignment if possible. Lowkey very specific, but super important ๐Ÿ’œ For example, targets with memory-mapped peripheral registers might require all such accesses to be 16 bits wide. With this flag, you can declare all peripheral bit-fields as unsigned short (assuming short is 16 bits on these targets) to force GCC to use 16-bit accesses instead of, perhaps, a more efficient 32-bit access ๐Ÿ”ฅ

If this option is disabled, the compiler uses the most efficient instruction. In the previous example, that might be a 32-bit load instruction, even though it accesses bytes that don't contain any portion of the bit-field, or memory-mapped registers unrelated to the one being updated ๐Ÿ˜ญ

In some cases, such as when the packed attribute is applied to a structure field, it may not be possible to access the field with a single read or write that is correctly aligned for the target machine. In that case, GCC falls back to generating multiple accesses, rather than code that will 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. It is therefore recommended to define all bits of the field's type as bit-field members ๐Ÿ’€

The default value of this option is determined by the application binary interface for the target processor ๐Ÿงš

โœจ -fsync-libcalls โœจ

This option controls whether any out-of-line instance of the __sync family of functions may be used to implement the C++11 __atomic family of functions ๐Ÿ’–

The default value of this option is enabled, so the only useful form of the option is -fno-sync-libcalls. This option is used in the implementation of the libatomic runtime library ๐Ÿ‘‘


๐Ÿงช GCC Developer Options ๐Ÿงช

This section is for command-line options that are mainly of interest to GCC developers, including options that support compiler testing and investigation of compiler bugs and compile-time performance problems ๐Ÿ” It covers options that produce debug dumps at various points in the compilation, options that print statistics like memory use and execution time, and options that print info about GCC's configuration, such as where it searches for libraries ๐Ÿ“Š You should rarely need any of these for ordinary compilation 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 omitted, a default dump file name gets built 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 the compiler produces if it's explicitly specified and isn't an executable. Otherwise, it's the source file name. The pass number is determined by the order passes are registered with the compiler's pass manager. This is generally the same as the order of execution, but passes registered by plugins, target-specific passes, or passes that are otherwise registered late get numbered higher than the pass named final, even if they run earlier ๐Ÿคฏ The phase letter is one of i (inter-procedural analysis), l (language-specific), r (RTL), or t (tree). The files get created in the directory of the output file ๐Ÿ“

  • -dletters, -fdump-rtl-pass, -fdump-rtl-pass=filename โ€” Makes debugging dumps during compilation at the times specified by letters. This is how you debug the RTL-based passes of the compiler ๐Ÿ›

Some -dletters switches mean something different when -E is used for preprocessing ๐Ÿ‘€

Debug dumps can be enabled with a -fdump-rtl switch or with some -d option letters. Here are the possible letters for the pass and letters, and what each one means ๐Ÿ’œ

  • -fdump-rtl-alignments โ€” dumps after branch alignments have been computed ๐Ÿ“
  • -fdump-rtl-asmcons โ€” dumps after fixing RTL statements that have unsatisfied in/out constraints ๐Ÿ› ๏ธ
  • -fdump-rtl-auto_inc_dec โ€” dumps after auto-inc-dec discovery. This pass only runs on architectures that have auto inc or auto dec instructions ๐Ÿง 
  • -fdump-rtl-barriers โ€” dumps after cleaning up the barrier instructions ๐Ÿงน
  • -fdump-rtl-bbpart โ€” dumps after partitioning hot and cold basic blocks ๐Ÿ”ฅ๐ŸงŠ
  • -fdump-rtl-bbro โ€” dumps after block reordering ๐Ÿ”€
  • -fdump-rtl-btl1, -fdump-rtl-btl2 โ€” dump after the two branch target load optimization passes โœจ
  • -fdump-rtl-bypass โ€” dumps after jump bypassing and control flow optimizations ๐Ÿฆ‹
  • -fdump-rtl-combine โ€” dumps after the RTL instruction combination pass ๐Ÿงฉ
  • -fdump-rtl-compgotos โ€” dumps after duplicating the computed gotos ๐Ÿซถ
  • -fdump-rtl-ce1, -fdump-rtl-ce2, -fdump-rtl-ce3 โ€” dump after the three if conversion passes ๐ŸŽ€
  • -fdump-rtl-cprop_hardreg โ€” dumps after hard register copy propagation ๐Ÿ“‹
  • -fdump-rtl-csa โ€” dumps after combining stack adjustments ๐Ÿฅž
  • -fdump-rtl-cse1, -fdump-rtl-cse2 โ€” dump after the two common subexpression elimination passes ๐Ÿ“
  • -fdump-rtl-dce โ€” dumps after the standalone dead code elimination passes ๐Ÿ—‘๏ธ
  • -fdump-rtl-dbr โ€” dumps after delayed branch scheduling โณ
  • -fdump-rtl-dce1, -fdump-rtl-dce2 โ€” dump after the two dead store elimination passes ๐Ÿ’€
  • -fdump-rtl-eh โ€” dumps after finalization of EH handling code ๐Ÿ›Ÿ
  • -fdump-rtl-eh_ranges โ€” dumps after conversion of EH handling range regions ๐Ÿ—บ๏ธ
  • -fdump-rtl-expand โ€” dumps after RTL generation ๐ŸŒฑ
  • -fdump-rtl-fwprop1, -fdump-rtl-fwprop2 โ€” dump after the two forward propagation passes โžก๏ธ
  • -fdump-rtl-gcse1, -fdump-rtl-gcse2 โ€” dump after global common subexpression elimination ๐ŸŒ
  • -fdump-rtl-init-regs โ€” dumps after the initialization of the registers ๐Ÿ
  • -fdump-rtl-initvals โ€” dumps after the computation of the initial value sets ๐Ÿ”ข
  • -fdump-rtl-into_cfglayout โ€” dumps after converting to cfglayout mode ๐Ÿงญ
  • -fdump-rtl-ira โ€” dumps after iterated register allocation ๐Ÿ—‚๏ธ
  • -fdump-rtl-jump โ€” dumps after the second jump optimization ๐Ÿฆ˜
  • -fdump-rtl-loop2 โ€” dumps after the RTL loop optimization passes ๐Ÿ”
  • -fdump-rtl-mach โ€” dumps after the machine dependent reorganization pass, if that pass exists โš™๏ธ
  • -fdump-rtl-mode_sw โ€” dumps after removing redundant mode switches ๐Ÿ”„
  • -fdump-rtl-rnreg โ€” dumps after register renumbering ๐Ÿ”ข
  • -fdump-rtl-outof_cfglayout โ€” dumps after converting from cfglayout mode ๐Ÿงญ
  • -fdump-rtl-peephole2 โ€” dumps after the peephole pass ๐Ÿ”
  • -fdump-rtl-postreload โ€” dumps after post-reload optimizations ๐Ÿš€
  • -fdump-rtl-pro_and_epilogue โ€” dumps after generating the function prologues and epilogues ๐ŸŽฌ
  • -fdump-rtl-sched1, -fdump-rtl-sched2 โ€” dump after the basic block scheduling passes ๐Ÿ“…
  • -fdump-rtl-ree โ€” dumps after sign/zero extension elimination โž•
  • -fdump-rtl-seqabstr โ€” dumps after common sequence discovery ๐Ÿงพ
  • -fdump-rtl-shorten โ€” โœ‚๏ธ okay so this one dumps the RTL after shortening branches, bestie.
  • -fdump-rtl-sibling โ€” ๐Ÿงš dumps the RTL after sibling call optimizations.
  • -fdump-rtl-split1, -fdump-rtl-split2, -fdump-rtl-split3, -fdump-rtl-split4, -fdump-rtl-split5 โ€” ๐Ÿ“ these five enable dumping after each of five rounds of instruction splitting. Five whole rounds, periodt.
  • -fdump-rtl-sms โ€” ๐ŸŒˆ dumps after modulo scheduling. Heads up, this pass only runs on some architectures, so don't be surprised if it's missing on yours ๐Ÿ™ˆ.
  • -fdump-rtl-stack โ€” ๐Ÿ’… dumps after the conversion from GCC's "flat register file" registers to the x87's stack-like registers. This pass is only run on x86 variants, so it's very much an x86 moment โœจ.
  • -fdump-rtl-subreg1, -fdump-rtl-subreg2 โ€” ๐Ÿฆ‹ these enable dumping after the two subreg expansion passes, one for each of the passes. Two passes, two dumps, zero drama.
  • -fdump-rtl-unshare โ€” ๐Ÿซถ dumps after all RTL has been unshared.
  • -fdump-rtl-vartrack โ€” ๐Ÿ‘€ dumps after variable tracking.
  • -fdump-rtl-vregs โ€” ๐Ÿ”ฅ dumps after virtual registers have been converted to hard registers.
  • -fdump-rtl-web โ€” ๐Ÿ•ธ๏ธ dumps after live range splitting.
  • -fdump-rtl-regclass, -fdump-rtl-subregs_of_mode_init, -fdump-rtl-subregs_of_mode_finish, -fdump-rtl-dfinit, -fdump-rtl-dfinish โ€” ๐Ÿ’€ these are defined, but they always produce empty files. Not a bug in your code, bestie, it's just how these ones are. Don't cry over blank files ๐Ÿ˜ญ.
  • -da, -fdump-rtl-all โ€” ๐Ÿ‘‘ produce all the dumps listed above, all at once. Full send energy.
  • -dA โ€” ๐Ÿ’œ annotates the assembler output with miscellaneous debugging information.
  • -dD โ€” ๐ŸŒธ dumps all macro definitions at the end of preprocessing, in addition to the normal output.
  • -dH โ€” โญ produces a core dump whenever an error occurs. Be prepared for a core dump every time something goes sideways.
  • -dp โ€” ๐ŸŽ€ annotates the assembler output with a comment indicating which pattern and alternative is used. The length and cost of each instruction get printed too.
  • -dP โ€” ๐Ÿง dumps the RTL in the assembler output as a comment before each instruction. This also turns on -dp annotation, so you get both vibes at once.
  • -dx โ€” ๐Ÿช„ just generates RTL for a function instead of compiling it. This is usually used with -fdump-rtl-expand, so pair them up, iykyk.

  • -fdump-debug โ€” ๐Ÿž dumps the debugging information generated during the debug generation phase.
  • -fdump-earlydebug โ€” โฐ dumps the debugging information generated during the early debug generation phase.
  • -fdump-noaddr โ€” ๐Ÿ™ˆ when doing debugging dumps, this suppresses address output. That makes it way more feasible to diff debugging dumps for compiler invocations with different compiler binaries and/or different text / bss / data / heap / stack / dso start locations. Lowkey a lifesaver.
  • -freport-bug โ€” ๐Ÿšจ collects and dumps debug information into a temporary file if an internal compiler error (ICE) occurs. Your ICE gets receipts, no cap.
  • -fdump-unnumbered โ€” ๐Ÿ”ข when doing debugging dumps, this suppresses instruction numbers and address output. That makes it more feasible to diff debugging dumps for compiler invocations with different options, especially with and without -g. Very useful, very main character.
  • -fdump-unnumbered-links โ€” ๐Ÿ”— when doing debugging dumps (see the -d option above), this suppresses instruction numbers for the links to the previous and next instructions in a sequence.

  • -fdump-ipa-switch, -fdump-ipa-switch-options โ€” ๐Ÿง  these control the dumping at various stages of inter-procedural analysis language tree to a file. The file name is generated by appending a switch-specific suffix to the source file name, and the file is created in the same directory as the output file. These dumps are possible:
    • all โ€” enables all inter-procedural analysis dumps.
    • cgraph โ€” dumps information about call-graph optimization, unused function removal, and inlining decisions.
    • inline โ€” dumps after function inlining.

Additionally, the options -optimized, -missed, -note, and -all can be provided, with the same meaning as for -fopt-info, defaulting to -optimized.

For example, -fdump-ipa-inline-optimized-missed will emit information on callsites that were inlined, along with callsites that were not inlined. Bestie, this is the one to reach for when you want the full tea โ˜•.

By default, the dump will contain messages about successful optimizations (equivalent to -optimized) together with 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 information. The options and filename parts behave exactly as described in the -fdump-tree option. These switch values are accepted:
    • all โ€” enables all language-specific dumps.
    • class โ€” dumps class hierarchy information. Virtual table information is emitted unless slim is specified. This one is C++ only, so it's a C++ girlie moment ๐Ÿ’œ.
    • raw โ€” dumps the raw internal tree data. Also C++ only.
  • -fdump-passes โ€” ๐Ÿ“‹ prints on stderr the list of optimization passes that are turned on and off by the current command-line options. A little roll call for your compiler ๐Ÿซก.
  • -fdump-statistics-option โ€” ๐Ÿ“Š enables and controls dumping of pass statistics in a separate file. The file name is generated by appending a suffix ending in .statistics to the source file name, and the file is created in the same directory as the output file. If the -option form is used, -stats causes counters to be summed over the whole compilation unit, while -details dumps every event as the passes generate them. The default with no option is to sum counters for each function compiled.

  • -fdump-tree-all, -fdump-tree-switch, -fdump-tree-switch-options, -fdump-tree-switch-options=filename โ€” ๐ŸŒณ these control the dumping at various stages of processing the intermediate language tree to a file. If the -options form is used, options is a list of - separated options that control the details of the dump. Not all options apply to all dumps, and any that aren't meaningful for a dump are ignored. The following options are available:
    • address โ€” prints the address of each node. Usually this isn't meaningful, since it changes according to the environment and source file. Its main use is tying up a dump file with 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 backward from mangled names in the assembly file.
    • slim โ€” when dumping front-end intermediate representations, inhibits dumping of members of a scope or body of a function merely because that scope has been reached. Only dumps such items when they are directly reachable by some other path. When dumping pretty-printed trees, this option inhibits dumping the bodies of control structures. When dumping RTL, prints the RTL in slim (condensed) form instead of the default LISP-like representation.
    • raw โ€” prints a raw representation of the tree. By default, trees are pretty-printed into a C-like representation.
    • details โ€” enables more detailed dumps (not honored by every dump option). Also includes information from the optimization passes.
    • stats โ€” enables dumping various statistics about the pass (not honored by every dump option).
    • 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 suitable for viewing with GraphViz to file.passid.pass.dot. Each function in the file is pretty-printed as a subgraph, so GraphViz can render them all in a single plot ๐Ÿ“ˆ. This option currently only works for RTL dumps, and the RTL is always dumped in slim form.
    • vops โ€” enables showing virtual operands for every statement.
    • lineno โ€” enables showing line numbers for statements.
    • uid โ€” enables showing the unique ID (DECL_UID) for each variable.
    • verbose โ€” enables showing the tree dump for each statement.
    • eh โ€” enables showing the EH region number holding each statement.
    • scev โ€” enables showing scalar evolution analysis details.
    • optimized โ€” enables showing optimization information (only available in certain passes).
    • missed โ€” enables showing missed optimization information (only available in certain passes).
    • note โ€” enables other detailed optimization information (only available in certain passes).
    • all โ€” turns on all options, except raw, slim, verbose and lineno.
    • optall โ€” turns on all optimization options, i.e., optimized, missed, and note.

Wanna know which tree dumps exist or find the dump for a pass you care about? Follow these steps, it's giving treasure map ๐Ÿ—บ๏ธ:

  1. Invoke GCC with -fdump-passes and, in the stderr output, look for a code that corresponds to the pass you're interested in. For example, the codes tree-evrp, tree-vrp1, and tree-vrp2 correspond to the three Value Range Propagation passes. The number at the end distinguishes distinct invocations of the same pass.
  2. To enable the creation of the dump file, append the pass code to the -fdump- option prefix and invoke GCC with it. For example, to enable the dump from the Early Value Range Propagation pass, invoke GCC with the -fdump-tree-evrp option. Optionally, you may specify the name of the dump file. If you don't specify one, GCC creates it as described below.
  3. Find the pass dump in a file whose name is composed 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. Note that the numeric codes are not stable and may change from one version of GCC to another ๐Ÿฅบ.

  • -fopt-info, -fopt-info-options, -fopt-info-options=filename โ€” ๐Ÿ” control optimization dumps from various optimization passes. If the -options form is used, options is a list of - separated option keywords that select the dump details and optimizations. Okay so the options can be divided into three groups:

You know how -fopt-info lets you pick your optimization drama? Here's the rest of the tea โ˜•โœจ

Okay so there are three buckets you can mix and match ๐Ÿ’…

  1. what kinds of messages get printed ๐Ÿ’ฌ
  2. how verbose the dump is ๐Ÿ“œ
  3. which optimizations get included ๐ŸŽฏ

You can freely mix options from each bucket because they don't overlap ๐Ÿซถ If things do clash, though, the later option on the command line wins. Main character energy, literally ๐Ÿ‘‘

The message kinds ๐ŸŒธ

  • optimized โ€” Prints info when an optimization is successfully applied ๐Ÿ”ฅ Each pass gets to decide what counts as relevant. For example, the vectorizer passes print the source location of loops that got successfully vectorized โœจ
  • missed โ€” Prints info about optimizations that didn't happen ๐Ÿ’€ Each pass controls what details show up here.
  • note โ€” Prints verbose info about optimizations, like certain transformations and more detailed messages about decisions ๐Ÿง
  • all โ€” Prints detailed optimization info, and this includes optimized, missed, and note ๐Ÿ’–

The verbosity dial ๐ŸŽš๏ธ

  • internals โ€” By default, only "high-level" messages come through. This turns on extra, more detailed messages that are probably only interesting to GCC developers ๐Ÿค“ (not us, bestie, we're just here to vibe ๐Ÿ˜ญ)

The optimization groups ๐Ÿงš

You can add one or more of these keywords to pick a whole group of optimizations:

  • ipa โ€” Enables dumps from all interprocedural optimizations ๐Ÿฆ‹
  • loop โ€” Enables dumps from all loop optimizations ๐Ÿ”
  • inline โ€” Enables dumps from all inlining optimizations ๐Ÿ“ฆ
  • omp โ€” Enables dumps from all OMP (Offloading and Multi Processing) optimizations ๐Ÿš€
  • vec โ€” Enables dumps from all vectorization optimizations ๐ŸŒˆ
  • optall โ€” Enables dumps from all optimizations. This is a superset of the groups above ๐Ÿ‘‘

If you leave options out, it defaults to optimized-optall, which means dumping messages about successful optimizations from all the passes, skipping anything treated as "internals" ๐Ÿซ 

Where the output goes ๐Ÿ“

If you give a filename, the dumps from all the applicable optimizations get concatenated into that file. If you don't, the dump goes to stderr. You're allowed to use multiple -fopt-info options, but only one of them can include a filename. If other filenames show up, all but the first such option get ignored ๐Ÿ™…โ€โ™€๏ธ

Heads up, bestie: the output filename gets overwritten when you have multiple translation units ๐Ÿ˜ฑ If you want one combined output from several translation units, use stderr instead.

Here are some examples, because examples are everything ๐Ÿฅน This one sends the optimization info to stderr:

gcc -O3 -fopt-info

This one dumps the missed optimization report from all the passes into missed.all:

gcc -O3 -fopt-info-missed=missed.all

And this one prints info about missed optimization opportunities from the vectorization passes on stderr. Also, -fopt-info-vec-missed is equivalent to -fopt-info-missed-vec, so the order of the group names and message types after -fopt-info doesn't matter ๐Ÿซถ

gcc -O2 -ftree-vectorize -fopt-info-vec-missed

Here's one that outputs info about missed optimizations and optimized locations from all the inlining passes into inline.txt:

gcc -O3 -fopt-info-inline-optimized-missed=inline.txt

Finally, the plot twist ๐Ÿ˜ˆ

gcc -fopt-info-vec-missed=vec.miss -fopt-info-loop-optimized=loop.opt

Here, the two output filenames vec.miss and loop.opt clash, 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 ๐Ÿ’”


-fsave-optimization-record

Okay this one is giving machine-readable ๐Ÿค–๐Ÿ’œ It writes a SRCFILE.opt-record.json.gz file detailing what optimizations were performed, for the ones that support -fopt-info.

This option is experimental, and the format of the data inside the compressed JSON file is subject to change. Don't build your whole life on it yet ๐Ÿ™ˆ

Roughly speaking, it's like a machine-readable version of -fopt-info-all, as a collection of messages with source file, line number, and column number. Each message also gets these extra goodies:

  • the execution count of the code being optimized, plus metadata about whether that came from actual profile data or just an estimate, so consumers can prioritize messages by code hotness ๐Ÿ”ฅ
  • the function name of the code being optimized, where applicable โœจ
  • the "inlining chain" for the code being optimized, so when a function gets inlined into several 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 inside other messages, which reflects the implementation details of the optimization passes. Wild, I know ๐Ÿ’€


-fsched-verbose=n

On targets that use instruction scheduling, this option controls how much debugging output the scheduler prints to the dump files ๐Ÿ“

  • For n greater than zero, -fsched-verbose outputs the same 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. That's a lot of info, bestie ๐Ÿ˜ตโ€๐Ÿ’ซ

-fenable-kind-pass and -fdisable-kind-pass=range-list

These are a set of options for explicitly disabling and enabling optimization passes ๐Ÿ”ง They're intended for debugging GCC itself.

Compiler users should stick to the regular options for enabling and disabling passes instead. These are for GCC devs only, so don't mess with them unless you're debugging the compiler ๐Ÿ™…โ€โ™€๏ธ
  • -fdisable-ipa-pass โ€” Disables the IPA pass pass, where pass is the pass name. If the same pass gets statically invoked in the compiler multiple times, append a sequential number to the pass name, starting from 1 ๐Ÿ”ข
  • -fdisable-rtl-pass and -fdisable-rtl-pass=range-list โ€” Disables the RTL pass pass, where pass is the pass name. The same numbering rule applies if the pass runs more than once. 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, you can simplify the number pair to a single number. If a function's call graph node uid falls inside one of the specified ranges, the pass gets disabled for that function. The uid shows up in the function header of a dump file, and you can dump the pass names with -fdump-passes ๐Ÿง 
  • -fdisable-tree-pass and -fdisable-tree-pass=range-list โ€” Disables the tree pass pass. Check out -fdisable-rtl for the description of the option arguments ๐ŸŒณ
  • -fenable-ipa-pass โ€” Enables the IPA pass pass, where pass is the pass name. Same numbering rule as above if it's invoked multiple times ๐Ÿฆ‹
  • -fenable-rtl-pass and -fenable-rtl-pass=range-list โ€” Enables the RTL pass pass. See -fdisable-rtl for the option argument description and examples โœจ
  • -fenable-tree-pass and -fenable-tree-pass=range-list โ€” Enables the tree pass pass. See -fdisable-rtl for the description of the option arguments ๐ŸŒธ

Here are some examples so you can see these in action ๐Ÿ‘€

# 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

Enables internal consistency checking ๐Ÿ•ต๏ธโ€โ™€๏ธ The default depends on how the compiler was configured. -fchecking=2 turns on further internal consistency checking that might affect code generation, so be careful with that one ๐Ÿ’…


-frandom-seed=string

This option gives GCC a seed to use instead of random numbers when generating certain symbol names that have to be different in every compiled file ๐ŸŽฒ It's also used to place unique stamps in coverage data files and 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. If it's an arbitrary string, it gets converted to a number by computing CRC32 ๐Ÿงฎ

The string should be different for every file you compile ๐ŸŒˆ


-save-temps and -save-temps=cwd

These 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. This makes a preprocessed foo.i output file even though the compiler now normally uses an integrated preprocessor, which is so extra but also very useful ๐Ÿงš

When you use -save-temps with the -x command-line option, it's smart enough to avoid overwriting an input source file that has the same extension as an intermediate file ๐Ÿง  If you want the intermediate file, you can rename the source file before using -save-temps ๐Ÿ’–

Okay so bestie, running GCC in parallel is fun until it absolutely isn't ๐Ÿ˜ญ If you compile several source files that share a base name (in different subdirectories), or the same source file for multiple output destinations, the parallel compilers are super likely to interfere with each other and overwrite each other's temporary files. Chaos ๐Ÿ’€ For instance:

gcc -save-temps -o outdir1/foo.o indir1/foo.c&
gcc -save-temps -o outdir2/foo.o indir2/foo.c&

This can end with foo.i and foo.o being written to at the same time by both compilers. Not it ๐Ÿ™ˆ

  • -save-temps=obj โ€” okay this one is so good โœจ It stores the usual "temporary" intermediate files permanently. If the -o option is used, the temp files are based on the object file. If -o is not used, -save-temps=obj just behaves like -save-temps.

For example:

gcc -save-temps=obj -c foo.c
gcc -save-temps=obj -c bar.c -o dir/xbar.o
gcc -save-temps=obj foobar.c -o dir2/yfoobar

Those create foo.i, foo.s, dir/xbar.i, dir/xbar.s, dir2/yfoobar.i, dir2/yfoobar.s, and dir2/yfoobar.o ๐Ÿงš

  • -time[=file] โ€” main character energy ๐Ÿ’… It reports the CPU time taken by each subprocess in the compilation sequence. For C source files, that's the compiler proper and the assembler (plus the linker if linking is done).

Without an output file specified, the output looks like this:

# cc1 0.12 0.01
# as 0.00 0.01

The first number on each line is the "user time," which is the time spent executing the program itself. The second number is the "system time," the time spent executing operating system routines on behalf of the program. Both numbers are in seconds โฑ๏ธ

With an output file specified, the output gets appended to the named file, and it looks like this:

0.12 0.01 cc1 <options>
0.00 0.01 as <options>

The "user time" and "system time" get moved before the program name, and the options passed to the program are displayed too, so you can later tell what file was being compiled and with which options ๐Ÿ“

  • -fdump-final-insns[=file] โ€” dumps the final internal representation (RTL) to file. If the optional argument is omitted (or if file is .), the dump file name is determined by appending .gkd to the compilation output file name ๐ŸŒธ
  • -fcompare-debug[=opts] โ€” okay this one is giving science experiment ๐Ÿงช If no error occurs during compilation, the compiler runs a second time, adding opts and -fcompare-debug-second to the arguments passed to the second compilation. It dumps the final internal representation in both compilations and prints an error if they differ.

If the equal sign is omitted, the default -gtoggle is used.

The environment variable GCC_COMPARE_DEBUG, if it's defined, non-empty, and nonzero, implicitly enables -fcompare-debug. If GCC_COMPARE_DEBUG is defined to a string starting with a dash, then that string is used for opts. Otherwise, the default -gtoggle is used ๐ŸŽ€

-fcompare-debug=, with the equal sign but without opts, is equivalent to -fno-compare-debug. That one disables the dumping of the final representation and the second compilation, and it even stops GCC_COMPARE_DEBUG from taking effect ๐Ÿ™…โ€โ™€๏ธ

To verify full coverage during -fcompare-debug testing, set GCC_COMPARE_DEBUG to say -fcompare-debug-not-overridden. GCC rejects that as an invalid option in any actual compilation (rather than preprocessing, assembly, or linking). To get just a warning instead, setting GCC_COMPARE_DEBUG to -w%n-fcompare-debug not overridden will do ๐Ÿซถ

  • -fcompare-debug-second โ€” this one 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 produce output to files or to standard output as a side effect. Dump files and preserved temporary files get renamed so they contain the additional .gk extension during the second compilation, so they don't overwrite the ones from the first ๐Ÿฆ‹
When this option is passed to the compiler driver, it causes the first compilation to be skipped. That makes it useful for little other than debugging the compiler proper, so don't be surprised if it's a whole vibe check ๐Ÿ’€
  • -gtoggle โ€” turns off generation of debug info if leaving out this option generates it, or turns it on at level 2 otherwise. Its position in the command line does not matter. It takes effect after all other options are processed, and it does so only once, no matter how many times it is given. It's mainly intended to be used with -fcompare-debug ๐Ÿ’œ
  • -fvar-tracking-assignments-toggle โ€” toggles -fvar-tracking-assignments, in the same way that -gtoggle toggles -g โœจ
  • -Q โ€” makes the compiler print out each function name as it is compiled, and print some statistics about each pass when it finishes ๐Ÿ“Š
  • -ftime-report โ€” makes the compiler print some statistics about the time consumed by each pass when it finishes โฐ
  • -ftime-report-details โ€” records the time consumed by infrastructure parts separately for each pass ๐Ÿ”
  • -fira-verbose=n โ€” controls the verbosity of the dump file for the integrated register allocator. The default value is 5. If the value n is greater than or equal to 10, the dump output is sent to stderr using the same format as n minus 10 ๐ŸŒˆ
  • -flto-report โ€” prints a report with internal details on the workings of the link-time optimizer. The contents of this report vary from version to version. It's meant to be useful to GCC developers when processing object files in LTO mode (via -flto).

Disabled by default ๐Ÿ™ˆ

  • -flto-report-wpa โ€” like -flto-report, but only prints for the WPA phase of Link Time Optimization ๐Ÿงš
  • -fmem-report โ€” makes the compiler print some statistics about permanent memory allocation when it finishes ๐Ÿง 
  • -fmem-report-wpa โ€” makes the compiler print some statistics about permanent memory allocation for the WPA phase only ๐Ÿ“
  • -fpre-ipa-mem-report, -fpost-ipa-mem-report โ€” make the compiler print some statistics about permanent memory allocation before or after interprocedural optimization ๐Ÿ’–
  • -fprofile-report โ€” makes the compiler print some statistics about consistency of the (estimated) profile and the effect of individual passes ๐Ÿ“ˆ
  • -fstack-usage โ€” okay this one is so detailed it's literally iconic ๐Ÿ‘‘ It makes the compiler output stack usage information for the program, on a per-function basis. The filename for the dump is made by appending .su to the auxname. The auxname is generated from the name of the output file, if one is explicitly specified and it is not an executable. Otherwise, it's the basename of the source file.

Each entry is made up of 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 are allocated for the frame on function entry and released on function exit, and no stack adjustments are otherwise made in the function. The second field is this fixed number of bytes ๐Ÿชต

The qualifier "dynamic" means the function manipulates the stack dynamically. In addition to the static allocation described above, stack adjustments are 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 of the total amount of stack used by the function. If it's not present, the amount of these adjustments is not bounded at compile time, and the second field only represents the bounded part ๐Ÿซ 

  • -fstats โ€” emits statistics about front-end processing at the end of the compilation. This option is supported only by the C++ front end, and the information 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 bound. counter-value-list is a comma-separated list of name:lower_bound:upper_bound tuples, which sets the lower and the upper bound of each debug counter name. The lower_bound is optional and is zero initialized if not set. All debug counters have the initial upper bound of "UINT_MAX", so dbg_cnt returns true always unless the upper bound is set by this option.

For example, with -fdbg-cnt=dce:2:4,tail_call:10, "dbg_cnt(dce)" returns true only for the third and fourth invocation. For "dbg_cnt(tail_call)", true is returned for the first 10 invocations ๐ŸŽฏ

  • -print-file-name=library โ€” prints the full absolute name of the library file library that would be used when linking, and then doesn't do anything else. With this option, GCC does not compile or link anything. It just prints the file name ๐Ÿ–จ๏ธ
  • -print-multi-directory โ€” prints the directory name corresponding to the multilib selected by any other switches present in 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 -, without spaces between multiple switches. This is supposed to ease shell processing ๐Ÿš
  • -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. Or, 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 searches for a program such as cpp ๐Ÿ”Ž
  • -print-libgcc-file-name โ€” same as -print-file-name=libgcc.a. This is useful when you use -nostdlib or -nodefaultlibs but you still want to link with libgcc.a. You can do:
gcc -nostdlib <files>... `gcc -print-libgcc-file-name`
  • -print-search-dirs โ€” okay so this one prints the name of the configured installation directory and a list of the program and library directories gcc searches, and then it stops. It doesn't do anything else ๐Ÿ’…

This is SO useful when gcc throws installation problem, cannot exec cpp0: No such file or directory. ๐Ÿ˜ญ To fix that, you either put cpp0 and the other compiler components where gcc expects to find them, or you set the environment variable GCC_EXEC_PREFIX to the directory where you installed them. Don't forget the trailing / ๐Ÿซถ

  • -print-sysroot โ€” prints the target sysroot directory used during compilation. This is the target sysroot set either at configure time or with the --sysroot option, and it might have an extra suffix that depends on your compilation options. If no target sysroot is set, this prints nothing ๐ŸŒธ
  • -print-sysroot-headers-suffix โ€” prints the suffix added to the target sysroot when searching for headers. If the compiler wasn't configured with one, you'll get an error instead. Then it's done, and it doesn't do anything else โœจ
  • -dumpmachine โ€” prints the compiler's target machine, like i686-pc-linux-gnu. Then it stops ๐Ÿฆ‹
  • -dumpversion โ€” prints the compiler version, like 3.0, 6.3.0 or 7, and then it's done ๐Ÿ’– This is the version used in filesystem paths and specs. Depending on how the compiler was configured, it can be one number (major version), two numbers split by a dot (major and minor), or three numbers split by dots (major, minor and patchlevel).
  • -dumpfullversion โ€” prints the full compiler version and then stops. The output is always three numbers separated by dots: major, minor and patchlevel ๐Ÿ”ฅ
  • -dumpspecs โ€” prints the compiler's built-in specs and then stops. (This one is used when GCC itself is being built ๐Ÿงš)

โœจ Machine-Dependent Options โœจ

Every target machine GCC supports can have its own options. Think: compiling for a specific processor variant or ABI, or tweaking optimizations for that exact machine ๐Ÿ‘‘ By convention, machine-specific option names start with -m.

Some compiler configurations also support extra target-specific options, usually so they match 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. ilp32 is the SysV-like model where int, long int and pointers are 32 bits. lp64 is the SysV-like model where int is 32 bits, but long int and pointers are 64 bits.

The default depends on your specific target configuration. Heads up, bestie: the LP64 and ILP32 ABIs are not link-compatible. You have to compile your whole program with the same ABI and link it with a compatible set of libraries ๐Ÿ’€

  • -mbig-endian โ€” generates big-endian code. This is the default when GCC is configured for an aarch64_be-*-* target ๐Ÿ“
  • -mgeneral-regs-only โ€” generates code that only uses the general-purpose registers. This stops the compiler from 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 addresses and section sizes. Programs can only be statically linked ๐Ÿ”ฅ
  • -mstrict-align, -mno-strict-align โ€” avoids or allows generating memory accesses that might not be aligned on a natural object boundary, as described in the architecture specification โœจ
  • -momit-leaf-frame-pointer, -mno-omit-leaf-frame-pointer โ€” omits or keeps the frame pointer in leaf functions. The first one, omitting it, is the default ๐Ÿ‘‘
  • -mstack-protector-guard=guard, -mstack-protector-guard-reg=reg, -mstack-protector-guard-offset=offset โ€” generates stack protection code using a canary at guard. The supported locations are global for a global canary, or sysreg for a canary in an appropriate system register ๐Ÿ›ก๏ธ

With the sysreg choice, -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 read from. 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 โ€” generates stack protection code using a canary at guard. The supported locations are global for a global canary, or sysreg for a canary in an appropriate system register ๐Ÿ›ก๏ธ

With the sysreg choice, -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 read from. There's no default register or offset, because this is entirely for use within the Linux kernel ๐Ÿง

  • -mtls-dialect=desc โ€” uses TLS descriptors as the thread-local storage mechanism for dynamic accesses of TLS variables. This is the default ๐Ÿ’œ
  • -mtls-dialect=traditional โ€” uses traditional TLS as the thread-local storage mechanism for dynamic accesses of TLS variables ๐ŸŽ€
  • -mtls-size=size โ€” specifies the bit size of immediate TLS offsets. Valid values are 12, 24, 32 and 48. This option requires binutils 2.26 or newer ๐Ÿงš
  • -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 workaround happens at link time, so this option only passes the matching flag to the linker ๐Ÿ”—
  • -mlow-precision-recip-sqrt, -mno-low-precision-recip-sqrt โ€” enables or disables the reciprocal square root approximation. This only does something if -ffast-math or -funsafe-math-optimizations is used too. Turning it on drops the precision of reciprocal square root results to about 16 bits for single precision and about 32 bits for double precision ๐Ÿซ 
  • -mlow-precision-sqrt, -mno-low-precision-sqrt โ€” enables or disables the square root approximation. This only does something if -ffast-math or -funsafe-math-optimizations is used too. Turning it on drops square root precision to about 16 bits for single precision and about 32 bits for double precision. If you enable it, it also implies -mlow-precision-recip-sqrt ๐ŸŒˆ
  • -mlow-precision-div, -mno-low-precision-div โ€” enables or disables the division approximation. This only does something if -ffast-math or -funsafe-math-optimizations is used too. Turning it on drops division precision to about 16 bits for single precision and about 32 bits for double precision โญ
  • -mtrack-speculation, -mno-track-speculation โ€” enables or disables generating extra code that tracks speculative execution through conditional branches. The tracking state can then be used by the compiler when it expands calls to "__builtin_speculation_safe_copy", so it can produce a more efficient code sequence ๐Ÿง 
  • -moutline-atomics, -mno-outline-atomics โ€” enables or disables calls to out-of-line helpers that implement atomic operations. At runtime, these helpers figure out whether the LSE instructions from ARMv8.1-A can be used. If not, they fall back to the load/store-exclusive instructions that are in the base ARMv8.0 ISA ๐Ÿ’ซ

This option only applies when compiling for the base ARMv8.0 instruction set. If you use 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 ๐Ÿ’…

  • -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 permissible values for arch are armv8-a, armv8.1-a, armv8.2-a, armv8.3-a, armv8.4-a, armv8.5-a or native.

The value armv8.5-a implies armv8.4-a and enables compiler support for the ARMv8.5-A architecture extensions.

The value armv8.4-a implies armv8.3-a and enables compiler support for the ARMv8.4-A architecture extensions.

The value armv8.3-a implies armv8.2-a and enables compiler support for the ARMv8.3-A architecture extensions.

The value armv8.2-a implies armv8.1-a and enables compiler support for the ARMv8.2-A architecture extensions.

The value armv8.1-a implies armv8-a and enables compiler support for the ARMv8.1-A architecture extension. In particular, it enables the +crc, +lse, and +rdma features ๐Ÿ”ฅ

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 can't recognize the architecture of the host system,

The permissible values for feature are listed in the sub-section on aarch64-feature-modifiers,,-march and -mcpu Feature Modifiers. If you specify conflicting feature modifiers, the right-most feature is used ๐Ÿ‘‘

GCC uses name to decide what kind of instructions it can emit when generating assembly code. If -march is specified without -mtune or -mcpu also being specified, the code is tuned to perform well across a range of target processors that implement the target architecture ๐ŸŒธ

  • -mtune=name โ€” okay bestie, this one tells GCC which target processor to tune your code's performance for ๐Ÿ’… The permissible values are: generic, cortex-a35, cortex-a53, cortex-a55, cortex-a57, cortex-a72, cortex-a73, cortex-a75, cortex-a76, ares, exynos-m1, emag, falkor, neoverse-e1, neoverse-n1, neoverse-n2, neoverse-v1, neoverse-512tvb, qdf24xx, saphira, phecda, xgene1, vulcan, octeontx, octeontx81, octeontx83, a64fx, thunderx, thunderxt88, thunderxt88p1, thunderxt81, tsv110, thunderxt83, thunderx2t99, 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, and native.

The big.LITTLE combos are lowkey the cutest ๐Ÿฆ‹ cortex-a57.cortex-a53, cortex-a72.cortex-a53, cortex-a73.cortex-a35, cortex-a73.cortex-a53, cortex-a75.cortex-a55, and cortex-a76.cortex-a55 tell GCC to tune for a big.LITTLE system.

neoverse-512tvb is giving very specific energy ๐Ÿ”ฅ It means GCC should tune for Neoverse cores that (a) implement SVE and (b) have a total vector bandwidth of 512 bits per cycle. In other words, GCC tunes for Neoverse cores that can run 4 128-bit Advanced SIMD arithmetic instructions a cycle, plus an equivalent number of SVE arithmetic instructions per cycle (2 for 256-bit SVE, 4 for 128-bit SVE). It's more general than tuning for one specific core like Neoverse V1, but more specific than the default tuning described below.

Also, on native AArch64 GNU/Linux systems, native tunes performance to the host system โœจ If the compiler can't recognize the host's processor, this option has no effect.

Where none of -mtune=, -mcpu= or -march= are specified, the code gets 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 attached ๐ŸŽ€ The form is -mcpu=cpu{+[no]feature}*, where cpu takes the same values as -mtune. The allowed feature values are documented in the sub-section aarch64-feature-modifiers,,-march and -mcpu Feature Modifiers. If you specify conflicting feature modifiers, the right-most one wins.

GCC uses name to decide what kind of instructions it can emit when generating assembly (as if by -march), and which processor to tune performance for (as if by -mtune). If you use this option together with -march or -mtune, those take precedence over the matching part of -mcpu.

-mcpu=neoverse-512tvb is special ๐Ÿ‘‘ It doesn't refer to one specific core, but to all Neoverse cores that (a) implement SVE and (b) have a total vector bandwidth of 512 bits a cycle. Unless you override it with -march, -mcpu=neoverse-512tvb generates code that can run on a Neoverse V1 core, since Neoverse V1 is the first Neoverse core with these properties. Unless you override it with -mtune, -mcpu=neoverse-512tvb tunes code the same way as -mtune=neoverse-512tvb.

  • -moverride=string โ€” lets you override tuning decisions the back-end makes in response to a -mtune= switch ๐Ÿ› ๏ธ The syntax, semantics, and accepted values for string aren't guaranteed to stay consistent across releases.
This option is only intended to be useful when developing GCC ๐Ÿšง
  • -mverbose-cost-dump โ€” turns on verbose cost model dumping in the debug dump files ๐Ÿ” This one's for debugging the compiler itself.
  • -mpc-relative-literal-loads, -mno-pc-relative-literal-loads โ€” enable or disable PC-relative literal loads ๐Ÿงš With this option, literal pools are accessed using a single instruction and emitted after each function. That limits the maximum size of functions to 1MB. It's enabled by default for -mcmodel=tiny.
  • -msign-return-address=scope โ€” picks the function scope where return address signing gets applied ๐Ÿ” The permissible values are none, which turns return address signing off, non-leaf, which enables pointer signing for functions that aren't leaf functions, and all, which enables pointer signing for all functions. The default value is none.
This option has been deprecated by -mbranch-protection ๐Ÿ’€
  • -mbranch-protection=none|standard|pac-ret[+leaf]|bti โ€” picks which branch protection features to use ๐Ÿ›ก๏ธ none is the default and turns off all types of branch protection. standard turns on all types of branch protection features, 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: it signs functions that save the return address to memory (non-leaf functions will practically always do this) using the a-key. The optional argument leaf can be used to extend the signing to include leaf functions. 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 ๐Ÿ“ It only has an effect when SVE is enabled.

GCC supports two forms of SVE code generation: "vector-length agnostic" output that works with any size of vector register, and "vector-length specific" output that lets GCC make assumptions about the vector length when that's useful for 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. All other values generate 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 their inverses nofeature ๐Ÿ’–

  • crc โ€” Enable CRC extension. This is on by default for -march=armv8.1-a.
  • crypto โ€” Enable Crypto extension. This also enables Advanced SIMD and floating-point instructions.
  • fp โ€” Enable floating-point instructions. This is on by default for all possible values for options -march and -mcpu.
  • simd โ€” Enable Advanced SIMD instructions. This also enables floating-point instructions. This is on by default for all possible values for options -march and -mcpu.
  • sve โ€” Enable Scalable Vector Extension instructions. This also enables Advanced SIMD and floating-point instructions.
  • lse โ€” Enable Large System Extension instructions. This is on by default for -march=armv8.1-a.
  • rdma โ€” Enable Round Double Multiply Accumulate instructions. This is on by default for -march=armv8.1-a.
  • fp16 โ€” Enable FP16 extension. This also enables floating-point instructions.
  • fp16fml โ€” Enable FP16 fmla extension. This also enables FP16 extensions and floating-point instructions. This option is enabled by default for -march=armv8.4-a. Use of this option with architectures prior to Armv8.2-A is not supported ๐Ÿ™…
  • rcpc โ€” Enable the RcPc extension. This doesn't change code generation from GCC, but it is passed on to the assembler, enabling inline asm statements to use instructions from the RcPc extension.
  • dotprod โ€” Enable the Dot Product extension. This also enables Advanced SIMD instructions.
  • aes โ€” Enable the Armv8-a aes and pmull crypto extension. This also enables Advanced SIMD instructions.
  • sha2 โ€” Enable the Armv8-a sha2 crypto extension. This also enables Advanced SIMD instructions.
  • sha3 โ€” Enable the sha512 and sha3 crypto extension. This also enables Advanced SIMD instructions. Use of this option with architectures prior to Armv8.2-A is not supported ๐Ÿ™…
  • sm4 โ€” Enable the sm3 and sm4 crypto extension. This also enables Advanced SIMD instructions. Use of this option with architectures prior to Armv8.2-A is not supported ๐Ÿ™…
  • profile โ€” Enable the Statistical Profiling extension. This option is only to enable the extension at the assembler level and does not affect code generation.
  • rng โ€” Enable the Armv8.5-a Random Number instructions. This option is only to enable the extension at the assembler level and does not affect code generation.
  • memtag โ€” Enable the Armv8.5-a Memory Tagging Extensions. This option is only to enable the extension at the assembler level and does not affect code generation.
  • sb โ€” Enable the Armv8-a Speculation Barrier instruction. This option is only to enable the extension at the assembler level and does not affect code generation. This option is enabled by default for -march=armv8.5-a.
  • ssbs โ€” Enable the Armv8-a Speculative Store Bypass Safe instruction. This option is only to enable the extension at the assembler level and does not affect code generation. This option is enabled by default for -march=armv8.5-a.
  • predres โ€” Enable the Armv8-a Execution and Data Prediction Restriction instructions. This option is only to enable the extension at the assembler level and does not affect code generation. This option is enabled by default for -march=armv8.5-a.

Feature crypto implies aes, sha2, and simd, which implies fp. Conversely, nofp implies nosimd, which implies nocrypto, noaes and nosha2 ๐Ÿ”„

๐Ÿธ Adapteva Epiphany Options

These -m options are defined for Adapteva Epiphany ๐ŸŒˆ

  • -mhalf-reg-file โ€” Don't allocate any register in the range "r32"..."r63". That lets code run on hardware variants that lack these registers ๐Ÿงš
  • -mprefer-short-insn-regs โ€” Preferentially allocate registers that allow short instruction generation. This can result in increased instruction count, so it may either reduce or increase overall code size ๐Ÿคทโ€โ™€๏ธ
  • -mbranch-cost=num โ€” okay so this sets how pricey branches are, roughly like num "simple" instructions ๐Ÿงš. It's only a heuristic though, so don't expect the exact same results across releases ๐Ÿ’€.
  • -mcmove โ€” turns on the generation of conditional moves โœจ
  • -mnops=num โ€” emits num NOPs before every other instruction it generates ๐Ÿฆ‹
  • -mno-soft-cmpsf โ€” for single-precision floating-point comparisons, this emits an fsub instruction and tests the flags ๐Ÿ”ฅ It's faster than a software comparison, BUT it can give wrong results with NaNs, or when two different small numbers subtract to zero ๐Ÿ˜ญ The default is -msoft-cmpsf, which is slower but IEEE-compliant, so it's the safe bestie choice ๐Ÿซถ
  • -mstack-offset=num โ€” sets the offset between the top of the stack and the stack pointer ๐Ÿฅž E.g., a value of 8 means the eight bytes in the range "sp+0...sp+7" can be used by leaf functions without stack allocation. Values other than 8 or 16 are untested and unlikely to work ๐Ÿ™ˆ
Heads up: this option changes the ABI, so compiling a program with a different stack offset than the libraries were built with generally does not work ๐Ÿšซ

This one is useful if you want to evaluate whether a different stack offset gives you better code. But to actually build working programs with a different stack offset, it's recommended to configure the toolchain with the appropriate --with-stack-offset=num option.

  • -mno-round-nearest โ€” makes the scheduler assume the rounding mode has been set to truncating. The default is -mround-nearest ๐Ÿ“
  • -mlong-calls โ€” if no attribute says otherwise, this assumes all calls might be beyond the offset range of the "b" / "bl" instructions. So it loads the function address into a register before doing a (otherwise direct) call ๐Ÿ“ž This is the default.
  • -mshort-calls โ€” if no attribute says otherwise, this assumes all direct calls are in range of the "b" / "bl" instructions, so it uses those for direct calls ๐Ÿƒโ€โ™€๏ธ The default is -mlong-calls.
  • -msmall16 โ€” assumes addresses can be loaded as 16-bit unsigned values ๐ŸŒˆ This does not apply to function addresses where -mlong-calls semantics are in effect.
  • -mfp-mode=mode โ€” sets the prevailing mode of the floating-point unit ๐Ÿ‘‘ This decides the floating-point mode that's provided and expected at function call and return time. Matching it to the mode you mostly need at function start can make your programs smaller and faster by avoiding unnecessary mode switches ๐Ÿ’…

mode can be set to one of the following values:

  • caller โ€” any mode at function entry is valid, and it gets retained or restored when the function returns and when it calls other functions. This is useful for compiling libraries or other compilation units you might want to drop into different programs with different prevailing FPU modes. Being able to use a single object file can outweigh the size and speed overhead of any extra mode switching you'd need with a more specific choice ๐Ÿงƒ
  • truncate โ€” the mode used for floating-point calculations with truncating (i.e. round towards zero) rounding mode. That includes conversion from floating point to integer โœ‚๏ธ
  • round-nearest โ€” the mode used for floating-point calculations with round-to-nearest-or-even rounding mode ๐ŸŽฏ
  • int โ€” the mode used to perform integer calculations in the FPU, e.g. integer multiply, or integer multiply-and-accumulate ๐Ÿ”ข

The default is -mfp-mode=caller โœจ

  • -mno-split-lohi, -mno-postinc, -mno-postmodify โ€” code generation tweaks that disable, respectively, splitting of 32-bit loads, generation of post-increment addresses, and generation of post-modify addresses ๐Ÿงฉ The defaults are msplit-lohi, -mpost-inc, and -mpost-modify.
  • -mnovect-double โ€” changes the preferred SIMD mode to SImode ๐ŸŽ€ The default is -mvect-double, which uses DImode as the preferred SIMD mode.
  • -max-vect-align=num โ€” the maximum alignment for SIMD vector mode types ๐Ÿ“ num may be 4 or 8, and the default is 8. Note that this is an ABI change, even though many library function interfaces are unaffected if they don't use SIMD vector modes in places that affect the size and/or alignment of relevant types ๐Ÿ™ƒ
  • -msplit-vecmove-early โ€” splits vector moves into single word moves before reload ๐Ÿช„ In theory this can give better register allocation, but so far the reverse seems to be generally the case ๐Ÿ’€
  • -m1reg-reg โ€” specifies a register to hold the constant -1, which makes loading small negative constants and certain bitmasks faster โšก Allowable values for reg are r43 and r63, which specify use of 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 ๐ŸŽฎ Supported values for gpu are:
    • fiji โ€” compile for GCN3 Fiji devices (gfx803).
    • gfx900 โ€” compile for GCN5 Vega 10 devices (gfx900).
  • -mstack-size=bytes โ€” specifies how many bytes of stack space will be requested for each GPU thread (wave-front) ๐Ÿงต Beware, because there may be many threads and limited memory available ๐Ÿ˜ญ The size of the stack allocation may also have an impact on run-time performance. The default is 32KB when using OpenACC or OpenMP, and 1MB otherwise.

๐Ÿฆ‹ ARC Options ๐Ÿฆ‹

The following options control the architecture variant that code is being compiled for ๐Ÿงš

  • -mbarrel-shifter โ€” generates instructions supported by the barrel shifter ๐Ÿ›ž This is the default unless -mcpu=ARC601 or -mcpu=ARCEM is in effect.
  • -mjli-always โ€” forces a function call to use the jli_s instruction ๐Ÿ“ฃ This option is valid only for the ARCv2 architecture.
  • -mcpu=cpu โ€” sets the architecture type, register usage, and instruction scheduling parameters for cpu ๐Ÿง  There are also shortcut alias options available for backward compatibility and convenience. Supported values for cpu are:
    • arc600 โ€” compile for ARC600. Aliases: -mA6, -mARC600.
    • arc601 โ€” compile for ARC601. Alias: -mARC601.
    • arc700 โ€” compile for ARC700. Aliases: -mA7, -mARC700. This is the default when configured with --with-cpu=arc700.
    • arcem โ€” compile for ARC EM.
    • archs โ€” compile for ARC HS.
    • em โ€” compile for ARC EM CPU with no hardware extensions.
    • em4 โ€” compile for ARC EM4 CPU.
    • em4_dmips โ€” compile for ARC EM4 DMIPS CPU.
    • em4_fpus โ€” compile for ARC EM4 DMIPS CPU with the single-precision floating-point extension.
    • em4_fpuda โ€” compile for ARC EM4 DMIPS CPU with single-precision floating-point and double assist instructions.
    • hs โ€” compile for ARC HS CPU with no hardware extensions except the atomic instructions.
    • hs34 โ€” compile for ARC HS34 CPU.
    • hs38 โ€” compile for ARC HS38 CPU.
    • hs38_linux โ€” compile for ARC HS38 CPU with all hardware extensions on.
    • 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 NPS400 chip.
    • em_mini โ€” compile for ARC EM minimalist configuration featuring a reduced register set.
  • -mdpfp, -mdpfp-compact โ€” generates double-precision FPX instructions, tuned for the compact implementation ๐ŸŒท
  • -mdpfp-fast โ€” generates double-precision FPX instructions, tuned for the fast implementation ๐ŸŽ๏ธ
  • -mno-dpfp-lrsr โ€” disables "lr" and "sr" instructions from using FPX extension aux registers ๐Ÿšซ
  • -mea โ€” generates extended arithmetic instructions ๐Ÿงฎ Currently only "divaw", "adds", "subs", and "sat16" are supported. This is always enabled for -mcpu=ARC700.
  • -mno-mpy โ€” does not 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 ๐Ÿ”ฅ Only valid for -mcpu=ARC600.
  • -mnorm โ€” generates "norm" instructions ๐ŸŒ€ This is the default if -mcpu=ARC700 is in effect.
  • -mspfp, -mspfp-compact โ€” generates single-precision FPX instructions, tuned for the compact implementation ๐ŸŒผ
  • -mspfp-fast โ€” generates single-precision FPX instructions, tuned for the fast implementation โšก
  • -msimd โ€” enables generation of ARC SIMD instructions via target-specific builtins ๐Ÿ’œ Only valid for -mcpu=ARC700.
  • -msoft-float โ€” this option is ignored; it's provided for compatibility purposes only ๐Ÿซ  Software floating-point code is emitted by default, and this default can be overridden by FPX options: -mspfp, -mspfp-compact, or -mspfp-fast for single precision, and -mdpfp, -mdpfp-compact, or -mdpfp-fast for double precision.
  • -mswap โ€” generates "swap" instructions ๐Ÿ”„
  • -matomic โ€” enables use of the locked load/store conditional extension to implement atomic memory built-in functions ๐Ÿ”’ Not available for ARC 6xx or ARC EM cores.
  • -mdiv-rem โ€” enables "div" and "rem" instructions for ARCv2 cores โž—
  • -mcode-density โ€” enables code density instructions for ARC EM ๐Ÿฐ This option is on by default for ARC HS.
  • -mll64 โ€” enables double load/store operations for ARC HS cores ๐Ÿ’…
  • -mtp-regno=regno โ€” specifies the thread pointer register number ๐Ÿงต
  • -mmpy-option=multo โ€” โœจ pick your multiplier design! You can pass multo as a string or a number. wlh1 is the default, and these are the options:
    • 0 or none โ€” No multiplier at all ๐Ÿ’€
    • 1 or w โ€” A 16x16 multiplier that's fully pipelined. It turns on "mpyw" and "mpyuw".
    • 2 or wlh1 โ€” A 32x32 multiplier that's fully pipelined (1 stage) ๐Ÿ”ฅ. It also unlocks "mpy", "mpyu", "mpym", "mpymu", and "mpy_s". This is the default ๐Ÿ‘‘.
    • 3 or wlh2 โ€” Also a 32x32 multiplier that's fully pipelined, but with 2 stages. It also unlocks "mpy", "mpyu", "mpym", "mpymu", and "mpy_s".
    • 4 or wlh3 โ€” Two 16x16 multipliers that are blocking and sequential. It also unlocks "mpy", "mpyu", "mpym", "mpymu", and "mpy_s".
    • 5 or wlh4 โ€” One 16x16 multiplier that's blocking and sequential. It also unlocks "mpy", "mpyu", "mpym", "mpymu", and "mpy_s".
    • 6 or wlh5 โ€” One 32x4 multiplier that's blocking and sequential. It also unlocks "mpy", "mpyu", "mpym", "mpymu", and "mpy_s".
    • 7 or plus_dmpy โ€” ARC HS SIMD support ๐Ÿฆ‹.
    • 8 or plus_macd โ€” ARC HS SIMD support ๐Ÿฆ‹.
    • 9 or plus_qmacw โ€” ARC HS SIMD support ๐Ÿฆ‹.

This option is only available for ARCv2 cores ๐Ÿซถ.

  • -mfpu=fpu โ€” โœจ turns on specific floating-point hardware extensions for ARCv2 cores. These are the fpu values you can use:
    • fpus โ€” Single-precision floating-point hardware extensions ๐ŸŒธ.
    • fpud โ€” Double-precision floating-point hardware extensions. The single-precision extension comes along too. Not available for ARC EM ๐Ÿ™ˆ.
    • fpuda โ€” Double-precision floating-point hardware extensions using double-precision assist instructions. The single-precision extension is on too. This option is only available for ARC EM.
    • fpuda_div โ€” Double-precision floating-point hardware extensions using double-precision assist instructions. The single-precision floating-point, square-root, and divide extensions are on as well. This option is only available for ARC EM.
    • fpuda_fma โ€” Double-precision floating-point hardware extensions using double-precision assist instructions. The single-precision floating-point and fused multiply and add extensions are on too. This option is only available for ARC EM.
    • fpuda_all โ€” Double-precision floating-point hardware extensions using double-precision assist instructions. Every single-precision floating-point hardware extension is on too. This option is only available for ARC EM.
    • fpus_div โ€” Single-precision floating-point, square-root, and divide hardware extensions ๐Ÿงš.
    • fpud_div โ€” Double-precision floating-point, square-root, and divide hardware extensions. This option includes fpus_div. Not available for ARC EM.
    • fpus_fma โ€” Single-precision floating-point and fused multiply and add hardware extensions ๐Ÿ’œ.
    • fpud_fma โ€” Double-precision floating-point and fused multiply and add hardware extensions. This option includes fpus_fma. Not available for ARC EM.
    • fpus_all โ€” Every single-precision floating-point hardware extension ๐ŸŒˆ.
    • fpud_all โ€” Every single- and double-precision floating-point hardware extension. Not available for ARC EM ๐Ÿ’….
  • -mirq-ctrl-saved=register-range, blink, lp_count โ€” tells the processor which general-purpose registers to automatically save and restore 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 โ€” sets how many registers get copied into the second register bank when a fast interrupt starts. Fast interrupts are the ones with the highest priority level, P0 โšก. They only save the PC and STATUS32 registers, so they skip memory transactions during entry and exit. Use this when you're using fast interrupts on an ARC V2 family processor. Permitted values are 4, 8, 16, and 32.
  • -mlpc-width=width โ€” sets the width of the "lp_count" register ๐Ÿ”ข. Valid values for width are 8, 16, 20, 24, 28, and 32 bits. The default is locked at 32 bits. If the width is less than 32, the compiler won't try to turn your loops into the zero-delay loop mechanism unless it knows that "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 "__ARC_LPC_WIDTH__" macro with the value of width.
  • -mrf16 โ€” makes the compiler generate code for a 16-entry register file ๐Ÿ“. This option defines the "__ARC_RF16__" preprocessor macro.
  • -mbranch-index โ€” turns on 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 "__Xdsp_packa" preprocessor symbol. This option is deprecated. ๐Ÿ™ˆ
  • -mdvbf โ€” passed down to the assembler to enable the dual Viterbi butterfly extension. It also sets the "__Xdvbf" preprocessor symbol. This option is deprecated. ๐Ÿ™ˆ
  • -mlock โ€” passed down to the assembler to enable the locked load/store conditional extension. It also sets the "__Xlock" preprocessor symbol ๐Ÿ”.
  • -mmac-d16 โ€” passed down to the assembler. It also sets the "__Xxmac_d16" preprocessor symbol. This option is deprecated. ๐Ÿ™ˆ
  • -mmac-24 โ€” passed down to the assembler. It also sets the "__Xxmac_24" preprocessor symbol. This option is deprecated. ๐Ÿ™ˆ
  • -mrtsc โ€” passed down to the assembler to enable the 64-bit time-stamp counter extension instruction. It also sets the "__Xrtsc" preprocessor symbol. This option is deprecated. ๐Ÿ™ˆ
  • -mswape โ€” passed down to the assembler to enable the swap byte ordering extension instruction. It also sets the "__Xswape" preprocessor symbol ๐Ÿ”„.
  • -mtelephony โ€” passed down to the assembler to enable dual- and single-operand instructions for telephony. It also sets the "__Xtelephony" preprocessor symbol. This option is deprecated. ๐Ÿ™ˆ
  • -mxy โ€” passed down to the assembler to enable the XY memory extension. It also sets the "__Xxy" preprocessor symbol ๐Ÿ’œ.

The following options control how the assembly code is annotated ๐Ÿ“.

  • -misize โ€” annotates assembler instructions with estimated addresses ๐Ÿ“.
  • -mannotate-align โ€” explains which alignment considerations led to the decision to make an instruction short or long ๐Ÿง.

The following options are passed through to the linker ๐Ÿ”—.

  • -marclinux โ€” passed through to the linker to specify use of the "arclinux" emulation. This option 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 option is enabled by default in tool chains built for "arc-linux-uclibc" and "arceb-linux-uclibc" targets when profiling is requested ๐Ÿ“Š.

The following options control the semantics of the generated code ๐Ÿง .

  • -mlong-calls โ€” generates calls as register indirect calls, so you get access to the full 32-bit address range ๐ŸŒ.
  • -mmedium-calls โ€” doesn't go below a 25-bit addressing range for calls, which is the offset available for an unconditional branch-and-link instruction ๐Ÿ“. Conditional execution of function calls is suppressed so the 25-bit range can be used, instead of the 21-bit range you'd get with a 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, as long as that data is no bigger than num bytes. The default value of num is 4 for any ARC configuration, or 8 when there are double load/store operations ๐Ÿ“ฆ.
  • -mno-sdata โ€” 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 the generation of these instructions when they're driven by the combiner pass ๐Ÿ™…โ€โ™€๏ธ.
  • -mcase-vector-pcrel โ€” uses PC-relative switch case tables to enable case table shortening. This is the default for -Os ๐Ÿง.
  • -mcompact-casesi โ€” enables the compact "casesi" pattern. This is the default for -Os, and it's only available for ARCv1 cores. This option is deprecated. ๐Ÿ™ˆ
  • -mno-cond-exec โ€” disables the ARCompact-specific pass that generates conditional execution instructions ๐Ÿšง.

Okay so the ARC port has its own special pass ๐Ÿ’… The regular conditional-execution pass kinda struggles, because delay slot scheduling, operand numbers, literal sizes, instruction lengths, and conditional execution support all get tangled together ๐ŸŒ€. So ARC keeps a separate pass that goes hunting for more conditional execution chances after register allocation, branch shortening, and delay slot scheduling are done โœจ. It usually (not always!) improves performance and code size, but it costs extra compile time, which is why there's an option to switch it off ๐Ÿซถ. If your call instructions are blowing past their allowed offset range because they got conditionalized ๐Ÿ˜ญ, bestie, consider -mmedium-calls instead ๐Ÿฆ‹.

  • -mearly-cbranchsi โ€” Turns on 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, so maybe don't build your whole vibe around it ๐Ÿ’€
  • -mindexed-loads โ€” Enables indexed loads ๐Ÿ“ Be careful though, because some optimizers then assume indexed stores exist, and they don't on ARC, so it can get messy ๐Ÿ™ˆ
  • -mlra โ€” Enables Local Register Allocation ๐Ÿงš It's still experimental for ARC, so by default the compiler uses standard reload (i.e. -mno-lra) ๐Ÿ’œ
  • -mlra-priority-none โ€” Doesn't indicate any priority for target registers ๐ŸŒˆ
  • -mlra-priority-compact โ€” Indicates target register priority for r0..r3 / r12..r15 ๐ŸŽ€
  • -mlra-priority-noncompact โ€” Reduces target register priority for r0..r3 / r12..r15 ๐Ÿฅ€
  • -mmillicode โ€” When you're optimizing for size (using -Os), prologues and epilogues that have to save or restore a big pile of registers often get shortened by calling a special function in libgcc, and that's called a millicode call โœจ Since these calls can cause performance issues, and/or linking issues when you link in a nonstandard way, 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, so check your CPU first, babe ๐Ÿ’…
  • -mmixed-code โ€” Tweaks register allocation to help 16-bit instruction generation โœจ The general vibe is shorter average instruction size, but a higher instruction count ๐ŸŒธ
  • -mq-class โ€” 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 yep, it's the default too โญ
  • -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 are used opportunistically ๐ŸŒท
    • 2 โ€” On top of that, alignment of loops and of code after barriers gets dropped ๐Ÿงธ
    • 3 โ€” On top of that, optional data alignment gets dropped, and the Os option is enabled ๐Ÿ‘‘

It defaults to 3 when -Os is in effect ๐Ÿ”ฅ Otherwise, if this isn't set, the behavior is equivalent to level 1 ๐Ÿ’…

  • -mtune=cpu โ€” Sets instruction scheduling parameters for cpu, overriding anything implied by -mcpu= ๐ŸŽฏ Supported values for cpu are:
    • ARC600 โ€” Tunes for the ARC600 CPU ๐ŸŒธ
    • ARC601 โ€” Tunes for the ARC601 CPU ๐ŸŒท
    • ARC700 โ€” Tunes for the ARC700 CPU with the standard multiplier block ๐Ÿ’œ
    • ARC700-xmac โ€” Tunes for the ARC700 CPU with the XMAC block ๐Ÿ”ฅ
    • ARC725D โ€” Tunes for the ARC725D CPU ๐Ÿงš
    • ARC750D โ€” Tunes for the ARC750D CPU โœจ
  • -mmultcost=num โ€” Sets the cost to assume for a multiply instruction, 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 of the branch being 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 ๐Ÿ’€ Use them at your own risk, bestie ๐Ÿ˜ญ

  • -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 instead, 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 instead, where little endian is the default ๐Ÿ’œ
  • -mbarrel_shifter โ€” Replaced by -mbarrel-shifter ๐Ÿ”
  • -mdpfp_compact โ€” Replaced by -mdpfp-compact ๐Ÿ”
  • -mdpfp_fast โ€” Replaced by -mdpfp-fast ๐Ÿ”
  • -mdsp_packa โ€” Replaced by -mdsp-packa ๐Ÿ”
  • -mEA โ€” Replaced by -mea ๐Ÿ”
  • -mmac_24 โ€” Replaced by -mmac-24 ๐Ÿ”
  • -mmac_d16 โ€” Replaced by -mmac-d16 ๐Ÿ”
  • -mspfp_compact โ€” Replaced by -mspfp-compact ๐Ÿ”
  • -mspfp_fast โ€” Replaced by -mspfp-fast ๐Ÿ”
  • -mtune=cpu โ€” The values arc600, arc601, arc700 and arc700-xmac for cpu are replaced by ARC600, ARC601, ARC700 and ARC700-xmac respectively ๐ŸŽ€
  • -multcost=num โ€” Replaced by -mmultcost ๐Ÿ”

โœจ ARM Options โœจ

These -m options are defined for the ARM port ๐Ÿฆ‹

  • -mabi=name โ€” Generates code for the specified ABI ๐ŸŒˆ Permissible values are: apcs-gnu, atpcs, aapcs, aapcs-linux and iwmmxt ๐Ÿงธ
  • -mapcs-frame โ€” Generates a stack frame that's compliant with the ARM Procedure Call Standard for all functions, even if it isn't strictly necessary for the code to run correctly ๐Ÿงฑ Specifying -fomit-frame-pointer with this option causes stack frames not to be generated for leaf functions ๐Ÿƒ The default is -mno-apcs-frame ๐Ÿ’… This option is deprecated ๐Ÿ’€
  • -mapcs โ€” A synonym for -mapcs-frame, and it's deprecated too ๐Ÿ™ˆ
  • -mthumb-interwork โ€” Generates code that supports calling between the ARM and Thumb instruction sets ๐Ÿ”€ Without this option, on pre-v5 architectures, the two instruction sets can't be reliably used inside one program ๐Ÿ˜ฌ The default is -mno-thumb-interwork, since slightly larger code is generated when -mthumb-interwork is specified ๐Ÿ“ In AAPCS configurations this option is meaningless ๐Ÿคทโ€โ™€๏ธ
  • -mno-sched-prolog โ€” Prevents the reordering of instructions in the function prologue, or the merging of those instructions with the instructions in the function's body ๐Ÿ”’ This means all functions start with a recognizable set of instructions (or in fact one of a choice from a small set of different function prologues), and that info can be used to locate the start of functions 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 ๐ŸŽฏ Note that the hard-float and soft-float ABIs are not link-compatible; you must compile your entire program with the same ABI, and link with a compatible set of libraries ๐Ÿšซ

  • -mgeneral-regs-only โ€” Generates code that uses only the general-purpose registers ๐ŸŒท This stops the compiler from using floating-point and Advanced SIMD registers, but it won't impose 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 code for a little-endian processor ๐Ÿ’–
  • -mbe8, -mbe32 โ€” When linking a big-endian image, selects between BE8 and BE32 formats ๐ŸŽ€ This option has no effect on little-endian images and is ignored there ๐Ÿ™ƒ 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 determine what kind 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, armv7-r, armv8-r, armv6-m, armv6s-m, armv7-m, armv7e-m, armv8-m.base, armv8-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 equivalent to writing -march=armv7-a+vfpv4, since the +simd option is entirely disabled by the +nofp option that follows it ๐Ÿ™ˆโœจ

Okay so extension names are super generic ๐Ÿซถ but what they actually do depends on which architecture you slap them onto โœจ Like, +simd works on both armv7-a and armv8-a, but on armv7-a it switches on the original ARMv7-A Advanced SIMD (Neon) stuff, and on armv8-a it's the ARMv8-A version ๐Ÿ’…

Here's the tea on what each architecture supports ๐Ÿ“ Anything not mentioned doesn't support any extensions at all, so no cap, skip those ๐Ÿ’€

armv5te, armv6, armv6j, armv6k, armv6kz, armv6t2, armv6z, armv6zk

These all share the same two extensions ๐ŸŒธ

  • +fp โ€” The VFPv2 floating-point instructions ๐Ÿฆ‹ You can also call it +vfpv2, since that's an alias for this extension.
  • +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 ๐Ÿ’– The alias +vfpv3-d16 works here too. Heads up, though: floating-point isn't supported by the base ARMv7-M architecture, but it is compatible with both ARMv7-A and ARMv7-R โš ๏ธ
  • +nofp โ€” Disables the floating-point instructions ๐Ÿ™ˆ

armv7-a

  • +mp โ€” The multiprocessing extension โœจ
  • +sec โ€” The security extension ๐Ÿ”
  • +fp โ€” The VFPv3 floating-point instructions, with 16 double-precision registers ๐Ÿ’– The alias +vfpv3-d16 works for this one as well.
  • +simd โ€” The Advanced SIMD (Neon) v1 plus the VFPv3 floating-point instructions ๐Ÿ”ฅ The aliases +neon and +neon-vfpv3 can be used instead of this one.
  • +vfpv3 โ€” The VFPv3 floating-point instructions, with 32 double-precision registers ๐Ÿ‘‘
  • +vfpv3-d16-fp16 โ€” The VFPv3 floating-point instructions with 16 double-precision registers, plus the half-precision floating-point conversion operations ๐ŸŒˆ
  • +vfpv3-fp16 โ€” The VFPv3 floating-point instructions with 32 double-precision registers, plus the half-precision floating-point conversion operations ๐ŸŒˆ
  • +vfpv4-d16 โ€” The VFPv4 floating-point instructions, with 16 double-precision registers ๐Ÿฆ‹
  • +vfpv4 โ€” The VFPv4 floating-point instructions, with 32 double-precision registers ๐Ÿฆ‹
  • +neon-fp16 โ€” The Advanced SIMD (Neon) v1 plus the VFPv3 floating-point instructions, with the half-precision floating-point conversion operations ๐Ÿ“
  • +neon-vfpv4 โ€” The Advanced SIMD (Neon) v2 plus the VFPv4 floating-point instructions ๐Ÿ’…
  • +nosimd โ€” Disables the Advanced SIMD instructions. Floating point stays on, though ๐Ÿซถ
  • +nofp โ€” Disables the floating-point and Advanced SIMD instructions ๐Ÿ™ˆ

armv7ve

The extended version of the ARMv7-A architecture, with support for virtualization ๐Ÿงš

  • +fp โ€” The VFPv4 floating-point instructions, with 16 double-precision registers ๐Ÿฆ‹ The alias +vfpv4-d16 can be used for this one.
  • +simd โ€” The Advanced SIMD (Neon) v2 plus the VFPv4 floating-point instructions ๐Ÿ”ฅ The alias +neon-vfpv4 can be used for this one.
  • +vfpv3-d16 โ€” The VFPv3 floating-point instructions, with 16 double-precision registers ๐Ÿ’–
  • +vfpv3 โ€” The VFPv3 floating-point instructions, with 32 double-precision registers ๐Ÿ‘‘
  • +vfpv3-d16-fp16 โ€” The VFPv3 floating-point instructions with 16 double-precision registers, plus the half-precision floating-point conversion operations ๐ŸŒˆ
  • +vfpv3-fp16 โ€” The VFPv3 floating-point instructions with 32 double-precision registers, plus the half-precision floating-point conversion operations ๐ŸŒˆ
  • +vfpv4-d16 โ€” The VFPv4 floating-point instructions, with 16 double-precision registers ๐Ÿฆ‹
  • +vfpv4 โ€” The VFPv4 floating-point instructions, with 32 double-precision registers ๐Ÿฆ‹
  • +neon โ€” The Advanced SIMD (Neon) v1 plus the VFPv3 floating-point instructions ๐Ÿ”ฅ The alias +neon-vfpv3 can be used for this one.
  • +neon-fp16 โ€” The Advanced SIMD (Neon) v1 plus the VFPv3 floating-point instructions, with the half-precision floating-point conversion operations ๐Ÿ“
  • +nosimd โ€” Disables the Advanced SIMD instructions. Floating point is still on ๐Ÿซถ
  • +nofp โ€” Disables the floating-point and Advanced SIMD instructions ๐Ÿ™ˆ

armv8-a

  • +crc โ€” The Cyclic Redundancy Check (CRC) instructions โœจ
  • +simd โ€” The ARMv8-A Advanced SIMD and floating-point instructions ๐Ÿ”ฅ
  • +crypto โ€” The cryptographic instructions ๐Ÿ”
  • +nocrypto โ€” Disables the cryptographic instructions ๐Ÿ™ˆ
  • +nofp โ€” Disables the floating-point, Advanced SIMD and cryptographic instructions ๐Ÿ’€
  • +sb โ€” The Speculation Barrier Instruction ๐Ÿ›ก๏ธ
  • +predres โ€” The Execution and Data Prediction Restriction Instructions ๐Ÿง 

armv8.1-a

  • +simd โ€” The ARMv8.1-A Advanced SIMD and floating-point instructions ๐Ÿ”ฅ
  • +crypto โ€” The cryptographic instructions ๐Ÿ” This also turns on the Advanced SIMD and floating-point instructions.
  • +nocrypto โ€” Disables the cryptographic instructions ๐Ÿ™ˆ
  • +nofp โ€” Disables the floating-point, Advanced SIMD and cryptographic instructions ๐Ÿ’€
  • +sb โ€” The Speculation Barrier Instruction ๐Ÿ›ก๏ธ
  • +predres โ€” The Execution and Data Prediction Restriction Instructions ๐Ÿง 

armv8.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 โ€” Enables the Dot Product extension ๐ŸŒธ This also enables Advanced SIMD instructions.
  • +nocrypto โ€” Disables the cryptographic extension ๐Ÿ™ˆ
  • +nofp โ€” Disables the floating-point, Advanced SIMD and cryptographic instructions ๐Ÿ’€
  • +sb โ€” The Speculation Barrier Instruction ๐Ÿ›ก๏ธ
  • +predres โ€” The Execution and Data Prediction Restriction Instructions ๐Ÿง 

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 โ€” Disables the cryptographic extension ๐Ÿ™ˆ
  • +nofp โ€” Disables the floating-point, Advanced SIMD and cryptographic instructions ๐Ÿ’€
  • +sb โ€” The Speculation Barrier Instruction ๐Ÿ›ก๏ธ
  • +predres โ€” The Execution and Data Prediction Restriction Instructions ๐Ÿง 

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 โ€” Disables the cryptographic extension ๐Ÿ™ˆ
  • +nofp โ€” Disables the floating-point, Advanced SIMD and cryptographic instructions ๐Ÿ’€

armv7-r

  • +fp.sp โ€” The single-precision VFPv3 floating-point instructions ๐Ÿ’… The alias +vfpv3xd can be used for this one.
  • +fp โ€” The VFPv3 floating-point instructions with 16 double-precision registers ๐Ÿ’– The alias +vfpv3-d16 can be used 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 ๐Ÿ™ˆ

Okay so the -march list is still going, and the ARMv8-M and ARMv8-R crew are iconic ๐Ÿ‘‘

  • armv8-m.main ๐ŸŒธ: the ARMv8-M main architecture, with these extensions:
    • +dsp: the DSP instructions ๐Ÿ’…
    • +nodsp: disable the DSP extension ๐Ÿ™ˆ
    • +fp: the single-precision floating-point instructions โœจ
    • +fp.dp: the single- and double-precision floating-point instructions ๐Ÿ”ฅ
    • +nofp: disable the floating-point extension ๐Ÿ’€
  • armv8-r ๐Ÿฆ‹: the ARMv8-R architecture, with these extensions:
    • +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: disable the cryptographic instructions
    • +nofp: disable the floating-point, Advanced SIMD and cryptographic instructions ๐Ÿ˜ญ

-march=native makes the compiler auto-detect the architecture of the build computer, bestie ๐Ÿซถ Right now this only works on GNU/Linux, and not every architecture gets recognized. If the auto-detect fails, the option has no effect.


-mtune=name

This one tells GCC which target ARM processor to tune the performance of the code for. Some ARM implementations get better performance when you use this option โœจ 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, 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-m1.small-multiply,
cortex-m0.small-multiply, cortex-m0plus.small-multiply, exynos-m1,
marvell-pj4, neoverse-n1, neoverse-n2, neoverse-v1, xscale, iwmmxt,
iwmmxt2, ep9312, fa526, fa626, fa606te, fa626te, fmp626, fa726te,
xgene1.

It can also tune for a big.LITTLE system ๐Ÿง  Here are the permissible big.LITTLE names:

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 tunes for a blend of processors within the architecture arch ๐Ÿ’– The goal is code that runs well on the most popular current processors, balancing optimizations that help some CPUs in the range while avoiding performance pitfalls on the others. Heads up: the effects of this option may shift in future GCC versions as CPU models come and go ๐ŸŒˆ

-mtune takes the same extension options as -mcpu, but the extensions don't change how the generated code gets tuned, okay? ๐ŸŽ€

-mtune=native auto-detects the CPU of the build computer ๐Ÿ” Same deal as before: GNU/Linux only for now, not every architecture is recognized, and if the auto-detect fails the option does nothing.


-mcpu=name[+extension...]

This one names the target ARM processor ๐Ÿ‘‘ GCC uses that name to figure out the target ARM architecture (like -march would) and the processor type to tune for (like -mtune would). If you use this alongside -march or -mtune, those win for their own part of the job ๐Ÿ’…

A bunch of the supported CPUs have optional architectural extensions, and those are usually enabled by default. If some versions of a CPU don't have an extension, you can use the extension syntax to switch off the ones that are missing ๐Ÿ™ˆ

Floating-point and Advanced SIMD (Neon) are a little extra, so -mfloat-abi and -mfpu matter here too. Floating-point and Advanced SIMD instructions only get used if -mfloat-abi is not set to soft. And any -mfpu setting other than auto overrides the floating-point and SIMD extension instructions that would otherwise be available ๐Ÿ”ฅ

For example, cortex-a9 shows up in three major configurations: integer only, with just a floating-point unit, or with floating-point and Advanced SIMD ๐Ÿฆ‹ By default, all the instructions are enabled. But you can use +nosimd to disable just the SIMD instructions, or +nofp to disable both SIMD and floating-point instructions.

The permissible names for this option are the same as the ones for -mtune ๐Ÿ’–

These extension options are common to the listed CPUs:

  • +nodsp: disables the DSP instructions on cortex-m33.
  • +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 and cortex-m33. On generic-armv7-a, cortex-a5, cortex-a7, cortex-a8, cortex-a9, cortex-a12, cortex-a15, cortex-a17, cortex-a15.cortex-a7, cortex-a17.cortex-a7, cortex-a32, cortex-a35, cortex-a53 and cortex-a55, it disables the floating-point and SIMD instructions.
  • +nofp.dp: disables the double-precision part of the floating-point instructions on cortex-r5, cortex-r7, cortex-r8, cortex-r52 and cortex-m7.
  • +nosimd: disables the SIMD instructions (but not the floating-point ones) on generic-armv7-a, cortex-a5, cortex-a7 and cortex-a9.
  • +crypto: enables the cryptographic instructions on cortex-a32, cortex-a35, cortex-a53, cortex-a55, cortex-a57, cortex-a72, cortex-a73, cortex-a75, exynos-m1, xgene1, cortex-a57.cortex-a53, cortex-a72.cortex-a53, cortex-a73.cortex-a35, cortex-a73.cortex-a53 and cortex-a75.cortex-a55. ๐Ÿ”

The generic-armv7-a pseudo target defaults to VFPv3 with 16 double-precision registers โœจ It supports these extension options: mp, sec, vfpv3-d16, vfpv3, vfpv3-d16-fp16, vfpv3-fp16, vfpv4-d16, vfpv4, neon, neon-vfpv3, neon-fp16 and neon-vfpv4. They mean the same thing as the extensions to -march=armv7-a.

-mcpu=generic-arch is also allowed, and it's equivalent to -march=arch -mtune=generic-arch. Check out -mtune for more info ๐Ÿงš

-mcpu=native auto-detects the CPU of the build computer ๐Ÿ” Once again: GNU/Linux only for now, not every architecture is recognized, and if the auto-detect fails the option has no effect.


-mfpu=name

This tells GCC what floating-point hardware (or hardware emulation) the target has ๐Ÿ”ฅ The permissible names are:

auto, vfpv2, vfpv3, vfpv3-fp16, vfpv3-d16, vfpv3-d16-fp16, vfpv3xd, vfpv3xd-fp16,
neon-vfpv3, neon-fp16, vfpv4, vfpv4-d16, fpv4-sp-d16, neon-vfpv4,
fpv5-d16, fpv5-sp-d16, fp-armv8, neon-fp-armv8 and
crypto-neon-fp-armv8.

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 special ๐Ÿ’œ It makes the compiler pick the floating-point and Advanced SIMD instructions based on the settings of -mcpu and -march.

If the selected floating-point hardware includes the NEON extension (e.g. -mfpu=neon), GCC's auto-vectorization pass won't generate floating-point operations unless you also specify -funsafe-math-optimizations. This is because 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 can lead to a loss of precision ๐Ÿ˜ญ

Heads up: NEON doesn't fully follow IEEE 754, so denormal values get treated as zero. Using NEON can lose precision, so only add -funsafe-math-optimizations if you're okay with that trade-off.

You can also set the fpu name at function level with the target("fpu=") function attributes or pragmas ๐ŸŽ€


-mfp16-format=name

This specifies the format of the "__fp16" half-precision floating-point type ๐Ÿ“ The permissible names are none, ieee and alternative. The default is none, and in that case the "__fp16" type is not defined.


-mstructure-size-boundary=n

The sizes of all structures and unions get rounded up to a multiple of the number of bits set by this option ๐Ÿ“ The permissible values are 8, 32 and 64. The default varies between toolchains. For the COFF targeted toolchain, the default is 8. A value of 64 is only allowed if the underlying ABI supports it.

A bigger number can give you faster, more efficient code, but it can also make your program bigger ๐ŸŒธ Different values are potentially incompatible. Code compiled with one value can't necessarily work with code or libraries compiled with another value, if they pass information through structures or unions.

This option is deprecated. ๐Ÿ’€ Don't build new stuff around it.

-mabort-on-noreturn

This generates a call to the function "abort" at the end of a "noreturn" function ๐Ÿงฏ It runs if the function tries to return.


-mlong-calls and -mno-long-calls

These tell the compiler to make function calls by first loading the function's address into a register, then doing a subroutine call on that register ๐Ÿงš You need this switch if the target function lives outside the 64-megabyte addressing range of the offset-based subroutine call instruction.

Even with this switch on, not every call becomes a long call ๐Ÿ™ˆ The heuristic is that these calls are not turned into long calls: static functions, functions with the "short_call" attribute, functions inside the scope of a "#pragma no_long_calls" directive, and functions whose definitions were already compiled within the current compilation unit.

The exceptions are the ones that are always turned into 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 one's off by default, bestie ๐Ÿ™ˆ Passing -mno-long-calls puts you back on the default path, and so does wrapping the calls in a #pragma long_calls_off directive ๐ŸŽ€. Just know these switches do nothing to calls made through function pointers ๐Ÿ’€.

  • -msingle-pic-base โ€” This one treats the PIC addressing register as read-only โœจ instead of loading it in the prologue of every function. The runtime system has to set that register to the right value before execution starts, so it's on you (or your runtime) ๐Ÿซถ.
  • -mpic-register=reg โ€” Pick the register used for PIC addressing ๐ŸŒธ. With the standard PIC base, the compiler picks any suitable register on its own. With the single PIC base, the default is R9 if the target is EABI based or stack-checking is enabled, and otherwise it's R10 ๐Ÿ‘‘.
  • -mpic-data-is-text-relative โ€” Assumes the gap between the text and data segments is locked in at static link time ๐Ÿฆ‹. That means PC-relative addressing can reach data you know lives in the data segment. On non-VxWorks RTP targets this is on by default ๐Ÿ’–. If you turn it off on those targets, -msingle-pic-base gets turned on by default instead ๐Ÿงš.
  • -mpoke-function-name โ€” This writes each function's name into the text section, sitting right before the function prologue ๐Ÿ“. The generated code looks roughly like this:
             t0
                 .ascii "arm_poke_function_name", 0
                 .align
             t1
                 .word 0xff000000 + (t1 - t0)
             arm_poke_function_name
                 mov     ip, sp
                 stmfd   sp!, {fp, ip, lr, pc}
                 sub     fp, ip, #4

When you do a stack backtrace, you can look at the pc value stored at fp + 0 ๐Ÿ”. If the trace function checks pc - 12 and the top 8 bits are set, then the function name is embedded right before that spot, and its length is ((pc[-3]) & 0xff000000) โœจ. Iykyk, it's giving detective energy ๐Ÿ•ต๏ธโ€โ™€๏ธ.

  • -mthumb, -marm โ€” Pick whether the code runs in ARM state or Thumb state ๐Ÿ’œ. Most configurations default to ARM state, but you can change that by configuring GCC with the --with-mode=state configure option ๐ŸŒˆ. You can also override ARM or Thumb mode for each function with the target("thumb") and target("arm") function attributes or pragmas ๐Ÿ’….
  • -mflip-thumb โ€” Flips ARM and Thumb modes on alternating functions ๐Ÿ”„. This is only here for regression testing of mixed Thumb/ARM code generation, so do not use it for ordinary compiling ๐Ÿšซ.
  • -mtpcs-frame โ€” Generates a stack frame that follows the Thumb Procedure Call Standard for all non-leaf functions ๐Ÿงฑ. (A leaf function is one that doesn't call any other functions ๐Ÿƒ.) The default is -mno-tpcs-frame.
  • -mtpcs-leaf-frame โ€” Same deal, but for all leaf functions ๐Ÿƒ. The default is -mno-apcs-leaf-frame.
  • -mcallee-super-interworking โ€” Gives every externally visible function in the file being compiled an ARM instruction set header ๐ŸŽ€. That header switches to Thumb mode before the rest of the function runs, so these functions can be called from non-interworking code โœจ. This option is not valid in AAPCS configurations, since interworking is already enabled by default ๐Ÿ’€.
  • -mcaller-super-interworking โ€” Lets calls through function pointers (including virtual functions) work correctly no matter whether the target code was compiled for interworking ๐Ÿฆ‹. Heads up, there's a small overhead when running a function pointer if you turn this on ๐Ÿข. Also not valid in AAPCS configurations, same reason as above โŒ.
  • -mtp=name โ€” Picks the access model for the thread local storage pointer ๐Ÿงต. The valid models are:
    • soft โ€” generates calls to __aeabi_read_tp
    • cp15 โ€” fetches the thread pointer from cp15 directly (supported in the arm6k architecture)
    • auto โ€” uses the best available method for the processor you picked

The default is auto ๐Ÿ’–.

  • -mtls-dialect=dialect โ€” Chooses the dialect for accessing thread local storage ๐ŸŒท. There are two: gnu and gnu2. The gnu one is the original GNU scheme for local and global dynamic TLS models ๐Ÿ“œ. The gnu2 one is the GNU descriptor scheme, which performs better for shared libraries ๐Ÿš€. The descriptor scheme is compatible with the original, but it needs new assembler, linker and library support, so check your toolchain first ๐Ÿ› ๏ธ. Initial and local exec TLS models ignore this option and always use the original scheme ๐Ÿ™…โ€โ™€๏ธ.
  • -mword-relocations โ€” Only generates absolute relocations on word-sized values, meaning R_ARM_ABS32 ๐Ÿงฉ. This is on by default on targets like uClinux and SymbianOS, where the runtime loader enforces this restriction, and whenever -fpic or -fPIC is specified ๐ŸŒˆ. It conflicts with -mslow-flash-data โš ๏ธ.
  • -mfix-cortex-m3-ldrd โ€” Some Cortex-M3 cores can corrupt data when ldrd instructions have overlapping destination and base registers ๐Ÿ˜ญ. This option stops the compiler from generating those instructions ๐Ÿ›ก๏ธ. It's on by default when -mcpu=cortex-m3 is specified ๐Ÿ’….
  • -munaligned-access, -mno-unaligned-access โ€” These turn on (or off) reading and writing of 16- and 32-bit values from addresses that aren't 16- or 32-bit aligned ๐Ÿงฒ. By default, unaligned access is disabled for all pre-ARMv6, all ARMv6-M, and ARMv8-M Baseline architectures, and enabled for all other architectures ๐Ÿ”ง. If unaligned access isn't enabled, words in packed data structures get accessed one byte at a time ๐ŸŒ.

The ARM attribute Tag_CPU_unaligned_access gets set in the generated object file to either true or false, depending on this option ๐Ÿท๏ธ. If unaligned access is enabled, the preprocessor symbol __ARM_FEATURE_UNALIGNED is defined too โœจ.

  • -mneon-for-64bits โ€” Lets Neon handle scalar 64-bit operations ๐ŸŽถ. It's disabled by default because moving data from core registers over to Neon is expensive ๐Ÿ’ธ.
  • -mslow-flash-data โ€” Assumes loading data from flash is slower than fetching instructions ๐Ÿข, so the compiler minimizes literal loads for better performance ๐ŸŽ๏ธ. This is only supported when compiling for ARMv7 M-profile, and it's off by default ๐Ÿšซ. It conflicts with -mword-relocations โš ๏ธ.
  • -masm-syntax-unified โ€” Assumes inline assembler uses unified asm syntax ๐Ÿ“. The default is currently off, which means divided syntax ๐Ÿช“. This option has no impact on Thumb2, although that could change in future GCC releases ๐Ÿ‘€. Divided syntax should be considered deprecated ๐Ÿ’€, so please don't start new code with it ๐Ÿ™.
  • -mrestrict-it โ€” Restricts IT block generation so it follows the ARMv8-A rules ๐Ÿ”’. IT blocks can only contain a single 16-bit instruction from a select set of instructions ๐ŸŽฏ. This is on by default for ARMv8-A Thumb mode ๐Ÿ’œ.
  • -mprint-tune-info โ€” Prints CPU tuning info as a comment in the assembler file ๐Ÿ—’๏ธ. This is only for regression testing of the compiler and isn't meant for ordinary code compiling ๐Ÿšซ. It's disabled by default ๐Ÿ’ค.
  • -mverbose-cost-dump โ€” Turns on verbose cost model dumping in the debug dump files ๐Ÿ”. It's provided for debugging the compiler itself ๐Ÿง‘โ€๐Ÿ’ป.
  • -mpure-code โ€” Stops constant data from being placed in code sections ๐ŸงŠ. When you compile for ELF object format, it also gives all text sections the ELF processor-specific section attribute SHF_ARM_PURECODE โœจ. This option is only available when generating non-PIC code for M-profile targets ๐Ÿ’….
  • -mcmse โ€” Generates secure code according to the "ARMv8-M Security Extensions: Requirements on Development Tools Engineering Specification" ๐Ÿ”. You can find that spec at https://developer.arm.com/documentation/ecm0359818/latest/ ๐Ÿ“–.

๐Ÿฆ‹ AVR Options ๐Ÿฆ‹

These options are defined for AVR implementations ๐ŸŒธ.

  • -mmcu=mcu โ€” Picks the Atmel AVR instruction set architecture (ISA) or MCU type ๐Ÿ’–.

The default for this option is avr2 โœจ.

GCC supports the following AVR devices and ISAs ๐Ÿ‘‘:

  • avr2 โ€” "Classic" devices with up to 8 KiB of program memory ๐ŸŽ€.
    • 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" โ€” the "Enhanced" squad with 16 KiB up to 64 KiB of program memory ๐Ÿ’–
    • mcu = "atmega16", "atmega16a", "atmega16hva", "atmega16hva2", "atmega16hvb", "atmega16hvbrevb", "atmega16m1", "atmega16u4", "atmega161", "atmega162", "atmega163", "atmega164a", "atmega164p", "atmega164pa", "atmega165", "atmega165a", "atmega165p", "atmega165pa", "atmega168", "atmega168a", "atmega168p", "atmega168pa", "atmega168pb", "atmega169", "atmega169a", "atmega169p", "atmega169pa", "atmega32", "atmega32a", "atmega32c1", "atmega32hvb", "atmega32hvbrevb", "atmega32m1", "atmega32u4", "atmega32u6", "atmega323", "atmega324a", "atmega324p", "atmega324pa", "atmega325", "atmega325a", "atmega325p", "atmega325pa", "atmega328", "atmega328p", "atmega328pb", "atmega329", "atmega329a", "atmega329p", "atmega329pa", "atmega3250", "atmega3250a", "atmega3250p", "atmega3250pa", "atmega3290", "atmega3290a", "atmega3290p", "atmega3290pa", "atmega406", "atmega64", "atmega64a", "atmega64c1", "atmega64hve", "atmega64hve2", "atmega64m1", "atmega64rfr2", "atmega640", "atmega644", "atmega644a", "atmega644p", "atmega644pa", "atmega644rfr2", "atmega645", "atmega645a", "atmega645p", "atmega649", "atmega649a", "atmega649p", "atmega6450", "atmega6450a", "atmega6450p", "atmega6490", "atmega6490a", "atmega6490p", "ata5795", "ata5790", "ata5790n", "ata5791", "ata6613c", "ata6614q", "ata5782", "ata5831", "ata8210", "ata8510", "ata5702m322", "at90pwm161", "at90pwm216", "at90pwm316", "at90can32", "at90can64", "at90scr100", "at90usb646", "at90usb647", "at94k", "m3000".
  • "avr51" โ€” more "Enhanced" devices, this time with 128 KiB of program memory ๐Ÿฆ‹
    • mcu = "atmega128", "atmega128a", "atmega128rfa1", "atmega128rfr2", "atmega1280", "atmega1281", "atmega1284", "atmega1284p", "atmega1284rfr2", "at90can128", "at90usb1286", "at90usb1287".
  • "avr6" โ€” the "Enhanced" devices with a 3-byte PC, so anything with more than 128 KiB of program memory ๐Ÿ‘‘
    • mcu = "atmega256rfr2", "atmega2560", "atmega2561", "atmega2564rfr2".
  • "avrxmega2" โ€” XMEGA devices with more than 8 KiB and up to 64 KiB of program memory โœจ
    • mcu = "atxmega8e5", "atxmega16a4", "atxmega16a4u", "atxmega16c4", "atxmega16d4", "atxmega16e5", "atxmega32a4", "atxmega32a4u", "atxmega32c3", "atxmega32c4", "atxmega32d3", "atxmega32d4", "atxmega32e5".
  • "avrxmega3" โ€” XMEGA devices with up to 64 KiB of combined program memory and RAM, where the program memory is visible in the RAM address space ๐Ÿงš
    • mcu = "attiny202", "attiny204", "attiny212", "attiny214", "attiny402", "attiny404", "attiny406", "attiny412", "attiny414", "attiny416", "attiny417", "attiny804", "attiny806", "attiny807", "attiny814", "attiny816", "attiny817", "attiny1604", "attiny1606", "attiny1607", "attiny1614", "attiny1616", "attiny1617", "attiny3214", "attiny3216", "attiny3217", "atmega808", "atmega809", "atmega1608", "atmega1609", "atmega3208", "atmega3209", "atmega4808", "atmega4809".
  • "avrxmega4" โ€” XMEGA devices with more than 64 KiB and up to 128 KiB of program memory ๐ŸŒˆ
    • mcu = "atxmega64a3", "atxmega64a3u", "atxmega64a4u", "atxmega64b1", "atxmega64b3", "atxmega64c3", "atxmega64d3", "atxmega64d4".
  • "avrxmega5" โ€” XMEGA devices with more than 64 KiB and up to 128 KiB of program memory, plus more than 64 KiB of RAM ๐Ÿ’œ
    • mcu = "atxmega64a1", "atxmega64a1u".
  • "avrxmega6" โ€” XMEGA devices with more than 128 KiB of program memory, the big-brain ones ๐Ÿง 
    • mcu = "atxmega128a3", "atxmega128a3u", "atxmega128b1", "atxmega128b3", "atxmega128c3", "atxmega128d3", "atxmega128d4", "atxmega192a3", "atxmega192a3u", "atxmega192c3", "atxmega192d3", "atxmega256a3", "atxmega256a3b", "atxmega256a3bu", "atxmega256a3u", "atxmega256c3", "atxmega256d3", "atxmega384c3", "atxmega384d3".
  • "avrxmega7" โ€” XMEGA devices with more than 128 KiB of program memory and more than 64 KiB of RAM ๐Ÿ”ฅ
    • mcu = "atxmega128a1", "atxmega128a1u", "atxmega128a4u".
  • "avrtiny" โ€” the "TINY" Tiny core devices with 512 B up to 4 KiB of program memory ๐ŸŒธ
    • mcu = "attiny4", "attiny5", "attiny9", "attiny10", "attiny20", "attiny40".
  • "avr1" โ€” this ISA is the minimal AVR core, and it's only supported for the assembler, so no C for these bestie ๐Ÿฅบ
    • mcu = "attiny11", "attiny12", "attiny15", "attiny28", "at90s1200".

  • -mabsdata โ€” assumes all data in static storage can be reached with LDS / STS instructions. This only does anything on reduced Tiny devices like ATtiny40. See also the "absdata" AVR Variable Attributes, variable attribute ๐Ÿ“
  • -maccumulate-args โ€” collects outgoing function arguments and grabs or drops the needed stack space once, in the function prologue and epilogue. Without this, arguments get pushed before a call and popped after it โœจ

Popping arguments after a call can be pricey on AVR, so accumulating the stack space can give you smaller executables, since the arguments never have to come off the stack after each call ๐Ÿ’…

This can shrink code for functions that make several calls to functions taking stack arguments, like printf-style functions ๐Ÿซถ

  • -mbranch-cost=cost โ€” sets the branch costs for conditional branch instructions to cost. Sensible values 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, so the code size is smaller ๐Ÿงš
  • -mgas-isr-prologues โ€” interrupt service routines (ISRs) can use the __gcc_isr pseudo instruction that GNU Binutils supports. If this is on, you can still turn it off for individual ISRs with the no_gccisr function attribute (see AVR Function Attributes). This is turned on by default when optimization is on, but not with -Og (see Optimize Options), and when GNU Binutils supports PR21683 at https://sourceware.org/PR21683 ๐ŸŒˆ
  • -mint8 โ€” treats int as an 8-bit integer. This changes the size 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 bestie: this option does NOT conform to the C standards. It does give you smaller code size though, so it's a trade-off ๐Ÿ’€
  • -mmain-is-OS_task โ€” stops main from saving registers. It does the same thing as putting the OS_task attribute (see AVR Function Attributes) on main. This is turned on by default when optimization is on ๐Ÿ‘‘
  • -mn-flash=num โ€” assumes the flash memory is num times 64 KiB in size ๐ŸŒธ
  • -mno-interrupts โ€” the generated code doesn't play nicely with hardware interrupts
Careful, this one isn't compatible with hardware interrupts at all. The upside is smaller code size ๐Ÿ˜ญ
  • -mrelax โ€” tries to swap a CALL or JMP instruction for the shorter RCALL or RJMP instruction when it applies. Setting -mrelax just adds the --mlink-relax option to the assembler's command line and the --relax option to the linker's command line ๐Ÿฆ‹

Jump relaxing happens in the linker, since jump offsets aren't known until the code gets placed. So the assembler code the compiler makes stays the same, but the instructions in the executable might look different from what's in the assembler code ๐Ÿ™ˆ

Relaxing has to be on if linker stubs are needed. Check the section on "EIND" and linker stubs below for more ๐Ÿ’…

  • -mrmw โ€” assumes the device supports the Read-Modify-Write instructions XCH, LAC, LAS and LAT ๐Ÿ”ฅ
  • -mshort-calls โ€” assumes RJMP and RCALL can reach the whole program memory

This one is used internally for multilib selection. It's not an optimization option, so you don't need to set it by hand ๐Ÿ™…โ€โ™€๏ธ

  • -msp8 โ€” treats the stack pointer register as an 8-bit register, so the high byte of the stack pointer is assumed to be zero. Generally you don't need to set this by hand ๐Ÿงš

The compiler uses this internally to pick and build multilibs for the avr2 and avr25 architectures, which mix devices with and without SPH. For any setting other than -mmcu=avr2 or -mmcu=avr25, the compiler driver adds or removes this option from the compiler proper's command line, since the compiler already knows whether the device has an 8-bit stack pointer and no SPH register ๐Ÿ’œ

  • -mstrict-X โ€” uses the address register X the way the hardware intends. That means X is only used for indirect, post-increment or pre-decrement addressing ๐Ÿซถ

Without this option, X can be used just like Y or Z, but then it gets emulated with extra instructions. For example, loading a value with X+const addressing, where const is small and non-negative (const < 64), into a register Rn looks like this:

        adiw r26, const   ; X += const
        ld   <Rn>, X        ; <Rn> = *X
        sbiw r26, const   ; X -= const
  • -mtiny-stack โ€” only changes the lower 8 bits of the stack pointer โœจ
  • -mfract-convert-truncate โ€” lets fractional fixed-point types use truncation instead of rounding towards zero ๐ŸŒˆ
  • -nodevicelib โ€” don't link against AVR-LibC's device specific library lib<mcu>.a ๐Ÿ“
  • -nodevicespecs โ€” don't add -specs=device-specs/specs-<mcu> to the compiler driver's command line. You're on the hook for giving the subprocesses (compiler proper, assembler and linker) the right command line options yourself ๐Ÿ™ˆ
  • -Waddr-space-convert โ€” warns about conversions between address spaces when the resulting address space isn't contained in the incoming one โญ
  • -Wmisspelled-isr โ€” warns if an ISR is misspelled, meaning it's missing the __vector prefix. This one's enabled by default ๐Ÿ’–

โœจ "EIND" and Devices with More Than 128 Ki Bytes of Flash โœจ

Pointers in the implementation are 16 bits wide. The address of a function or label gets represented as a word address, so indirect jumps and calls can target any code address in the range of 64 Ki words ๐Ÿฆ‹

In order to facilitate indirect jump on devices with more than 128 Ki bytes of program memory space, there is a special function register called EIND ๐Ÿ’œ It's the most significant part of the target address when EICALL or EIJMP instructions are used, and it's giving very specific rules, so let's go โœจ

Indirect jumps and calls on these devices are handled like this by the compiler, and they come with some limitations. Read these, bestie, they matter ๐Ÿซถ

  • The compiler never sets EIND.
  • The compiler uses EIND implicitly in EICALL/EIJMP instructions or might read EIND directly in order to emulate an indirect call/jump by means of a RET instruction.
  • The compiler assumes that EIND never changes during the startup code or during the application. In particular, EIND is not saved/restored in function or interrupt service routine prologue/epilogue.
  • For indirect calls to functions and computed goto, the linker generates stubs ๐Ÿงš Stubs are jump pads, sometimes also called trampolines. So the indirect call/jump lands on such a stub, and the stub contains a direct jump to the desired address.
  • Linker relaxation must be turned on so that the linker generates the stubs correctly in all situations. See the compiler option -mrelax and the linker option --relax.
There are corner cases where the linker is supposed to generate stubs but aborts without relaxation and without a helpful error message. Yikes ๐Ÿ’€
  • The default linker script is arranged for code with EIND = 0. If code is supposed to work for a setup with EIND != 0, a custom linker script has to be used in order to place the sections whose name start with .trampolines into the segment where EIND points to.
  • The startup code from libgcc never sets EIND. Notice that startup code is a blend of code from libgcc and AVR-LibC. For the impact of AVR-LibC on EIND, see the AVR-LibC user manual (http://nongnu.org/avr-libc/user-manual/).
  • It is legitimate for user-specific startup code to set up EIND early, for example by means of initialization code located in section .init3. Such code runs prior to general startup code that initializes RAM and calls constructors, but after the bit of startup code from AVR-LibC that sets EIND to the segment where the vector table is located.
#include <avr/io.h>

static void
__attribute__((section(".init3"),naked,used,no_instrument_function))
init3_set_eind (void)
{
  __asm volatile ("ldi r24,pm_hh8(__trampolines_start)\n\t"
                  "out %i0,r24" :: "n" (&EIND) : "r24","memory");
}

The __trampolines_start symbol is defined in the linker script.

  • Stubs are generated automatically by the linker if the following two conditions are met:
    • The address of a label is taken by means of the gs modifier (short for generate stubs), like so:
LDI r24, lo8(gs(<func>))
LDI r25, hi8(gs(<func>))
  • The final location of that label is in a code segment outside the segment where the stubs are located.
  • The compiler emits such gs modifiers for code labels in the following situations:
    • Taking address of a function or code label.
    • Computed goto.
    • If prologue-save function is used, see -mcall-prologues command-line option.
    • Switch/case dispatch tables. If you do not want such dispatch tables you can specify the -fno-jump-tables command-line option.
    • C and C++ constructors/destructors called during startup/shutdown.
    • If the tools hit a gs() modifier explained above.
  • Jumping to non-symbolic addresses like so is not supported ๐Ÿ™ˆ
int main (void)
{
    /* Call function at word address 0x2 */
    return ((int(*)(void)) 0x2)();
}

Instead, a stub has to be set up, i.e. the function has to be called through a symbol (func_4 in the example):

int main (void)
{
    extern int func_4 (void);

    /* Call function at byte address 0x4 */
    return func_4();
}

and the application be linked with -Wl,--defsym,func_4=0x4. Alternatively, func_4 can be defined in the linker script.


โœจ Handling of the RAMPD, RAMPX, RAMPY and RAMPZ Special Function Registers ๐ŸŒธ

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 content of a RAMP register is used as the high part of the address. The X, Y, Z address register is concatenated with the RAMPX, RAMPY, RAMPZ special function register, respectively, to get a wide address. Similarly, RAMPD is used together with direct addressing ๐Ÿฆ‹

  • The startup code initializes the RAMP special function registers with zero.
  • If a AVR Named Address Spaces, named address space other than generic or __flash is used, then RAMPZ is set as needed before the operation.
  • If the device supports RAM larger than 64 KiB and the compiler needs to change RAMPZ to accomplish an operation, RAMPZ is reset to zero after the operation.
  • If the device comes with a specific RAMP register, the ISR prologue/epilogue saves/restores that SFR and initializes it with zero in case the ISR code might (implicitly) use it.
  • RAM larger than 64 KiB is not supported by GCC for AVR targets.
If you use inline assembler to read from locations outside the 16-bit address range and change one of the RAMP registers, you must reset it to zero after the access. Do not skip this, periodt ๐Ÿ˜ญ

โœจ AVR Built-in Macros ๐ŸŽ€

GCC defines several built-in macros so that the user code can test for the presence or absence of features. Almost any of the following built-in macros are deduced from device capabilities and thus triggered by the -mmcu= command-line option ๐Ÿ“

For even more AVR-specific built-in macros see AVR Named Address Spaces and AVR Built-in Functions.

  • __AVR_ARCH__ โ€” A built-in macro that resolves to a decimal number identifying the architecture. It depends on the -mmcu=mcu option. Possible values are:
    • 2, 25, 3, 31, 35, 4, 5, 51, 6 for mcu="avr2", "avr25", "avr3", "avr31", "avr35", "avr4", "avr5", "avr51", "avr6", respectively
    • 100, 102, 103, 104, 105, 106, 107 for mcu="avrtiny", "avrxmega2", "avrxmega3", "avrxmega4", "avrxmega5", "avrxmega6", "avrxmega7", respectively

If mcu specifies a device, this built-in macro is set accordingly. For example, with -mmcu=atmega8 the macro is defined to 4.

  • __AVR_Device__ โ€” Setting -mmcu=device defines this built-in macro, which reflects the device's name. For example, -mmcu=atmega8 defines the built-in macro __AVR_ATmega8__, -mmcu=attiny261a defines __AVR_ATtiny261A__, etc.

The built-in macros' names follow the scheme __AVR_Device__, where Device is the device name as from the AVR user manual. The difference between Device in the built-in macro and device in -mmcu=device is that the latter is always lowercase.

If device is not a device but only a core architecture like avr51, this macro is not defined.

  • __AVR_DEVICE_NAME__ โ€” Setting -mmcu=device defines this built-in macro to the device's name. For example, with -mmcu=atmega8 the macro is defined to "atmega8".

If device is not a device but only a core architecture like avr51, this macro is not defined.

  • __AVR_XMEGA__ โ€” The device / architecture belongs to the XMEGA family of devices.
  • __AVR_HAVE_ELPM__ โ€” The device has the ELPM instruction.
  • __AVR_HAVE_ELPMX__ โ€” The device has the ELPM Rn,Z and ELPM Rn,Z+ instructions.
  • __AVR_HAVE_MOVW__ โ€” The device has the MOVW instruction to perform 16-bit register-register moves.
  • __AVR_HAVE_LPMX__ โ€” The device has the LPM Rn,Z and LPM Rn,Z+ instructions.
  • __AVR_HAVE_MUL__ โ€” The device has a hardware multiplier.
  • __AVR_HAVE_JMP_CALL__ โ€” The device has the JMP and CALL instructions. This is the case for devices with more than 8 KiB of program memory.
  • __AVR_HAVE_EIJMP_EICALL__ and __AVR_3_BYTE_PC__ โ€” The device has the EIJMP and EICALL instructions. This is the case for devices with more than 128 KiB of program memory. This also means that the program counter (PC) is 3 bytes wide. ๐Ÿ’–
  • __AVR_2_BYTE_PC__ โ€” The program counter (PC) is 2 bytes wide. This is the case for devices with up to 128 KiB of program memory.
  • __AVR_HAVE_8BIT_SP__ and __AVR_HAVE_16BIT_SP__ โ€” The stack pointer (SP) register is treated as an 8-bit or 16-bit register by the compiler, respectively. The definition of these macros is affected by -mtiny-stack.
  • __AVR_HAVE_SPH__ and __AVR_SP8__ โ€” The device has the SPH (high part of stack pointer) special function register, or has an 8-bit stack pointer, respectively. The definition of these macros is affected by -mmcu= and, in the cases of -mmcu=avr2 and -mmcu=avr25, also by -msp8.
  • __AVR_HAVE_RAMPD__, __AVR_HAVE_RAMPX__, __AVR_HAVE_RAMPY__ and __AVR_HAVE_RAMPZ__ โ€” The device has the RAMPD, RAMPX, RAMPY, RAMPZ special function register, respectively.
  • __NO_INTERRUPTS__ โ€” This macro reflects the -mno-interrupts command-line option.
  • __AVR_ERRATA_SKIP__ and __AVR_ERRATA_SKIP_JMP_CALL__ โ€” Some AVR devices (AT90S8515, ATmega103) must not skip 32-bit instructions because of a hardware erratum. Skip instructions are SBRS, SBRC, SBIS, SBIC and CPSE. The second macro is only defined if __AVR_HAVE_JMP_CALL__ is also set. ๐Ÿ™ˆ
  • __AVR_ISA_RMW__ โ€” The device has Read-Modify-Write instructions (XCH, LAC, LAS and LAT). ๐Ÿ‘‘
  • __AVR_SFR_OFFSET__=offset โ€” Instructions that can address I/O special function registers directly, like IN, OUT, SBI, etc., may use a different address than an instruction accessing RAM, like LD or STS. This offset depends on the device architecture and has to be subtracted from the RAM address in order to get the respective I/O address.
  • __AVR_SHORT_CALLS__ โ€” The -mshort-calls command line option is set. ๐ŸŒˆ

"__AVR_PM_BASE_ADDRESS__=addr"

Okay so some AVR devices can read from flash memory with LD* instructions ๐Ÿงš The flash shows up in the data address space at an offset of __AVR_PM_BASE_ADDRESS__. If this macro isn't defined, the feature just isn't available ๐Ÿ’€ If it is defined, the address space is linear and you don't need to shove .rodata into RAM. The default linker description file handles that, and it's currently available for avrtiny and avrxmega3 โœจ It's even more convenient bc you don't need address spaces like __flash or stuff like the progmem attribute and pgm_read_* ๐Ÿ’…

"__WITH_AVRLIBC__"

This one's giving "the compiler was set up to play nicely with AVR-Libc" ๐ŸŽ€ Check the --with-avrlibc configure option if you want the details ๐Ÿซถ


โœจ Blackfin Options โœจ

  • -mcpu=cpu[-sirevision] โ€” This is how you name your target Blackfin processor ๐Ÿ’œ The cpu can be any of these, and I'm not kidding, it's a whole list: 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 tells GCC which silicon revision you're on, and any workarounds for that revision get turned on ๐Ÿ”ฅ If you write none, no workarounds are enabled. If you write any, every workaround for that processor is enabled. The __SILICON_REVISION__ macro gets defined as two hex digits, one for the major number and one for the minor number, of the silicon revision. With none, __SILICON_REVISION__ isn't defined at all. With any, it's defined as 0xffff. If you skip the optional sirevision completely, GCC assumes the latest silicon revision it knows about for your processor ๐ŸŒˆ GCC also defines a preprocessor macro for whatever cpu you picked. On the bfin-elf toolchain, this option makes the hardware BSP from libgloss get linked in, as long as you didn't also pass -msim โœจ Without this option, bf532 is the default processor ๐Ÿ“
Note that support for bf561 is incomplete. For bf561, only the preprocessor macro gets defined, so don't expect the rest to be there ๐Ÿ’€
  • -msim โ€” Tells the compiler your program is running on the simulator, so the simulator BSP from libgloss gets linked in ๐Ÿงš This only does something on the bfin-elf toolchain. Some other options, like -mid-shared-library and -mfdpic, imply -msim on their own ๐Ÿ‘‘
  • -momit-leaf-frame-pointer โ€” Don't keep the frame pointer in a register for leaf functions ๐Ÿฆ‹ That skips the instructions that save, set up, and restore frame pointers, and it frees up an extra register in leaf functions ๐Ÿ”ฅ
  • -mspecld-anomaly โ€” When this is on, the compiler makes sure the generated code doesn't have speculative loads right after jump instructions ๐Ÿ™ˆ If you use this option, __WORKAROUND_SPECULATIVE_LOADS gets defined ๐Ÿ’œ
  • -mno-specld-anomaly โ€” Don't generate the extra code that stops speculative loads from happening ๐Ÿซถ
  • -mcsync-anomaly โ€” When this is on, the compiler makes sure the generated code doesn't have CSYNC or SSYNC instructions too soon after conditional branches ๐ŸŒธ If you use this option, __WORKAROUND_SPECULATIVE_SYNCS gets defined โœจ
  • -mno-csync-anomaly โ€” Don't generate the extra code that keeps CSYNC or SSYNC instructions from popping up too soon after a conditional branch ๐Ÿ’…
  • -mlow64k โ€” The compiler is allowed to take advantage of the fact that the whole program fits in the low 64k of memory ๐ŸŽ€
  • -mno-low64k โ€” Assume the program is arbitrarily large. This is the default ๐ŸŒˆ
  • -mstack-check-l1 โ€” Does stack checking using information the uClinux kernel puts into L1 scratchpad memory ๐Ÿงš
  • -mid-shared-library โ€” Generates code that supports shared libraries through the library ID method โœจ This lets you do execute in place and shared libraries in an environment with no virtual memory management ๐Ÿฆ‹ This option implies -fPIC, and with a bfin-elf target it also implies -msim ๐Ÿ’–
  • -mno-id-shared-library โ€” Generates code that doesn't assume ID-based shared libraries are being used. This is the default ๐ŸŒธ
  • -mleaf-id-shared-library โ€” Generates code that supports shared libraries through the library ID method, but assumes this library or executable won't link against any other ID shared libraries. That lets the compiler use faster code for jumps and calls ๐Ÿ”ฅ
  • -mno-leaf-id-shared-library โ€” Don't assume the code you're compiling won't link against any ID shared libraries. This makes slower code for jump and call instructions ๐Ÿ™ˆ
  • -mshared-library-id=n โ€” Sets the identification number of the ID-based shared library you're compiling ๐Ÿซถ A value of 0 makes more compact code. Other values force that number onto the current library, but that's no more space- or time-efficient than just leaving this option out ๐Ÿ’œ
  • -msep-data โ€” Generates code that lets the data segment live in a different area of memory from the text segment ๐Ÿ‘‘ This allows execute in place in an environment without virtual memory management, because it gets rid of relocations against the text section ๐Ÿงš
  • -mno-sep-data โ€” Generates code that assumes the data segment follows the text segment. This is the default ๐Ÿ“
  • -mlong-calls, -mno-long-calls โ€” -mlong-calls tells the compiler to call functions by first loading the function's address into a register, then doing a subroutine call on that register ๐Ÿฆ‹ You need this switch if the target function is outside the 24-bit addressing range of the offset-based subroutine call instruction ๐Ÿ’€ This feature isn't enabled by default, and -mno-long-calls puts the default behavior back ๐ŸŒˆ These switches don't change how the compiler handles function calls through function pointers, so keep that in mind ๐Ÿ‘€
  • -mfast-fp โ€” Links with the fast floating-point library โšก It relaxes some of the IEEE floating-point standard's rules for checking inputs against Not-a-Number (NAN), in the name of performance ๐Ÿ”ฅ
  • -minline-plt โ€” Enables inlining of PLT entries in function calls to functions that aren't known to bind locally โœจ It does nothing without -mfdpic ๐Ÿ’…
  • -mmulticore โ€” Builds a standalone application for multicore Blackfin processors ๐Ÿ’– This option makes sure the proper start files and link scripts for multicore get used, and it defines the macro __BFIN_MULTICORE. It can only be used with -mcpu=bf561[-sirevision] ๐ŸŽ€

This option can be paired with -mcorea or -mcoreb, which pick the one-application-per-core programming model ๐Ÿซถ Without either of those, the single-application/dual-core model gets used, and in that model the main function of Core B should be named coreb_main ๐Ÿงš

If you don't use this option, you get the single-core application programming model ๐ŸŒธ

  • -mcorea โ€” Builds a standalone application for Core A of BF561 when you're using the one-application-per-core model ๐Ÿ‘‘ The proper start files and link scripts for Core A get used, and the macro __BFIN_COREA gets defined. This option can only be used together with -mmulticore ๐Ÿ’œ
  • -mcoreb โ€” Builds a standalone application for Core B of BF561 when you're using the one-application-per-core model ๐Ÿฆ‹ The proper start files and link scripts for Core B get used, and the macro __BFIN_COREB gets defined. When you use this option, coreb_main should be used instead of main ๐Ÿ™ˆ It can only be used together with -mmulticore ๐Ÿ”ฅ
  • -msdram โ€” Builds a standalone application for SDRAM ๐ŸŒˆ Proper start files and link scripts put the application into SDRAM, and the macro __BFIN_SDRAM gets defined. Your loader needs to initialize SDRAM before it loads the application ๐Ÿ’…
  • -micplb โ€” Assumes ICPLBs are enabled at run time. This affects certain anomaly workarounds ๐Ÿงš For Linux targets, the default is to assume ICPLBs are enabled. For standalone applications, the default is off โœจ

โœจ C6X Options โœจ

  • -march=name โ€” Specifies the name of the target architecture ๐ŸŽ€ GCC uses this name to figure out what kinds of instructions it can emit when generating assembly code ๐Ÿ’– The permissible names are: c62x, c64x, c64x+, c67x, c67x+, c674x ๐Ÿ‘‘
  • -mbig-endian โ€” Generates code for a big-endian target ๐ŸŒธ
  • -mlittle-endian โ€” Generates code for a little-endian target. This is the default ๐Ÿ’œ
  • -msim โ€” Chooses startup files and a linker script that 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 large pieces of data are .fardata, .far, and .const ๐ŸŒˆ
  • -msdata=all โ€” Puts all data, not just small objects, into the sections reserved for small data, and uses addressing relative to the B14 register to get to them โœจ
  • -msdata=none โ€” Makes no use of the sections reserved for small data, and uses absolute addresses to access all data ๐Ÿ’… All initialized global and static data goes in the .fardata section, and all uninitialized data goes in the .far section ๐Ÿ”ฅ All constant data goes in the .const section ๐Ÿ‘‘

โœจ CRIS Options โœจ

These options are defined specifically for the CRIS ports ๐Ÿฆ‹

  • -march=architecture-type, -mcpu=architecture-type โ€” Generates code for the architecture you specify ๐Ÿ’– The choices for architecture-type are v3, v8, and v10, which are 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 architecture-type, except for the ABI and the set of available instructions ๐ŸŒธ The choices for architecture-type are the same as for -march=architecture-type ๐Ÿ’œ
  • -mmax-stack-frame=n โ€” Warns when the stack frame of a function goes over n bytes ๐Ÿ™ˆ โš ๏ธ
  • -metrax4, -metrax100 โ€” -metrax4 and -metrax100 are synonyms for -march=v3 and -march=v8 respectively ๐Ÿซถ
  • -mmul-bug-workaround, -mno-mul-bug-workaround โ€” okay so these patch up a bug in the muls and mulu instructions on the CPU models where it actually shows up ๐Ÿ”ง. It's on by default, so you literally don't have to lift a finger โœจ
  • -mpdebug โ€” turns on CRIS-specific verbose debug info in the assembly code ๐Ÿ›. It also switches off the #NO_APP formatted-code indicator at the very top of the assembly file ๐Ÿ™ˆ
  • -mcc-init โ€” don't reuse condition-code results from earlier instructions. Always throw in compare and test instructions before you touch the condition codes ๐Ÿ’…
  • -mno-side-effects โ€” no instructions with side effects in addressing modes, except post-increment ๐Ÿฆ‹
  • -mstack-align, -mno-stack-align, -mdata-align, -mno-data-align, -mconst-align, -mno-const-align โ€” these make the stack frame, individual data, and constants line up to the biggest single data access size for your chosen CPU model ๐ŸŽ€ The no- versions undo that alignment. The default is 32-bit alignment, and ABI stuff like structure layout is not affected by any of these ๐Ÿซถ
  • -m32-bit, -m16-bit, -m8-bit โ€” same vibe as the stack, data, and const align options, but these make the stack frame, writable data, and constants 32-bit, 16-bit, or 8-bit aligned. 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 skipped, and no return instructions or return sequences get generated ๐Ÿ˜ญ Only do this if you're checking the compiled code by eye. No warnings or errors show up when call-saved registers need saving or local variable storage needs allocating ๐Ÿ’€
  • -mno-gotplt, -mgotplt โ€” with -fpic and -fPIC, -mno-gotplt skips the instruction sequences that load function addresses from the PLT part of the GOT. -mgotplt (the default) does generate them, instead of making traditional calls to the PLT like other architectures do ๐Ÿงš
  • -melf โ€” a legacy no-op. It's only recognized with the cris-axis-elf and cris-axis-linux-gnu targets ๐Ÿฆ•
  • -mlinux โ€” another 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 consecutively ๐Ÿ’œ
  • -sim2 โ€” basically -sim, but it also passes linker options so initialized data lands at 0x40000000 and zero-initialized data lands at 0x80000000 ๐Ÿ‘‘

โœจ CR16 Options โœจ

These are defined specifically for the CR16 ports, so they're the CR16 crew's vibe ๐ŸŒˆ

  • -mmac โ€” enables the multiply-accumulate instructions. Off by default. ๐Ÿ”ฅ
  • -mcr16cplus, -mcr16c โ€” generates code for the CR16C or CR16C+ architecture. CR16C+ is the default. โญ
  • -msim โ€” links the library libsim.a, which is compatible with the simulator. 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: far is not valid with -mcr16c, because the CR16C architecture doesn't support the far data model ๐Ÿ™ˆ

โœจ C-SKY Options โœจ

GCC supports these options when compiling for C-SKY V2 processors ๐Ÿซถ

  • -march=arch โ€” specifies the C-SKY target architecture. Valid values for arch are ck801, ck802, ck803, ck807, and ck810. The default is ck810. ๐Ÿ“
  • -mcpu=cpu โ€” specifies the C-SKY target processor. Valid values for cpu are ck801, ck801t, ck802, ck802t, ck802j, ck803, ck803h, ck803t, ck803ht, ck803f, ck803fh, ck803e, ck803eh, ck803et, ck803eht, ck803ef, ck803efh, ck803ft, ck803eft, ck803efht, ck803r1, ck803hr1, ck803tr1, ck803htr1, ck803fr1, ck803fhr1, ck803er1, ck803ehr1, ck803etr1, ck803ehtr1, ck803efr1, ck803efhr1, ck803ftr1, ck803eftr1, ck803efhtr1, ck803s, ck803st, ck803se, ck803sf, ck803sef, ck803seft, ck807e, ck807ef, ck807, ck807f, ck810e, ck810et, ck810ef, ck810eft, ck810, ck810v, ck810f, ck810t, ck810fv, ck810tv, ck810ft, and ck810ftv. The whole list is a lot, bestie, but it's all there ๐Ÿ’–
  • -mbig-endian, -EB, -mlittle-endian, -EL โ€” picks big-endian or little-endian code. Little-endian is the default. ๐ŸŒˆ
  • -mhard-float, -msoft-float โ€” picks hardware or software floating-point. Soft float is the default. ๐Ÿ”ง
  • -mdouble-float, -mno-double-float โ€” when -mhard-float is in effect, -mdouble-float enables double-precision float instructions. This is the default except when compiling for CK803 โœจ
  • -mfdivdu, -mno-fdivdu โ€” when -mhard-float is in effect, -mfdivdu enables frecipd, fsqrtd, and fdivd instructions. Also the default except when compiling for CK803 ๐Ÿ’…
  • -mfpu=fpu โ€” selects the floating-point processor. This only works with -mhard-float. The values for fpu are fpv2_sf (equivalent to -mno-double-float -mno-fdivdu), fpv2 (-mdouble-float -mno-divdu), and fpv2_divd (-mdouble-float -mdivdu) ๐Ÿฆ‹
  • -melrw, -mno-elrw โ€” enables the extended lrw instruction. Defaults to on for CK801 and off otherwise. ๐ŸŽ€
  • -mistack, -mno-istack โ€” enables interrupt stack instructions. The default is off. ๐Ÿซถ
The -mistack option is required to handle the interrupt and isr function attributes. Don't skip it, bestie ๐Ÿšจ
  • -mmp โ€” enables multiprocessor instructions. Default is off. ๐ŸŒธ
  • -mcp โ€” enables coprocessor instructions. Default is off. ๐Ÿงš
  • -mcache โ€” enables coprocessor instructions. Default is off. ๐Ÿ’œ
  • -msecurity โ€” enables C-SKY security instructions. Default is off. ๐Ÿ”
  • -mtrust โ€” enables C-SKY trust instructions. Default is off. ๐ŸŒŸ
  • -mdsp, -medsp, -mvdsp โ€” enables C-SKY DSP, Enhanced DSP, or Vector DSP instructions, respectively. All of these default to off. ๐ŸŽถ
  • -mdiv, -mno-div โ€” generates divide instructions. Default is off. โž—
  • -msmart, -mno-smart โ€” generates code for Smart Mode, which only uses registers numbered 0-7 so you can use 16-bit instructions. This is ignored for CK801, where this is the required behavior, and it defaults to on for CK802. For other targets, the default is off. ๐Ÿ“
  • -mhigh-registers, -mno-high-registers โ€” generates code that uses the high registers numbered 16-31. This isn't supported on CK801, CK802, or CK803, and it's enabled by default for other processors ๐Ÿ‘‘
  • -manchor, -mno-anchor โ€” generates code using global anchor symbol addresses โš“
  • -mpushpop, -mno-pushpop โ€” generates code using push and pop instructions. This option defaults to on. ๐Ÿงš
  • -mmultiple-stld, -mstm, -mno-multiple-stld, -mno-stm โ€” generates code using stm and ldm instructions. This isn't supported on CK801, but it's enabled by default on other processors ๐ŸŒˆ
  • -mconstpool, -mno-constpool โ€” creates constant pools in the compiler instead of handing that job off to the assembler. This is the default and is required for correct code generation on CK801 and CK802. It's optional on other processors ๐Ÿซถ
  • -mstack-size, -mno-stack-size โ€” emits .stack_size directives for each function in the assembly output. This option defaults to off. ๐Ÿ“
  • -mccrt, -mno-ccrt โ€” generates code for the C-SKY compiler runtime instead of libgcc. This option defaults to off. ๐Ÿ”ง
  • -mbranch-cost=n โ€” sets the branch costs to roughly n instructions. The default is 1. ๐Ÿ“
  • -msched-prolog, -mno-sched-prolog โ€” permits scheduling of function prologue and epilogue sequences. Here's the drama: using this can result in code that isn't compliant with the C-SKY V2 ABI prologue requirements, and that code can't be debugged or backtraced ๐Ÿ˜ฑ It's disabled by default.

โœจ Darwin Options โœจ

These options are defined for all architectures running the Darwin operating system ๐ŸŽ

FSF GCC on Darwin doesn't make "fat" object files. It makes an object file for the single architecture GCC was built to target ๐ŸŽฏ Apple's GCC on Darwin does make "fat" files if you use multiple -arch options. It does that by running the compiler or linker multiple times and then joining the results together with lipo ๐Ÿงฉ

The subtype of the file (like ppc7400, 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 is your friend ๐Ÿ’–

The Darwin tools act differently when they hit an ISA mismatch. The assembler, as, only lets you use instructions that are valid for the subtype of the file it's generating. So you can't put 64-bit instructions in a ppc750 object file ๐Ÿ™… The linker for shared libraries, /usr/bin/libtool, fails and prints an error if you ask it to make a shared library with a less restrictive subtype than its input files. For example, trying to put a ppc970 object file in a ppc7400 library is a no-go ๐Ÿ’€ The linker for executables, ld, quietly gives the executable the most restrictive subtype of any of its input files ๐Ÿคซ

  • -Fdir โ€” adds the framework directory dir to the head of the list of directories searched for header files. These directories are interleaved with the ones from -I options, and they're scanned in a left-to-right order ๐Ÿฆ‹

Okay bestie, so a framework directory is just a directory that's full of frameworks ๐Ÿ“โœจ A framework is a directory with a Headers and/or PrivateHeaders directory sitting directly inside it, and its name has to end in .framework. The framework's name is the directory name minus 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 are only allowed 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 should not share a name with a framework, and if it does, GCC issues a warning. Right now subframeworks can't have subframeworks of their own, but that could change later ๐ŸŒธ

The standard frameworks are 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 โ€” This is 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 stuff inside header files found through that directory. This option only works for the C family of languages.
  • -gused โ€” Emits debugging info for symbols that are used ๐Ÿ” For stabs debugging format, this turns on -feliminate-unused-debug-symbols. It's ON by default, so you basically get it for free โœจ
  • -gfull โ€” Emits debugging info for all symbols and types, no exceptions ๐Ÿ’œ
  • -mmacosx-version-min=version โ€” This sets the earliest version of macOS X your executable will run on ๐ŸŽ Typical values are 10.1, 10.2, and 10.3.9.

If the compiler was built to use the system's headers by default, the default for this option is whatever system version the compiler is running on. Otherwise, it makes choices that play nicest with as many systems and codebases as possible ๐Ÿซถ

  • -mkernel โ€” Turns on kernel development mode ๐Ÿ”ฅ This sets -static, -fno-common, -fno-use-cxa-atexit, -fno-exceptions, -fno-non-call-exceptions, -fapple-kext, -fno-weak and -fno-rtti where applicable. It also sets -mno-altivec, -msoft-float, -fno-builtin and -mlong-branch for PowerPC targets ๐Ÿ‘‘
  • -mone-byte-bool โ€” Overrides the defaults for "bool" so that "sizeof(bool)==1" ๐Ÿ™ˆ By default, "sizeof(bool)" is 4 when compiling for Darwin/PowerPC and 1 when compiling for Darwin/x86, so this option does nothing on x86.
Warning: The -mone-byte-bool switch makes GCC generate code that is NOT binary compatible with code generated without it ๐Ÿ˜ญ You may have to recompile all the other modules in your program, including system libraries. Only use this switch when you need to match a non-default data model.
  • -mfix-and-continue, -ffix-and-continue, -findirect-data โ€” These generate code built for fast turnaround development, like letting GDB dynamically load .o files into programs that are already running ๐Ÿฆ‹ -findirect-data and -ffix-and-continue are only here for backwards compatibility.
  • -all_load โ€” Loads all members of static archive libraries ๐Ÿ“š See man ld(1) for more info.
  • -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 info.
  • -bundle_loader executable โ€” Specifies the executable that will load the build output file being linked ๐ŸŽ€ See man ld(1) for more info.
  • -dynamiclib โ€” When you pass this, GCC produces a dynamic library instead of an executable when linking, using the Darwin libtool command ๐Ÿ’–
  • -force_cpusubtype_ALL โ€” Gives GCC's output file the ALL subtype, instead of one controlled by -mcpu or -march ๐ŸŒˆ

These options are passed to the Darwin linker, and the Darwin linker man page describes every single one in detail ๐Ÿ“– Here's the whole squad:

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

๐Ÿ’œ DEC Alpha Options ๐Ÿ’œ

These -m options are defined for the DEC Alpha implementations ๐Ÿฆ‹

  • -mno-soft-float, -msoft-float โ€” Use (or don't use) the hardware floating-point instructions for floating-point operations ๐Ÿ”ง With -msoft-float, functions in libgcc.a do the floating-point work instead. Unless they've been replaced by routines that emulate those operations, or compiled to call such emulation routines, these routines issue floating-point operations. If you're compiling for an Alpha without floating-point operations, you have to make sure the library is built so it doesn't call them ๐Ÿ˜ญ

Note that Alpha implementations without floating-point operations are still required to have floating-point registers ๐Ÿค“

  • -mfp-reg, -mno-fp-regs โ€” Generates code that uses (or doesn't use) the floating-point register set โœจ -mno-fp-regs implies -msoft-float. If the register set isn't used, floating-point operands get passed in integer registers as if they were integers, and floating-point results are passed in $0 instead of $f0. This is a non-standard calling sequence, so any function with a floating-point argument or return value that's called by code compiled with -mno-fp-regs must also be compiled with that option ๐Ÿ™ˆ

A typical use 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 optimized for maximum performance, and it's mostly IEEE compliant, but full compliance needs some software help ๐Ÿซถ This option generates code that's fully IEEE-compliant, except the inexact-flag isn't maintained (more on that below). When it's on, the preprocessor macro "_IEEE_FP" is defined during compilation. The resulting code is less efficient, but it can correctly support denormalized numbers and exceptional IEEE values like not-a-number and plus/minus infinity. Other Alpha compilers call this option -ieee_with_no_inexact.

DEBIAN SPECIFIC: This option is on by default for alpha-linux-gnu, unless -ffinite-math-only (which is part of the -ffast-math set) is specified ๐ŸŒธ The reason: the software functions in the GNU libc math libraries generate denormalized numbers, NaNs, and infs, and all of those will cause a program to SIGFPE when it tries to use the results without -mieee.

  • -mieee-with-inexact โ€” This is like -mieee, except the generated code also maintains the IEEE inexact-flag ๐Ÿ’– Turning it on makes the generated code fully-compliant IEEE math. In addition to "_IEEE_FP", the preprocessor macro "_IEEE_FP_EXACT" is defined. On some Alpha implementations, the code may run significantly slower than the default code. Since very little code depends on the inexact-flag, you should normally not specify this option ๐Ÿ™…โ€โ™€๏ธ Other Alpha compilers call this option -ieee_with_inexact.
  • -mfp-trap-mode=trap-mode โ€” Controls which floating-point related traps are enabled ๐Ÿ”ฅ Other Alpha compilers call this option -fptm trap-mode. The trap mode can be set to one of four values:
    • n โ€” This is the default (normal) setting. The only traps enabled are the ones that can't be disabled in software (for example, the division by zero trap) ๐Ÿงฎ
    • u โ€” On top of the traps enabled by n, underflow traps are enabled as well ๐ŸŒŠ
    • su โ€” Like u, but the instructions are marked as safe for software completion (see 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 โ€” Rounds 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 rounding towards plus infinity โฌ†๏ธ
  • -mtrap-precision=trap-precision โ€” okay so on the Alpha, floating-point traps are imprecise ๐Ÿ˜ญ That means without software help you basically can't recover from a float trap, and the program normally has to be terminated ๐Ÿ’€ GCC can generate code that helps OS trap handlers figure out the exact spot that caused a floating-point trap โœจ Pick your precision based on what your app needs:
    • p โ€” Program precision ๐ŸŒธ This is the default. The trap handler can only tell which program caused the floating-point exception.
    • f โ€” Function precision ๐ŸŽ€ The trap handler can find the function that caused the floating-point exception.
    • i โ€” Instruction precision ๐Ÿ‘‘ The trap handler can pinpoint the exact instruction that caused the floating-point exception.

Other Alpha compilers have the same idea under the names -scope_safe and -resumption_safe ๐Ÿซถ

  • -mieee-conformant โ€” this marks the generated code as IEEE conformant ๐Ÿฆ‹ Its only effect is to emit the line .eflag 48 in the function prologue of the generated assembly file.
Careful, bestie โš ๏ธ You must not use this unless you also specify -mtrap-precision=i and either -mfp-trap-mode=su or -mfp-trap-mode=sui. Don't skip the pairing or it's giving chaos ๐Ÿ’€
  • -mbuild-constants โ€” normally GCC looks at a 32- or 64-bit integer constant and checks if it can build it from smaller constants in two or three instructions ๐Ÿงš If it can't, it outputs the constant as a literal and generates code to load it from the data segment at run time.

Use this option to make GCC build all integer constants with code, even if that takes more instructions (the maximum is six) ๐Ÿ’…

You typically use this when building a shared library dynamic loader ๐ŸŒˆ It's a shared library itself, so it has to relocate itself in memory before it can find the variables and constants in its own data segment. Lowkey wild, iykyk ๐Ÿ˜ญ

  • -mbwx, -mno-bwx, -mcix, -mno-cix, -mfix, -mno-fix, -mmax, -mno-max โ€” these decide whether GCC generates code using the optional BWX, CIX, FIX and MAX instruction sets โœจ By default it uses whatever instruction sets the CPU type from -mcpu= supports, or the CPU GCC was built on if you don't specify one ๐ŸŒธ
  • -mfloat-vax, -mfloat-ieee โ€” -mfloat-vax generates code that uses VAX F and G floating-point arithmetic, and -mfloat-ieee generates code that does not use it, so you get IEEE single and double precision instead ๐ŸŽ€
  • -mexplicit-relocs, -mno-explicit-relocs โ€” okay this one is a little nerdy ๐Ÿค“ Older Alpha assemblers had no way to make symbol relocations except through assembler macros, and those macros don't allow optimal instruction scheduling ๐Ÿ˜ค GNU binutils as of version 2.12 has a new syntax that lets the compiler explicitly mark which relocations apply to which instructions ๐Ÿ’œ This option is mostly useful for debugging, since GCC detects the assembler's capabilities when it's built and sets the default to match โœจ
  • -msmall-data, -mlarge-data โ€” when -mexplicit-relocs is in effect, static data is accessed through gp-relative relocations ๐Ÿงš With -msmall-data, objects 8 bytes long or smaller go into a small data area (the .sdata and .sbss sections) and get accessed through 16-bit relocations off the $gp register. This caps the small data area at 64KB, but the variables can be accessed with a single instruction, which is so efficient ๐Ÿ”ฅ

The default is -mlarge-data ๐Ÿ‘‘ With this option, the data area is limited to just below 2GB. Programs that need more than 2GB of data must use malloc or mmap to allocate that data on the heap instead of in the program's data segment ๐Ÿซถ

When generating code for shared libraries, -fpic implies -msmall-data, and -fPIC implies -mlarge-data ๐Ÿฆ‹

  • -msmall-text, -mlarge-text โ€” with -msmall-text, the compiler assumes the code for the whole program (or shared library) fits in 4MB, so it's reachable with a branch instruction ๐ŸŒˆ When -msmall-data is also used, the compiler can assume all local symbols share the same $gp value, which cuts the instructions needed for a function call from 4 down to 1 ๐Ÿคฏ The default is -mlarge-text ๐Ÿ’…
  • -mcpu=cpu_type โ€” sets the instruction set and instruction scheduling parameters for the machine type cpu_type โœจ You can use either the EV style name or the matching chip number. GCC has scheduling parameters for the EV4, EV5 and EV6 families, and it picks the default instruction set values from the processor you name ๐ŸŽ€ If you don't specify a processor, GCC defaults to the processor the compiler was built on.

Supported values for cpu_type are:

  • ev4, ev45, 21064 โ€” schedules as an EV4 and has no instruction set extensions.
  • ev5, 21164 โ€” schedules as an EV5 and has no instruction set extensions.
  • ev56, 21164a โ€” schedules as an EV5 and supports the BWX extension.
  • pca56, 21164pc, 21164PC โ€” schedules as an EV5 and supports the BWX and MAX extensions.
  • ev6, 21264 โ€” schedules as an EV6 and supports the BWX, FIX, and MAX extensions.
  • ev67, 21264a โ€” schedules as an EV6 and supports the BWX, CIX, FIX, and MAX extensions.

Native toolchains also support the value native, which picks the best architecture option for the host processor ๐Ÿ’– -mcpu=native has no effect if GCC doesn't recognise the processor ๐Ÿ™ˆ

  • -mtune=cpu_type โ€” sets only the instruction scheduling parameters for cpu_type. The instruction set doesn't change, so no vibe shift there ๐Ÿ’œ

Native toolchains also support native, which selects the best architecture option for the host processor โœจ -mtune=native has no effect if GCC doesn't recognise the processor.

  • -mmemory-latency=time โ€” sets the latency the scheduler should assume for typical memory references as seen by the application ๐Ÿง  This number depends a LOT on the application's memory access patterns and the size of the external cache on the machine ๐Ÿ˜ญ

Valid options for time are:

  • number โ€” a decimal number representing clock cycles.
  • L1, L2, L3, main โ€” the compiler has estimates of clock cycles for "typical" EV4 & EV5 hardware for the Level 1, 2 & 3 caches (also called Dcache, Scache, and Bcache), plus main memory. Note that L3 is only valid for EV5 ๐ŸŒธ

๐Ÿงš 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 all symbolic values and addresses fit into a 20-bit range.
  • -mno-lsim โ€” assumes runtime support has already been provided, so there's no need to include the simulator library (libsim.a) on the linker command line ๐Ÿ’…

๐ŸŒˆ FT32 Options ๐ŸŒˆ

These options are defined specifically for the FT32 port ๐Ÿ’–

  • -msim โ€” specifies that the program will be run on the simulator ๐Ÿ–ฅ๏ธ This links in an alternate runtime startup and library.
Danger zone ๐Ÿšจ You must not use this option when generating programs for real hardware. You have to provide your own runtime library for whatever I/O functions you need.
  • -mlra โ€” enables Local Register Allocation ๐Ÿ”ฌ It's still experimental for FT32, so by default the compiler uses standard reload.
  • -mnodiv โ€” don't use div and mod instructions ๐Ÿ™…โ€โ™€๏ธ
  • -mft32b โ€” enables the extended instructions of the FT32B processor โœจ
  • -mcompress โ€” compresses all code using the Ft32B code compression scheme ๐Ÿ—œ๏ธ
  • -mnopm โ€” don't generate code that reads program memory ๐Ÿซถ

๐ŸŽ€ FRV Options ๐ŸŽ€

  • -mgpr-32 โ€” only use the first 32 general-purpose registers ๐ŸŒธ
  • -mgpr-64 โ€” use all 64 general-purpose registers ๐Ÿ‘‘
  • -mfpr-32 โ€” use only the first 32 floating-point registers ๐Ÿ“
  • -mfpr-64 โ€” use all 64 floating-point registers ๐Ÿ’œ
  • -mhard-float โ€” use hardware instructions for floating-point operations โšก
  • -msoft-float โ€” use library routines for floating-point operations ๐Ÿ“š
  • -malloc-cc โ€” dynamically allocate condition code registers ๐Ÿง 
  • -mfixed-cc โ€” don't try to dynamically allocate condition code registers; only use icc0 and fcc0 ๐Ÿ”’
  • -mdword โ€” changes the ABI to use double word instructions ๐Ÿ’ซ
  • -mno-dword โ€” don't use double word instructions ๐Ÿ™…โ€โ™€๏ธ
  • -mdouble โ€” use floating-point double instructions ๐Ÿฆ‹
  • -mno-double โ€” don't use floating-point double instructions ๐Ÿ™ˆ
  • -mmedia โ€” use media instructions ๐ŸŽถ
  • -mno-media โ€” don't use media instructions ๐Ÿซฅ
  • -mmuladd โ€” use multiply and add/subtract instructions โœ–๏ธ
  • -mno-muladd โ€” don't use multiply and add/subtract instructions ๐Ÿ’€
  • -mfdpic โ€” selects the FDPIC ABI, which uses function descriptors to represent pointers to functions ๐Ÿงฉ Without any PIC/PIE-related options, it implies -fPIE. With -fpic or -fpie, it assumes GOT entries and small data are within a 12-bit range from the GOT base address. With -fPIC or -fPIE, GOT offsets are computed with 32 bits ๐ŸŒˆ With a bfin-elf target, this option implies -msim.
  • -minline-plt โ€” enables inlining of PLT entries in function calls to functions that aren't known to bind locally โœจ It has no effect without -mfdpic. It's enabled by default if you're optimizing for speed and compiling for shared libraries (i.e., -fPIC or -fpic), or when an optimization option such as -O3 or above is on the command line ๐Ÿš€
  • -mTLS โ€” assumes a large TLS segment when generating thread-local code ๐Ÿงต
  • -mtls โ€” does not assume a large TLS segment when generating thread-local code ๐Ÿชก
  • -mgprel-ro โ€” enables the use of GPREL relocations in the FDPIC ABI for data known to be in read-only sections ๐Ÿ“– It's enabled by default, except for -fpic or -fpie: even though it may 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 needing a GOT entry for the referenced symbol, so it's more likely to be a win ๐Ÿ† If it isn't, -mno-gprel-ro can be used to disable it ๐Ÿ™…โ€โ™€๏ธ
  • -multilib-library-pic โ€” okay so this one links with the (library, not FD) pic libraries ๐ŸŒธ. It's implied by -mlibrary-pic, and also by -fPIC and -fpic when -mfdpic isn't in the mix. You should literally never have to type it yourself ๐Ÿ’….
  • -mlinked-fp โ€” the EABI says you always need a frame pointer whenever a stack frame gets allocated, and this is on by default ๐Ÿฆ‹. If you want it gone, use -mno-linked-fp.
  • -mlong-calls โ€” uses indirect addressing to call functions outside the current compilation unit ๐Ÿงš. The payoff is that those functions can be placed anywhere in the 32-bit address space โœจ.
  • -malign-labels โ€” tries to align labels to an 8-byte boundary by sticking NOPs into the previous packet ๐Ÿซถ. Only works when VLIW packing is enabled. It doesn't make new packets, it just adds NOPs to the ones that already exist ๐Ÿ’€.
  • -mlibrary-pic โ€” generates position-independent EABI code ๐Ÿ’–.
  • -macc-4 โ€” only uses the first four media accumulator registers ๐ŸŒˆ.
  • -macc-8 โ€” uses all eight media accumulator registers ๐Ÿ‘‘.
  • -mpack โ€” packs VLIW instructions ๐Ÿ“.
  • -mno-pack โ€” does NOT pack VLIW instructions ๐Ÿ™ˆ.
  • -mno-eflags โ€” doesn't mark ABI switches in e_flags ๐Ÿงš.
  • -mcond-move โ€” enables conditional-move instructions, and this is the default ๐Ÿ’….
    • Heads up bestie, this switch is mainly for debugging the compiler and will likely be removed in a future version ๐Ÿฅบ.
  • -mno-cond-move โ€” disables conditional-move instructions ๐Ÿ™ƒ.
    • This one is mainly for debugging the compiler too, and it'll likely be yeeted in a future version ๐Ÿซ .
  • -mscc โ€” enables conditional set instructions (default) โœจ.
    • Mainly for compiler debugging, and likely to be removed in a future version ๐Ÿฃ.
  • -mno-scc โ€” disables conditional set instructions ๐Ÿ™ˆ.
    • Also mainly for compiler debugging, and likely to be removed in a future version ๐Ÿ’€.
  • -mcond-exec โ€” enables conditional execution (default) ๐Ÿฆ‹.
    • Mainly a debugging switch, and likely to be removed in a future version ๐Ÿฅฒ.
  • -mno-cond-exec โ€” disables conditional execution ๐Ÿซฅ.
    • Mainly for debugging the compiler, and likely to be removed in a future version ๐Ÿ˜ญ.
  • -mvliw-branch โ€” runs a pass to pack branches into VLIW instructions (default) ๐ŸŒธ.
    • Mainly a debugging switch, and likely to be removed in a future version ๐Ÿซถ.
  • -mno-vliw-branch โ€” does NOT run a pass to pack branches into VLIW instructions ๐Ÿ™….
    • Mainly for debugging, and likely to be removed in a future version ๐ŸŽ€.
  • -mmulti-cond-exec โ€” enables optimization of "&&" and "||" in conditional execution (default) ๐Ÿ’–.
    • Mainly a debugging switch, and likely to be removed in a future version ๐Ÿงš.
  • -mno-multi-cond-exec โ€” disables optimization of "&&" and "||" in conditional execution ๐Ÿ™ƒ.
    • Mainly for compiler debugging, and likely to be removed in a future version ๐Ÿซ .
  • -mnested-cond-exec โ€” enables nested conditional execution optimizations (default) ๐Ÿ‘‘.
    • Mainly a debugging switch, and likely to be removed in a future version ๐Ÿฅบ.
  • -mno-nested-cond-exec โ€” disables nested conditional execution optimizations ๐Ÿซฅ.
    • Mainly for debugging, and likely to be removed in a future version ๐Ÿ˜ญ.
  • -moptimize-membar โ€” removes redundant "membar" instructions from the compiler-generated code โœจ. It's enabled by default, so you get this one for free ๐Ÿ“.
  • -mno-optimize-membar โ€” turns off the automatic removal of redundant "membar" instructions from the generated code ๐Ÿ™ˆ.
  • -mtomcat-stats โ€” makes gas print out tomcat statistics ๐Ÿ“Š.
  • -mcpu=cpu โ€” picks the processor type you want code generated for ๐Ÿ’…. The possible values are frv, fr550, tomcat, fr500, fr450, fr405, fr400, fr300 and simple ๐ŸŒˆ.

โœจ GNU/Linux Options โœจ

These -m options are defined for GNU/Linux targets ๐Ÿง.

  • -mglibc โ€” uses the GNU C library ๐Ÿ’œ. This is the default except on *-*-linux-*uclibc*, *-*-linux-*musl* and *-*-linux-*android* targets.
  • -muclibc โ€” uses the uClibc C library ๐Ÿฆ‹. This is the default on *-*-linux-*uclibc* targets.
  • -mmusl โ€” uses the musl C library ๐ŸŒธ. This is the default on *-*-linux-*musl* targets.
  • -mbionic โ€” uses the Bionic C library ๐Ÿ“ฑ. This is the default on *-*-linux-*android* targets.
  • -mandroid โ€” compiles code that's compatible with the Android platform ๐Ÿค–. This is the default on *-*-linux-*android* targets.
    • When compiling, this option enables -mbionic, -fPIC, -fno-exceptions and -fno-rtti by default ๐Ÿ’–.
    • When linking, this option makes the GCC driver pass Android-specific options to the linker ๐Ÿ”—.
    • Finally, this option causes the preprocessor macro "__ANDROID__" to be defined ๐ŸŽ€.
  • -tno-android-cc โ€” disables the compilation effects of -mandroid, i.e., it does NOT enable -mbionic, -fPIC, -fno-exceptions and -fno-rtti by default ๐Ÿ™….
  • -tno-android-ld โ€” disables the linking effects of -mandroid, i.e., it passes standard Linux linking options to the linker ๐Ÿง.

๐Ÿ H8/300 Options

These -m options are defined for the H8/300 implementations ๐ŸŒˆ.

  • -mrelax โ€” shortens some address references at link time when it's possible ๐Ÿƒ. It uses the linker option -relax.
  • -mh โ€” generates code for the H8/300H ๐Ÿ’ซ.
  • -ms โ€” generates code for the H8S ๐Ÿ‘‘.
  • -mn โ€” generates code for the H8S and H8/300H in the normal mode ๐Ÿซถ. This switch must be used either with -mh or -ms.
  • -ms2600 โ€” generates code for the H8S/2600 ๐Ÿฆ‹. This switch must be used with -ms.
  • -mexr โ€” stores extended registers on the stack before a function with the monitor attribute runs ๐Ÿ“š. This is the default option. It's only valid for H8S targets.
  • -mno-exr โ€” does NOT store extended registers on the stack before a function with the monitor attribute runs ๐Ÿ™ˆ. This option is the default one is -mno-exr, I mean, if you don't pick -mexr ๐Ÿ’…. It's only valid for H8S targets.
  • -mint32 โ€” makes "int" data 32 bits by default ๐Ÿ“.
  • -malign-300 โ€” on the H8/300H and H8S, uses the same alignment rules as the H8/300 ๐ŸŒธ. The default for the H8/300H and H8S is to align longs and floats on 4-byte boundaries, but -malign-300 moves them to 2-byte boundaries instead. This option has no effect on the H8/300.

๐ŸŒท HPPA Options

These -m options are defined for the HPPA family of computers ๐Ÿ’ป.

  • -march=architecture-type โ€” generates code for the architecture you specify ๐Ÿ—๏ธ. 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. Refer to /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 architectures, but not the other way around ๐Ÿ’ซ.
  • -mpa-risc-1-0, -mpa-risc-1-1, -mpa-risc-2-0 โ€” these are synonyms for -march=1.0, -march=1.1, and -march=2.0 respectively ๐Ÿ‘ฏ.
  • -mcaller-copies โ€” the caller copies function arguments that get passed by hidden reference ๐Ÿ“‹.
โš ๏ธ Use this one with care, bestie! It is not compatible with the default 32-bit runtime. However, only aggregates larger than eight bytes are passed by hidden reference, and this option gives you better compatibility with OpenMP ๐Ÿซฃ.
  • -mjump-in-delay โ€” this option is ignored and only provided for compatibility purposes ๐Ÿ™ƒ.
  • -mdisable-fpregs โ€” stops floating-point registers from being used in any manner ๐Ÿšซ. This is necessary for compiling kernels that do lazy context switching of floating-point registers ๐Ÿง .
๐Ÿ’€ If you use this option and then try to do floating-point operations, the compiler aborts. Literally dead.
  • -mdisable-indexing โ€” stops the compiler from using indexing address modes ๐Ÿ™…. This avoids 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 โšก. Such code is suitable for level 0 PA systems and kernels ๐Ÿ–ฅ๏ธ.
  • -mfast-indirect-calls โ€” generates code that assumes calls never cross space boundaries ๐ŸŽ๏ธ. This lets GCC emit code that does faster indirect calls.
โš ๏ธ This option does not work in the presence of shared libraries or nested functions. Don't say I didn't warn you ๐Ÿ˜ญ.
  • -mfixed-range=register-range โ€” generates code that treats the given register range as fixed registers ๐Ÿงฑ. A fixed register is one the register allocator can't use, which is super useful when compiling kernel code ๐Ÿ› ๏ธ. You specify a register range as two registers separated by a dash, and you can separate multiple ranges with a comma ๐ŸŽ€.
  • -mlong-load-store โ€” generates 3-instruction load and store sequences, which the HP-UX 10 linker sometimes needs ๐Ÿ“ฆ. This is equivalent to the +k option on the HP compilers.
  • -mportable-runtime โ€” uses the portable calling conventions HP proposed for ELF systems ๐ŸŒ.
  • -mgas โ€” enables the use of assembler directives that only GAS understands ๐Ÿฃ.
  • -mschedule=cpu-type โ€” schedules code according to the constraints for the machine type cpu-type ๐Ÿ—“๏ธ. The choices for cpu-type are 700 7100, 7100LC, 7200, 7300 and 8000. Refer to /usr/lib/sched.models on an HP-UX system to find the right scheduling option for your machine ๐Ÿ”Ž. The default scheduling is 8000.
  • -mlinker-opt โ€” enables the optimization pass in the HP-UX linker ๐Ÿ”ง.
๐Ÿ™ˆ Heads up: this makes symbolic debugging impossible. It also triggers a bug in the HP-UX 8 and HP-UX 9 linkers, where they give bogus error messages when linking some programs. Not it ๐Ÿ’€.
  • -msoft-float โ€” generates output containing library calls for floating point ๐Ÿงฎ.
โš ๏ธ The requisite libraries are not available for all HPPA targets. Normally the facilities of the machine's usual C compiler are used, but this cannot be done directly in cross-compilation. You must make your own arrangements to provide suitable library functions for cross-compilation.

-msoft-float changes the calling convention in the output file, so it's only useful if you compile your whole program with this option ๐Ÿซถ. 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 โ€” okay so this one tells GCC to use the GNU ld energy ๐Ÿงš It passes -shared to ld when building a shared library. It's the default when GCC is configured, explicitly or implicitly, with the GNU linker. Heads up: this option does NOT decide which ld gets called, it only changes the parameters sent to it ๐Ÿ’… The ld that gets called is picked by the --with-ld configure option, GCC's program search path, and finally the user's PATH. You can check which linker GCC is using with which gcc -print-prog-name=ld. This is only available on the 64-bit HP-UX GCC, i.e. configured with hppa*64*-*-hpux* ๐Ÿซถ
  • -mhp-ld โ€” the HP linker's turn to shine ๐ŸŒธ 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 above: it doesn't change which ld is called, just the parameters. That's decided by the --with-ld configure option, GCC's program search path, and finally the user's PATH. The linker GCC uses can be printed with which gcc -print-prog-name=ld. Also only available on the 64-bit HP-UX GCC, i.e. configured with hppa*64*-*-hpux* โœจ
  • -mlong-calls โ€” generates long call sequences, so a call can ALWAYS reach linker-generated stubs ๐Ÿฆ‹ By default, long calls only get generated when the distance from the call site to the beginning of the function or translation unit (depending on the case) goes past a predefined limit set by the branch type being used. The limits for normal calls are 7,600,000 and 240,000 bytes, respectively for the PA 2.0 and PA 1.X architectures. Sibcalls are always limited at 240,000 bytes.

Distances get measured from the beginning of functions when using the -ffunction-sections option, or when using the -mgas and -mno-portable-runtime options together under HP-UX with the SOM linker.

Real talk, it's normally not desirable to use this one because 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, plus the type of code being generated. On systems that support long absolute calls, and long pic symbol-difference or pc-relative calls, the impact should be relatively small. BUT an indirect call is used on 32-bit ELF systems in pic code, and it is quite long ๐Ÿ’€

  • -munix=unix-std โ€” picks a UNIX standard, and GCC generates compiler predefines and selects a startfile for it ๐Ÿ“ The choices for unix-std are 93, 95 and 98. 93 works on all HP-UX versions. 95 is available on HP-UX 10.10 and later. 98 is available on HP-UX 11.11 and later. The defaults are 93 for HP-UX 10.00, 95 for HP-UX 10.10 through 11.00, and 98 for HP-UX 11.11 and later.

-munix=93 gives you the same predefines as GCC 3.3 and 3.4. -munix=95 adds predefines for "XOPEN_UNIX" and "_XOPEN_SOURCE_EXTENDED", plus the startfile unix95.o. -munix=98 adds predefines for "_XOPEN_UNIX", "_XOPEN_SOURCE_EXTENDED", "_INCLUDE__STDC_A1_SOURCE" and "_INCLUDE_XOPEN_SOURCE_500", plus the startfile unix98.o.

โš ๏ธ Be careful with this one, bestie! This option changes the interfaces for various library routines, and it also affects the operational behavior of the C library. Extreme care is needed when using it.

Library code that's meant to work with more than one UNIX standard has to test, set and restore the variable "__xpg4_extended_mask" as appropriate. Most GNU software doesn't provide this capability ๐Ÿ™ˆ

  • -nolibdld โ€” stops GCC from adding the link options that search libdld.sl when -static is specified on HP-UX 10 and later ๐Ÿ›‘
  • -static โ€” okay, this one has drama ๐ŸŽญ The HP-UX implementation of setlocale in libc depends on libdld.sl. There isn't an archive version of libdld.sl, so when -static is specified, special link options are needed to resolve that dependency.

On HP-UX 10 and later, the GCC driver adds the necessary options to link with libdld.sl when -static is specified. This makes the resulting binary dynamic. On the 64-bit port, the linkers generate dynamic binaries by default anyway. If you don't want the GCC driver adding these link options, use -nolibdld ๐Ÿซถ

  • -threads โ€” adds support for multithreading with the dce thread library under HP-UX ๐Ÿงต This option sets flags for both the preprocessor and the linker.

โœจ IA-64 Options โœจ

These are the -m options defined for the Intel IA-64 architecture ๐Ÿ’œ

  • -mbig-endian โ€” generates code for a big-endian target. This is the default for HP-UX ๐ŸŒˆ
  • -mlittle-endian โ€” generates code for a little-endian target. This is the default for AIX5 and GNU/Linux ๐Ÿฃ
  • -mgnu-as, -mno-gnu-as โ€” generates (or doesn't) code for the GNU assembler. The default is -mgnu-as ๐Ÿงš
  • -mgnu-ld, -mno-gnu-ld โ€” generates (or doesn't) code for the GNU linker. The default is -mgnu-ld โœจ
  • -mno-pic โ€” generates code that does NOT use a global pointer register. The result is not position independent code, and it violates the IA-64 ABI ๐Ÿ’€
  • -mvolatile-asm-stop, -mno-volatile-asm-stop โ€” generates (or doesn't) a stop bit immediately before and after volatile asm statements ๐Ÿ›‘
  • -mregister-names, -mno-register-names โ€” generates (or doesn't) in, loc, and out register names for the stacked registers. This may make the assembler output more readable ๐Ÿ‘€
  • -mno-sdata, -msdata โ€” disables (or enables) optimizations that use the small data section. This may be useful for working around optimizer bugs ๐Ÿ›
  • -mconstant-gp โ€” generates code that uses a single constant global pointer value. This is useful when compiling kernel code ๐Ÿ–ฅ๏ธ
  • -mauto-pic โ€” generates code that is self-relocatable. This implies -mconstant-gp. It's useful when compiling firmware code ๐Ÿ”ง
  • -minline-float-divide-min-latency โ€” generates code for inline divides of floating-point values using the minimum latency algorithm โšก
  • -minline-float-divide-max-throughput โ€” generates code for inline divides of floating-point values using the maximum throughput algorithm ๐Ÿš€
  • -mno-inline-float-divide โ€” does NOT generate inline code for divides of floating-point values ๐Ÿ™…
  • -minline-int-divide-min-latency โ€” generates code for inline divides of integer values using the minimum latency algorithm โšก
  • -minline-int-divide-max-throughput โ€” generates code for inline divides of integer values using the maximum throughput algorithm ๐Ÿš€
  • -mno-inline-int-divide โ€” does NOT generate inline code for divides of integer values ๐Ÿ™…
  • -minline-sqrt-min-latency โ€” generates code for inline square roots using the minimum latency algorithm โšก
  • -minline-sqrt-max-throughput โ€” generates code for inline square roots using the maximum throughput algorithm ๐Ÿš€
  • -mno-inline-sqrt โ€” does NOT generate inline code for "sqrt" ๐Ÿ™…
  • -mfused-madd, -mno-fused-madd โ€” does (or doesn't) generate code that uses the fused multiply/add or multiply/subtract instructions. The default is to use these instructions ๐Ÿ”ฅ
  • -mno-dwarf2-asm, -mdwarf2-asm โ€” doesn't (or does) generate assembler code for the DWARF line number debugging info. This may be useful when NOT using the GNU assembler ๐Ÿงฉ
  • -mearly-stop-bits, -mno-early-stop-bits โ€” allows stop bits to be placed earlier than immediately preceding the instruction that triggered the stop bit. This can improve instruction scheduling, but it 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 cannot use. This is useful when compiling kernel code. A register range is specified as two registers separated by a dash, and you can specify multiple register 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 โ€” disables (or enables) 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 โ€” enables (or disables) 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 โ€” disables (or enables) control speculative scheduling. This feature is available only during region scheduling (i.e. before reload). This 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 โ€” enables (or disables) speculative scheduling of the instructions that depend on the data speculative loads before reload. This is effective only with -msched-br-data-spec enabled. The default setting is enabled ๐ŸŒท
  • -msched-ar-in-data-spec, -mno-sched-ar-in-data-spec โ€” enables (or disables) speculative scheduling of the instructions that depend on the data speculative loads after reload. This is effective only with -msched-ar-data-spec enabled. The default setting is enabled ๐Ÿญ
  • -msched-in-control-spec, -mno-sched-in-control-spec โ€” enables (or disables) speculative scheduling of the instructions that depend on the control speculative loads. This is effective only with -msched-control-spec enabled. The default setting is enabled ๐Ÿ‘‘
  • -mno-sched-prefer-non-data-spec-insns, -msched-prefer-non-data-spec-insns โ€” ๐ŸŒธ When this is on, data-speculative instructions only get picked for scheduling if there's literally nothing else available. It makes data speculation super conservative. It's off by default.
  • -mno-sched-prefer-non-control-spec-insns, -msched-prefer-non-control-spec-insns โ€” ๐Ÿฆ‹ Same vibe, but for control-speculative instructions. They only get chosen when there are no other options left, so control speculation gets very conservative. Off by default.
  • -mno-sched-count-spec-in-critical-path, -msched-count-spec-in-critical-path โ€” ๐Ÿ’… When enabled, speculative dependencies get counted when GCC works out instruction priorities. That makes speculation a bit more cautious. It's disabled by default.
  • -msched-spec-ldc โ€” ๐Ÿงš Uses a simple data speculation check. This one is on by default, bestie.
  • -msched-control-spec-ldc โ€” โœจ Uses a simple check for control speculation. Also on by default.
  • -msched-stop-bits-after-every-cycle โ€” ๐Ÿ“ Puts a stop bit after every cycle while scheduling. On by default.
  • -msched-fp-mem-deps-zero-cost โ€” ๐Ÿ’œ Tells GCC to assume floating-point stores and loads aren't likely to clash when they land in the same instruction group. Disabled by default.
  • -msel-sched-dont-check-control-spec โ€” ๐Ÿ™ˆ Generates checks for control speculation in selective scheduling. Heads up: this flag is disabled by default.
  • -msched-max-memory-insns=max-insns โ€” ๐Ÿ”ฅ Sets a limit on how many memory insns can go in one instruction group. Any extra memory insns trying to squeeze into that same group get lower priority. This is super handy for avoiding cache bank conflicts. The default value is 1.
  • -msched-max-memory-insns-hard-limit โ€” ๐Ÿ‘‘ Turns the -msched-max-memory-insns limit into a hard limit, so no more than that many memory insns can ever show up in one instruction group. Without this, the limit is "soft": non-memory ops get preferred once you hit it, but memory ops can still sneak in if they need to.

๐ŸŒˆ 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 โ€” ๐Ÿ’… Picks the CPU you're generating code for. name can be r8c for the R8C/Tiny series, m16c for the M16C (up to /60) series, m32cm for the M16C/80 series, or m32c for the M32C/80 series.
  • -msim โ€” ๐ŸŒธ Says the program will run on the simulator. This links in an alternate runtime library that supports stuff like file I/O. > You must not use this option when generating programs for real hardware! For that you need to provide your own runtime library for whatever I/O functions you need, bestie. ๐Ÿ™ˆ
  • -memregs=number โ€” ๐Ÿ”ฅ Sets how many memory-based pseudo-registers GCC uses during code generation. They get used like real registers, so it's a tradeoff: fitting code into the available registers versus the performance hit from using memory instead. Every module in a program has to be compiled with the same value for this option. Because of that, you must not use this option with GCC's default runtime libraries.

๐Ÿฆ‹ M32R/D Options ๐Ÿฆ‹

These -m options are defined for Renesas M32R/D architectures:

  • -m32r2 โ€” โœจ Generates code for the M32R/2.
  • -m32rx โ€” ๐Ÿ‘‘ Generates code for the M32R/X.
  • -m32r โ€” ๐Ÿ’– Generates code for the M32R. This is the default.
  • -mmodel=small โ€” ๐ŸŒˆ Assumes all objects live in the lower 16MB of memory, so their addresses can be loaded with the "ld24" instruction. It also assumes all subroutines are reachable with the "bl" instruction. This is the default.

The addressability of a particular object can be set with the "model" attribute.

  • -mmodel=medium โ€” ๐Ÿงš Assumes objects may be anywhere in the 32-bit address space, so the compiler generates "seth/add3" instructions to load their addresses. It still assumes all subroutines are reachable with the "bl" instruction.
  • -mmodel=large โ€” ๐Ÿ”ฅ Assumes objects may be anywhere in the 32-bit address space (the compiler generates "seth/add3" instructions to load their addresses). It also assumes subroutines may not be reachable with the "bl" instruction, so the compiler generates the much slower "seth/add3/jl" instruction sequence. Slow but steady, periodt. ๐Ÿข
  • -msdata=none โ€” ๐Ÿ“ Disables use of the small data area. Variables get put into one of ".data", ".bss", or ".rodata" (unless the "section" attribute has been specified). This is the default.

The small data area is made up of the ".sdata" and ".sbss" sections. You can explicitly put objects in the small data area with the "section" attribute using one of these sections.

  • -msdata=sdata โ€” ๐ŸŒธ Puts small global and static data in the small data area, but doesn't generate any special code to reference them.
  • -msdata=use โ€” ๐Ÿ’œ Puts small global and static data in the small data area and generates special instructions to reference them.
  • -G num โ€” ๐ŸŽ€ Puts global and static objects that are less than or equal to num bytes into the small data or BSS sections instead of the normal data or BSS sections. The default value of num is 8. The -msdata option has to be set to either sdata or use for this option to do anything.

All modules should be compiled with the same -G num value. Compiling with different values of num may or may not work. If it doesn't, the linker throws an error message. Incorrect code is not generated, though, so no sneaky bugs. ๐Ÿซถ

  • -mdebug โ€” ๐Ÿ” Makes the M32R-specific code in the compiler display some statistics that might help you debug your programs.
  • -malign-loops โ€” โœจ Aligns all loops to a 32-byte boundary.
  • -mno-align-loops โ€” ๐Ÿ™… Does not enforce a 32-byte alignment for loops. This is the default.
  • -missue-rate=number โ€” ๐Ÿ”ฅ Issues number instructions per cycle. number can only be 1 or 2.
  • -mbranch-cost=number โ€” ๐Ÿ’… number can only be 1 or 2. If it's 1, branches are preferred over conditional code. If it's 2, the opposite applies.
  • -mflush-trap=number โ€” ๐ŸŒˆ Specifies the trap number to use to flush the cache. The default is 12. Valid numbers are between 0 and 15 inclusive.
  • -mno-flush-trap โ€” ๐Ÿฆ‹ Specifies that the cache cannot be flushed by using a trap.
  • -mflush-func=name โ€” ๐Ÿงš Specifies the name of the operating system function to call to flush the cache. The default is _flush_cache, but a function call is only used if a trap isn't available.
  • -mno-flush-func โ€” ๐Ÿ’œ Indicates that there's no OS function for flushing the cache.

๐ŸŒธ M680x0 Options ๐ŸŒธ

These are the -m options defined for M680x0 and ColdFire processors. The default settings depend on which architecture was selected when the compiler was configured. The defaults for the most common choices are given below.

  • -march=arch โ€” ๐Ÿ‘‘ Generates code for a specific M680x0 or ColdFire instruction set architecture. Valid values of arch for M680x0 architectures are: 68000, 68010, 68020, 68030, 68040, 68060 and cpu32. ColdFire architectures are picked according to Freescale's ISA classification, and the valid values are: isaa, isaaplus, isab and isac.

GCC defines a macro __mcfarch__ whenever it's generating code for a ColdFire target. The arch in this macro is one of the -march arguments listed above.

When you use -march and -mtune together, you get code that runs on a family of similar processors but is optimized for one particular microarchitecture. ๐Ÿซถ

  • -mcpu=cpu โ€” ๐Ÿ’– Generates code for a specific M680x0 or ColdFire processor. The M680x0 cpus are: 68000, 68010, 68020, 68030, 68040, 68060, 68302, 68332 and cpu32. The ColdFire cpus are in the table below, which also sorts the CPUs into families:
Family : -mcpu arguments
51 : 51 51ac 51ag 51cn 51em 51je 51jf 51jg 51jm 51mm 51qe 51qm
5206 : 5202 5204 5206
5206e : 5206e
5208 : 5207 5208
5211a : 5210a 5211a
5213 : 5211 5212 5213
5216 : 5214 5216
52235 : 52230 52231 52232 52233 52234 52235
5225 : 5224 5225
52259 : 52252 52254 52255 52256 52258 52259
5235 : 5232 5233 5234 5235 523x
5249 : 5249
5250 : 5250
5271 : 5270 5271
5272 : 5272
5275 : 5274 5275
5282 : 5280 5281 5282 528x
53017 : 53011 53012 53013 53014 53015 53016 53017
5307 : 5307
5329 : 5327 5328 5329 532x
5373 : 5372 5373 537x
5407 : 5407
5475 : 5470 5471 5472 5473 5474 5475 547x 5480 5481 5482 5483 5484
5485

-mcpu=cpu overrides -march=arch if arch is compatible with cpu. Other combinations of -mcpu and -march get rejected, so watch out! โš ๏ธ

GCC defines the macro __mcf_cpu_cpu when a ColdFire target cpu is selected. It also defines __mcf_family_family, where the value of family comes from the table above. โœจ

  • -mtune=tune โ€” ๐Ÿ”ฅ Tunes the code for a particular microarchitecture, within the limits set by -march and -mcpu. The M680x0 microarchitectures are: 68000, 68010, 68020, 68030, 68040, 68060 and cpu32. The ColdFire microarchitectures are: cfv1, cfv2, cfv3, cfv4 and cfv4e.

You can also use -mtune=68020-40 for code that needs to run pretty well on 68020, 68030 and 68040 targets. -mtune=68020-60 is similar, but it includes 68060 targets too. These two options pick 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 listed above. ๐Ÿฆ‹

๐Ÿ’… OPTIONS, continued ๐Ÿ’…

  • -m68000, -mc68000 โ€” okay so this one is the 68000 output, and it's the default if your compiler was set up for 68000-based systems ๐ŸŒธ It's the same as -march=68000. Use it for microcontrollers with a 68000 or EC000 core, like the 68008, 68302, 68306, 68307, 68322, 68328 and 68356 ๐Ÿซถ
  • -m68010 โ€” generates code for a 68010 ๐Ÿฆ‹ Default when you're configured for 68010 systems, and it's the same as -march=68010.
  • -m68020, -mc68020 โ€” the 68020 version โœจ Default for 68020 configs, equal to -march=68020. Slay.
  • -m68030 โ€” a 68030 build ๐Ÿ’œ Default for 68030 configs, same as -march=68030.
  • -m68040 โ€” the 68040 build ๐Ÿ‘‘ Default for 68040 configs, and it's the same as -march=68040. Lowkey important bit: this one stops using the 68881/68882 instructions that the 68040 has to fake in software. Only use it if your 68040 doesn't have the code to emulate those, bestie ๐Ÿ˜ญ
  • -m68060 โ€” 68060 output ๐Ÿ”ฅ Default for 68060 configs, same as -march=68060. It blocks the 68020 and 68881/68882 instructions that the 68060 has to emulate in software, so use it only if your 68060 lacks that emulation code ๐Ÿ’€
  • -mcpu32 โ€” CPU32 output ๐Ÿงš Default for CPU32 configs, same as -march=cpu32. It's for microcontrollers with a CPU32 or CPU32+ core, including the 68330, 68331, 68332, 68333, 68334, 68336, 68340, 68341, 68349 and 68360 ๐ŸŒˆ
  • -m5200 โ€” a 520X ColdFire CPU ๐Ÿ“ Default for 520X configs. It's the same as -mcpu=5206, but it's deprecated now, so use -mcpu=5206 instead. It's meant for microcontrollers with a 5200 core, like the MCF5202, MCF5203, MCF5204 and MCF5206.
  • -m5206e โ€” a 5206e ColdFire CPU. Deprecated, so just switch to -mcpu=5206e ๐Ÿ™ˆ
  • -m528x โ€” a member of the ColdFire 528X family. Also deprecated, use -mcpu=528x instead โœจ
  • -m5307 โ€” a ColdFire 5307 CPU. Deprecated! Go with -mcpu=5307 ๐Ÿ’–
  • -m5407 โ€” a ColdFire 5407 CPU. Deprecated too, so it's -mcpu=5407 now ๐Ÿฆ‹
  • -mcfv4e โ€” ColdFire V4e family vibes (think 547x/548x) ๐Ÿ”ฅ This includes the hardware floating-point instructions. It's equal to -mcpu=547x, and yep, it's deprecated in favor of that.
  • -m68020-40 โ€” generates 68040 code without any of the new instructions ๐Ÿ’… The result runs pretty efficiently on a 68020/68881, a 68030, or a 68040. The generated code does use the 68881 instructions that the 68040 emulates. This is the same as -march=68020 -mtune=68020-40.
  • -m68020-60 โ€” same energy as above, but for 68060 code, still without any of the new instructions ๐Ÿซถ It runs pretty efficiently on a 68020/68881, a 68030, or a 68040, and it does use the 68881 instructions that get emulated on the 68060. Equivalent to -march=68020 -mtune=68020-60.
  • -mhard-float, -m68881 โ€” turns on floating-point instructions ๐ŸŒธ This is the default for the 68020 and up, and for ColdFire devices with an FPU. It defines the macro __HAVE_68881__ on M680x0 targets and __mcffpu__ on ColdFire targets.
  • -msoft-float โ€” no floating-point instructions here, bestie ๐Ÿ™… Library calls do the math instead. It's the default for 68000, 68010, and 68832 targets, and also for ColdFire devices that don't have an FPU.
  • -mdiv, -mno-div โ€” -mdiv turns on ColdFire hardware divide and remainder instructions, and -mno-div turns them off ๐Ÿงฎ 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, either the default CPU or whichever one you picked with -mcpu. For example, it's "off" for -mcpu=5206 but "on" for -mcpu=5206e. Also, GCC defines the macro __mcfhwdiv__ when this is enabled, so you can check for it โœจ
  • -mshort โ€” this one treats int as 16 bits wide, just like short int ๐Ÿ“ On top of that, parameters passed on the stack get aligned to a 16-bit boundary, even on targets that are supposed to promote them to 32-bit.
  • -mno-short โ€” int is not 16 bits wide. This is the default, so you're probably already here ๐Ÿ’–
  • -mnobitfield, -mno-bitfield โ€” don't use the bit-field instructions ๐Ÿ™ˆ Heads up, -m68000, -mcpu32 and -m5200 all imply -mnobitfield.
  • -mbitfield โ€” do use the bit-field instructions ๐Ÿ”ฅ -m68020 implies this, and it's the default if you're using a configuration designed for a 68020.
  • -mrtd โ€” okay this one is a whole vibe ๐Ÿ’€ It switches to a different function-calling convention, where functions with a fixed number of arguments return with the rtd instruction, which pops their arguments on the way out. That saves one instruction in the caller since it doesn't have to pop anything. The default is -mno-rtd.
Warning, bestie: 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 must provide function prototypes for every function that takes a variable number of arguments (including printf), or the code generated for those calls will be incorrect. And if you call a function with too many arguments, you get seriously incorrect code. 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.

  • -malign-int, -mno-align-int โ€” controls whether GCC aligns int, long, long long, float, double, and long double variables on a 32-bit boundary (-malign-int) or a 16-bit boundary (-mno-align-int) ๐Ÿ“ Aligning on 32-bit boundaries makes code run a bit faster on processors with 32-bit busses, but it costs more memory.
Warning: if you use -malign-int, GCC aligns structures containing those types differently than most published application binary interface specifications for the m68k. Watch out for that one, bestie ๐Ÿซฃ
  • -mpcrel โ€” uses the 68000's pc-relative addressing mode directly, instead of a global offset table ๐Ÿฆ‹ For now this option implies -fpic, which allows at most a 16-bit offset for pc-relative addressing. -fPIC isn't supported with -mpcrel yet, although that could be supported for 68020 and higher processors.
  • -mno-strict-align, -mstrict-align โ€” -mno-strict-align means GCC does not assume that unaligned memory references get handled by the system, and -mstrict-align means it does assume that ๐Ÿง 
  • -msep-data โ€” generates code that lets the data segment sit in a different area of memory than the text segment ๐Ÿ’œ This allows execute-in-place in an environment without virtual memory management. It implies -fPIC.
  • -mno-sep-data โ€” generates code that assumes the data segment follows the text segment. This is the default ๐ŸŒธ
  • -mid-shared-library โ€” generates code that supports shared libraries through the library ID method โœจ This allows execute-in-place and shared libraries in an environment without virtual memory management. It implies -fPIC.
  • -mno-id-shared-library โ€” generates code that doesn't assume ID-based shared libraries are being used. This is the default ๐Ÿ™…
  • -mshared-library-id=n โ€” specifies the identification number of the ID-based shared library being compiled ๐Ÿงš Specifying 0 generates more compact code. Other values force that number onto the current library, but it's no more space- or time-efficient than leaving this option out.
  • -mxgot, -mno-xgot โ€” when generating position-independent code for ColdFire, -mxgot makes code that works even if the GOT has more than 8192 entries ๐ŸŒˆ That code is larger and slower than the normal stuff. On M680x0 processors you don't need this one, since -fPIC is enough.

Normally GCC 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 throw an error like this:

relocation truncated to fit: R_68K_GOT16O foobar

If that happens, recompile your code with -mxgot, and it should work with very large GOTs ๐Ÿซถ Heads up though: code built with -mxgot is less efficient, since it takes 4 instructions to fetch the value of a global symbol.

Also, 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, so you're probably fine ๐Ÿ’…

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 โ€” -mhardlit inlines constants into the code stream if it can be done in two instructions or less โœจ -mno-hardlit turns that off.
  • -mdiv, -mno-div โ€” -mdiv uses the divide instruction ๐Ÿงฎ It's enabled by default, so -mno-div is the one you'd have to ask for.
  • -mrelax-immediate, -mno-relax-immediate โ€” -mrelax-immediate allows arbitrary-sized immediates in bit operations ๐ŸŒธ -mno-relax-immediate shuts that down.
  • -mwide-bitfields, -mno-wide-bitfields โ€” -mwide-bitfields always treats bit-fields as int-sized ๐Ÿ’– -mno-wide-bitfields is the opposite.
  • -m4byte-functions, -mno-4byte-functions โ€” -m4byte-functions forces all functions to be aligned to a 4-byte boundary ๐Ÿ“ -mno-4byte-functions doesn't force that.
  • -mcallgraph-data, -mno-callgraph-data โ€” -mcallgraph-data emits callgraph information ๐Ÿ•ธ๏ธ -mno-callgraph-data doesn't.
  • -mslow-bytes, -mno-slow-bytes โ€” -mslow-bytes prefers word access when reading byte quantities ๐Ÿ™ˆ -mno-slow-bytes turns that preference off.
  • -mlittle-endian, -mbig-endian โ€” okay so these two share one description: generate code for a little-endian target ๐Ÿ’–
  • -m210, -m340 โ€” generate code for the 210 processor โœจ
  • -mno-lsim โ€” assume the runtime support is already taken care of, so skip the simulator library (libsim.a) on the linker command line ๐ŸŒธ
  • -mstack-increment=size โ€” sets the max amount for a single stack increment operation ๐Ÿฆ‹ Big values can speed up programs with functions that need a lot of stack space, but they can also trigger a segmentation fault if the stack gets extended too much. The default is 0x1000.
๐Ÿ’€ bestie, don't go too wild with size. A huge value can cause a segfault if the stack gets extended too far.

โœจ MeP Options โœจ

  • -mabsdiff โ€” ๐Ÿ’… enables the abs instruction, which gives you 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. Main character energy, no cap.
  • -maverage โ€” โœจ enables the ave instruction, which computes the average of two registers.
  • -mbased=n โ€” ๐Ÿงš variables of n bytes or smaller get placed in the .based section by default. Based variables use the $tp register as their base register, and there's a 128-byte limit on the .based section.
  • -mbitops โ€” ๐Ÿ”ฅ enables the bit operation instructions: bit test (btstm), set (bsetm), clear (bclrm), invert (bnotm), and test-and-set (tas).
  • -mc=name โ€” ๐ŸŽ€ picks which section constant data gets placed in. name can be tiny, near, or far.
  • -mclip โ€” ๐Ÿฆ‹ enables the clip instruction. Heads up: -mclip isn't useful unless you also pass -mminmax.
  • -mconfig=name โ€” ๐ŸŒˆ picks 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 (not part of GCC) provides these configurations through this option, and 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 via the -mconfig= option.
  • -mcop32 โ€” enables the 32-bit coprocessor's instructions.
  • -mcop64 โ€” enables the 64-bit coprocessor's instructions.
  • -mivc2 โ€” enables IVC2 scheduling. IVC2 is a 64-bit VLIW coprocessor.
  • -mdc โ€” causes constant variables to be placed in the .near section.
  • -mdiv โ€” enables the div and divu instructions.
  • -meb โ€” generate big-endian code.
  • -mel โ€” generate little-endian code.
  • -mio-volatile โ€” tells the compiler that any variable marked with the io attribute is to be considered volatile.
  • -ml โ€” causes variables to be assigned to the .far section by default.
  • -mleadz โ€” enables the leadz (leading zero) instruction.
  • -mm โ€” causes variables to be assigned to the .near section by default.
  • -mminmax โ€” enables the min and max instructions.
  • -mmult โ€” enables the multiplication and multiply-accumulate instructions.
  • -mno-opts โ€” disables all the optional instructions enabled by -mall-opts ๐Ÿ™…โ€โ™€๏ธ
  • -mrepeat โ€” enables the repeat and erepeat instructions, which are used for low-overhead looping ๐Ÿ”
  • -ms โ€” 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 generate these itself right now, 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 built-in support for reset and exception vectors and tables.
  • -mtf โ€” causes all functions to default to the .far section. Without this option, functions default to the .near section.
  • -mtiny=n โ€” variables that are n bytes or smaller get allocated to the .tiny section. These use the $gp base register. The default for this option is 4, but there's a 65536-byte limit to the .tiny section.

โœจ MicroBlaze Options โœจ

  • -msoft-float โ€” use software emulation for floating point (default). ๐Ÿงธ
  • -mhard-float โ€” use hardware floating-point instructions.
  • -mmemcpy โ€” don't optimize block moves, use memcpy instead.
  • -mno-clearbss โ€” deprecated, bestie. Use -fno-zero-initialized-in-bss instead.
  • -mcpu=cpu-type โ€” use features of, and schedule code for, the given CPU. Supported values are in the format vX.YY.Z, where X is a major version, YY is the minor version, and Z is compatibility code. Example values are v3.00.a, v4.00.b, v5.00.a, v5.00.b, and v6.00.a.
  • -mxl-soft-mul โ€” use software multiply emulation (default).
  • -mxl-soft-div โ€” use software emulation for divides (default).
  • -mxl-barrel-shift โ€” use the hardware barrel shifter.
  • -mxl-pattern-compare โ€” use pattern compare instructions.
  • -msmall-divides โ€” use table lookup optimization for small signed integer divisions.
  • -mxl-stack-check โ€” deprecated, so use -fstack-check instead.
  • -mxl-gp-opt โ€” use GP-relative .sdata/.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. Valid models are:
    • executable โ€” normal executable (default), uses 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. This uses startup file crt1.o and sets the start address of the program to 0x800.
    • bootstrap โ€” for applications that are loaded using a bootloader. This model uses startup file crt2.o, which doesn't contain a processor reset vector handler. It's suitable for handing control to the bootloader on a processor reset rather than the application.
    • novectors โ€” for applications that don't require any of the MicroBlaze vectors. This can be useful for applications running within a monitoring application. This model uses crt3.o as a startup file.
๐Ÿฅ€ Option -xl-mode-app-model is a deprecated alias for -mxl-mode-app-model.

โœจ 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 the name of a generic MIPS ISA or the name of a particular processor. The ISA names are: mips1, mips2, mips3, mips4, mips32, mips32r2, mips32r3, mips32r5, mips32r6, mips64, mips64r2, mips64r3, mips64r5 and mips64r6. The processor names are: 4kc, 4km, 4kp, 4ksc, 4kec, 4kem, 4kep, 4ksd, 5kc, 5kf, 20kc, 24kc, 24kf2_1, 24kf1_1, 24kec, 24kef2_1, 24kef1_1, 34kc, 34kf2_1, 34kf1_1, 34kn, 74kc, 74kf2_1, 74kf1_1, 74kf3_2, 1004kc, 1004kf2_1, 1004kf1_1, i6400, i6500, interaptiv, loongson2e, loongson2f, loongson3a, gs464, gs464e, gs264e, m4k, m14k, m14kc, m14ke, m14kec, m5100, m5101, octeon, octeon+, octeon2, octeon3, orion, p5600, p6600, r2000, r3000, r3900, r4000, r4400, r4600, r4650, r4700, r5900, r6000, r8000, rm7000, rm9000, r10000, r12000, r14000, r16000, sb1, sr71000, vr4100, vr4111, vr4120, vr4130, vr4300, vr5000, vr5400, vr5500, xlr and xlp. The special value from-abi selects the most compatible architecture for the selected ABI (that is, mips1 for 32-bit ABIs and mips3 for 64-bit ABIs).

The native Linux/GNU toolchain also supports the value native, which selects the best architecture option for the host processor. -march=native has no effect if GCC does not recognize the processor.

In processor names, a final 000 can be abbreviated as k (for example, -march=r2k). Prefixes are optional, and vr may be written r.

Names of the form nf2_1 refer to processors with FPUs clocked at half the rate of the core, names of the form nf1_1 refer to processors with FPUs clocked at the same rate as the core, and names of the form nf3_2 refer to processors with FPUs clocked at a ratio of 3:2 with respect to the core. For compatibility reasons, nf is accepted as a synonym for nf2_1, while nx and bfx are accepted as synonyms for nf1_1.

GCC defines two macros based on the value of this option. The first is "_MIPS_ARCH", which gives the name of the target architecture as a string. The second has the form "_MIPS_ARCH_foo", where foo is the capitalized value of "_MIPS_ARCH". For example, -march=r2000 sets "_MIPS_ARCH" to "r2000" and defines the macro "_MIPS_ARCH_R2000".

Note that the "_MIPS_ARCH" macro uses the processor names given above. In other words, it has the full prefix and doesn't abbreviate 000 as k. In the case of from-abi, the macro names the resolved architecture (either "mips1" or "mips3"). It names the default architecture when no -march option is given.

  • -mtune=arch โ€” ๐ŸŽ€ 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 is not used, GCC optimizes for the processor specified by -march. By using -march and -mtune together, it's possible to generate code that runs on a family of processors, but optimize the code for one particular member of that family. iconic ๐ŸŒˆ

Okay so -mtune also sets up the macros _MIPS_TUNE and _MIPS_TUNE_foo ๐ŸŽ€. They work exactly like the -march ones we just went over โœจ

  • -mips1 โ€” same as -march=mips1 ๐ŸŒธ
  • -mips2 โ€” same as -march=mips2 ๐ŸŒธ
  • -mips3 โ€” same as -march=mips3 ๐ŸŒธ
  • -mips4 โ€” same as -march=mips4 ๐ŸŒธ
  • -mips32 โ€” same as -march=mips32 ๐ŸŒธ
  • -mips32r3 โ€” same as -march=mips32r3 ๐ŸŒธ
  • -mips32r5 โ€” same as -march=mips32r5 ๐ŸŒธ
  • -mips32r6 โ€” same as -march=mips32r6 ๐ŸŒธ
  • -mips64 โ€” same as -march=mips64 ๐ŸŒธ
  • -mips64r2 โ€” same as -march=mips64r2 ๐ŸŒธ
  • -mips64r3 โ€” same as -march=mips64r3 ๐ŸŒธ
  • -mips64r5 โ€” same as -march=mips64r5 ๐ŸŒธ
  • -mips64r6 โ€” same as -march=mips64r6 ๐ŸŒธ

  • -mips16, -mno-mips16 โ€” Turns MIPS16 code generation on (or off) ๐Ÿงš If GCC is targeting a MIPS32 or MIPS64 architecture, it uses the MIPS16e ASE.

You can also control MIPS16 on a per-function basis with the mips16 and nomips16 attributes ๐Ÿ’…

  • -mflip-mips16 โ€” Generates MIPS16 code on alternating functions ๐Ÿฆ‹ This one exists for regression testing of mixed MIPS16/non-MIPS16 code generation.
โš ๏ธ This is not meant for ordinary use when compiling your own code, bestie ๐Ÿ™ˆ
  • -minterlink-compressed, -mno-interlink-compressed โ€” Requires (or doesn't require) that code using the standard (uncompressed) MIPS ISA be link-compatible with MIPS16 and microMIPS code, and the other way around ๐Ÿ”—

Like, code using the standard ISA encoding can't jump straight into MIPS16 or microMIPS code ๐Ÿ’€ It has to use a call or an indirect jump instead. So -minterlink-compressed turns off direct jumps unless GCC knows the jump target isn't compressed.

  • -minterlink-mips16, -mno-interlink-mips16 โ€” These are just aliases of -minterlink-compressed and -mno-interlink-compressed ๐Ÿซถ They're older than the microMIPS ASE and only stuck around for backwards compatibility.

  • -mabi=32, -mabi=o64, -mabi=n32, -mabi=64, -mabi=eabi โ€” Generates code for the ABI you pick ๐Ÿ‘‘

The EABI comes in a 32-bit and a 64-bit flavour ๐ŸŒˆ GCC usually makes 64-bit code when you pick a 64-bit architecture, but you can use -mgp32 if you want 32-bit code instead.

For the O64 ABI deets, check out http://gcc.gnu.org/projects/mipso64-abi.html ๐Ÿ“–

GCC also supports a version of the o32 ABI where the floating-point registers are 64 bits wide instead of 32 โœจ You can get this combo with -mabi=32 -mfp64. It leans on the mthc1 and mfhc1 instructions, so it's only supported on MIPS32R2, MIPS32R3 and MIPS32R5 processors. Be careful with that one ๐Ÿ™ƒ

The argument and return value registers stay the same, but each scalar value gets passed in one 64-bit register instead of a pair of 32-bit ones. For example, scalar floating-point values come back in $f0 only, not a $f0/$f1 pair ๐Ÿ’– The call-saved registers are the same too, in that the even-numbered double-precision registers get saved.

Two more o32 variants exist to help you move from 32-bit to 64-bit registers ๐Ÿฆ‹ They're FPXX (-mfpxx) and FP64A (-mfp64 -mno-odd-spreg). The FPXX one means all code has to run correctly with either 32-bit or 64-bit registers ๐Ÿงฉ It can link with FP32 or FP64 code, but not both at once. FP64A is similar to FP64 but doesn't allow odd-numbered single-precision registers. It pairs well with the "FRE" mode of FPUs on MIPS32R5 processors, and lets FP32 and FP64A code link together and run in the same process without switching FPU modes ๐Ÿ”ฅ

  • -mabicalls, -mno-abicalls โ€” Generates (or doesn't generate) code that's suitable for SVR4-style dynamic objects ๐ŸŒˆ -mabicalls is the default on SVR4-based systems.
  • -mshared, -mno-shared โ€” Generates (or doesn't generate) code that's fully position-independent, so it can be linked into shared libraries ๐Ÿ’œ This option only affects -mabicalls.

Traditionally all -mabicalls code has been position-independent, no matter what you pass like -fPIC or -fpic ๐Ÿ™„ But as an extension, the GNU toolchain lets executables use absolute accesses for locally-binding symbols. It can also use shorter GP initialization sequences and generate direct calls to locally-defined functions. -mno-shared is how you turn that mode on ๐Ÿง 

โš ๏ธ -mno-shared needs binutils 2.16 or higher, and the objects it makes can only be linked by the GNU linker. The good news is it doesn't change the ABI of the final executable, only the ABI of relocatable objects. Using -mno-shared usually makes executables both smaller and quicker ๐Ÿƒโ€โ™€๏ธ

-mshared is the default โœจ

  • -mplt, -mno-plt โ€” Assumes (or doesn't assume) that the static and dynamic linkers support PLTs and copy relocations ๐ŸŽฏ This only affects -mno-shared -mabicalls. For the n64 ABI, this option does nothing without -msym32.

You can make -mplt the default by configuring GCC with --with-mips-plt. Otherwise the default is -mno-plt ๐Ÿ’…

  • -mxgot, -mno-xgot โ€” Lifts (or doesn't lift) the usual size limits on the global offset table ๐Ÿ“ฆ

GCC normally uses a single instruction to load values from the GOT. It's pretty efficient, but it only works if the GOT is smaller than about 64k. Anything bigger and the linker will throw an error like this:

relocation truncated to fit: R_MIPS_GOT16 foobar

If you see that, recompile your code with -mxgot ๐Ÿซ  It works with really huge GOTs, though the code is less efficient since it takes three instructions to fetch the value of a global symbol.

Some linkers can make multiple GOTs. If yours does, you should only need -mxgot when one object file accesses more than 64k's worth of GOT entries. Very few linkers do this ๐Ÿคทโ€โ™€๏ธ

These options do nothing unless GCC is generating position-independent code ๐Ÿ™ˆ

  • -mgp32 โ€” Assumes general-purpose registers are 32 bits wide ๐ŸŽ€
  • -mgp64 โ€” Assumes general-purpose registers are 64 bits wide ๐ŸŽ€
  • -mfp32 โ€” Assumes floating-point registers are 32 bits wide ๐ŸŽ€
  • -mfp64 โ€” Assumes floating-point registers are 64 bits wide ๐ŸŽ€
  • -mfpxx โ€” Doesn't assume anything about how wide the floating-point registers are ๐Ÿคทโ€โ™€๏ธ
  • -mhard-float โ€” Uses the floating-point coprocessor instructions ๐Ÿ”ฅ
  • -msoft-float โ€” Doesn't use the floating-point coprocessor instructions. Floating-point math is done with library calls instead ๐Ÿ“š
  • -mno-float โ€” Same as -msoft-float, but it also promises that the program doesn't do any floating-point operations at all ๐Ÿคž This is only supported on some bare-metal MIPS configurations, where it might pick a special set of libraries with zero floating-point support. That includes stuff like the floating-point printf formats.
๐Ÿ’€ If code compiled with -mno-float accidentally has floating-point operations in it, it'll probably crash with a link-time or run-time failure.
  • -msingle-float โ€” Assumes the floating-point coprocessor only does single-precision operations ๐Ÿ”น
  • -mdouble-float โ€” Assumes the floating-point coprocessor does double-precision operations. This is the default ๐Ÿ‘‘
  • -modd-spreg, -mno-odd-spreg โ€” Enables (or disables) using odd-numbered single-precision floating-point registers for the o32 ABI ๐Ÿงฉ Odd registers are the default on processors known to support them. When you use the o32 FPXX ABI, -mno-odd-spreg is set by default.
  • -mabs=2008, -mabs=legacy โ€” These control how special not-a-number (NaN) IEEE 754 floating-point data gets handled by the abs.fmt and neg.fmt machine instructions ๐ŸŒ€

By default, or with -mabs=legacy, you get the legacy treatment. Here those instructions count as arithmetic and get avoided wherever correct behaviour matters and the input might be a NaN ๐Ÿ™…โ€โ™€๏ธ Instead, a longer sequence of instructions that fiddles with the sign bit by hand gets used, unless -ffinite-math-only is also specified.

-mabs=2008 gives you the IEEE 754-2008 treatment. Now those instructions count as non-arithmetic, so they work correctly in every case, including when the input is a NaN. They get used for the matching operations every time ๐Ÿ’–

  • -mnan=2008, -mnan=legacy โ€” These control how special not-a-number (NaN) IEEE 754 floating-point data is encoded ๐ŸŒธ

-mnan=legacy picks the legacy encoding. Here quiet NaNs (qNaNs) have the first bit of their trailing significand field set to 0, and signaling NaNs (sNaNs) have it set to 1.

-mnan=2008 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 โ€” Uses (or doesn't use) the ll, sc, and sync instructions to build the atomic memory built-in functions โš›๏ธ If you don't specify either, GCC uses those instructions as long as the target architecture supports them.

-mllsc is handy if the runtime environment can emulate the instructions, and -mno-llsc can help when you're compiling for nonstandard ISAs ๐Ÿงช You can make either one the default by configuring GCC with --with-llsc or --without-llsc. --with-llsc is already the default for some configurations, so check the installation docs for the details ๐Ÿ“–

  • -mdsp, -mno-dsp โ€” Uses (or doesn't use) revision 1 of the MIPS DSP ASE ๐ŸŽถ This defines the preprocessor macro __mips_dsp, and also sets __mips_dsp_rev to 1.
  • -mdspr2, -mno-dspr2 โ€” Uses (or doesn't use) revision 2 of the MIPS DSP ASE ๐ŸŽถ This defines the preprocessor macros __mips_dsp and __mips_dspr2, and also sets __mips_dsp_rev to 2.

Okay bestie, the MIPS options keep going and they are a LOT ๐Ÿ’…๐ŸŒธ Let's get into it.

  • -msmartmips, -mno-smartmips โ€” โœจ Turn the MIPS SmartMIPS ASE on or off. -msmartmips uses it, -mno-smartmips skips it ๐Ÿงš
  • -mpaired-single, -mno-paired-single โ€” ๐Ÿฆ‹ Use or skip the paired-single floating-point instructions. Heads up, this one needs hardware floating-point support turned on too, so it won't work without it ๐Ÿ˜ญ
  • -mdmx, -mno-mdmx โ€” ๐ŸŽ€ Use or skip the MIPS Digital Media Extension instructions. Two things to know: it only works when you're generating 64-bit code, and it also needs hardware floating-point support enabled ๐Ÿ’–
  • -mips3d, -mno-mips3d โ€” ๐ŸŒˆ Use or skip the MIPS-3D ASE. Fun fact, -mips3d automatically implies -mpaired-single, so you're getting that one too ๐Ÿซถ
  • -mmicromips, -mno-micromips โ€” ๐Ÿ“ Generate or don't generate microMIPS code. You can also control this one per function with the "micromips" and "nomicromips" attributes, which is so precise it's giving ๐Ÿ‘‘
  • -mmt, -mno-mt โ€” ๐Ÿงต Use or skip the MT Multithreading instructions โœจ
  • -mmcu, -mno-mcu โ€” ๐Ÿ”ง Use or skip the MIPS MCU ASE instructions ๐Ÿ’…
  • -meva, -mno-eva โ€” ๐Ÿ—บ๏ธ Use or skip the MIPS Enhanced Virtual Addressing instructions ๐ŸŒธ
  • -mvirt, -mno-virt โ€” ๐Ÿ–ฅ๏ธ Use or skip the MIPS Virtualization (VZ) instructions ๐Ÿ’œ
  • -mxpa, -mno-xpa โ€” ๐Ÿ“ Use or skip the MIPS eXtended Physical Address (XPA) instructions ๐Ÿฆ‹
  • -mcrc, -mno-crc โ€” ๐Ÿงฎ Use or skip the MIPS Cyclic Redundancy Check (CRC) instructions ๐ŸŒŸ
  • -mginv, -mno-ginv โ€” ๐Ÿงน Use or skip the MIPS Global INValidate (GINV) instructions โœจ
  • -mloongson-mmi, -mno-loongson-mmi โ€” ๐ŸŽถ Use or skip the MIPS Loongson MultiMedia extensions Instructions (MMI) ๐Ÿฉท
  • -mloongson-ext, -mno-loongson-ext โ€” ๐Ÿงฉ Use or skip the MIPS Loongson EXTensions (EXT) instructions ๐Ÿ’–
  • -mloongson-ext2, -mno-loongson-ext2 โ€” ๐Ÿงฉ Use or skip the MIPS Loongson EXTensions r2 (EXT2) instructions. The r2 upgrade, obsessed ๐Ÿ˜ญ

  • -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. Here's the default tea โ˜•:
    • Every supported ABI uses 32-bit "int"s.
    • The n64 ABI uses 64-bit "long"s, and so does the 64-bit EABI. Everyone else uses 32-bit "long"s.
    • Pointers match the size of "long"s, or the size of integer registers, whichever one 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 especially useful combined with -mabi=64 and -mno-abicalls, because GCC can then make shorter, faster references to symbolic addresses ๐Ÿš€
  • -G num โ€” ๐Ÿ“ฆ Stick externally-visible data definitions in a small data section, as long as the data is no bigger than num bytes. This lets GCC access the data more efficiently. Peep -mgpopt for the details ๐Ÿ‘€
    • The default -G value depends on your configuration ๐ŸŒธ
  • -mlocal-sdata, -mno-local-sdata โ€” ๐Ÿ  Extend (or don't extend) the -G behaviour to local data too, like static variables in C. -mlocal-sdata is the default for every configuration ๐Ÿ’…
    • If the linker starts complaining that your app is using too much small data, try rebuilding the less performance-critical parts with -mno-local-sdata ๐Ÿ˜ญ
    • Building large libraries with -mno-local-sdata is also a power move, since it leaves more room for the main program ๐Ÿ‘‘
  • -mextern-sdata, -mno-extern-sdata โ€” ๐ŸŒ Assume (or don't assume) that externally-defined data sits in a small data section, as long as its size fits within the -G limit. -mextern-sdata is the default for every configuration ๐Ÿซถ
โš ๏ธ Okay, this part is serious. If you compile a module Mod with -mextern-sdata -G num -mgpopt, and Mod references a variable Var no bigger than num bytes, you MUST make sure Var lands in a small data section. If another module defines Var, either compile that module with a high-enough -G setting or attach a "section" attribute to Var's definition. If Var is common, link the application with a high-enough -G setting. No skipping these rules, bestie ๐Ÿ’€
  • The easiest way to stay safe is to compile and link every module with the same -G option ๐Ÿง
  • If you're building a library that has to support several different small data limits, compile it with the highest supported -G setting. Then add -mno-extern-sdata so the library stops making assumptions about externally-defined data ๐Ÿฆ‹

  • -mgpopt, -mno-gpopt โ€” ๐ŸŽฏ Use (or don't use) GP-relative accesses for symbols that are known to live in a small data section. See -G, -mlocal-sdata and -mextern-sdata for the related stuff. -mgpopt is the default for every configuration ๐ŸŒˆ
    • -mno-gpopt is clutch when the $gp register might not hold the value of "_gp". For example, if your 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. (In those situations, the boot monitor itself is usually compiled with -G0.) ๐Ÿ–ฅ๏ธ
    • -mno-gpopt implies -mno-local-sdata and -mno-extern-sdata โœจ
  • -membedded-data, -mno-embedded-data โ€” ๐Ÿงธ Allocate variables to the read-only data section first if possible, then the small data section if possible, and otherwise to data. The code is slightly slower than the default, but it cuts down on the RAM needed while running, so some embedded systems might prefer it ๐Ÿ”‹
  • -muninit-const-in-rodata, -mno-uninit-const-in-rodata โ€” ๐Ÿ“– Put uninitialized "const" variables in the read-only data section. This only means something when you're also using -membedded-data ๐Ÿฉท

  • -mcode-readable=setting โ€” ๐Ÿ‘€ Tell GCC whether it's allowed to generate code that reads from executable sections. There are three possible settings, and I've got all the tea:
    • -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 is handy on 4KSc and 4KSd processors when the code TLBs have the Read Inhibit bit set. It's also useful on processors that can be set up with a dual instruction/data SRAM interface and that, like the M4K, automatically redirect PC-relative loads to the instruction RAM ๐Ÿฆ‹
    • -mcode-readable=no โ€” Instructions must NOT access executable sections. This can help on targets configured with a dual instruction/data SRAM interface that (unlike the M4K) don't automatically redirect PC-relative loads to the instruction RAM ๐Ÿ”ฅ
  • -msplit-addresses, -mno-split-addresses โ€” โœ‚๏ธ Enable (or disable) the use of the "%hi()" and "%lo()" assembler relocation operators. This has 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 handling 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"). Use -mdivide-traps to allow conditional traps on architectures that support them, and -mdivide-breaks to force the use of breaks ๐Ÿ˜ญ
    • The default is usually -mdivide-traps, but you can override that at configure time with --with-divide=breaks ๐Ÿ”ง
    • Divide-by-zero checks can be completely disabled with -mno-check-zero-division ๐Ÿ’€
  • -mload-store-pairs, -mno-load-store-pairs โ€” ๐Ÿ‘ฏ Enable (or disable) an optimization that pairs consecutive load or store instructions so they can do load/store bonding. It's on by default, but it only kicks in 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 โ€” ๐Ÿ“ž Disable (or don't disable) the use of the "jal" instruction. Calling functions with "jal" is more efficient, but it requires the caller and callee to be in the same 256 megabyte segment. This option has no effect on abicalls code. The default is -mno-long-calls ๐Ÿž๏ธ

  • -mmad, -mno-mad โ€” โœ–๏ธ Enable (or disable) the use of the "mad", "madu" and "mul" instructions, as provided by the R4650 ISA ๐ŸŽ€
  • -mimadd, -mno-imadd โ€” โž• Enable (or disable) the use of the "madd" and "msub" integer instructions. The default is -mimadd on architectures that support "madd" and "msub", except the 74k architecture, where it was found to generate slower code ๐Ÿข
  • -mfused-madd, -mno-fused-madd โ€” ๐Ÿง Enable (or disable) 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 gets calculated to infinite precision and is NOT subject to the FCSR Flush to Zero bit. That might be undesirable in some situations. On other processors, the result is numerically identical to the equivalent computation using separate multiply, add, subtract and negate instructions ๐Ÿค“

  • -nocpp โ€” ๐Ÿšซ Tell 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 errata (lost data on stores during refill). 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 it's executed immediately after starting an integer division. Be careful with that one, bestie ๐Ÿ˜ญ

Okay so the R4000 errata list is still going, bestie ๐ŸŒธ there are two more gremlins to know about:

  • A double-word or a variable shift can give a wrong answer if it runs while an integer multiplication is still in progress ๐Ÿ’€
  • An integer division can give a wrong answer if it starts in the delay slot of a taken branch or a jump ๐Ÿ™ˆ
  • -mfix-r4400, -mno-fix-r4400 โ€” Works around some R4400 CPU errata ๐ŸŽ€
    • A double-word or a variable shift can give a wrong answer if it runs right after an integer division starts ๐Ÿ˜ญ
  • -mfix-r10000, -mno-fix-r10000 โ€” Works around some R10000 errata ๐Ÿ’…
    • ll/sc sequences might not behave atomically on revisions before 3.0. On revisions 2.6 and earlier, they can deadlock ๐Ÿ’€

This option only works if the target architecture supports branch-likely instructions. -mfix-r10000 is the default when -march=r10000 is used, and -mno-fix-r10000 is the default otherwise โœจ

  • -mfix-r5900, -mno-fix-r5900 โ€” Stops GCC from scheduling the instruction before a branch into that branch's delay slot when the branch sits at the end of a short loop of six instructions or fewer. Instead, a nop always goes in there ๐Ÿฆ‹ The short loop bug can make loops run only once or twice because of a hardware bug in the R5900 chip. The assembler handles this workaround, not GCC ๐Ÿงš
  • -mfix-rm7000, -mno-fix-rm7000 โ€” Works around the RM7000 dmult/dmultu errata. The assembler does the workarounds, not GCC ๐Ÿ”ฅ
  • -mfix-vr4120, -mno-fix-vr4120 โ€” Works around some VR4120 errata ๐ŸŒˆ
    • dmultu doesn't always give the correct result ๐Ÿ˜ญ
    • div and ddiv don't always give the correct result if one of the operands is negative ๐Ÿ’€

The division workarounds rely on special functions in libgcc.a. Right now, those functions only come with the mips64vr*-elf configurations ๐Ÿซถ

The other VR4120 errata need a NOP inserted between certain pairs of instructions. The assembler takes care of those, not GCC itself ๐ŸŒธ

  • -mfix-vr4130 โ€” Works around the VR4130 mflo/mfhi errata. The assembler implements the workarounds rather than GCC, but GCC avoids using mflo and mfhi when the VR4130 macc, macchi, dmacc and dmacchi instructions are available instead โœจ
  • -mfix-sb1, -mno-fix-sb1 โ€” Works around certain SB-1 CPU core errata ๐Ÿ“ (This flag currently works around the SB-1 revision 2 "F1" and "F2" floating-point errata.)
  • -mr10k-cache-barrier=setting โ€” Decides whether GCC should insert cache barriers to avoid the side effects of speculation on R10K processors ๐Ÿ‘‘

Okay, so the R10K is kind of a drama queen. Like many processors, it tries to guess how a conditional branch will go and speculatively runs instructions from the "taken" branch. If the guess was wrong, it aborts those instructions. But on the R10K, even aborted instructions can leave side effects behind ๐Ÿ™ˆ

This only affects kernel stores and, depending on the system, kernel loads. For example, a speculatively executed store might pull the target memory into cache and mark the cache line as dirty, even if the store itself gets aborted later. If a DMA operation writes to the same memory before that dirty line gets flushed, the cached data overwrites the DMA'd data ๐Ÿ˜ญ The R10K processor manual has the full story, including other potential problems ๐Ÿ“–

One workaround is to insert cache barrier instructions before every memory access that might be speculatively executed and might have side effects even if aborted. -mr10k-cache-barrier=setting controls how GCC implements 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's the kernel's job to make sure speculative accesses to these regions really are safe ๐Ÿซถ

If the input program has a function declaration like this:

void foo (void);

then the implementation of foo must allow j foo and jal foo to run speculatively. GCC follows this rule for functions it compiles itself, and it expects non-GCC functions (like hand-written assembly) to do the same ๐Ÿ’œ

This 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 might have side effects even if aborted ๐Ÿฆ‹
  • -mr10k-cache-barrier=store โ€” Inserts a cache barrier before a store that might be speculatively executed and might have side effects even if aborted ๐ŸŽ€
  • -mr10k-cache-barrier=none โ€” Turns off cache barrier insertion. 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 call no such function ๐ŸŒธ If one is called, it has to take the same arguments as the common _flush_func: the address of the memory range being flushed, the size of that range, and the number 3 (to flush both caches). The default depends on the target GCC was configured for, but it's commonly either _flush_func or __cpu_flush โœจ
  • mbranch-cost=num โ€” Sets the cost of branches to roughly num "simple" instructions. This cost is only a heuristic, so it isn't guaranteed to give consistent results across releases ๐Ÿคทโ€โ™€๏ธ A zero cost just selects the default again, which is based on the -mtune setting ๐Ÿงš
  • -mbranch-likely, -mno-branch-likely โ€” Turns Branch Likely instructions on or off, no matter what the selected architecture's default is ๐Ÿ”ฅ By default, Branch Likely instructions can be generated if the selected architecture supports them. The exception is the MIPS32 and MIPS64 architectures, and processors that implement them. For those, Branch Likely instructions aren't generated by default, because MIPS32 and MIPS64 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 gets filled successfully. If the delay slot doesn't get filled, a compact branch is picked when one is available ๐Ÿซถ
  • -mcompact-branches=always โ€” Makes sure a compact branch instruction is generated whenever one is available. If none is available, a delay slot form of the branch gets used instead ๐Ÿ‘‘

The default is -mcompact-branches=optimal. This option is supported from MIPS Release 6 onwards ๐ŸŒˆ

  • -mfp-exceptions, -mno-fp-exceptions โ€” Controls whether FP exceptions are enabled. This affects how FP instructions get scheduled on some processors. FP exceptions are enabled by default ๐Ÿ’–

For instance, on the SB-1, if FP exceptions are disabled and GCC is emitting 64-bit code, both FP pipes can be used. Otherwise, only one FP pipe can be used ๐Ÿฆ‹

  • -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 on, GCC aligns pairs of instructions it thinks should run in parallel ๐ŸŽ€

This option only does something when optimizing for the VR4130. It usually makes code faster, but the tradeoff is that the code gets bigger ๐Ÿ“ It's turned on by default at optimization level -O3 โœจ

  • -msynci, -mno-synci โ€” Enables or disables generating synci instructions on architectures that support them. When enabled, synci instructions are generated while __builtin___clear_cache is compiled ๐Ÿงš

-mno-synci is the default, but you can change that by configuring GCC with --with-synci ๐Ÿ”ฅ

Using synci is generally safe on single processor systems. On many multi-core (SMP) systems, though, it doesn't invalidate the instruction caches on all cores and may lead to undefined behavior ๐Ÿ’€

  • -mrelax-pic-calls, -mno-relax-pic-calls โ€” Tries to turn PIC calls that normally go through 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, the assembler and linker can do this optimization on their own, without help from the compiler ๐Ÿซถ

  • -mmcount-ra-address, -mno-mcount-ra-address โ€” Emits (or doesn't emit) code that lets _mcount change the calling function's return address ๐ŸŒธ When enabled, this option extends the usual _mcount interface with a new ra-address parameter. It has type intptr_t * and is passed in register $12. _mcount can then change the return address by doing both of the following:
    • Returning the new address in register $31.
    • Storing the new address in *ra-address, if ra-address is nonnull.

The default is -mno-mcount-ra-address ๐Ÿ’…

  • -mframe-header-opt, -mno-frame-header-opt โ€” Enables (or disables) frame header optimization in the o32 ABI. With the o32 ABI, calling functions allocate 16 bytes on the stack for the called function to write out register arguments. When this optimization is enabled, it suppresses allocating the frame header if it can be determined that the header is unused ๐Ÿงš

This optimization is off by default at all optimization levels ๐Ÿ’œ

  • -mlxc1-sxc1, -mno-lxc1-sxc1 โ€” When applicable, enables (or disables) generating lwxc1, swxc1, ldxc1, and sdxc1 instructions. It's enabled by default โœจ๐ŸŒˆ
  • -mmadd4, -mno-madd4 โ€” okay so when it's applicable, -mmadd4 turns on the 4-operand madd.s, madd.d and related instructions ๐Ÿ’–. -mno-madd4 turns them off. They're enabled by default โœจ.

๐ŸŽ€ MMIX Options ๐ŸŽ€

These options are defined for the MMIX ๐Ÿฆ‹:

  • -mlibfuncs, -mno-libfuncs โ€” bestie, this one is iconic ๐Ÿ‘‘. -mlibfuncs tells the compiler that intrinsic library functions are being compiled, so all values get passed in registers no matter how big they are. -mno-libfuncs turns that off.
  • -mepsilon, -mno-epsilon โ€” -mepsilon generates floating-point comparison instructions that compare with respect to the rE epsilon register ๐Ÿงš. -mno-epsilon skips that.
  • -mabi=mmixware, -mabi=gnu โ€” -mabi=mmixware generates code where function parameters and return values are seen (in the called function) as registers $0 and up. -mabi=gnu goes with the GNU ABI instead, which uses global registers $231 and up ๐Ÿ’….
  • -mzero-extend, -mno-zero-extend โ€” when reading data from memory in sizes shorter than 64 bits, -mzero-extend uses zero-extending load instructions by default instead of sign-extending ones. -mno-zero-extend does not use them ๐ŸŒธ.
  • -mknuthdiv, -mno-knuthdiv โ€” -mknuthdiv makes the result of a division yielding a remainder have the same sign as the divisor. With the default, -mno-knuthdiv, the sign of the remainder follows the sign of the dividend. Both methods are arithmetically valid, but the latter is almost exclusively used ๐Ÿ™ˆ.
  • -mtoplevel-symbols, -mno-toplevel-symbols โ€” -mtoplevel-symbols prepends a : to all global symbols, so the assembly code can be used with the PREFIX assembly directive. -mno-toplevel-symbols does not prepend it โœจ.
  • -melf โ€” generates an executable in the ELF format, instead of the default mmo format used by the mmix simulator ๐Ÿฆ‹.
  • -mbranch-predict, -mno-branch-predict โ€” -mbranch-predict uses the probable-branch instructions when static branch prediction indicates a probable branch. -mno-branch-predict doesn't use them ๐Ÿ’œ.
  • -mbase-addresses, -mno-base-addresses โ€” -mbase-addresses generates code that uses base addresses, and -mno-base-addresses doesn't. 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. It generally leads to short and fast code, but the number of different data items that can be addressed is limited ๐Ÿฅบ. So a program that uses lots of static data may require -mno-base-addresses.
  • -msingle-exit, -mno-single-exit โ€” -msingle-exit forces generated code to have a single exit point in each function. -mno-single-exit does not force that ๐Ÿ“.

๐ŸŒˆ MN10300 Options ๐ŸŒˆ

These -m options are defined for Matsushita MN10300 architectures ๐Ÿ’…:

  • -mmult-bug โ€” generates code to avoid bugs in the multiply instructions for the MN10300 processors. This is the default ๐Ÿ›ก๏ธ.
  • -mno-mult-bug โ€” does not generate code to avoid those multiply bugs for the MN10300 processors.
  • -mam33 โ€” generates code using features specific to the AM33 processor ๐Ÿ”ฅ.
  • -mno-am33 โ€” does not generate code using AM33-specific features. This is the default.
  • -mam33-2 โ€” generates code using features specific to the AM33/2.0 processor โœจ.
  • -mam34 โ€” generates code using features specific to the AM34 processor ๐Ÿฆ‹.
  • -mtune=cpu-type โ€” uses the timing characteristics of the indicated CPU type when scheduling instructions. This does not change the targeted processor type, so it's just about timing ๐ŸŽ€. The CPU type must be one of mn10300, am33, am33-2 or am34.
  • -mreturn-pointer-on-d0 โ€” when generating a function that returns a pointer, the pointer is returned in both a0 and d0. Otherwise, the pointer is returned only in a0, and attempts to call such functions without a prototype result in errors ๐Ÿ˜ญ. This option is on by default, so use -mno-return-pointer-on-d0 to disable it.
  • -mno-crt0 โ€” does not link in the C run-time initialization object file ๐Ÿงš.
  • -mrelax โ€” tells the linker it should perform a relaxation optimization pass to shorten branches, calls and absolute memory addresses โญ. This option only has an effect when used on the command line for the final link step.
This option makes symbolic debugging impossible. ๐Ÿ’€
  • -mliw โ€” allows the compiler to generate Long Instruction Word instructions if the target is the AM33 or later. This is the default. This option defines the preprocessor macro __LIW__ ๐ŸŒธ.
  • -mno-liw โ€” does not allow the compiler to generate Long Instruction Word instructions. This option defines the preprocessor macro __NO_LIW__.
  • -msetlb โ€” allows the compiler to generate the SETLB and Lcc instructions if the target is the AM33 or later. This is the default. This option defines the preprocessor macro __SETLB__ ๐Ÿ’–.
  • -mno-setlb โ€” does not allow the compiler to generate SETLB or Lcc instructions. This option defines the preprocessor macro __NO_SETLB__.

๐Ÿฆ‹ Moxie Options ๐Ÿฆ‹

  • -meb โ€” generates big-endian code. This is the default for moxie-*-* configurations ๐Ÿ’œ.
  • -mel โ€” generates little-endian code ๐Ÿ“.
  • -mmul.x โ€” generates mul.x and umul.x instructions. This is the default for moxiebox-*-* configurations โœจ.
  • -mno-crt0 โ€” does not link in the C run-time initialization object file ๐Ÿงš.

๐Ÿ’– MSP430 Options ๐Ÿ’–

These options are defined for the MSP430 ๐ŸŒธ:

  • -masm-hex โ€” forces assembly output to always use hex constants. Normally such constants are signed decimals, but this option is available for testsuite and/or aesthetic purposes ๐ŸŽ€.
  • -mmcu= โ€” selects the MCU to target. This is used to create a C preprocessor symbol based upon the MCU name, converted to upper case and pre- and post-fixed with __. That symbol in turn is used by the msp430.h header file to select an MCU-specific supplementary header file ๐Ÿ‘‘.

The option also sets the ISA to use. If the MCU name is one that is known to only support the 430 ISA, then that is selected. Otherwise the 430X ISA is selected. A generic MCU name of msp430 can also be used to select the 430 ISA. Similarly, the generic msp430x MCU name selects the 430X ISA.

An MCU-specific linker script is also added to the linker command line. The script's name is the name of the MCU with .ld appended. So specifying -mmcu=xxx on the gcc command line defines the C preprocessor symbol __XXX__ and causes the linker to search for a script called xxx.ld ๐Ÿ”ฅ. This option is also passed on to the assembler.

  • -mwarn-mcu, -mno-warn-mcu โ€” -mwarn-mcu enables warnings about conflicts between the MCU name specified by the -mmcu option and the ISA set by the -mcpu option and/or the hardware multiply support set by the -mhwmult option. It also toggles warnings about unrecognized MCU names. -mno-warn-mcu turns those off. This option is on by default ๐Ÿ™ˆ.
  • -mcpu= โ€” specifies the ISA to use. Accepted values are msp430, msp430x and msp430xv2. This option is deprecated ๐Ÿ’€. The -mmcu= option should be used to select the ISA instead.
  • -msim โ€” links to the simulator runtime libraries and linker script. It overrides any scripts that would be selected by the -mmcu= option ๐Ÿงš.
  • -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 โ€” this option is passed to the assembler and linker, and allows the linker to perform certain optimizations that cannot be done until the final link โญ.
  • mhwmult= โ€” describes the type of hardware multiply supported by the target ๐Ÿ’œ. Accepted values are none for no hardware multiply, 16bit for the original 16-bit-only multiply supported by early MCUs, 32bit for the 16/32-bit multiply supported by later MCUs, and f5series for the 16/32-bit multiply supported by F5-series MCUs. A value of auto can also be given. This tells GCC to deduce the hardware multiply support based upon the MCU name provided by the -mmcu option. If no -mmcu option is specified, or if the MCU name is not recognized, then no hardware multiply support is assumed. auto is the default setting ๐Ÿซถ.

Hardware multiplies are normally performed by calling a library routine, which saves space in the generated code. When compiling at -O3 or higher, however, the hardware multiplier is invoked inline. That makes for bigger but faster code ๐Ÿ”ฅ.

The hardware multiply routines disable interrupts whilst running and restore the previous interrupt state when they finish. This makes them safe to use inside interrupt handlers as well as in normal code ๐Ÿ›ก๏ธ.

  • -minrt โ€” enables the use of a minimum runtime environment, with no static initializers or constructors. This is intended for memory-constrained devices ๐ŸŒธ. The compiler includes special symbols in some objects that tell the linker and runtime which code fragments are required.
  • -mcode-region=, -mdata-region= โ€” these options tell the compiler where to place functions and data that do not have one of the lower, upper, either or section attributes ๐Ÿ“. Possible values are lower, upper, either or any. The first three behave like the corresponding attribute. The fourth possible value, any, is the default, and it leaves placement entirely up to the linker script and how it assigns the standard sections (.text, .data, etc) to the memory regions.
  • -msilicon-errata= โ€” passes on a request to the assembler to enable the fixes for the named silicon errata ๐Ÿ”ง.
  • -msilicon-errata-warn= โ€” passes on a request to the assembler to enable warning messages when a silicon errata might need to be applied โš ๏ธ.

๐Ÿงš NDS32 Options ๐Ÿงš

These options are defined for NDS32 implementations โœจ:

  • -mbig-endian โ€” generates code in big-endian mode ๐Ÿ’œ.
  • -mlittle-endian โ€” generates code in little-endian mode ๐Ÿ“.
  • -mreduced-regs โ€” uses reduced-set registers for register allocation ๐ŸŒธ.
  • -mfull-regs โ€” uses full-set registers for register allocation ๐Ÿ‘‘.
  • -mcmov โ€” generates conditional move instructions ๐Ÿฆ‹.
  • -mno-cmov โ€” does not generate conditional move instructions.
  • -mext-perf โ€” generates performance extension instructions ๐Ÿ”ฅ.
  • -mno-ext-perf โ€” does not generate performance extension instructions.
  • -mext-perf2 โ€” generates performance extension 2 instructions ๐Ÿš€.
  • -mno-ext-perf2 โ€” does not generate performance extension 2 instructions.
  • -mext-string โ€” generates string extension instructions ๐ŸŽ€.
  • -mno-ext-string โ€” does not generate string extension instructions.
  • -mv3push โ€” generates v3 push25/pop25 instructions ๐Ÿ’….
  • -mno-v3push โ€” Bestie, this one is a hard pass ๐Ÿ™…โ€โ™€๏ธ It tells GCC not to generate the v3 push25/pop25 instructions. Ghosted ๐Ÿ‘ป
  • -m16-bit โ€” Main character move โœจ This makes GCC generate 16-bit instructions.
  • -mno-16-bit โ€” The opposite energy: GCC will not generate 16-bit instructions ๐Ÿ’€
  • -misr-vector-size=num โ€” You get to pick how big each interrupt vector is, and it has to be either 4 or 16. Those are the only two options, no cap ๐Ÿ”ฅ
  • -mcache-block-size=num โ€” Sets how big each cache block is. It has to be a power of 2 between 4 and 512 ๐Ÿงš
  • -march=arch โ€” This is where you name the target architecture ๐ŸŽ€
  • -mcmodel=code-model โ€” Pick your code model. It has to be one of these:
    • small โ€” All the data and read-only data segments have to live within 512KB of addressing space. The text segment has to stay within 16MB of addressing space ๐Ÿฆ‹
    • medium โ€” The data segment has to be within 512KB, but the read-only data segment can stretch out to 4GB of addressing space. The text segment should still stay within 16MB of addressing space ๐ŸŒธ
    • large โ€” All the text and data segments can be within 4GB of addressing space. Anything goes ๐Ÿ‘‘
  • -mctor-dtor โ€” Turns on the constructor/destructor feature ๐Ÿ’…
  • -mrelax โ€” Tells the linker to relax instructions ๐Ÿง˜

๐Ÿฆ‹ Nios II Options ๐Ÿฆ‹

These are the options for the Altera Nios II processor, so if that's your chip, this section is literally your whole vibe ๐Ÿ–ฅ๏ธ

  • -G num โ€” Anything global or static that's num bytes or smaller gets tucked into the small data or BSS sections instead of the normal data or BSS sections. The default value of num is 8 ๐Ÿ“
  • -mgpopt=option, -mgpopt, -mno-gpopt โ€” Okay, this one is a whole thing ๐Ÿ˜ญ It lets you generate (or not generate) GP-relative accesses. These are the option names it recognizes:
    • none โ€” Don't generate GP-relative accesses at all.
    • local โ€” Generate GP-relative accesses for small data objects that aren't external, weak, or uninitialized common symbols. You also get GP-relative addressing for objects you've explicitly placed in a small data section with a section attribute.
    • global โ€” Same as local, but also generates GP-relative accesses for small data objects that are external, weak, or common. If you go this route, you must make sure every part of your program (including libraries) is compiled with the same -G setting โš ๏ธ
    • data โ€” Generate GP-relative accesses for all data objects in the program. If you use this, the entire data and BSS segments of your program must fit in 64K of memory, and you must use an appropriate linker script to allocate them within the addressable range of the global pointer.
    • all โ€” Generate GP-relative addresses for function pointers as well as data pointers. If you use this, the entire text, data, and BSS segments of your program must fit in 64K of memory, and you must use an appropriate linker script to allocate them within the addressable range of the global pointer.

-mgpopt is equivalent to -mgpopt=local, and -mno-gpopt is equivalent to -mgpopt=none.

The default is -mgpopt except when -fpic or -fPIC is specified to generate position-independent code.

Note that the Nios II ABI does not permit GP-relative accesses from shared libraries.

You may need to specify -mno-gpopt explicitly when building programs that include large amounts of small data, including large GOT data sections. In this case, the 16-bit offset for GP-relative addressing may not be large enough to allow access to the entire small data section.

  • -mgprel-sec=regexp โ€” This one adds extra section names that can be reached via GP-relative addressing. It's most useful alongside section attributes on variable declarations and a custom linker script. The regexp is a POSIX Extended Regular Expression ๐Ÿง 

This option doesn't change how -G behaves. The sections you list are on top of the standard .sdata and .sbss small-data sections that -mgpopt already recognizes.

  • -mr0rel-sec=regexp โ€” This one names sections you can reach with a 16-bit offset from r0, which means 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, and the regexp is a POSIX Extended Regular Expression ๐ŸŒˆ

Unlike GP-relative addressing for small data, zero-based addressing is never generated by default, and there are no conventional section names used in standard linker scripts for sections in the low or high areas of memory.

  • -mel, -meb โ€” Generate little-endian (the default) or big-endian (experimental) code, respectively. Big-endian is still experimental, so be brave ๐Ÿซถ
  • -march=arch โ€” This is the name of the target Nios II architecture. GCC uses this name to figure out what kinds of instructions it can emit when generating assembly code. Permissible names are r1 and r2 ๐Ÿ’œ

The preprocessor macro __nios2_arch__ is available to your programs, with value 1 or 2, indicating the targeted ISA level.

  • -mbypass-cache, -mno-bypass-cache โ€” Forces every load and store instruction to always bypass the cache by using the I/O variants of the instructions. The default is not to bypass the cache ๐Ÿ™ˆ
  • -mno-cache-volatile, -mcache-volatile โ€” Volatile memory 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 โ€” Don't use the table-based fast divide for small numbers. The default is to use the fast divide at -O3 and above ๐Ÿ”ฅ
  • -mno-hw-mul, -mhw-mul, -mno-hw-mulx, -mhw-mulx, -mno-hw-div, -mhw-div โ€” Enable or disable the compiler emitting the mul, mulx, and div family of instructions. The default is to emit mul and not emit div and mulx ๐Ÿฆ‹
  • -mbmx, -mno-bmx, -mcdx, -mno-cdx โ€” Enable or disable generation of Nios II R2 BMX (bit manipulation) and CDX (code density) instructions. Enabling these also requires -march=r2. Since these are optional extensions to the R2 architecture, the default is not to emit them ๐ŸŒธ
  • -mcustom-insn=N, -mno-custom-insn โ€” Each -mcustom-insn=N option turns on 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 of making 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.

In addition, all of the following transfer instructions for internal registers X and Y must be provided to use any of the double-precision floating-point instructions.

Custom instructions taking two double-precision source operands expect the first operand in the 64-bit register X. The other operand (or only operand of a unary operation) is given to the custom arithmetic instruction with the least significant half in source register src1 and the most significant half in src2. A custom instruction that returns a double-precision result returns the most significant 32 bits in the destination register and the other half in 32-bit register Y. GCC automatically generates the necessary code sequences to write register X and/or read register Y when double-precision floating-point instructions are used.
  • fwrx โ€” Write src1 into the least significant half of X and src2 into the most significant half of X.
  • fwry โ€” Write src1 into Y.
  • frdxhi, frdxlo โ€” Read the most or least (respectively) significant half of X and store it in dest.
  • frdy โ€” Read the value of Y and store it into dest.

Note that you can gain more local control over generation of Nios II custom instructions by using the target("custom-insn=N") and target("no-custom-insn") function attributes or pragmas. It's giving precision ๐Ÿ’–

  • -mcustom-fpu-cfg=name โ€” This enables a predefined, named set of custom instruction encodings (see -mcustom-insn above). Currently, the following sets are defined:

-mcustom-fpu-cfg=60-1 is equivalent to: -mcustom-fmuls=252 -mcustom-fadds=253 -mcustom-fsubs=254 -fsingle-precision-constant ๐Ÿ’…

-mcustom-fpu-cfg=60-2 is equivalent to: -mcustom-fmuls=252 -mcustom-fadds=253 -mcustom-fsubs=254 -mcustom-fdivs=255 -fsingle-precision-constant ๐Ÿฆ‹

-mcustom-fpu-cfg=72-3 is equivalent to: -mcustom-floatus=243 -mcustom-fixsi=244 -mcustom-floatis=245 -mcustom-fcmpgts=246 -mcustom-fcmples=249 -mcustom-fcmpeqs=250 -mcustom-fcmpnes=251 -mcustom-fmuls=252 -mcustom-fadds=253 -mcustom-fsubs=254 -mcustom-fdivs=255 -fsingle-precision-constant ๐Ÿคฏ

Okay, bestie, the individual -mcustom-insn= assignments always beat whatever -mcustom-fpu-cfg= hands out, no matter where they sit on the command line. Order doesn't matter, so don't stress ๐Ÿซถ

Also, if you want local control over which FPU config a function uses, you can slap target("custom-fpu-cfg=name") on it as a function attribute or pragma. Main character energy ๐Ÿ‘‘โœจ

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= so you can point at the alternate startup code the HAL BSP brings along ๐ŸŒธ
  • -msmallc โ€” Links with a limited version of the C library, -lsmallc, instead of Newlib ๐ŸŽ€
  • -msys-crt0=startfile โ€” startfile is the name of the startfile (crt0) to use while linking. This only does anything together with -mhal ๐Ÿ’œ
  • -msys-lib=systemlib โ€” systemlib is 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 from a HAL BSP ๐Ÿ”ฅ

๐Ÿ’– Nvidia PTX Options ๐Ÿ’–

These options are defined for Nvidia PTX: ๐ŸŒˆ

  • -m32, -m64 โ€” Generates code for the 32-bit or 64-bit ABI ๐Ÿ’…
  • -misa=ISA-string โ€” Generates code for the PTX ISA you specify (like sm_35). ISA strings have to be lower-case, and valid ones include sm_30 and sm_35. The default ISA is sm_30 ๐Ÿ“
  • -mmainkernel โ€” Links in code for a __main kernel. This is for stand-alone execution instead of offloading ๐Ÿงš
  • -moptimize โ€” Applies partitioned execution optimizations. This is the default whenever any level of optimization is selected โœจ
  • -msoft-stack โ€” Generates code that doesn't use ".local" memory directly for stack storage. Instead, a per-warp stack pointer gets maintained explicitly. This unlocks 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. OpenMP offloading uses this code generation variant, but the option is exposed on its own so you can test the compiler. If you want code that's suitable for linking into programs using OpenMP offloading, use -mgomp instead ๐Ÿฆ‹
  • -muniform-simt โ€” Switches to a code generation variant that lets every thread in each warp execute, while keeping memory state and side effects the same as if only one thread in each warp was active outside of OpenMP SIMD regions. All atomic operations and calls to the runtime (malloc, free, vprintf) run conditionally (iff the current lane index equals the master lane index), and the register being assigned gets copied from the master lane via a shuffle instruction. Outside of SIMD regions, lane 0 is the master. Inside them, each thread sees itself as the master. The shared memory array "int __nvptx_uni[]" stores all-zeros or all-ones bitmasks for each warp, which tells you the current mode (0 outside of SIMD regions). Each thread can bitwise-and the bitmask at position "tid.y" with the current lane index to compute the master lane index ๐Ÿค“
  • -mgomp โ€” Generates code for OpenMP offloading. It enables -msoft-stack and -muniform-simt, and selects the matching multilib variant ๐Ÿ‘‘

๐ŸŒธ OpenRISC Options ๐ŸŒธ

These options are defined for OpenRISC: ๐Ÿ’œ

  • -mboard=name โ€” Configures a board-specific runtime. This gets passed to the linker for newlib board library linking. The default is "or1ksim" ๐ŸŽ€
  • -mnewlib โ€” For compatibility, it's always newlib for elf now ๐Ÿ’…
  • -mhard-div โ€” Generates code for hardware that supports divide instructions. This is the default โœจ
  • -mhard-mul โ€” Generates code for hardware that supports multiply instructions. This is also the default ๐Ÿ”ฅ
  • -mcmov โ€” Generates code for hardware that supports the conditional move (l.cmov) instruction ๐Ÿฆ‹
  • -mror โ€” Generates code for hardware that supports rotate right instructions ๐ŸŒˆ
  • -msext โ€” Generates code for hardware that supports sign-extension instructions ๐Ÿ“
  • -msfimm โ€” Generates code for hardware that supports set flag immediate (l.sf*i) instructions ๐Ÿงš
  • -mshftimm โ€” Generates code for hardware that supports shift-immediate-related instructions (i.e. "l.srai", "l.srli", "l.slli", "1.rori"). Heads up: to get the l.rori instruction generated, you also need -mror ๐Ÿ™ˆ
  • -msoft-div โ€” Generates code for hardware that needs divide instruction emulation ๐Ÿ’€
  • -msoft-mul โ€” Generates code for hardware that needs multiply instruction emulation ๐Ÿ’€

๐ŸŽ€ 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 โ€” Target has split instruction and data space. Implies -m45 ๐Ÿ’œ
  • -munix-asm โ€” Uses Unix assembler syntax ๐Ÿค“
  • -mdec-asm โ€” Uses DEC assembler syntax ๐ŸŒธ
  • -mgnu-asm โ€” Uses GNU assembler syntax. This is the default ๐Ÿ’…
  • -mlra โ€” Uses the new LRA register allocator. By default, the old "reload" allocator is used ๐ŸŽ€

๐Ÿฆ‹ picoChip Options ๐Ÿฆ‹

These -m options are defined for picoChip implementations: ๐Ÿ’–

  • -mae=ae_type โ€” Sets the instruction set, register set, and instruction scheduling parameters for array element type ae_type. Supported values for ae_type are ANY, MUL, and MAC.

-mae=ANY selects a completely generic AE type. Code generated with this option runs on any of the other AE types. It's not as efficient as code 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 use a symbol name directly as an address in a load/store instruction, without loading it into a register first. This usually makes bigger programs that run faster than without the option. The results vary from program to program, though, so it's left as a user option instead of being permanently enabled ๐Ÿงš
  • -mno-inefficient-warnings โ€” Disables warnings about generating inefficient code. These warnings can show up when you compile code that does byte-level memory operations on the MAC AE type. The MAC AE has no hardware support for byte-level memory operations, so every byte load/store has to be synthesized from word load/store operations. That's inefficient, so GCC warns you to rewrite the code to avoid byte operations, or to target an AE type with the necessary hardware support. This option turns those warnings off ๐Ÿ™ˆ

๐ŸŒˆ PowerPC Options ๐ŸŒˆ

These are listed under

๐Ÿ“ RISC-V Options ๐Ÿ“

These command-line options are defined for RISC-V targets: ๐Ÿซถ

  • -mbranch-cost=n โ€” Sets the cost of branches to roughly n instructions ๐Ÿ’…
  • -mplt, -mno-plt โ€” When generating PIC code, these control whether PLTs are allowed. They're ignored for non-PIC. The default is -mplt ๐Ÿฆ‹
  • -mabi=ABI-string โ€” Specifies the integer and floating-point calling convention. ABI-string has two parts: the size of integer types, and the registers used for floating-point types. For example, -march=rv64ifd -mabi=lp64d means that long and pointers are 64-bit (implicitly making int 32-bit), and that floating-point values up to 64 bits wide get passed in F registers. Compare that with -march=rv64ifd -mabi=lp64f, which still lets the compiler generate code using the F and D extensions, but only allows floating-point values up to 32 bits long to be passed in registers. Or -march=rv64ifd -mabi=lp64, where no floating-point arguments get passed in registers at all ๐Ÿงš

The default for this argument is system dependent, so users who want a specific calling convention should specify one explicitly. The valid calling conventions are: ilp32, ilp32f, ilp32d, lp64, lp64f, and lp64d. Some calling conventions are impossible to implement on some ISAs. For example, -march=rv32if -mabi=ilp32d is invalid, because the ABI requires 64-bit values to be passed in F registers, but F registers are only 32 bits wide ๐Ÿ˜ญ There's also the ilp32e ABI, which can only be used with the rv32e architecture. This ABI isn't well specified at present, and it's subject to change ๐Ÿฅบ

  • -mfdiv, -mno-fdiv โ€” Do or don't use hardware floating-point divide and square root instructions. This requires the F or D extensions for floating-point registers. The default is to use them if the specified architecture has these instructions ๐Ÿ‘‘

โœจ RISC-V Options โœจ

  • -mdiv, -mno-div โ€” okay bestie, these decide whether hardware instructions get used for integer division ๐Ÿงฎ. -mdiv says yes, -mno-div says nah. This one needs the M extension. By default it uses them if the architecture you picked actually has them ๐Ÿ’…
  • -march=ISA-string โ€” tell GCC which RISC-V ISA to generate code for, like rv64im. ISA strings have to be lower-case (no caps, no cap ๐Ÿงข). Examples are rv64i, rv32g, rv32e, and rv32imaf ๐Ÿฆ‹
  • -mtune=processor-string โ€” optimize the output for a specific processor, named by its microarchitecture. The allowed values are rocket, sifive-3-series, sifive-5-series, sifive-7-series, and size ๐ŸŒˆ

If you don't specify -mtune=, the default is rocket ๐Ÿš€

Okay, the size choice is not really meant for end-users, so don't go picking it for fun ๐Ÿ™ˆ It gets used when -Os is specified. It overrides the instruction cost info from -mtune=, but it does not override the pipeline info. The vibe is smaller code that still performs well โœจ

  • -mpreferred-stack-boundary=num โ€” tries to keep the stack boundary aligned to a 2 raised to num byte boundary ๐Ÿ“š If you don't specify this, the default is 4, which is 16 bytes or 128-bits.
๐Ÿšจ Warning: if you use this switch, you have to build all modules with the same value, libraries included. That means the system libraries and startup modules too. No exceptions, bestie ๐Ÿ˜ญ
  • -msmall-data-limit=n โ€” puts global and static data smaller than n bytes into a special section (on some targets). Small data, special treatment ๐ŸŽ€
  • -msave-restore, -mno-save-restore โ€” -msave-restore uses smaller prologue and epilogue code that calls library functions. It's smaller but slower, so it's giving "tiny but sluggish" ๐Ÿข -mno-save-restore is the opposite. By default you get fast inline prologues and epilogues โšก
  • -mstrict-align, -mno-strict-align โ€” -mstrict-align means no unaligned memory accesses, and -mno-strict-align means you're allowed to do them. The default depends on whether your target processor supports fast unaligned access ๐Ÿง 
  • -mcmodel=medlow โ€” generates code for the medium-low code model ๐ŸŒ™ Your program and its statically defined symbols have to fit inside a single 2 GiB address range, 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 ๐ŸŒ Your program and its statically defined symbols just need to fit in any single 2 GiB address range. Static or dynamic linking both work โœจ
  • -mexplicit-relocs, -mno-exlicit-relocs โ€” -mexplicit-relocs uses assembler relocation operators when dealing with symbolic addresses. -mno-exlicit-relocs skips those and uses assembler macros instead, which can limit optimization ๐Ÿ™ƒ (Yes, that's how the spelling appears in the manpage, typo and all ๐Ÿ™ˆ)
  • -mrelax, -mno-relax โ€” -mrelax takes advantage of linker relaxations to cut down the number of instructions needed to materialize symbol addresses. The default is to take advantage of them ๐Ÿ’… -mno-relax turns that off.
  • -memit-attribute, -mno-emit-attribute โ€” -memit-attribute emits a RISC-V attribute that records extra info into ELF objects, and -mno-emit-attribute does not. This feature needs at least binutils 2.32 ๐Ÿ› ๏ธ

๐ŸŒธ RL78 Options ๐ŸŒธ

  • -msim โ€” links in extra target libraries so your code can run inside a simulator ๐Ÿ–ฅ๏ธ
  • -mmul=none, -mmul=g10, -mmul=g13, -mmul=g14, -mmul=rl78 โ€” picks which type of hardware multiplication and division support to use. The simplest, "none", uses software for both multiplying and dividing, and it's the default ๐Ÿง "g13" is for the hardware multiply/divide peripheral on the RL78/G13 (S2 core) targets. "g14" uses the multiplication and division instructions from the RL78/G14 (S3 core) parts. "rl78" is an alias for "g14", and "mg10" is an alias for "none" ๐Ÿ”ฅ

Also, a C preprocessor macro gets defined based on this setting. The possible values are "__RL78_MUL_NONE__", "__RL78_MUL_G13__", or "__RL78_MUL_G14__" ๐Ÿงš

  • -mcpu=g10, -mcpu=g13, -mcpu=g14, -mcpu=rl78 โ€” picks the RL78 core to target. The default is the G14 core, which is also called the S3 core or just RL78 ๐Ÿ‘‘ The G13 (or S2) core has no multiply or divide instructions. It uses a hardware peripheral for those jobs instead. The G10 (or S1) core has no register banks, so it uses a different calling convention ๐Ÿ’œ

If you set this option, it also picks the type of hardware multiply support, unless an explicit -mmul=none on the command line overrides it. So -mcpu=g13 turns on the G13 hardware multiply peripheral, and -mcpu=g10 turns off hardware multiplication altogether ๐Ÿซถ

๐Ÿ‘€ Note: the RL78/G14 core is the default target, but specifying -mcpu=g14 or -mcpu=rl78 on the command line does change how the toolchain behaves, because it also turns on G14 hardware multiply support. If you don't specify these 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 ๐Ÿฅน

Another C preprocessor macro gets defined based on this option. The possible values are "__RL78_G10__", "__RL78_G13__", or "__RL78_G14__" ๐ŸŒˆ

  • -mg10, -mg13, -mg14, -mrl78 โ€” these are aliases for the matching -mcpu= option. They're only around for backwards compatibility ๐Ÿ•ฐ๏ธ
  • -mallregs โ€” lets the compiler use all of the available registers ๐Ÿฆ‹ By default, r24..r31 are reserved for interrupt handlers. With this option on, those registers can be used in ordinary functions too ๐Ÿ’–
  • -m64bit-doubles, -m32bit-doubles โ€” makes the double data type 64 bits (-m64bit-doubles) or 32 bits (-m32bit-doubles). The default is -m32bit-doubles ๐Ÿ“
  • -msave-mduc-in-interrupts, -mno-save-mduc-in-interrupts โ€” -msave-mduc-in-interrupts says interrupt handler functions should preserve the MDUC registers. You only need this if normal code might touch the MDUC registers, for example because it does multiplication and division โœจ By default the MDUC registers get ignored, which keeps the interrupt handlers faster โšก To make this work, you need to pass the target option -mg13, since this feature is only available on the G13 target (S2 core). The MDUC registers only get saved if the interrupt handler does a multiplication or division, or calls another function ๐Ÿซถ

๐ŸŽ€ IBM RS/6000 and PowerPC Options ๐ŸŽ€

These -m options are defined for the IBM RS/6000 and PowerPC ๐ŸŒธ

  • -mpowerpc-gpopt, -mno-powerpc-gpopt โ€” tells GCC which instructions your processor has access to ๐Ÿง 
  • -mpowerpc-gfxopt, -mno-powerpc-gfxopt โ€” same vibe, for the optional instructions ๐Ÿ’…
  • -mpowerpc64, -mno-powerpc64 โ€” 64-bit goodies ๐ŸŒˆ
  • -mmfcrf, -mno-mfcrf โ€” ๐Ÿ”
  • -mpopcntb, -mno-popcntb โ€” โœจ
  • -mpopcntd, -mno-popcntd โ€” ๐Ÿ’œ
  • -mfprnd, -mno-fprnd โ€” ๐Ÿง
  • -mcmpb, -mno-cmpb โ€” ๐Ÿ“
  • -mmfpgpr, -mno-mfpgpr โ€” ๐Ÿฆ‹
  • -mhard-dfp, -mno-hard-dfp โ€” ๐Ÿ‘‘

You use these options to specify which instructions are available on the processor you're using ๐Ÿซถ The default value of these options gets determined when GCC is configured. Specifying -mcpu=cpu_type overrides these options. We recommend using -mcpu=cpu_type instead of the options listed above, bestie ๐Ÿ’–

Specifying -mpowerpc-gpopt lets GCC use the optional PowerPC architecture instructions in the General Purpose group, including floating-point square root โœจ Specifying -mpowerpc-gfxopt lets GCC use the optional instructions in the Graphics group, including floating-point select ๐ŸŽจ

The -mmfcrf option lets GCC generate the move from condition register field instruction. It's implemented on the POWER4 processor and other processors that support the PowerPC V2.01 architecture ๐Ÿงญ The -mpopcntb option lets GCC generate the popcount and double-precision FP reciprocal estimate instruction, which is implemented on the POWER5 processor and other processors that support the PowerPC V2.02 architecture ๐Ÿ”ข The -mpopcntd option lets GCC generate the popcount instruction, implemented on the POWER7 processor and other processors that support the PowerPC V2.06 architecture ๐Ÿ’ช The -mfprnd option lets GCC generate the FP round to integer instructions, implemented on the POWER5+ processor and other processors that support the PowerPC V2.03 architecture ๐ŸŒ€ The -mcmpb option lets GCC generate the compare bytes instruction, implemented on the POWER6 processor and other processors that support the PowerPC V2.05 architecture ๐Ÿซง The -mmfpgpr option lets GCC generate the FP move to/from general-purpose register instructions, implemented on the POWER6X processor and other processors that support the extended PowerPC V2.05 architecture ๐ŸŽ€ The -mhard-dfp option lets GCC generate the decimal floating-point instructions implemented on some POWER processors ๐ŸŒŸ

The -mpowerpc64 option lets GCC generate the additional 64-bit instructions found in the full PowerPC64 architecture, and treats GPRs as 64-bit, doubleword quantities ๐Ÿ’œ GCC defaults to -mno-powerpc64 ๐Ÿ™ˆ

  • -mcpu=cpu_type โ€” sets the architecture type, register usage, and instruction scheduling parameters for the machine type cpu_type ๐Ÿ–ฅ๏ธ The supported values for cpu_type are 401, 403, 405, 405fp, 440, 440fp, 464, 464fp, 476, 476fp, 505, 601, 602, 603, 603e, 604, 604e, 620, 630, 740, 7400, 7450, 750, 801, 821, 823, 860, 970, 8540, a2, e300c2, e300c3, e500mc, e500mc64, e5500, e6500, ec603e, G3, G4, G5, titan, power3, power4, power5, power5+, power6, power6x, power7, power8, power9, 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 architecture machine types ๐Ÿงš An appropriate, generic processor model gets assumed for scheduling purposes.

Specifying native as the cpu type detects the host processor of the system doing the compiling, and selects the architecture option that matches it ๐Ÿ” -mcpu=native has no effect if GCC doesn't recognize the processor, so no drama ๐Ÿซถ

The other options name a specific processor. Code generated under those options runs best on that processor, and it may not run at all on others ๐Ÿ˜ญ Choose wisely, bestie!

The -mcpu options automatically enable or disable the following options ๐Ÿ‘€:

Okay so the list of flags that -mcpu can switch on for a CPU keeps going, bestie ๐Ÿ’…

-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

The exact combo of options a CPU gets can change between compiler versions ๐Ÿ”„, because GCC picks whatever it thinks makes the best code for that chip. It is not a receipt of what the hardware can actually do ๐Ÿ™ˆ. Want to override one flag? Just put it after -mcpu, like -mcpu=970 -mno-altivec. Iconic move ๐Ÿ‘‘.

On AIX, -maltivec and -mpowerpc64 don't get flipped by -mcpu right now, because AIX doesn't fully support them yet ๐Ÿ˜ญ. You can still turn them on or off yourself if you're sure it'll work in your setup ๐Ÿซถ.

  • -mtune=cpu_type โ€” Sets up the instruction scheduling for the machine type cpu_type ๐ŸŽ€, but leaves the architecture and register usage alone (that's -mcpu=cpu_type's job). Same values as -mcpu work here. If you use both, the code uses the architecture and registers from -mcpu, but the scheduling comes from -mtune โœจ.
  • -mcmodel=small โ€” PowerPC64 code for the small model ๐Ÿงš. The TOC is capped at 64k.
  • -mcmodel=medium โ€” PowerPC64 code for the medium model ๐ŸŒธ. The TOC and other static data can total up to 4G. This is the default for 64-bit Linux ๐Ÿ’œ.
  • -mcmodel=large โ€” PowerPC64 code for the large model ๐ŸŒˆ. The TOC can be up to 4G. Other data and code are only limited by the 64-bit address space.
  • -maltivec, -mno-altivec โ€” Turns AltiVec instructions on or off ๐Ÿ’…, and also unlocks built-in functions for more direct access to the AltiVec instruction set. You might need -mabi=altivec too, to update the ABI with the AltiVec ABI enhancements ๐Ÿฆ‹.

When you use -maltivec, the element order for AltiVec intrinsics like "vec_splat", "vec_extract", and "vec_insert" matches the array element order for the target's endianness ๐Ÿง . On a big-endian target, element zero is the leftmost element in a vector register. On a little-endian target, element zero is the rightmost one.

  • -mvrsave, -mno-vrsave โ€” Generates VRSAVE instructions when making AltiVec code ๐ŸŒท.
  • -msecure-plt โ€” Makes code so ld and ld.so can build executables and shared libraries with non-executable ".plt" and ".got" sections ๐Ÿ”. This one's a PowerPC 32-bit SYSV ABI option.
  • -mbss-plt โ€” Uses a BSS ".plt" section that ld.so fills in ๐Ÿช„. It needs ".plt" and ".got" sections that are both writable and executable (a bit spicy ๐ŸŒถ๏ธ). This is also a PowerPC 32-bit SYSV ABI option.
  • -misel, -mno-isel โ€” Turns ISEL instruction generation on or off ๐ŸŽฏ.
  • -mvsx, -mno-vsx โ€” Makes code that does (or doesn't) use vector/scalar (VSX) instructions โšก. Turning it on also unlocks built-in functions for more direct access to the VSX instruction set ๐Ÿ’–.
  • -mcrypto, -mno-crypto โ€” Enables (or disables) 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) 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 โ€” Makes code that keeps some integer operations next to each other, so the instructions can fuse together on POWER8 and later processors ๐Ÿ”—. The -mno- version does not keep them together.
  • -mpower8-vector, -mno-power8-vector โ€” Makes code that does (or doesn't) use the vector and scalar instructions added in version 2.07 of the PowerPC ISA ๐Ÿฆ„. Turning it on also unlocks built-in functions for more direct access to the vector instructions ๐Ÿ’….
  • -mquad-memory, -mno-quad-memory โ€” Makes code that does (or doesn't) use the non-atomic quad word memory instructions ๐Ÿ“ฆ. -mquad-memory needs 64-bit mode, so don't skip that part ๐Ÿ™ˆ.
  • -mquad-memory-atomic, -mno-quad-memory-atomic โ€” Makes code that does (or doesn't) use the atomic quad word memory instructions โš›๏ธ. -mquad-memory-atomic also needs 64-bit mode ๐Ÿ’€.
  • -mfloat128, -mno-float128 โ€” Turns the __float128 keyword on or off for IEEE 128-bit floating point ๐ŸŒŸ, and picks either software emulation or hardware instructions for it ๐Ÿ› ๏ธ.

You need the VSX instruction set (-mvsx, -mcpu=power7, or -mcpu=power8), or -mcpu=power9, enabled to use IEEE 128-bit floating point support ๐Ÿซถ. This support only works on PowerPC Linux systems ๐Ÿง.

-mfloat128 is on by default on PowerPC Linux systems using the VSX instruction set, and off everywhere else ๐ŸŒˆ.

If you use the ISA 3.0 instruction set (-mpower9-vector or -mcpu=power9) on a 64-bit system, IEEE 128-bit floating point support also turns on generation of ISA 3.0 IEEE 128-bit floating point instructions ๐Ÿš€. Otherwise, if you don't ask for ISA 3.0 instructions, or you're targeting a 32-bit big endian system, IEEE 128-bit floating point gets done with software emulation ๐Ÿข.

  • -mfloat128-hardware, -mno-float128-hardware โ€” Turns ISA 3.0 hardware instructions on or off for supporting the __float128 data type ๐Ÿ”ง.

This one is on by default on PowerPC Linux systems using the ISA 3.0 instruction set, and off on other systems ๐Ÿ’œ.

  • -m32, -m64 โ€” Generates code for 32-bit or 64-bit environments on Darwin and SVR4 targets (including GNU/Linux) ๐Ÿ“. The 32-bit environment sets int, long, and pointer to 32 bits, and runs on any PowerPC variant ๐Ÿฆ‹. The 64-bit environment sets int to 32 bits, sets long and pointer to 64 bits, and generates code for PowerPC64, same as -mpowerpc64 โœจ.
  • -mfull-toc, -mno-fp-in-toc, -mno-sum-in-toc, -mminimal-toc โ€” These change how the TOC (Table Of Contents) gets made, and every executable file has one ๐Ÿ“–. -mfull-toc is the default. With it, GCC gives at least one TOC entry to each unique non-automatic variable reference in your program, and it also puts floating-point constants in the TOC ๐Ÿงพ. The catch is that only 16,384 entries fit in the TOC ๐Ÿ˜ญ.

If the linker yells that you've overflowed the available TOC space, you can shrink the TOC use 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 works out the sum of an address and a constant at run time, instead of stashing that sum in the TOC ๐Ÿงฎ. You can use one or both. Each one makes the code very slightly slower and bigger, but saves TOC space ๐Ÿ’….

If you still run out of TOC space with both of those, try -mminimal-toc ๐Ÿฅบ. It makes just one TOC entry for every file. The code gets slower and bigger, but it uses extremely little TOC space. You might only want it for files with less frequently-executed code ๐ŸŒ™.

  • -maix64, -maix32 โ€” Turns on the 64-bit AIX ABI and calling convention ๐Ÿ‘‘, with 64-bit pointers, a 64-bit "long" type, and the infrastructure needed to support them. -maix64 implies -mpowerpc64. -maix32 turns off the 64-bit ABI and implies -mno-powerpc64. GCC defaults to -maix32 ๐Ÿซง.
  • -mxl-compat, -mno-xl-compat โ€” Makes code that matches IBM XL compiler semantics more closely when you're using the AIX-compatible ABI ๐ŸŽ€. It does a few things:
    • It passes floating-point arguments to prototyped functions beyond the register save area (RSA) on the stack, in addition to argument FPRs.
    • It doesn't assume that the most significant double in a 128-bit long double value is properly rounded when comparing values and converting to double.
    • It uses XL symbol names for long double support routines.

The AIX calling convention got extended without being documented at first ๐Ÿ“œ, to handle an obscure K&R C case: calling a function that takes the address of its arguments with fewer arguments than it declares ๐Ÿ™ˆ. IBM XL compilers read floating-point arguments that don't fit in the RSA from the stack when a subroutine gets compiled without optimization. Always storing floating-point arguments on the stack is inefficient and rarely needed, so this option is off by default. You only need it when calling subroutines compiled by IBM XL compilers without optimization ๐Ÿซถ.

  • -mpe โ€” Supports the IBM RS/6000 SP Parallel Environment (PE) ๐Ÿ–ฅ๏ธ. It links an app that uses message passing with special startup code so the app can run ๐Ÿš€. The system needs PE installed in the standard location (/usr/lpp/ppe.poe/), or you have to override the specs file with -specs= to point at the right directory ๐Ÿ“‚. The Parallel Environment doesn't support threads, so -mpe and -pthread are incompatible ๐Ÿšซ.
  • -malign-natural, -malign-power โ€” On AIX, 32-bit Darwin, and 64-bit PowerPC GNU/Linux, -malign-natural overrides the ABI-defined alignment of bigger types (like floating-point doubles) and puts them on their natural size-based boundary ๐Ÿ“. -malign-power tells GCC to follow the ABI's alignment rules instead. GCC defaults to the standard alignment from the ABI ๐Ÿ’….

On 64-bit Darwin, natural alignment is the default, and -malign-power isn't supported there ๐Ÿ™…โ€โ™€๏ธ.

  • -msoft-float, -mhard-float โ€” Makes code that doesn't use (or does use) the floating-point register set ๐Ÿงฎ. If you use -msoft-float, software floating-point emulation gets provided, as long as you also pass the option to GCC when linking โš ๏ธ.
  • -mmultiple, -mno-multiple โ€” okay so these decide whether GCC generates code using the load multiple word and store multiple word instructions ๐Ÿ’… They're on by default for POWER systems and off for PowerPC systems. ๐Ÿซถ Bestie, don't use -mmultiple on little-endian PowerPC systems ๐Ÿ˜ญ those instructions don't work when the processor is in little-endian mode. The exceptions are PPC740 and PPC750, which are totally fine with them in little-endian mode โœจ
  • -mupdate, -mno-update โ€” this one is about the load or store instructions that update the base register to the address of the calculated memory location ๐Ÿฆ‹ They're on by default. Using -mno-update leaves a small window between the moment the stack pointer gets updated and the moment the address of the previous frame gets stored.
โš ๏ธ Because of that window, code that walks the stack frame across interrupts or signals may end up with corrupted data. Not a vibe ๐Ÿ’€
  • -mavoid-indexed-addresses, -mno-avoid-indexed-addresses โ€” this tells GCC to try to avoid (or, with the -mno- version, not avoid) indexed load or store instructions ๐ŸŒธ Those can cost you performance on Power6 processors in certain situations, like stepping through large arrays that cross a 16M boundary. It's enabled by default when targeting Power6 and disabled otherwise.
  • -mfused-madd, -mno-fused-madd โ€” these control whether GCC uses the floating-point multiply and accumulate instructions ๐Ÿ”ฅ They're generated by default if hardware floating point is being used. Fun fact: 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 control the half-word multiply and multiply-accumulate instructions on the IBM 405, 440, 464 and 476 processors ๐Ÿ“ They're generated by default when you're targeting those processors.
  • -mdlmzb, -mno-dlmzb โ€” these control the string-search dlmzb instruction on the IBM 405, 440, 464 and 476 processors ๐Ÿงš Same deal, it's generated by default when targeting those processors.
  • -mno-bit-align, -mbit-align โ€” on System V.4 and embedded PowerPC systems, these decide whether structures and unions containing bit-fields get forced to align to the base type of the bit-field ๐ŸŽ€ The -mno-bit-align version means "do not force it," and plain -mbit-align means "do force it."

By default, a structure with nothing but 8 "unsigned" bit-fields of length 1 gets aligned to a 4-byte boundary and ends up being 4 bytes in size. Slide in with -mno-bit-align though, and that same structure is aligned to a 1-byte boundary and is just 1 byte in size ๐Ÿคฏ

  • -mno-strict-align, -mstrict-align โ€” on System V.4 and embedded PowerPC systems, these say whether GCC should assume unaligned memory references are handled by the system ๐Ÿซ  -mno-strict-align means "do not assume that," and -mstrict-align means "do assume that."
  • -mrelocatable, -mno-relocatable โ€” these allow (or, with -mno-, do 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, which is a table of 32-bit addresses generated by this option. For this to work, all objects linked together must be compiled with -mrelocatable or -mrelocatable-lib. Also, -mrelocatable code aligns the stack to an 8-byte boundary ๐Ÿ“
  • -mrelocatable-lib, -mno-relocatable-lib โ€” this one is basically the cousin of -mrelocatable ๐Ÿฆ‹ It also generates a ".fixup" section so static executables can be relocated at run time, but it does not 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, these decide whether GCC assumes register 2 contains a pointer to a global area pointing to the addresses used in the program ๐Ÿง  -mno-toc says "nope, don't assume that," and -mtoc says "yes, assume it."
  • -mlittle, -mlittle-endian โ€” on System V.4 and embedded PowerPC systems, this compiles your code for the processor in little-endian mode ๐ŸŒŠ Also, -mlittle-endian is exactly the same as -mlittle, so pick whichever one your heart desires ๐Ÿ’œ
  • -mbig, -mbig-endian โ€” same energy as above, but on System V.4 and embedded PowerPC systems this compiles code for the processor in big-endian mode ๐Ÿ˜ And yep, -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 for shared libraries.
  • -msingle-pic-base โ€” this treats the register used for PIC addressing as read-only, instead of loading it in the prologue for each function โœจ The runtime system is responsible for initializing this register with an appropriate value before execution begins, so make sure it's on it ๐Ÿ‘‘
  • -mprioritize-restricted-insns=priority โ€” this one controls the priority given to dispatch-slot restricted instructions during the second scheduling pass โญ The priority argument takes the value 0, 1, or 2, which assigns no, highest, or 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 for which the latency is greater than or equal to number is costly.
  • -minsert-sched-nops=scheme โ€” this picks which NOP insertion scheme gets used during the second scheduling pass ๐Ÿงš The scheme argument takes one of these values:
    • no โ€” Don't insert NOPs.
    • pad โ€” Pad with NOPs any dispatch group that has vacant issue slots, according to the scheduler's grouping.
    • regroup_exact โ€” Insert NOPs to force costly dependent insns into separate groups. Insert exactly as many NOPs as needed to force an insn to a new group, according to the estimated processor grouping.
    • number โ€” Insert NOPs to force costly dependent insns into separate groups. Insert number NOPs to force an insn to a new group.
  • -mcall-sysv โ€” on System V.4 and embedded PowerPC systems, this compiles code using calling conventions that adhere to 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 shorthand for specifying both -mcall-sysv and -meabi options ๐ŸŽ€
  • -mcall-sysv-noeabi โ€” this one is shorthand for specifying both -mcall-sysv and -mno-eabi options ๐Ÿ™ˆ
  • -mcall-aixdesc โ€” on System V.4 and embedded PowerPC systems, this compiles code for the AIX operating system ๐Ÿฆ…
  • -mcall-linux โ€” on System V.4 and embedded PowerPC systems, this compiles code for the Linux-based GNU system ๐Ÿง
  • -mcall-freebsd โ€” on System V.4 and embedded PowerPC systems, this compiles code for the FreeBSD operating system ๐Ÿ˜ˆ
  • -mcall-netbsd โ€” on System V.4 and embedded PowerPC systems, this compiles code for the NetBSD operating system ๐ŸŒฟ
  • -mcall-openbsd โ€” on System V.4 and embedded PowerPC systems, this compiles code for the OpenBSD operating system ๐Ÿก
  • -mtraceback=traceback_type โ€” this selects the type of traceback table ๐Ÿ” Valid values for traceback_type are full, part, and no.
  • -maix-struct-return โ€” 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 ๐Ÿƒโ€โ™€๏ธ
  • -mabi=abi-type โ€” this extends the current ABI with a particular extension, or removes that extension ๐ŸŒธ Valid values are altivec, no-altivec, ibmlongdouble, ieeelongdouble, elfv1, and elfv2.
  • -mabi=ibmlongdouble โ€” this changes the current ABI to use 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 will issue a warning unless you use the -Wno-psabi option. It requires -mlong-double-128 to be enabled.
  • -mabi=ieeelongdouble โ€” this changes the current ABI to use 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 will issue a warning unless you use the -Wno-psabi option. It requires -mlong-double-128 to be enabled.
  • -mabi=elfv1 โ€” this changes the current ABI to the ELFv1 ABI ๐Ÿงพ It's the default ABI for big-endian PowerPC 64-bit Linux.
๐Ÿ’€ Overriding the default ABI requires special system support and is likely to fail in spectacular ways. Proceed with caution, bestie.
  • -mabi=elfv2 โ€” this changes the current ABI to the ELFv2 ABI ๐Ÿงพ It's the default ABI for little-endian PowerPC 64-bit Linux.
๐Ÿ’€ Same warning as above: overriding the default ABI requires special system support and is likely to fail in spectacular ways.
  • -mgnu-attribute, -mno-gnu-attribute โ€” these emit .gnu_attribute assembly directives to set tag/value pairs in a .gnu.attributes section, which specifies ABI variations in function parameters or return values ๐Ÿงฉ
  • -mprototype, -mno-prototype โ€” on System V.4 and embedded PowerPC systems, -mprototype assumes that all calls to variable argument functions are properly prototyped ๐Ÿฆ‹ Otherwise, the compiler has to insert an instruction before every non-prototyped call to set or clear bit 6 of the condition code register ("CR"), which indicates whether floating-point values are passed in the floating-point registers in case the function takes variable arguments. With -mprototype, only calls to prototyped variable argument functions set or clear that bit.
  • -msim โ€” on embedded PowerPC systems, this assumes the startup module is called sim-crt0.o and that the standard C libraries are libsim.a and libc.a ๐ŸŽฎ This is the default for powerpc-*-eabisim configurations.
  • -mmvme โ€” on embedded PowerPC systems, this assumes the startup module is called crt0.o and the standard C libraries are libmvme.a and libc.a ๐Ÿ•น๏ธ
  • -mads โ€” okay bestie, on embedded PowerPC ๐Ÿงš this one assumes your startup module is crt0.o and your standard C libraries are libads.a and libc.a ๐ŸŽ€
  • -myellowknife โ€” same main character energy, but the library swap is different ๐Ÿฆ‹ on embedded PowerPC, the startup module is still crt0.o, but the C libraries are now libyk.a and libc.a
  • -mvxworks โ€” tell GCC you're building for a VxWorks system ๐ŸŒธ this one works on System V.4 and embedded PowerPC systems
  • -memb โ€” on embedded PowerPC systems, this sets the PPC_EMB bit in the ELF flags header ๐Ÿ’œ which is how you signal that eabi extended relocations are being used
  • -meabi, -mno-eabi โ€” on System V.4 and embedded PowerPC systems, -meabi means you adhere to the Embedded Applications Binary Interface (EABI), a set of tweaks on top of the System V.4 specs ๐Ÿซถ -mno-eabi means you don't. Here's the lowkey important part:
    • With -meabi, the stack is aligned to an 8-byte boundary, a function __eabi gets called from main to set up the EABI environment, and the -msdata option can use both r2 and r13 to point to two separate small data areas.
    • With -mno-eabi, the stack is aligned to a 16-byte boundary, no EABI initialization function gets called from main, and the -msdata option only uses r13 to point to a single small data area.
    • -meabi 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, this gets organized super neatly ๐Ÿ“
    • Small initialized const global and static data goes in the .sdata2 section, which is pointed to by register r2.
    • Small initialized non-const global and static data goes in the .sdata section, which is pointed to by register r13.
    • Small uninitialized global and static data goes in the .sbss section, which sits right next to .sdata.
    • -msdata=eabi is incompatible with -mrelocatable, and it also turns on -memb.
  • -msdata=sysv โ€” on System V.4 and embedded PowerPC systems, small global and static data goes in the .sdata section, which is pointed to by register r13 ๐Ÿ’… small uninitialized global and static data goes in .sbss, right beside .sdata. Heads up: -msdata=sysv is incompatible with -mrelocatable.
  • -msdata=default, -msdata โ€” on System V.4 and embedded PowerPC systems, if -meabi is used, the code gets compiled the same as -msdata=eabi. Otherwise, it gets compiled the same as -msdata=sysv ๐Ÿ”ฅ
  • -msdata=data โ€” on System V.4 and embedded PowerPC systems, small global data goes in the .sdata section and small uninitialized global data goes in .sbss ๐ŸŒˆ the vibe here is that register r13 does not get used to address small data. This is the default behavior unless other -msdata options are used.
  • -msdata=none, -mno-sdata โ€” on embedded PowerPC systems, all initialized global and static data goes in the .data section, and all uninitialized data goes in the .bss section ๐Ÿงธ
  • -mreadonly-in-sdata โ€” read-only objects get put in the .sdata section too ๐Ÿ’– this is the default.
  • -mblock-move-inline-limit=num โ€” inlines all block moves (like calls to memcpy or structure copies) that are less than or equal to num bytes โญ the minimum value for num is 32 bytes on 32-bit targets and 64 bytes on 64-bit targets. The default is target-specific.
  • -mblock-compare-inline-limit=num โ€” generates non-looping inline code for all block compares (like calls to memcmp or structure compares) that are less than or equal to num bytes ๐Ÿ™ˆ if num is 0, all inline expansion of block compare is disabled, both the non-loop and loop kinds. The default is target-specific.
  • -mblock-compare-inline-loop-limit=num โ€” generates an inline expansion using loop code for all block compares that are less than or equal to num bytes, but greater than the limit for non-loop inline block compare expansion ๐Ÿฆ‹ if the block length isn't constant, at most num bytes get compared before memcmp is called to handle the remainder 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, global and static items that are less than or equal to num bytes get put into the small data or BSS sections instead of the normal data or BSS section ๐Ÿ‘‘ by default, num is 8. The -G num switch also gets passed to the linker. Iykyk, but all modules should be compiled with the same -G num value ๐Ÿ˜ญ
  • -mregnames, -mno-regnames โ€” on System V.4 and embedded PowerPC systems, this makes GCC emit register names in the assembly language output using symbolic forms (-mregnames), or not (-mno-regnames) ๐Ÿ’œ
  • -mlongcall, -mno-longcall โ€” by default, GCC assumes all calls are far away, so it uses a longer and more expensive calling sequence. This is required for calls farther than 32 megabytes (33,554,432 bytes) from the current location ๐Ÿ’€ a short call only gets generated if the compiler knows the call can't be that far away. 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's planned to add this feature to the GNU linker for 32-bit PowerPC systems as well.
    • On PowerPC64 ELFv2 and 32-bit PowerPC systems with newer GNU linkers, GCC can generate long calls using an inline PLT call sequence (see -mpltseq). PowerPC with -mbss-plt and PowerPC64 ELFv1 (big-endian) do not support inline PLT calls.
    • On Darwin/PPC systems, #pragma longcall generates jbsr callee, L42, plus a branch island (glue code). The two target addresses represent the callee and the branch island. The Darwin/PPC linker prefers the first address and generates bl callee if the PPC bl instruction reaches the callee directly. Otherwise, it generates bl L42 to call the branch island. The branch island gets appended to the body of the calling function, and it computes the full 32-bit address of the callee and jumps to it.
    • On Mach-O (Darwin) systems, this option tells the compiler to emit the glue for every direct call, and then the Darwin linker decides whether to use it or discard it.
    • In the future, GCC may ignore all longcall specifications when the linker is known to generate glue ๐Ÿ”ฎ
  • -mpltseq, -mno-pltseq โ€” implements (-mpltseq) or does not implement (-mno-pltseq) -fno-plt and long calls using an inline PLT call sequence. This supports lazy linking and long calls to functions in dlopen'd shared libraries โœจ inline PLT calls are only supported on PowerPC64 ELFv2 and 32-bit PowerPC systems with newer GNU linkers. They're enabled by default if the support is detected when configuring GCC, and, in the case of 32-bit PowerPC, only if GCC is configured with --enable-secureplt.
Watch out: -mpltseq code and -mbss-plt 32-bit PowerPC relocatable objects may not be linked together.
  • -mtls-markers, -mno-tls-markers โ€” marks (-mtls-markers) or does not mark (-mno-tls-markers) calls to __tls_get_addr with a relocation that specifies the function argument ๐ŸŽ€ this lets the linker reliably associate the function call with the argument setup instructions for TLS optimization, which in turn lets GCC schedule the sequence better.

  • -mrecip, -mno-recip โ€” this enables the use of the reciprocal estimate and reciprocal square root estimate instructions, with additional Newton-Raphson steps to boost precision, instead of doing a divide, or a square root and a divide, for floating-point arguments ๐Ÿง  you should use -ffast-math when using -mrecip, or at least -funsafe-math-optimizations, -ffinite-math-only, -freciprocal-math and -fno-trapping-math.
Heads up: while the throughput of the sequence is generally higher than the throughput of the non-reciprocal instruction, the precision of the sequence can drop by up to 2 ulp (i.e. the inverse of 1.0 equals 0.99999994) for reciprocal square roots ๐Ÿ’€
  • -mrecip=opt โ€” controls which reciprocal estimate instructions may be used ๐Ÿ’… opt is a comma-separated list of options, and any of them can be preceded by a ! to invert the option.
    • all โ€” enables all estimate instructions.
    • default โ€” enables the default instructions, which is the same as -mrecip.
    • none โ€” disables all estimate instructions, which is the same as -mno-recip.
    • div โ€” enables the reciprocal approximation instructions for both single and double precision.
    • divf โ€” enables the single-precision reciprocal approximation instructions.
    • divd โ€” enables the double-precision reciprocal approximation instructions.
    • rsqrt โ€” enables the reciprocal square root approximation instructions for both single and double precision.
    • rsqrtf โ€” enables the single-precision reciprocal square root approximation instructions.
    • rsqrtd โ€” enables the double-precision reciprocal square root approximation instructions.
    • So, for example, -mrecip=all,!rsqrtd enables all of the reciprocal estimate instructions except for the FRSQRTE, XSRSQRTEDP, and XVRSQRTEDP instructions, which handle the double-precision reciprocal square root calculations ๐ŸŒธ
  • -mrecip-precision, -mno-recip-precision โ€” assumes (-mrecip-precision) or does not assume (-mno-recip-precision) that the reciprocal estimate instructions provide higher-precision estimates than the PowerPC ABI mandates ๐Ÿ‘‘ selecting -mcpu=power6, -mcpu=power7 or -mcpu=power8 automatically selects -mrecip-precision. The double-precision square root estimate instructions aren't generated by default on low-precision machines, since they don't provide an estimate that converges after three steps ๐Ÿซถ
  • -mveclibabi=type โ€” okay so this one picks the ABI for vectorizing intrinsics through an external library ๐ŸŽ€ The only type that's supported right now is mass, which tells GCC to use IBM's Mathematical Acceleration Subsystem (MASS) libraries for vectorizing intrinsics with external libraries. GCC currently emits calls to the functions below when generating code for power7 โœจ
acosd2, acosf4, acoshd2, acoshf4, asind2, asinf4, asinhd2, asinhf4,
atan2d2, atan2f4, atand2, atanf4, atanhd2, atanhf4, cbrtd2, cbrtf4,
cosd2, cosf4, coshd2, coshf4, erfcd2, erfcf4, erfd2, erff4,
exp2d2, exp2f4, expd2, expf4, expm1d2, expm1f4, hypotd2, hypotf4,
lgammad2, lgammaf4, log10d2, log10f4, log1pd2, log1pf4, log2d2, log2f4,
logd2, logf4, powd2, powf4, sind2, sinf4, sinhd2, sinhf4,
sqrtd2, sqrtf4, tand2, tanf4, tanhd2, tanhf4

Both -ftree-vectorize and -funsafe-math-optimizations must also be enabled, and the MASS libraries must be specified at link time. Don't forget that part, bestie ๐Ÿ˜ญ

  • -mfriz, -mno-friz โ€” -mfriz makes GCC generate (and -mno-friz makes it not generate) the friz instruction ๐Ÿฆ‹ This only kicks in when -funsafe-math-optimizations is on, and it's used to optimize rounding floating-point values to 64-bit integers and back again. Heads up: friz doesn't return the same value if the float is too big to fit in an integer, so it's not totally innocent ๐Ÿ’€
  • -mpointers-to-nested-functions, -mno-pointers-to-nested-functions โ€” on AIX and 64-bit Linux systems, a function pointer points to a 3-word descriptor that holds the function address, the TOC value to load into register r2, and the static chain value to load into register r11. With -mpointers-to-nested-functions (on by default), GCC generates code that loads up the static chain register r11 when calling through a pointer. With -mno-pointers-to-nested-functions, it doesn't ๐Ÿ™ˆ
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. Rough, I know ๐Ÿ˜ญ
  • -msave-toc-indirect, -mno-save-toc-indirect โ€” on AIX and 64-bit Linux systems, if a function calls through a pointer, -msave-toc-indirect generates code that saves the TOC value in the reserved stack location in the function prologue. If the TOC value isn't saved in the prologue, it gets saved right before the call through the pointer. -mno-save-toc-indirect is the default ๐ŸŒธ
  • -mcompat-align-parm, -mno-compat-align-parm โ€” -mcompat-align-parm generates code that passes structure parameters with a maximum alignment of 64 bits, so it stays compatible with older versions of GCC. -mno-compat-align-parm (the default) doesn't ๐Ÿ’…

Older versions of GCC (prior to 4.9.0) incorrectly didn't align a structure parameter on a 128-bit boundary when that structure had a member that needed 128-bit alignment. Newer versions fixed this, and this option lets you generate code that works with functions compiled by those older versions โœจ

  • -mstack-protector-guard=guard โ€” generates stack protection code using a canary at guard. The supported locations are global (a global canary) or tls (a per-thread canary in the TLS block, which is the default with GNU libc version 2.4 or later) ๐Ÿ”ฅ
  • -mstack-protector-guard-reg=reg and -mstack-protector-guard-offset=offset โ€” these only come into play with the tls choice. They specify which register to use as the base register for reading the canary, and what offset from that base register to read from. If you don't set them, the defaults come from the relevant ABI ๐Ÿงš
  • -mstack-protector-guard-symbol=symbol โ€” this one overrides the offset with a symbol reference to a canary in the TLS block ๐Ÿ‘‘

๐Ÿฆ‹ RX Options ๐Ÿฆ‹

These command-line options are defined for RX targets ๐ŸŒˆ

  • -m64bit-doubles, -m32bit-doubles โ€” makes the double data type 64 bits (-m64bit-doubles) or 32 bits (-m32bit-doubles) in size. The default is -m32bit-doubles, and that's on purpose: 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 by default for the RX200 series ๐Ÿ’–

Floating-point instructions only get generated for 32-bit floating-point values, though. So if -m64bit-doubles is used, the FPU hardware isn't used for doubles.

Note: if -fpu is enabled, then -funsafe-math-optimizations gets enabled automatically too. That's because the RX FPU instructions are themselves unsafe ๐Ÿ’€
  • -mcpu=name โ€” selects the type of RX CPU to target. Three types are supported right now: the generic RX600 and RX200 series hardware, and the specific RX610 CPU. The default is RX600 ๐Ÿ“

The only difference between RX600 and RX610 is that the RX610 doesn't support the MVTIPL instruction. And since the RX200 series doesn't have a hardware floating-point unit, -nofpu is turned on by default when that type is selected.

  • -mbig-endian-data, -mlittle-endian-data โ€” stores data (but not code) in big-endian format with -mbig-endian-data. The default is -mlittle-endian-data, which stores data in little-endian format ๐ŸŒŠ
  • -msmall-data-limit=N โ€” sets the maximum size in bytes of global and static variables that can be placed into the small data area ๐Ÿซถ Using the small data area can lead to smaller and faster code, but the area's size is limited, and 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) gets reserved to point at this area, so the compiler can't use it anymore. That can make code slower and/or larger if variables get pushed onto the stack instead of being held in that register.

Note: common variables (uninitialized variables) and constants aren't placed in the small data area, because they get assigned to other sections in the output executable.

The default value is 0, which disables this feature. It isn't turned on by default at higher optimization levels (like -O2) because reserving a register can have potentially detrimental effects. You'll have to experiment and figure out if it helps your program ๐Ÿ”ฌ For how the register holding the small data area pointer gets chosen, check out the -mpid option below.

  • -msim, -mno-sim โ€” -msim uses the simulator runtime. The default is to use the libgloss board-specific runtime ๐Ÿงช
  • -mas100-syntax, -mno-as100-syntax โ€” when generating assembler output, -mas100-syntax uses a syntax that's compatible with Renesas's AS100 assembler. The GAS assembler can handle this syntax too, but it has some restrictions, so it isn't generated by default ๐Ÿ“
  • -mmax-constant-size=N โ€” sets the maximum size, in bytes, of a constant that can be used as an operand in an RX instruction. The RX instruction set does allow constants up to 4 bytes long, but a longer value means a longer instruction. So in some situations it can actually help to restrict the size of constants used in instructions โœจ Constants that are too big get put into a constant pool instead and referenced through register indirection.

N can be between 0 and 4. A value of 0 (the default) or 4 means constants of any size are allowed ๐ŸŒˆ

  • -mrelax โ€” enables linker relaxation. This is where the linker tries to shrink your program by finding shorter versions of various instructions. It's disabled by default ๐Ÿฆ‹
  • -mint-register=N โ€” specifies how many registers to reserve for fast interrupt handler functions. N can be between 0 and 4 ๐Ÿ’œ
    • 1 reserves r13 for the exclusive use of fast interrupt handlers.
    • 2 reserves r13 and r12.
    • 3 reserves r13, r12 and r11.
    • 4 reserves r13 through r10.
    • 0 (the default) doesn't reserve any registers.
  • -msave-acc-in-interrupts โ€” says that interrupt handler functions should preserve the accumulator register ๐Ÿ”ฅ This is only needed if normal code might use the accumulator, for example because it does 64-bit multiplications. By default GCC ignores the accumulator, because that makes the interrupt handlers faster ๐ŸŽ๏ธ
  • -mpid, -mno-pid โ€” -mpid enables generating position-independent data. With it on, any access to constant data is done via an offset from a base address held in a register. That lets the location of constant data get figured out at run time without the executable needing to be relocated, which is a big win for embedded apps with tight memory constraints ๐Ÿงš Data that can be modified isn't affected by this option.

Heads up: using this feature reserves a register (usually r13) for the constant data base address. That can make code slower and/or larger, especially in complicated functions ๐Ÿ™ˆ

Which register ends up holding the constant data base address depends on whether -msmall-data-limit and/or -mint-register are enabled. Starting with r13 and moving downwards, registers get allocated first to satisfy -mint-register, then -mpid, and finally -msmall-data-limit. So it's possible for the small data area register to end up being r8 if both -mint-register=4 and -mpid are specified on the command line ๐Ÿคฏ

By default this feature is not enabled. You can restore the default with -mno-pid ๐Ÿ’…

  • -mno-warn-multiple-fast-interrupts, -mwarn-multiple-fast-interrupts โ€” -mno-warn-multiple-fast-interrupts stops GCC from issuing a warning if it finds more than one fast interrupt handler while compiling a file. By default GCC warns for each extra fast interrupt handler it finds, because the RX only supports one of them ๐Ÿ‘‘

-mallow-string-insns -mno-allow-string-insns โœจ Enables or disables the string manipulation instructions

Okay so bestie, this part picks up mid-OPTIONS, right where we left off with the RX port flags and keeps going through the S/390 and zSeries stuff. Let's gooo ๐Ÿฆ‹


-mallow-string-insns
-mno-allow-string-insns

Okay so these two toggle the string manipulation instructions SMOVF, SCMPU, SMOVB, SMOVU, SUNTIL, SWHILE, and also the RMPA instruction ๐Ÿ’…. Lowkey important, because these instructions may prefetch data, and that is NOT safe if you're touching an I/O register ๐Ÿ˜ญ. (Check section 12.2.7 of the RX62N Group User's Manual if you want the deets ๐Ÿ“–.)

The default is to allow them ๐ŸŒธ. BUT GCC cannot reliably detect every time a string instruction might poke an I/O register, so it can't turn them off automatically ๐Ÿ’€. It's literally on you, the programmer, to pass -mno-allow-string-insns if your program accesses I/O space ๐Ÿซถ.

When they're enabled, GCC defines the C preprocessor symbol __RX_ALLOW_STRING_INSNS__. Otherwise it defines __RX_DISALLOW_STRING_INSNS__ โœจ.

-mjsr
-mno-jsr

These tell the compiler to use only (or not only) JSR instructions to access functions ๐Ÿงš. This one is clutch when your code size goes past the range of BSR instructions ๐Ÿ”ฅ. Note that -mno-jsr does NOT mean "don't use JSR" ๐Ÿ™ˆ. It just means any type of branch may be used.

Note: The generic GCC command-line option -ffixed-reg has special significance to the RX port when used with the interrupt function attribute ๐Ÿ‘‘. That attribute marks a function meant to handle fast interrupts. GCC makes sure it only uses the registers r10, r11, r12 and/or r13, and only if the normal use of those registers has been restricted via -ffixed-reg or -mint-register ๐Ÿ’œ.

โœจ OPTIONS โœจ

S/390 and zSeries Options

These are the -m options defined for the S/390 and zSeries architecture ๐Ÿ’–. Main character energy ๐Ÿ‘‘.

  • -mhard-float, -msoft-float โ€” Use (or don't use) the hardware floating-point instructions and registers for floating-point operations ๐Ÿ”ฅ. With -msoft-float, functions in libgcc.a do the floating-point work ๐Ÿซ . With -mhard-float, the compiler generates IEEE floating-point instructions. This is the default โœจ.
  • -mhard-dfp, -mno-hard-dfp โ€” Use (or don't use) the hardware decimal-floating-point instructions for decimal-floating-point operations ๐Ÿงฎ. With -mno-hard-dfp, functions in libgcc.a handle the 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 equivalent to double, and this is the default ๐ŸŽ€.
  • -mbackchain, -mno-backchain โ€” Store (or don't store) the address of the caller's frame as a backchain pointer in the callee's stack frame ๐Ÿฆ‹. A backchain may be needed to allow debugging with tools that don't understand DWARF call frame information ๐Ÿ”. When -mno-packed-stack is in effect, the backchain pointer is stored at the bottom of the stack frame. When -mpacked-stack is in effect, the backchain goes into the topmost word of the 96/160 byte register save area ๐Ÿงš.

In general, code compiled with -mbackchain is call-compatible with code compiled with -mmo-backchain ๐Ÿซถ. Heads up though: 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're building a Linux kernel, use -msoft-float ๐Ÿ’€.

The default is to not maintain the backchain ๐ŸŒธ.

  • -mpacked-stack, -mno-packed-stack โ€” Use (or don't use) the packed stack layout ๐Ÿ“ฆ. With -mno-packed-stack, the compiler uses all the fields of the 96/160 byte register save area only for their default purpose, so unused fields still eat stack space ๐Ÿ˜ญ. With -mpacked-stack, register save slots are densely packed at the top of the register save area, and unused space gets reused for other stuff, which is way more efficient ๐Ÿ”ฅ. However, when -mbackchain is also in effect, the topmost word of the save area is always used for the backchain, and the return address register is always saved two words below the backchain ๐Ÿ™ˆ.

As long as the stack frame backchain isn't used, code generated with -mpacked-stack is call-compatible with code generated with -mno-packed-stack โœจ. Some non-FSF releases of GCC 2.95 for S/390 or zSeries generated code that uses the stack frame backchain at run time, not just for debugging. That code is NOT call-compatible with code compiled with -mpacked-stack ๐Ÿ’€. Also, the combination of -mbackchain, -mpacked-stack and -mhard-float is not supported. For a Linux kernel, use -msoft-float ๐Ÿซถ.

The default is to not use the packed stack layout ๐ŸŒธ.

  • -msmall-exec, -mno-small-exec โ€” Generate (or don't generate) code using the bras instruction for subroutine calls ๐Ÿ“ž. This only works reliably if the total executable size doesn't exceed 64k ๐Ÿ˜ฌ. The default is to use the basr instruction instead, which doesn't have this limitation ๐Ÿ’–.
  • -m64, -m31 โ€” With -m31, generate code compliant to the GNU/Linux for S/390 ABI ๐Ÿงฉ. With -m64, generate code compliant to the GNU/Linux for zSeries ABI. This lets GCC generate 64-bit instructions, which is so iconic ๐Ÿ‘‘. For the s390 targets the default is -m31, while the s390x targets default to -m64 ๐ŸŒˆ.
  • -mzarch, -mesa โ€” With -mzarch, generate code using the instructions available on z/Architecture ๐Ÿฆ‹. With -mesa, generate code 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. 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, introduced with the IBM zEnterprise EC12 machine generation (S/390 System z Built-in Functions) ๐Ÿง . -mhtm is enabled by default when using -march=zEC12 โœจ.
  • -mvx, -mno-vx โ€” With -mvx, generate code using the instructions from the vector extension facility, introduced with the IBM z13 machine generation ๐ŸŒŸ. This option changes the ABI for some vector type values when it comes to alignment and calling conventions ๐Ÿ˜ญ. If vector type values are used in an ABI-relevant context, a GAS .gnu_attribute command gets added to mark the resulting binary with the ABI used ๐Ÿท๏ธ. -mvx is enabled by default when using -march=z13 ๐Ÿ’….
  • -mzvector, -mno-zvector โ€” This enables vector language extensions and builtins that use instructions from the vector extension facility (IBM z13) ๐ŸŽ€. It adds support for vector as a keyword to define vector type variables and arguments ๐Ÿซถ. Important: vector is only available when GNU extensions are enabled. It won't be expanded when you request strict standard compliance, e.g. with -std=c99 ๐Ÿ™…. On top of the GCC low-level builtins, -mzvector also enables a set of builtins added for compatibility with AltiVec-style implementations like Power and Cell ๐Ÿงš. To use these builtins you need to include the header file vecintrin.h ๐Ÿ“œ. -mzvector is disabled by default ๐ŸŒธ.
  • -mmvcle, -mno-mvcle โ€” Generate (or don't generate) code using the mvcle instruction for block moves ๐Ÿšš. With -mno-mvcle, use an mvc loop instead. This is the default unless you're optimizing for size ๐Ÿ’œ.
  • -mdebug, -mno-debug โ€” Print (or don't print) additional debug information when compiling ๐Ÿ”. The default is to not print debug information ๐ŸŒธ.
  • -march=cpu-type โ€” Generate code that runs on cpu-type, which is the name of a system representing a certain processor type ๐Ÿ–ฅ๏ธ. Possible values for cpu-type are z900/arch5, z990/arch6, z9-109, z9-ec/arch7, z10/arch8, z196/arch9, zEC12, z13/arch11, z14/arch12, and native โœจ. The default is -march=z900 ๐Ÿฆ‹.

Specifying native as the cpu type can be used to select the best architecture option for the host processor ๐Ÿซถ. -march=native has no effect if GCC doesn't recognize the processor ๐Ÿคท.

  • -mtune=cpu-type โ€” Tune everything applicable about the generated code to cpu-type, except for the ABI and the set of available instructions ๐ŸŽ›๏ธ. The list of cpu-type values is the same as for -march ๐Ÿ’–. The default is the value used for -march ๐ŸŒˆ.
  • -mtpf-trace, -mno-tpf-trace โ€” Generate code that adds (or doesn't add) TPF OS specific branches to trace routines in the operating system ๐Ÿ›ฐ๏ธ. This option is off by default, even when compiling for the TPF OS ๐Ÿ™ƒ.
  • -mfused-madd, -mno-fused-madd โ€” Generate code that uses (or doesn't use) the floating-point multiply and accumulate instructions โž•. These are generated by default if hardware floating point is used ๐Ÿ”ฅ.
  • -mwarn-framesize=framesize โ€” Emit a warning if the current function exceeds the given frame size ๐Ÿšจ. Because this is a compile-time check, it doesn't need to be a real problem when the program runs ๐Ÿ™Œ. It's meant to flag functions that most probably cause a stack overflow, so it's 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 ๐Ÿ“ข. This is generally a bad idea with a limited stack size ๐Ÿ˜ฌ.

-mstack-guard=stack-guard โ€” wait, let's go! ๐Ÿงš These two are a matching set ๐Ÿ’– Turn on -mstack-guard=stack-guard and -mstack-size=stack-size together, and the S/390 back end slips extra instructions into the function prologue that trigger a trap if the stack gets stack-guard bytes past stack-size. (Reminder: on S/390 the stack grows downward, so the vibe is "how close am I to the edge" ๐Ÿ˜ญ) If you leave out the stack-guard value, the compiler picks the smallest power of 2 larger than the frame size of the compiled function. These are built for debugging stack overflows ๐Ÿ”, and the extra code is so light that you could honestly keep it on in production-like systems without a big performance hit โœจ

Rules, bestie ๐Ÿ“œ: both values have to be exact powers of 2, stack-size has to be greater than stack-guard, and it can't go past 64k ๐Ÿ™…โ€โ™€๏ธ The code also assumes the stack starts at an address aligned to the value given by stack-size, which is how it stays efficient ๐Ÿ’… And stack-guard only works in conjunction with stack-size, so never show up to the party without it ๐ŸŽ€

  • -mhotpatch=pre-halfwords,post-halfwords โ€” main character hotpatch energy ๐Ÿ”ฅ When this is enabled, every function in the compilation unit gets a "hot-patching" prologue. The function label gets a bunch of two-byte NOP instructions stuck in front of it (pre-halfwords, max 1000000), and after the label, 2 * post-halfwords bytes get tacked on using the biggest NOP-like instructions the architecture allows (max 1000000) ๐Ÿฆ‹

If both arguments are zero, hotpatching is switched off ๐Ÿ™ˆ

Also, you can override this for individual functions with the "hotpatch" attribute, so you're still in control of the drama ๐Ÿ‘‘


โœจ Score Options โœจ

These options are defined for Score implementations ๐ŸŒธ

  • -meb โ€” big-endian mode, and it's the default ๐Ÿ’œ
  • -mel โ€” compile for little-endian mode ๐Ÿซถ
  • -mnhwloop โ€” disables generation of "bcnz" instructions ๐Ÿ™…โ€โ™€๏ธ
  • -muls โ€” turns on generation of unaligned load and store instructions ๐Ÿ”ฅ
  • -mmac โ€” enables the multiply-accumulate instructions ๐Ÿงฎ Heads up, it's disabled by default, so you gotta ask for it ๐Ÿ’…
  • -mscore5 โ€” targets the SCORE5 architecture ๐ŸŽ€
  • -mscore5u โ€” targets the SCORE5U architecture ๐ŸŒˆ
  • -mscore7 โ€” targets the SCORE7 architecture, and yes, it's the default โญ
  • -mscore7d โ€” targets the SCORE7D architecture โœจ

โœจ SH Options โœจ

These -m options are defined for the SH implementations ๐Ÿฆ‹ Let's go through the whole SH lineup ๐Ÿ’–

  • -m1 โ€” generates code for the SH1 ๐ŸŒธ
  • -m2 โ€” generates code for the SH2 ๐ŸŒธ
  • -m2e โ€” generates code for the SH2e ๐ŸŒธ
  • -m2a-nofpu โ€” generates code for the SH2a without an FPU, or for an SH2a-FPU in a way where the floating-point unit isn't used ๐Ÿ™ˆ
  • -m2a-single-only โ€” generates code for the SH2a-FPU so that no double-precision floating-point operations get used ๐Ÿง 
  • -m2a-single โ€” generates code for the SH2a-FPU, assuming the FPU is in single-precision mode by default ๐Ÿ”ฅ
  • -m2a โ€” generates code for the SH2a-FPU, assuming the FPU is in double-precision mode by default ๐Ÿ‘‘
  • -m3 โ€” generates code for the SH3 ๐ŸŒธ
  • -m3e โ€” generates code for the SH3e ๐ŸŒธ
  • -m4-nofpu โ€” generates code for the SH4 without a floating-point unit ๐Ÿ’€
  • -m4-single-only โ€” generates code for the SH4 with an FPU that only does single-precision arithmetic ๐ŸŽ€
  • -m4-single โ€” generates code for the SH4, assuming the FPU is in single-precision mode by default ๐ŸŒˆ
  • -m4 โ€” generates code for the SH4 ๐ŸŒธ
  • -m4-100 โ€” generates code for SH4-100 ๐ŸŒธ
  • -m4-100-nofpu โ€” generates code for SH4-100 in a way where the FPU isn't used ๐Ÿ™ˆ
  • -m4-100-single โ€” generates code for SH4-100, assuming the FPU is in single-precision mode by default ๐Ÿ”ฅ
  • -m4-100-single-only โ€” generates code for SH4-100 so that no double-precision floating-point operations get used ๐Ÿง 
  • -m4-200 โ€” generates code for SH4-200 ๐ŸŒธ
  • -m4-200-nofpu โ€” generates code for SH4-200 in a way where the FPU isn't used ๐Ÿ™ˆ
  • -m4-200-single โ€” generates code for SH4-200, assuming the FPU is in single-precision mode by default ๐Ÿ”ฅ
  • -m4-200-single-only โ€” generates code for SH4-200 so that no double-precision floating-point operations get used ๐Ÿง 
  • -m4-300 โ€” generates code for SH4-300 ๐ŸŒธ
  • -m4-300-nofpu โ€” generates code for SH4-300 in a way where the FPU isn't used ๐Ÿ™ˆ
  • -m4-300-single โ€” generates code for SH4-300 so that no double-precision floating-point operations get used ๐Ÿง 
  • -m4-300-single-only โ€” generates code for SH4-300 so that no double-precision floating-point operations get used ๐Ÿง 
  • -m4-340 โ€” generates code for SH4-340, which has no MMU and no FPU ๐Ÿ’…
  • -m4-500 โ€” generates code for SH4-500, which has no FPU ๐Ÿ’€ It also passes -isa=sh4-nofpu to the assembler ๐Ÿ”ง
  • -m4a-nofpu โ€” generates code for the SH4al-dsp, or for an SH4a in a way where the FPU isn't used ๐Ÿ™ˆ
  • -m4a-single-only โ€” generates code for the SH4a so that no double-precision floating-point operations get used ๐Ÿง 
  • -m4a-single โ€” generates code for the SH4a, assuming the FPU is in single-precision mode by default ๐Ÿ”ฅ
  • -m4a โ€” generates code for the SH4a ๐ŸŒธ
  • -m4al โ€” basically the same as -m4a-nofpu, except it implicitly passes -dsp to the assembler โœจ Lowkey, GCC doesn't generate any DSP instructions at the moment ๐Ÿ™ƒ
  • -mb โ€” compiles for the processor in big-endian mode ๐Ÿ’œ
  • -ml โ€” compiles for the processor in little-endian mode ๐Ÿซถ
  • -mdalign โ€” aligns doubles at 64-bit boundaries ๐Ÿ“
โš ๏ธ Bestie, be careful with -mdalign! It changes the calling conventions, so some functions from the standard C library won't work unless you recompile it first with -mdalign ๐Ÿ˜ญ
  • -mrelax โ€” shortens some address references at link time when it's possible, using the linker option -relax ๐Ÿ”—
  • -mbigtable โ€” uses 32-bit offsets in "switch" tables ๐Ÿ“Š The default is 16-bit offsets, so this is the upgrade ๐Ÿ’…
  • -mbitops โ€” enables bit manipulation instructions on SH2A ๐Ÿง 
  • -mfmovd โ€” enables the use of the fmovd instruction ๐Ÿฆ‹ Make sure to check -mdalign for alignment constraints ๐Ÿ“
  • -mrenesas โ€” follows the calling conventions defined by Renesas ๐ŸŽ€
  • -mno-renesas โ€” follows the calling conventions defined for GCC before the Renesas conventions were available ๐Ÿ•ฐ๏ธ This one is the default for all targets of the SH toolchain ๐Ÿ‘‘
  • -mnomacsave โ€” marks the "MAC" register as call-clobbered, even if -mrenesas is given ๐Ÿ™ˆ
  • -mieee, -mno-ieee โ€” these control the IEEE compliance of floating-point comparisons, which decides how cases with an unordered comparison result get handled ๐Ÿง By default, -mieee is implicitly enabled. If -ffinite-math-only is enabled, then -mno-ieee is implicitly set, which makes floating-point greater-equal and less-equal comparisons faster โšก You can override either implicit setting by specifying -mieee or -mno-ieee yourself ๐Ÿ’…
  • -minline-ic_invalidate โ€” inlines code that invalidates instruction cache entries after setting up nested function trampolines ๐Ÿง  This does nothing if -musermode is in effect and the code generation option you picked (like -m4) doesn't allow the "icbi" instruction ๐Ÿ™ƒ If the option doesn't allow "icbi" and -musermode isn't in effect, the inlined code pokes the instruction cache address array directly with an associative write ๐Ÿ˜ฌ That needs privileged mode at run time, and it also fails if the cache line got mapped via the TLB and became unmapped ๐Ÿ’€
  • -misize โ€” dumps instruction size and location in the assembly code ๐Ÿ“œ
  • -mpadstruct โ€” deprecated, so please don't reach for it ๐Ÿ™…โ€โ™€๏ธ It pads structures to multiples of 4 bytes, which is incompatible with the SH ABI ๐Ÿ’€
  • -matomic-model=model โ€” sets the model of atomic operations plus any additional parameters, as a comma-separated list ๐Ÿงต For the deets on atomic built-in functions, check out __atomic Builtins ๐Ÿ“š These are the models and parameters that are supported:
    • none โ€” turns off compiler-generated atomic sequences and emits library calls for atomic operations instead ๐Ÿ“ž This is the default if the target is not "sh*-*-linux*" ๐Ÿ’…
    • soft-gusa โ€” generates GNU/Linux-compatible gUSA software atomic sequences for the atomic built-in functions ๐Ÿง These need extra help from the interrupt/exception handling code of the system, and they're only suitable for SH3* and SH4* single-core systems ๐ŸŽฏ This option is enabled by default when the target is "sh*-*-linux*" and the chip is 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 also works on SH1* and SH2* targets ๐ŸŒŸ These sequences need extra support from the interrupt/exception handling code, and they're only suitable for single-core systems ๐ŸŽฏ When you use this model, you also have to specify the gbr-offset= parameter ๐Ÿ“Œ
    • soft-imask โ€” generates software atomic sequences that temporarily disable interrupts by setting "SR.IMASK = 1111" ๐Ÿ˜ค This model only works when the program runs in privileged mode and is only suitable for single-core systems ๐ŸŽฏ You don't need extra support from the interrupt/exception handling code for this one ๐Ÿ™Œ It's enabled by default when the target is "sh*-*-linux*" and the chip is 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 variables, access to 8- or 16-bit variables gets emulated with 32-bit accesses ๐Ÿงฉ Code compiled with this option is also compatible with other software atomic model interrupt/exception handling systems if it runs on an SH4A system ๐Ÿซถ You don't need extra support from the interrupt/exception handling code for this model either ๐ŸŽ‰
  • gbr-offset= โ€” Okay so this one picks the byte offset of the variable inside the thread control block structure that the generated atomic sequences use, but only when the soft-tcb model is selected ๐Ÿงš. Every other model just ignores it. The value has to be an integer multiple of four and sit somewhere in the 0-1020 range ๐Ÿ’….
  • strict โ€” This one bans mixing multiple atomic models, even when they'd be compatible ๐Ÿ™…โ€โ™€๏ธ. It also makes the compiler generate atomic sequences for the specified model only ๐ŸŽ€.

  • -mtas โ€” This makes the compiler emit the tas.b opcode for __atomic_test_and_set ๐Ÿฆ‹. ngl, depending on your hardware and software setup, it can tank overall performance, because tas.b forces operand cache line flushes ๐Ÿ’€. On multi-core SH4A processors, you have to be extra careful with tas.b, since certain cache configurations can end in data corruption ๐Ÿ˜ญ.
  • -mprefergot โ€” When you're generating position-independent code, this emits function calls through the Global Offset Table instead of the Procedure Linkage Table ๐ŸŒธ.
  • -musermode, -mno-usermode โ€” The first one means don't allow the compiler to generate privileged mode code, and the second one means allow it ๐Ÿ”. -musermode also implies -mno-inline-ic_invalidate if the inlined code wouldn't work in user mode โœจ. -musermode is the default when the target is sh*-*-linux* ๐Ÿง. If the target is SH1* or SH2*, -musermode does nothing, because those chips have no user mode ๐Ÿ™ˆ.
  • -multcost=number โ€” Sets the cost the compiler assumes for a multiply insn ๐Ÿ”ข.
  • -mdiv=strategy โ€” Picks the division strategy for integer division operations ๐Ÿ‘‘. strategy can be one of these vibes:
    • call-div1 โ€” Calls a library function that uses the single-step division instruction div1 to do the math ๐Ÿงฎ. Dividing by zero gives an unspecified result and doesn't trap. This is the default except for SH4, SH2A and SHcompact.
    • call-fp โ€” Calls a library function that does the operation in double precision floating point ๐ŸŒˆ. Dividing by zero causes a floating-point exception. This is the default for SHcompact with FPU. If you ask for this on a target without a double precision FPU, it falls back to call-div1.
    • call-table โ€” Calls a library function that uses a lookup table for small divisors, and the div1 instruction with case distinction for bigger divisors ๐Ÿ“š. Dividing by zero gives an unspecified result and doesn't trap. This is the default for SH4. If you ask for this on a target without dynamic shift instructions, it falls back to call-div1.

If you don't specify a strategy, the compiler picks the default based on the current target ๐ŸŽฏ. For SH2A, the default is to use the divs and divu instructions instead of library function calls โšก.

  • -maccumulate-outgoing-args โ€” Reserves space once for outgoing arguments in the function prologue, instead of around each call ๐Ÿง. This is generally great for performance and size ๐Ÿ’–. It's also needed for unwinding, so the stack frame doesn't change around conditional code ๐Ÿซถ.
  • -mdivsi3_libfunc=name โ€” Sets the name of the library function used for 32-bit signed division to name ๐Ÿท๏ธ. This only changes the name used in the call division strategies, and the compiler still expects the same sets of input, output and clobbered registers as if this option weren't there ๐Ÿ™ƒ.
  • -mfixed-range=register-range โ€” Makes the compiler treat the given register range as fixed registers ๐Ÿ“Œ. A fixed register is one the register allocator isn't allowed to use, which is super useful when compiling kernel code ๐Ÿง‘โ€๐Ÿ’ป. You write a register range as two registers separated by a dash, and if you want multiple ranges, separate them with a comma ๐Ÿงต.
  • -mbranch-cost=num โ€” Tells the compiler to assume num is the cost of a branch instruction ๐ŸŒฟ. Higher numbers make the compiler try to generate more branch-free code when that's possible ๐Ÿฆ‹. If you don't specify it, the value is picked based on the processor type you're compiling for ๐ŸŽ€.
  • -mzdcbranch, -mno-zdcbranch โ€” These assume (or don't assume) that zero displacement conditional branch instructions bt and bf are fast โšก. With -mzdcbranch, the compiler prefers zero displacement branch code sequences ๐Ÿ’œ. It's enabled by default for SH4 and SH4A, and you can turn it off explicitly with -mno-zdcbranch ๐Ÿ™…โ€โ™€๏ธ.
  • -mcbranch-force-delay-slot โ€” Forces the use of delay slots for conditional branches, filling the delay slot with a nop if a suitable instruction can't be found ๐Ÿฅฑ. This is disabled by default. You can enable it to work around hardware bugs like the ones found in the original SH7055 ๐Ÿ› ๏ธ.
  • -mfused-madd, -mno-fused-madd โ€” These generate code that does (or doesn't) use the floating-point multiply and accumulate instructions ๐Ÿ”ฅ. They're generated by default when hardware floating point is in use ๐Ÿ’…. Heads up: the machine-dependent -mfused-madd is now mapped to the machine-independent -ffp-contract=fast, and -mno-fused-madd is mapped to -ffp-contract=off ๐Ÿ“.
  • -mfsca, -mno-fsca โ€” These allow (or disallow) the compiler to emit the fsca instruction for sine and cosine approximations ๐ŸŒŠ. -mfsca has to be used together 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 โ€” These allow (or disallow) the compiler to emit the fsrra instruction for reciprocal square root approximations โœจ. -mfsrra has to be used together 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 give you faster code on the SH4 processor ๐ŸŽ๏ธ.
  • -mfdpic โ€” Generates code using the FDPIC ABI ๐Ÿงš.

๐ŸŽ€ Solaris 2 Options ๐ŸŽ€

These -m options are supported on Solaris 2 ๐ŸŒž:

  • -mclear-hwcap โ€” Okay, so this tells the compiler to remove the hardware capabilities generated by the Solaris assembler ๐Ÿงน. It's only necessary when object files use ISA extensions the current machine doesn't support, but still check at runtime whether or not to use them ๐Ÿคทโ€โ™€๏ธ.
  • -mimpure-text โ€” Used alongside -shared, this tells the compiler not to pass -z text to the linker when linking a shared object ๐Ÿ”—. With it, you can link position-dependent code into a shared object ๐Ÿฆ‹.
Warning: -mimpure-text quiets the "relocations remain against allocatable but non-writable sections" linker error ๐Ÿ™ˆ. But the necessary relocations trigger copy-on-write, so the shared object isn't actually shared across processes ๐Ÿ’€. Instead of using -mimpure-text, compile all your source code with -fpic or -fPIC ๐Ÿซถ.

These switches are supported in addition to the above on Solaris 2 โœจ:

  • -pthreads โ€” This is just a synonym for -pthread ๐Ÿงต.

๐Ÿ’… SPARC Options ๐Ÿ’…

These -m options are supported on the SPARC ๐ŸŒˆ:

  • -mno-app-regs, -mapp-regs โ€” Specifying -mapp-regs generates output using global registers 2 through 4, which the SPARC SVR4 ABI reserves for applications ๐Ÿ”ง. Like global register 1, each of global registers 2 through 4 is then treated as an allocable register that gets clobbered by function calls. This is the default ๐ŸŒธ.

To be fully SVR4 ABI-compliant (at the cost of some performance loss), specify -mno-app-regs ๐Ÿ“œ. You should compile libraries and system software with this option ๐Ÿซถ.

  • -mflat, -mno-flat โ€” With -mflat, the compiler doesn't generate save/restore instructions and uses a "flat" or single register window model ๐ŸชŸ. This model is compatible with the regular register window model ๐Ÿ’œ. The local registers and the input registers (0--5) are still treated as "call-saved" registers and get saved on the stack as needed ๐Ÿ“ฆ.

With -mno-flat (the default), the compiler generates save/restore instructions, except for leaf functions ๐Ÿƒ. This is the normal operating mode ๐Ÿ’–.

  • -mfpu, -mhard-float โ€” Generates output containing floating-point instructions. This is the default ๐Ÿ”ฅ.
  • -mno-fpu, -msoft-float โ€” Generates output containing library calls for floating point ๐Ÿ“š.
Warning: the requisite libraries are NOT available for all SPARC targets ๐Ÿ˜ญ. Normally the facilities of the machine's usual C compiler are used, but that can't be done directly in cross-compilation. You must make your own arrangements to provide suitable library functions for cross-compilation ๐Ÿ› ๏ธ. The embedded targets sparc-*-aout and sparclite-*-* do provide software floating-point support ๐Ÿ™Œ.

-msoft-float changes the calling convention in the output file, so it's only useful if you compile all of a program with this option ๐Ÿง. In particular, you need to compile libgcc.a, the library that comes with GCC, with -msoft-float for this to work ๐ŸŽ€.

  • -mhard-quad-float โ€” Generates output containing quad-word (long double) floating-point instructions ๐ŸŒŸ.
  • -msoft-quad-float โ€” Generates output containing library calls for quad-word (long double) floating-point instructions ๐Ÿ“ž. The functions called are the ones specified in the SPARC ABI. This is the default ๐Ÿ‘‘.

As of this writing, there are no SPARC implementations with hardware support for the quad-word floating-point instructions ๐Ÿ™ƒ. They all invoke a trap handler for one of these instructions, and then the trap handler emulates the effect of the instruction ๐Ÿซ . Because of the trap handler overhead, this is much slower than calling the ABI library routines, so the -msoft-quad-float option is the default ๐Ÿข.

  • -mno-unaligned-doubles, -munaligned-doubles โ€” Assumes that doubles have 8-byte alignment. This is the default ๐Ÿ“.

With -munaligned-doubles, GCC only assumes doubles have 8-byte alignment if they're tucked inside another type or have an absolute address. Otherwise it assumes 4-byte alignment, bestie ๐ŸŽ€ Turning this on avoids some rare compatibility problems with code from other compilers, but it's not the default because it costs performance, especially for floating-point code ๐Ÿ’€

  • -muser-mode, -mno-user-mode โ€” Don't generate code that can only run in supervisor mode ๐Ÿ”’ This only matters for the casa instruction emitted for the LEON3 processor. This is the default โœจ
  • -mfaster-structs, -mno-faster-structs โ€” With -mfaster-structs, the compiler assumes structures should have 8-byte alignment ๐Ÿ“ That unlocks pairs of ldd and std instructions for copies in structure assignment, instead of twice as many ld and st pairs, so it's faster ๐ŸŽ๏ธ
โš ๏ธ Okay, this one is serious. Changing the alignment like this directly violates the SPARC ABI ๐Ÿ˜ญ So it's only for targets where the developer acknowledges their resulting code isn't fully in line with the ABI rules. Don't just sprinkle it on everything, babe.
  • -mstd-struct-return, -mno-std-struct-return โ€” With -mstd-struct-return, the compiler adds checking code to functions that return structures or unions ๐Ÿ” It's there to catch size mismatches between the two sides of a function call, following the 32-bit ABI ๐Ÿง

The default is -mno-std-struct-return ๐ŸŒธ This option has no effect in 64-bit mode ๐Ÿ™…โ€โ™€๏ธ

  • -mlra, -mno-lra โ€” Turns on Local Register Allocation ๐Ÿง  This has been the default for SPARC since GCC 7, so if you want the old Reload behaviour, you have to pass -mno-lra ๐Ÿ•ฐ๏ธ
  • -mcpu=cpu_type โ€” Sets the instruction set, register set, and instruction scheduling parameters for the machine type cpu_type ๐Ÿ–ฅ๏ธ The supported values are v7, cypress, v8, supersparc, hypersparc, leon, leon3, leon3v7, sparclite, f930, f934, sparclite86x, sparclet, tsc701, v9, ultrasparc, ultrasparc3, niagara, niagara2, niagara3, niagara4, niagara7 and m8 ๐Ÿ’œ

Native Solaris and GNU/Linux toolchains also accept native, which picks the best architecture option for the host processor โœจ Heads up: -mcpu=native has no effect if GCC doesn't recognise the processor ๐Ÿ™ˆ

Default scheduling parameters are used for the values that select an architecture rather than an implementation ๐Ÿ“‹ Those are v7, v8, sparclite, sparclet and v9 ๐Ÿ’…

Here's the lineup of each supported architecture and its implementations, no cap ๐Ÿ‘‘

  • v7 โ€” cypress, leon3v7
  • v8 โ€” supersparc, hypersparc, leon, leon3
  • sparclite โ€” f930, f934, sparclite86x
  • sparclet โ€” tsc701
  • v9 โ€” ultrasparc, ultrasparc3, niagara, niagara2, niagara3, niagara4, niagara7, m8

By default (unless configured otherwise), GCC generates code for the V7 variant of the SPARC architecture ๐Ÿฆ‹ With -mcpu=cypress, the compiler also optimises for the Cypress CY7C602 chip, as used in the SPARCStation/SPARCServer 3xx series ๐Ÿ–ฅ๏ธ This is 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 is that the compiler emits the integer multiply and integer divide instructions that exist in SPARC-V8 but not SPARC-V7 โž• With -mcpu=supersparc, it's also optimised 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, the compiler also optimises for the Fujitsu MB86930, which is the original SPARClite with no FPU ๐Ÿงฉ With -mcpu=f934, it optimises for the Fujitsu MB86934, the more recent SPARClite with 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, the compiler also optimises for the TEMIC SPARClet chip ๐Ÿ“

With -mcpu=v9, GCC generates code for the V9 variant ๐ŸŒธ This adds 64-bit integer and floating-point move instructions, 3 additional floating-point condition code registers and conditional move instructions ๐ŸŽ€ With -mcpu=ultrasparc, the compiler also optimises for the Sun UltraSPARC I/II/IIi chips โ˜€๏ธ With -mcpu=ultrasparc3, it optimises for the Sun UltraSPARC III/III+/IIIi/IIIi+/IV/IV+ chips ๐Ÿ”ฅ With -mcpu=niagara, it optimises for Sun UltraSPARC T1 chips ๐ŸŒŠ With -mcpu=niagara2, it optimises for Sun UltraSPARC T2 chips ๐ŸŒŠ With -mcpu=niagara3, it optimises for Sun UltraSPARC T3 chips ๐ŸŒŠ With -mcpu=niagara4, it optimises for Sun UltraSPARC T4 chips ๐ŸŒŠ With -mcpu=niagara7, it optimises for Oracle SPARC M7 chips ๐Ÿ’Ž And With -mcpu=m8, it optimises for Oracle M8 chips ๐Ÿ‘‘

  • -mtune=cpu_type โ€” Sets the instruction scheduling parameters for the machine type cpu_type, but doesn't set the instruction set or register set the way -mcpu=cpu_type does ๐ŸŽฏ

The same values for -mcpu=cpu_type work for -mtune=cpu_type, but the only useful ones are those that select a particular CPU implementation ๐Ÿ’… Those are cypress, supersparc, hypersparc, leon, leon3, leon3v7, f930, f934, sparclite86x, tsc701, ultrasparc, ultrasparc3, niagara, niagara2, niagara3, niagara4, niagara7 and m8 ๐Ÿซถ With native Solaris and GNU/Linux toolchains, native can also be used โœจ

  • -mv8plus, -mno-v8plus โ€” With -mv8plus, GCC generates code for the SPARC-V8+ ABI ๐Ÿง The difference from the V8 ABI is that the global and out registers are considered 64 bits wide ๐Ÿ“ This is enabled by default on Solaris in 32-bit mode for all SPARC-V9 processors ๐ŸŒž
  • -mvis, -mno-vis โ€” With -mvis, GCC generates code that takes advantage of the UltraSPARC Visual Instruction Set extensions ๐Ÿ‘€ The default is -mno-vis ๐Ÿ™ƒ
  • -mvis2, -mno-vis2 โ€” With -mvis2, GCC uses version 2.0 of the UltraSPARC Visual Instruction Set extensions ๐Ÿฆ„ The default is -mvis2 when targeting a CPU that supports such instructions, like UltraSPARC-III and later ๐Ÿš€ Setting -mvis2 also sets -mvis ๐Ÿ’ซ
  • -mvis3, -mno-vis3 โ€” With -mvis3, GCC uses version 3.0 of the UltraSPARC Visual Instruction Set extensions ๐ŸŒ  The default is -mvis3 when targeting a CPU that supports such instructions, like niagara-3 and later ๐ŸŒˆ Setting -mvis3 also sets -mvis2 and -mvis ๐Ÿ™Œ
  • -mvis4, -mno-vis4 โ€” With -mvis4, GCC uses version 4.0 of the UltraSPARC Visual Instruction Set extensions ๐Ÿ›ธ The default is -mvis4 when targeting a CPU that supports such instructions, like niagara-7 and later ๐Ÿ’– Setting -mvis4 also sets -mvis3, -mvis2 and -mvis ๐Ÿง 
  • -mvis4b, -mno-vis4b โ€” With -mvis4b, GCC uses version 4.0 of the UltraSPARC Visual Instruction Set extensions, plus the additional VIS instructions introduced in the Oracle SPARC Architecture 2017 ๐Ÿงฌ The default is -mvis4b when targeting a CPU that supports such instructions, like m8 and later ๐Ÿ‘‘ Setting -mvis4b also sets -mvis4, -mvis3, -mvis2 and -mvis ๐Ÿซถ
  • -mcbcond, -mno-cbcond โ€” With -mcbcond, GCC uses the UltraSPARC Compare-and-Branch-on-Condition instructions ๐Ÿ”€ The default is -mcbcond when targeting a CPU that supports them, like Niagara-4 and later ๐ŸŒธ
  • -mfmaf, -mno-fmaf โ€” With -mfmaf, GCC uses the UltraSPARC Fused Multiply-Add Floating-point instructions ๐Ÿงฎ The default is -mfmaf when targeting a CPU that supports them, like Niagara-3 and later ๐ŸŽ€
  • -mfsmuld, -mno-fsmuld โ€” With -mfsmuld, GCC uses the Floating-point Multiply Single to Double (FsMULd) instruction โœ–๏ธ The default is -mfsmuld when targeting a CPU that supports the architecture versions V8 or V9 with an FPU, except -mcpu=leon ๐Ÿ™ˆ
  • -mpopc, -mno-popc โ€” With -mpopc, GCC uses the UltraSPARC Population Count instruction ๐Ÿ”ข The default is -mpopc when targeting a CPU that supports it, like Niagara-2 and later ๐Ÿ“
  • -msubxc, -mno-subxc โ€” With -msubxc, GCC uses the UltraSPARC Subtract-Extended-with-Carry instruction โž– The default is -msubxc when targeting a CPU that supports it, like Niagara-7 and later ๐Ÿ’…
  • -mfix-at697f โ€” Enables the documented workaround for the single erratum of the Atmel AT697F processor, which corresponds to erratum #13 of the AT697E processor ๐Ÿฉน
  • -mfix-ut699 โ€” Enables the documented workarounds for the floating-point errata and the data cache nullify errata of the UT699 processor ๐Ÿ› ๏ธ
  • -mfix-ut700 โ€” Enables the documented workaround for the back-to-back store errata of the UT699E/UT700 processor ๐Ÿงฏ
  • -mfix-gr712rc โ€” Enables the documented workaround for the back-to-back store errata of the GR712RC processor ๐Ÿงท

These -m options are supported in addition to the above on SPARC-V9 processors in 64-bit environments ๐ŸŒŒ

  • -m32, -m64 โ€” Generates code for a 32-bit or 64-bit environment ๐ŸŒ™ The 32-bit environment sets int, long and pointer to 32 bits ๐Ÿ”ข The 64-bit environment sets int to 32 bits and long and pointer to 64 bits ๐Ÿš€
  • -mcmodel=which โ€” Sets the code model to one of the following ๐Ÿงฉ
    • medlow โ€” The Medium/Low code model: 64-bit addresses, and programs must be linked in the low 32 bits of memory ๐Ÿงธ Programs can be statically or dynamically linked ๐Ÿ”—
    • medmid โ€” The Medium/Middle code model: 64-bit addresses, and programs must be linked in the low 44 bits of memory ๐ŸŒ The text and data segments must each be less than 2GB in size, and the data segment must be located within 2GB of the text segment ๐Ÿ“
  • medany: okay so this is the Medium/Anywhere code model ๐Ÿ’… You get 64-bit addresses โœจ programs can be linked anywhere in memory ๐Ÿ—บ๏ธ but the text and data segments have to be less than 2GB in size, and the data segment has to sit within 2GB of the text segment ๐Ÿซถ
  • embmedany: the Medium/Anywhere model but for embedded systems ๐Ÿ”Œ It's still 64-bit addresses, and the text and data segments must be less than 2GB, but both can start anywhere in memory (that gets decided at link time ๐Ÿฆ‹). The global register %g4 points to the base of the data segment ๐Ÿ‘‘ Programs are statically linked, and PIC is not supported ๐Ÿ’€

โœจ -mmemory-model=mem-model โœจ

Use this to set the memory model the processor runs with ๐ŸŒธ Pick one of these:

  • default: the default memory model for the processor and operating system ๐Ÿ’–
  • rmo: Relaxed Memory Order ๐ŸŒˆ
  • pso: Partial Store Order ๐Ÿ“
  • tso: Total Store Order ๐ŸŽ€
  • sc: Sequential Consistency ๐Ÿงš

These memory models are formally defined in Appendix D of the SPARC-V9 architecture manual ๐Ÿ“–, and they get set in the processor's PSTATE.MM field ๐Ÿ”ฅ very technical, very iconic ๐Ÿ˜ญ

  • -mstack-bias, -mno-stack-bias: with -mstack-bias, GCC assumes the stack pointer (and the frame pointer, if there is one) is offset by -2047, and that offset has to be added back whenever it makes a stack frame reference ๐Ÿซถ This is the default in 64-bit mode ๐Ÿ’… Otherwise, GCC assumes no offset is there at all โœจ

๐Ÿ”ฅ SPU Options ๐Ÿ”ฅ

These -m options are supported on the SPU ๐Ÿฆ‹

  • -mwarn-reloc, -merror-reloc: the SPU loader doesn't handle dynamic relocations, so by default GCC throws an error when it generates code that needs one ๐Ÿ’€ -mno-error-reloc turns that error off, and -mwarn-reloc gives you a warning instead ๐Ÿ™ˆ
  • -msafe-dma, -munsafe-dma: instructions that start a DMA or check whether one has finished must not get reordered around loads and stores of the memory being accessed ๐Ÿ˜ญ With -munsafe-dma, you have to use the volatile keyword to protect those memory accesses, but that can make the code inefficient wherever the memory is known not to change ๐Ÿฅบ Instead of marking everything volatile, you can use -msafe-dma to tell the compiler to treat DMA instructions as potentially affecting all memory ๐Ÿง 
  • -mbranch-hints: by default, GCC generates a branch hint instruction to avoid pipeline stalls for always-taken or probably-taken branches โœจ A hint is never generated closer than 8 instructions away from its branch ๐Ÿ“ There's little reason to turn these off, except for debugging or to make an object a little smaller ๐Ÿค
  • -msmall-mem, -mlarge-mem: by default, GCC generates code assuming addresses are never larger than 18 bits ๐ŸŒธ With -mlarge-mem, the code assumes a full 32-bit address ๐Ÿ‘‘
  • -mstdmain: by default, GCC links against startup code that assumes the SPU-style main function interface (which has an unconventional parameter list) ๐Ÿค” With -mstdmain, GCC links your program against startup code that assumes a C99-style interface to main, including a local copy of argv strings ๐ŸŽ€
  • -mfixed-range=register-range: makes GCC generate code that treats the given register range as fixed registers ๐Ÿ”’ A fixed register is one the register allocator can't 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 ๐Ÿ’…
  • -mea32, -mea64: compiles code assuming pointers to the PPU address space, accessed through the __ea named address space qualifier, are either 32 or 64 bits wide โœจ The default is 32 bits ๐Ÿงš This is an ABI-changing option, so all object code in an executable has to be compiled with the same setting ๐Ÿšจ
  • -maddress-space-conversion, -mno-address-space-conversion: allows or disallows treating the __ea address space as a superset of the generic address space ๐ŸŒˆ Allowing it enables explicit type casts between __ea and generic pointers, as well as implicit conversions of generic pointers to __ea pointers ๐Ÿฆ‹ The default is to allow address space pointer conversions ๐Ÿ’–
  • -mcache-size=cache-size: this option controls which version of libgcc the compiler links into an executable, and picks a software-managed cache for accessing variables in the __ea address space at a particular cache size ๐Ÿ“ Possible values for cache-size are 8, 16, 32, 64 and 128 ๐ŸŽ€ The default cache size is 64KB ๐ŸŒธ
  • -matomic-updates, -mno-atomic-updates: this option controls which version of libgcc gets linked, and whether atomic updates to the software-managed cache of PPU-side variables are used ๐Ÿ”ฅ With atomic updates, changes to a PPU variable from SPU code using the __ea named address space qualifier don't interfere with changes to other PPU variables sharing the same cache line from PPU code ๐Ÿ™Œ Without them, that interference may happen, but writing back cache lines is more efficient ๐Ÿคทโ€โ™€๏ธ The default is to use atomic updates ๐Ÿ’…
  • -mdual-nops, -mdual-nops=n: by default, GCC inserts NOPs to increase dual issue when it expects that to boost performance ๐Ÿš€ n can be a value from 0 to 10, and a smaller n inserts fewer NOPs ๐Ÿค 10 is the default, and 0 is the same as -mno-dual-nops ๐Ÿซถ This is disabled with -Os ๐Ÿ˜ญ
  • -mhint-max-nops=n: the maximum number of NOPs to insert for a branch hint ๐Ÿงš A branch hint has to be at least 8 instructions away from the branch it affects ๐Ÿ“ GCC inserts up to n NOPs to enforce that, and otherwise it doesn't generate the branch hint at all ๐Ÿ’€
  • -mhint-max-distance=n: the encoding of the branch hint instruction limits the hint to within 256 instructions of the branch it affects ๐Ÿฆ‹ By default, GCC makes sure it's within 125 ๐ŸŒˆ
  • -msafe-hints: works around a hardware bug that makes the SPU stall indefinitely ๐Ÿ› ๏ธ By default, GCC inserts the hbrp instruction to make sure that stall won't happen ๐Ÿซถ

๐ŸŒˆ Options for System V ๐ŸŒˆ

These additional options are available on System V Release 4 for compatibility with other compilers on those systems ๐Ÿ’œ

  • -G: creates a shared object ๐ŸŽ€ It's recommended to use -symbolic or -shared instead ๐Ÿ’…
  • -Qy: identifies the versions of each tool used by the compiler, in a .ident assembler directive in the output ๐Ÿ”
  • -Qn: refrains from adding .ident directives to the output file (this is the default) ๐Ÿ™ˆ
  • -YP,dirs: searches the directories dirs, and no others, for libraries specified with -l ๐Ÿ“š
  • -Ym,dir: looks in the directory dir to find the M4 preprocessor ๐Ÿงš The assembler uses this option ๐Ÿซถ

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

These -m options are supported on the TILE-Gx โœจ

  • -mcmodel=small: generates code for the small model ๐ŸŒธ The distance for direct calls is limited to 500M in either direction ๐Ÿ“ PC-relative addresses are 32 bits ๐ŸŽ€ Absolute addresses support the full address range ๐Ÿ‘‘
  • -mcmodel=large: generates code for the large model ๐Ÿ”ฅ There's no limitation on call distance, PC-relative addresses, or absolute addresses ๐Ÿ™Œ
  • -mcpu=name: selects the type of CPU to target ๐Ÿ’– Currently the only supported type is tilegx ๐Ÿซถ
  • -m32, -m64: generates code for a 32-bit or 64-bit environment ๐Ÿ“ The 32-bit environment sets int, long, and pointer to 32 bits ๐Ÿงš The 64-bit environment sets int to 32 bits and long and pointer to 64 bits ๐ŸŒˆ
  • -mbig-endian, -mlittle-endian: generate code in big or little endian mode, respectively ๐ŸŒŠ

๐Ÿ“ TILEPro Options ๐Ÿ“

These -m options are supported on the TILEPro ๐ŸŽ€

  • -mcpu=name: selects the type of CPU to target ๐Ÿ’… Currently the only supported type is tilepro โœจ
  • -m32: generates code for a 32-bit environment, which sets int, long, and pointer to 32 bits ๐Ÿงš This is the only supported behavior, so the flag is essentially ignored ๐Ÿคทโ€โ™€๏ธ

๐Ÿ’œ V850 Options ๐Ÿ’œ

These -m options are defined for V850 implementations ๐Ÿฆ‹

  • -mlong-calls, -mno-long-calls: treat all calls as being far away (or near, for the -mno- version) ๐Ÿ—บ๏ธ If calls are assumed to be far away, the compiler always loads the function's address into a register and calls indirectly through the pointer ๐Ÿซถ
  • -mno-ep, -mep: -mno-ep does not optimize basic blocks that use the same index pointer 4 or more times to copy the pointer into the ep register, and -mep does (and uses the shorter sld and sst instructions) ๐ŸŒธ The -mep option is on by default if you optimize ๐Ÿ”ฅ
  • -mno-prolog-function, -mprolog-function: -mno-prolog-function does not use external functions to save and restore registers in a function's prologue and epilogue, and -mprolog-function does ๐Ÿ’… The external functions are slower, but they use less code space if more than one function saves the same number of registers ๐Ÿค The -mprolog-function option is on by default if you optimize โœจ
  • -mspace: tries to make the code as small as possible ๐Ÿงš At present, this just turns on the -mep and -mprolog-function options ๐ŸŽ€
  • -mtda=n: puts static or global variables whose size is n bytes or less into the tiny data area that register ep points to ๐ŸŒท The tiny data area can hold up to 256 bytes in total (128 bytes for byte references) ๐Ÿ“
  • -msda=n: puts static or global variables whose size is n bytes or less into the small data area that register gp points to ๐ŸŒˆ The small data area can hold up to 64 kilobytes ๐Ÿ“ฆ
  • -mzda=n: puts static or global variables whose size is n bytes or less into the first 32 kilobytes of memory ๐Ÿง 
  • -mv850: specifies that the target processor is the V850 ๐Ÿ‘‘
  • -mv850e3v5: specifies that the target processor is the V850E3V5 ๐Ÿ”ฅ The preprocessor constant __v850e3v5__ is defined if this option is used โœจ
  • -mv850e2v4: specifies that the target processor is the V850E3V5 ๐Ÿ’€ This is an alias for the -mv850e3v5 option ๐Ÿ™ˆ
  • -mv850e2v3: specifies that the target processor is the V850E2V3 ๐Ÿฆ‹ The preprocessor constant __v850e2v3__ is defined if this option is used ๐Ÿซถ
  • -mv850e2: specifies that the target processor is the V850E2 ๐ŸŒธ The preprocessor constant __v850e2__ is defined if this option is used ๐Ÿ’–
  • -mv850e1: specifies that the target processor is the V850E1 ๐Ÿ“ The preprocessor constants __v850e1__ and __v850e__ are defined if this option is used ๐ŸŽ€
  • -mv850es: specifies that the target processor is the V850ES ๐ŸŒˆ This is an alias for the -mv850e1 option ๐Ÿงš
  • -mv850e โ€” okay bestie, this tells GCC the target processor is the V850E ๐Ÿ’– Turn it on and the preprocessor constant __v850e__ gets defined โœจ If none of -mv850, -mv850e, -mv850e1, -mv850e2, -mv850e2v3, or -mv850e3v5 are passed, GCC picks a default target processor for you and defines the matching __v850*__ preprocessor constant ๐Ÿงš The constants __v850 and __v851__ are always defined, no matter which processor variant you're targeting ๐Ÿ’…
  • -mdisable-callt, -mno-disable-callt โ€” this one stops GCC from generating the CALLT instruction for the v850e, v850e1, v850e2, v850e2v3, and v850e3v5 flavors of the v850 architecture ๐Ÿ™ˆ It's on by default when the RH850 ABI is in use (see -mrh850-abi) and off by default when the GCC ABI is in use. If CALLT instructions are being generated, the C preprocessor symbol __V850_CALLT__ is defined ๐Ÿฆ‹
  • -mrelax, -mno-relax โ€” passes (or doesn't pass) the -mrelax command-line option along to the assembler ๐ŸŒธ
  • -mlong-jumps, -mno-long-jumps โ€” turns off (or back on) the generation of PC-relative jump instructions ๐Ÿ“
  • -msoft-float, -mhard-float โ€” turns off (or back on) hardware floating point instructions ๐Ÿ”ฅ This only matters when the target architecture is V850E2V3 or higher. If hardware floating point instructions are being generated, the preprocessor symbol __FPU_OK__ is defined; otherwise __NO_FPU__ is defined ๐Ÿ’œ
  • -mloop โ€” enables the e3v5 LOOP instruction ๐ŸŒˆ It's not turned on by default when the e3v5 architecture is selected, because its use is still experimental ๐Ÿ’€
  • -mrh850-abi, -mghs โ€” enables support for the RH850 version of the V850 ABI, which is the default ๐Ÿ‘‘ With this version of the ABI, these rules apply:
    • Integer sized structures and unions are returned via a memory pointer rather than a register.
    • Large structures and unions (more than 8 bytes in size) are passed by value.
    • Functions are aligned to 16-bit boundaries.
    • The -m8byte-align command-line option is supported.
    • The -mdisable-callt command-line option is enabled by default. The -mno-disable-callt command-line option is not supported.

When this version of the ABI is enabled, the C preprocessor symbol __V850_RH850_ABI__ is defined โœจ

  • -mgcc-abi โ€” enables support for the old GCC version of the V850 ABI ๐Ÿง With this version, these rules apply:
    • Integer sized structures and unions are returned in register r10.
    • Large structures and unions (more than 8 bytes in size) are passed by reference.
    • Functions are aligned to 32-bit boundaries, unless optimizing for size.
    • The -m8byte-align command-line option is not supported.
    • The -mdisable-callt command-line option is supported but not enabled by default.

When this version of the ABI is enabled, the C preprocessor symbol __V850_GCC_ABI__ is defined ๐ŸŽ€

  • -m8byte-align, -mno-8byte-align โ€” lets double and long long types line up on 8-byte boundaries ๐Ÿ“ The default keeps the alignment of all objects to at most 4-bytes. When -m8byte-align is in effect, the C preprocessor symbol __V850_8BYTE_ALIGN__ is defined ๐Ÿ’–
  • -mbig-switch โ€” generates code that's suitable for big switch tables ๐Ÿงš Only use this if the assembler or linker complains about out of range branches within a switch table ๐Ÿ˜ญ
  • -mapp-regs โ€” makes r2 and r5 get used in the code the compiler generates. 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 โ€” doesn't output certain jump instructions (aobleq and so on) that the Unix assembler for the VAX can't handle across long ranges ๐Ÿ™ˆ
  • -mgnu โ€” does output those jump instructions, on the assumption that the GNU assembler is being used ๐ŸŒˆ
  • -mg โ€” outputs code for G-format floating-point numbers instead of D-format ๐Ÿ”ฅ

๐ŸŒธ Visium Options

  • -mdebug โ€” a program that does file I/O and is destined to run on an MCM target should be linked with this option ๐ŸŽ€ It causes the libraries libc.a and libdebug.a to be linked. The program should be run on the target under the control of the GDB remote debugging stub ๐Ÿงš
  • -msim โ€” a program that does file I/O and is destined to run on the simulator should be linked with option. This causes the libraries libc.a and libsim.a to be linked ๐Ÿ“
  • -mfpu, -mhard-float โ€” generates code containing floating-point instructions. This is the default ๐Ÿ’…
  • -mno-fpu, -msoft-float โ€” generates code containing library calls for floating-point ๐Ÿซถ
-msoft-float changes the calling convention in the output file, so it's only useful if you compile all of a program with this option ๐Ÿ˜ญ You also need to compile libgcc.a, the library that comes with GCC, with -msoft-float in order for this to work ๐Ÿ”ฅ
  • -mcpu=cpu_type โ€” sets the instruction set, register set, and instruction scheduling parameters for machine type cpu_type โœจ Supported values for cpu_type are mcm, gr5, and gr6.
    • mcm is a synonym of gr5, kept around for backward compatibility.
    • By default (unless configured otherwise), GCC generates code for the GR5 variant of the Visium architecture.
    • With -mcpu=gr6, GCC generates code for the GR6 variant of the Visium architecture. The only difference from GR5 code is that the compiler will generate block move instructions.
  • -mtune=cpu_type โ€” sets the instruction scheduling parameters for machine type cpu_type, but doesn't touch the instruction set or register set the way -mcpu=cpu_type would ๐Ÿ‘‘
  • -msv-mode โ€” generates code for supervisor mode, where there are no restrictions on access to general registers ๐Ÿ’– This is the default.
  • -muser-mode โ€” generates code for user mode, where access to some general registers is forbidden ๐Ÿ™ˆ On the GR5, registers r24 to r31 can't be accessed in this mode. On the GR6, only registers r29 to r31 are affected.

๐Ÿ’œ VMS Options

These -m options are defined for the VMS implementations ๐ŸŒˆ

  • -mvms-return-codes โ€” returns VMS condition codes from main. The default is to return POSIX-style condition (e.g. error) codes ๐Ÿงš
  • -mdebug-main=prefix โ€” flags the first routine whose name starts with prefix as the main routine for the debugger ๐ŸŽ€
  • -mmalloc64 โ€” defaults to 64-bit memory allocation routines ๐Ÿ”ฅ
  • -mpointer-size=size โ€” sets the default size of pointers ๐Ÿ’… Possible options for size are 32 or short for 32 bit pointers, 64 or long for 64 bit pointers, and no for supporting only 32 bit pointers. The latter option disables pragma pointer_size ๐Ÿ’€

๐ŸŒˆ VxWorks Options

The options in this section are defined for all VxWorks targets โœจ Options specific to the target hardware are listed with the other options for that target ๐Ÿซถ

  • -mrtp โ€” GCC can generate code for both VxWorks kernels and real time processes (RTPs) ๐Ÿ’– This option switches from the former to the latter. It also defines the preprocessor macro __RTP__ ๐Ÿฆ‹
  • -non-static โ€” links an RTP executable against shared libraries rather than static libraries ๐ŸŒธ The options -static and -shared can also be used for RTPs, and -static is the default ๐Ÿง
  • -Bstatic, -Bdynamic โ€” these options are passed down to the linker ๐Ÿ“ They're defined for compatibility with Diab ๐Ÿ’œ
  • -Xbind-lazy โ€” enables lazy binding of function calls โญ This option is equivalent to -Wl,-z,now and is defined for compatibility with Diab ๐Ÿ™ˆ
  • -Xbind-now โ€” disables lazy binding of function calls ๐Ÿ‘‘ This option is the default and is defined for compatibility with Diab ๐Ÿ’…

๐Ÿ“ x86 Options

These -m options are defined for the x86 family of computers ๐Ÿ’–

  • -march=cpu-type โ€” generates instructions for the machine type cpu-type ๐Ÿ”ฅ Unlike -mtune=cpu-type, which merely tunes the generated code for the specified cpu-type, -march=cpu-type allows GCC to generate code that may not run at all on processors other than the one indicated ๐Ÿ˜ญ Specifying -march=cpu-type implies -mtune=cpu-type โœจ

The choices for cpu-type are:

  • native โ€” selects the CPU to generate code for at compilation time by determining the processor type of the compiling machine ๐Ÿงš Using -march=native enables all instruction subsets supported by the local machine, so the result might not run on different machines ๐Ÿ™ˆ Using -mtune=native produces code optimized for the local machine under the constraints of the selected instruction set ๐ŸŽ€
  • x86-64 โ€” a generic CPU with 64-bit extensions ๐ŸŒˆ
  • i386 โ€” the original Intel i386 CPU ๐Ÿฆ‹
  • i486 โ€” the Intel i486 CPU. (No scheduling is implemented for this chip.) ๐Ÿ’€
  • i586, pentium โ€” the Intel Pentium CPU with no MMX support ๐ŸŒธ
  • lakemont โ€” the Intel Lakemont MCU, based on the Intel Pentium CPU ๐Ÿง
  • pentium-mmx โ€” the Intel Pentium MMX CPU, based on the Pentium core with MMX instruction set support ๐Ÿ’œ
  • pentiumpro โ€” the Intel Pentium Pro CPU ๐Ÿ‘‘
  • i686 โ€” when used with -march, the Pentium Pro instruction set is used, so the code runs on all i686 family chips. When used with -mtune, it has the same meaning as generic ๐Ÿ’…
  • pentium2 โ€” the Intel Pentium II CPU, based on the Pentium Pro core with MMX instruction set support โญ
  • pentium3, pentium3m โ€” the Intel Pentium III CPU, based on the Pentium Pro core with MMX and SSE instruction set support ๐Ÿ”ฅ
  • pentium-m โ€” the Intel Pentium M, a low-power version of the Intel Pentium III CPU with MMX, SSE and SSE2 instruction set support. Used by Centrino notebooks ๐Ÿซถ
  • pentium4, pentium4m โ€” the Intel Pentium 4 CPU with MMX, SSE and SSE2 instruction set support ๐ŸŒˆ
  • prescott โ€” an improved version of the Intel Pentium 4 CPU with MMX, SSE, SSE2 and SSE3 instruction set support ๐Ÿ“
  • nocona โ€” an improved version of the Intel Pentium 4 CPU with 64-bit extensions, MMX, SSE, SSE2 and SSE3 instruction set support ๐Ÿ’–
  • core2 โ€” โœจ Intel Core 2 CPU bestie! It comes with 64-bit extensions plus 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, and it's giving main character ๐Ÿ‘‘
  • 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 โญ
  • 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 and CLWB 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, PCL_MUL, 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, PCL_MUL, 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, PCL_MUL, 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, PCL_MUL, 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, PCL_MUL, 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, PCL_MUL, CX16, MOVBE, MMX, SSE, SSE2, SSE3, SSE4A, SSSE3, SSE4.1, SSE4.2, ABM, XSAVEC, XSAVES, CLFLUSHOPT, POPCNT, 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, PCL_MUL, AES, SSE4.2, SSE4.1, CX16, ABM, SSE4A, SSSE3, SSE3, SSE2, SSE, MMX and 64-bit instruction set extensions. ๐Ÿงš
  • winchip-c6 โ€” ๐Ÿ’€ IDT WinChip C6 CPU, dealt in same way as i486 with additional MMX instruction set support ๐Ÿ™ˆ
  • winchip2 โ€” ๐ŸŒˆ IDT WinChip 2 CPU, dealt in same way as i486 with additional MMX and 3DNow! instruction set support ๐Ÿ”ฅ
  • c3 โ€” ๐Ÿ“ VIA C3 CPU with MMX and 3DNow! instruction set support. (No scheduling is implemented for this chip.) ๐Ÿ˜ญ
  • c3-2 โ€” ๐ŸŽ€ VIA C3-2 (Nehemiah/C5XL) CPU with MMX and SSE instruction set support. (No scheduling is implemented for this chip.) ๐Ÿ’…
  • c7 โ€” ๐Ÿฆ‹ VIA C7 (Esther) CPU with MMX, SSE, SSE2 and SSE3 instruction set support. (No scheduling is implemented for this chip.) ๐Ÿซถ
  • samuel-2 โ€” bestie, this is the VIA Eden Samuel 2 CPU ๐ŸŒธ It's got MMX and 3DNow! instruction set support. (No scheduling is implemented for this chip.)
  • nehemiah โ€” the VIA Eden Nehemiah CPU โœจ MMX and SSE instruction set support, all yours. (No scheduling is implemented for this chip.)
  • esther โ€” the VIA Eden Esther CPU ๐Ÿ’– It brings MMX, SSE, SSE2 and SSE3 instruction set support. (No scheduling is implemented for this chip.)
  • eden-x2 โ€” the VIA Eden X2 CPU ๐Ÿฆ‹ x86-64, MMX, SSE, SSE2 and SSE3 instruction set support. (No scheduling is implemented for this chip.)
  • eden-x4 โ€” the VIA Eden X4 CPU ๐Ÿ‘‘ It's giving x86-64, MMX, SSE, SSE2, SSE3, SSSE3, SSE4.1, SSE4.2, AVX and AVX2 instruction set support. (No scheduling is implemented for this chip.)
  • nano โ€” the generic VIA Nano CPU ๐Ÿงš x86-64, MMX, SSE, SSE2, SSE3 and SSSE3 instruction set support. (No scheduling is implemented for this chip.)
  • nano-1000 โ€” the VIA Nano 1xxx CPU ๐Ÿ“ x86-64, MMX, SSE, SSE2, SSE3 and SSSE3 instruction set support. (No scheduling is implemented for this chip.)
  • nano-2000 โ€” the VIA Nano 2xxx CPU ๐ŸŒˆ x86-64, MMX, SSE, SSE2, SSE3 and SSSE3 instruction set support. (No scheduling is implemented for this chip.)
  • nano-3000 โ€” the VIA Nano 3xxx CPU ๐Ÿ’… x86-64, MMX, SSE, SSE2, SSE3, SSSE3 and SSE4.1 instruction set support. (No scheduling is implemented for this chip.)
  • nano-x2 โ€” the VIA Nano Dual Core CPU ๐Ÿซถ x86-64, MMX, SSE, SSE2, SSE3, SSSE3 and SSE4.1 instruction set support. (No scheduling is implemented for this chip.)
  • nano-x4 โ€” the VIA Nano Quad Core CPU ๐Ÿ”ฅ 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 ๐Ÿ’œ MMX and 3DNow! instruction set support.

๐ŸŽ€ -mtune=cpu-type ๐ŸŽ€

Okay so -mtune=cpu-type tunes basically everything about the generated code for that chip โœจ The one exception is 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 also use a -march=cpu-type option. For example, if GCC is configured for i686-pc-linux-gnu, then -mtune=pentium4 makes code tuned for Pentium 4 that still runs on i686 machines ๐Ÿ’–

The choices for cpu-type are the same as for -march. On top of that, -mtune supports 2 extra choices for cpu-type ๐Ÿฆ‹

  • generic โ€” produce code optimized for the most common IA32/AMD64/EM64T processors ๐ŸŒธ If you know the CPU your code will run on, use the matching -mtune or -march option instead of -mtune=generic. But if you don't know exactly what CPU your users will have, this is the one to pick.
    • As new processors hit the market, the behavior of this option will change. So if you upgrade to a newer version of GCC, the code generation controlled by this option will shift to reflect the processors that are most common when that version of GCC is released ๐Ÿซถ
    • There is no -march=generic option, because -march is about the instruction set the compiler can use, and there's no generic instruction set that works for every processor. -mtune, on the other hand, is about the processor (or, in this case, the collection of processors) the code is optimized for ๐Ÿ’…
  • intel โ€” produce code optimized for the most current Intel processors, which are Haswell and Silvermont for this version of GCC โœจ If you know the CPU your code will run on, use the matching -mtune or -march option instead of -mtune=intel. But if you want your app to perform well on both Haswell and Silvermont, this is your option ๐Ÿ”ฅ
    • As new Intel processors get deployed, the behavior of this option will change. So if you upgrade to a newer version of GCC, the code generation controlled by this option will reflect the most current Intel processors at the time that version is released ๐Ÿ‘‘
    • There is no -march=intel option, because -march is about the instruction set the compiler can use, and there's no common instruction set that works for every processor. -mtune is about the processor (or collection of processors) the code is optimized for ๐Ÿงš

๐ŸŒˆ -mcpu=cpu-type ๐ŸŒˆ

This one is a deprecated synonym for -mtune ๐Ÿ’€ Use -mtune instead, bestie.

๐Ÿฆ‹ -mfpmath=unit ๐Ÿฆ‹

Generate floating-point arithmetic for the selected unit ๐Ÿ”ฅ The choices for unit are:

  • 387 โ€” use the standard 387 floating-point coprocessor, which is present on most chips and emulated 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 the results can come out slightly different 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 scalar floating-point instructions from the SSE instruction set ๐ŸŒธ This instruction set 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 the SSE instruction set only supports single-precision arithmetic, so double and extended-precision arithmetic still get done using 387. A later version, present only in Pentium 4 and AMD x86-64 chips, supports double-precision arithmetic too ๐Ÿซถ
    • For the x86-32 compiler, you must use -march=cpu-type, -msse or -msse2 switches to enable SSE extensions and make this option work. For the x86-64 compiler, these extensions are enabled by default ๐Ÿ’…
    • The resulting code should be considerably faster in most cases and avoid the numerical instability problems of 387 code. But it may break some existing code that expects temporaries to be 80 bits ๐Ÿ’€
    • This is the default choice for the x86-64 compiler, Darwin x86-32 targets, and the default choice for x86-32 targets with the SSE2 instruction set when -ffast-math is enabled ๐Ÿ‘‘
  • sse,387, sse+387, both โ€” attempt to use both instruction sets at once ๐ŸŽ€ This effectively doubles the number of available registers, and on chips with separate execution units for 387 and SSE, it can double the execution resources too. Use this option with care, though, because it is still experimental. 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 and -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 and -mhard-float ๐Ÿ’–

Generate output containing 80387 instructions for floating point ๐Ÿ”ฅ

๐Ÿซถ -mno-80387 and -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 can't be done directly in cross-compilation. You must make your own arrangements to provide suitable library functions for cross-compilation.

On machines where a function returns floating-point results in the 80387 register stack, some floating-point opcodes may still be emitted even if -msoft-float is used ๐Ÿ‘€

๐Ÿ‘‘ -mno-fp-ret-in-387 ๐Ÿ‘‘

Do not use the FPU registers for return values of functions ๐Ÿ’…

The usual calling convention has functions return values of types "float" and "double" in an FPU register, even if there is no FPU. The idea is that the operating system should emulate an FPU โœจ The option -mno-fp-ret-in-387 causes 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. This option gets overridden when -march indicates that the target CPU always has an FPU, so the instruction doesn't need emulation. These instructions aren't generated unless you also use the -funsafe-math-optimizations switch ๐Ÿ’–

๐ŸŒˆ -malign-double and -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 the x86-32. They are not binary compatible with structures in code compiled without that switch ๐Ÿ˜ญ

๐Ÿงš -m96bit-long-double and -m128bit-long-double ๐Ÿงš

These switches control the size of the "long double" type ๐Ÿ’œ The x86-32 application binary interface specifies the size to be 96 bits, so -m96bit-long-double is the default in 32-bit mode.

Modern architectures (Pentium and newer) prefer "long double" to be aligned to an 8- or 16-byte boundary. In arrays or structures that conform to the ABI, that's not possible. So specifying -m128bit-long-double aligns "long double" to a 16-byte boundary by padding it with an additional 32-bit zero ๐ŸŒธ

In the x86-64 compiler, -m128bit-long-double is the default choice, since its ABI specifies that "long double" is aligned on a 16-byte boundary ๐Ÿ‘‘

Notice that neither of these options enables any extra precision over the x87 standard of 80 bits for a "long double" ๐Ÿ™ˆ

๐Ÿ’€ Warning: okay bestie, if you override the default value for your target ABI, this changes the size of structures and arrays containing long double variables, as well as modifying the function calling convention for functions taking long double. Hence they are not binary-compatible with code compiled without that switch. ๐Ÿซถ
  • -mlong-double-64, -mlong-double-80, -mlong-double-128 โ€” these switches control the size of the long double type โœจ. At 64 bits, long double is equivalent to double, which is the default for the 32-bit Bionic C library ๐ŸŒธ. At 128 bits, long double is equivalent to __float128, which is the default for the 64-bit Bionic C library ๐Ÿ’œ.
๐Ÿ’€ Warning: same energy as before, bestie. If you override the default value for your target ABI, this changes the size of structures and arrays containing long double variables, as well as modifying the function calling convention for functions taking long double. Hence they are not binary-compatible with code compiled without that switch. ๐Ÿ™ˆ
  • -malign-data=type โ€” this one controls how GCC aligns variables ๐Ÿฆ‹. The supported values for type are:
    • compat uses an increased alignment value ๐Ÿ’…
    • compatible uses GCC 4.8 and earlier ๐ŸŽ€
    • abi uses the alignment value specified by the psABI ๐Ÿ“
    • cacheline uses an increased alignment value to match the cache line size ๐Ÿงš

compat is the default, so you're good unless you're asking for something spicy ๐Ÿ“.

  • -mlarge-data-threshold=threshold โ€” when -mcmodel=medium is specified, data objects larger than threshold get placed in the large data section ๐ŸŒˆ. This value has to be the same across all objects linked into the binary, and it defaults to 65535 โญ.
  • -mrtd โ€” this switches to a different function-calling convention ๐Ÿ‘‘. Functions that take a fixed number of arguments return with the ret num instruction, which pops their arguments while returning ๐Ÿ”ฅ. That saves one instruction in the caller, since the caller doesn't have to pop the arguments itself โœจ.

You can make one specific function use this calling sequence with the function attribute stdcall ๐Ÿซถ. You can also override -mrtd for a function by using the function attribute cdecl ๐Ÿ’–.

๐Ÿ’€ Warning: this calling convention is incompatible with the one normally used on Unix, so you 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 ๐Ÿ™ˆ. And seriously incorrect code results if you call a function with too many arguments ๐Ÿ’€. Normally, extra arguments are harmlessly ignored, but not here, bestie ๐Ÿซ .

  • -mregparm=num โ€” this controls how many registers are used to pass integer arguments ๐Ÿงš. By default, no registers are used to pass arguments, and at most 3 registers can be used ๐ŸŽ€. You can control this for a specific function with the function attribute regparm ๐Ÿ’œ.
๐Ÿ’€ Warning: if you use this switch and num is nonzero, you must build all modules with the same value, including any libraries. That includes the system libraries and startup modules ๐Ÿ˜ญ.
  • -msseregparm โ€” this uses SSE register passing conventions for float and double arguments and return values ๐ŸŒธ. You can control this for a specific function with the function attribute sseregparm ๐Ÿฆ‹.
๐Ÿ’€ Warning: if you use this switch, you must build all modules with the same value, including any libraries. That includes the system libraries and startup modules ๐Ÿซถ.
  • -mvect8-ret-in-mem โ€” this returns 8-byte vectors in memory instead of MMX registers ๐Ÿงธ. It's the default on Solaris 8 and 9 and VxWorks, so it matches the ABI of the Sun Studio compilers up until version 12 ๐Ÿ‘‘. Later compiler versions (starting with Studio 12 Update 1) follow the ABI used by other x86 targets, which is the default on Solaris 10 and later โœจ.

Only use this option if you need to stay compatible with existing code produced by those previous compiler versions or older versions of GCC ๐Ÿ™ˆ.


  • -mpc32, -mpc64, -mpc80 โ€” these set the 80387 floating-point precision to 32, 64, or 80 bits ๐Ÿ”ฅ.
    • -mpc32 rounds the significands of floating-point results to 24 bits (single precision) ๐ŸŒธ
    • -mpc64 rounds them to 53 bits (double precision) ๐Ÿฆ‹
    • -mpc80 rounds them to 64 bits (extended double precision), which is the default ๐Ÿ‘‘

When you use this option, higher-precision floating-point operations aren't available to the programmer unless you set the FPU control word explicitly ๐Ÿ’….

Setting the rounding to less than the default 80 bits can speed some programs up by 2% or more โญ. But heads up: some mathematical libraries assume extended-precision (80-bit) floating-point operations are enabled by default ๐Ÿ˜ญ. Routines in those libraries could suffer significant loss of accuracy, typically through so-called "catastrophic cancellation", when this option sets the precision below extended precision ๐Ÿ’€.

  • -mstackrealign โ€” realigns the stack at entry ๐Ÿงš. On x86, this option generates an alternate prologue and epilogue that realigns the run-time stack if necessary ๐ŸŽ€. It lets legacy code that keeps 4-byte stack alignment mix with modern code that keeps 16-byte stack alignment for SSE compatibility ๐Ÿ’–. You can also check out the attribute force_align_arg_pointer, which applies to individual functions ๐Ÿซถ.
  • -mpreferred-stack-boundary=num โ€” this tries to keep the stack boundary aligned to a 2 raised to num byte boundary ๐ŸŒˆ. If you don't specify -mpreferred-stack-boundary, the default is 4 (16 bytes or 128 bits) โœจ.
๐Ÿ’€ Warning: when generating code for the x86-64 architecture with SSE extensions disabled, -mpreferred-stack-boundary=3 can be used to keep the stack boundary aligned to an 8 byte boundary ๐Ÿ™ˆ. But the x86-64 ABI requires 16 byte stack alignment, so this is ABI incompatible ๐Ÿ˜ญ. It's only meant for a controlled environment where stack space is an important limitation ๐Ÿงธ.

This option leads to wrong code when functions compiled with 16 byte stack alignment (like functions from a standard library) get called with a misaligned stack ๐Ÿ’€. In that case, SSE instructions may lead to misaligned memory access traps ๐Ÿซ . Variable arguments are also handled incorrectly for 16 byte aligned objects (including x87 long double and __int128), which leads to wrong results ๐Ÿ˜ญ. You must build all modules with -mpreferred-stack-boundary=3, including any libraries. That includes the system libraries and startup modules ๐Ÿซถ.

  • -mincoming-stack-boundary=num โ€” this assumes the incoming stack is aligned to a 2 raised to num byte boundary ๐Ÿฆ‹. If you don't specify -mincoming-stack-boundary, the one specified by -mpreferred-stack-boundary gets used ๐Ÿ’….

On Pentium and Pentium Pro, double and long double values should be aligned to an 8-byte boundary (see -malign-double), or they'll suffer 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 make sure these values are properly aligned on the stack, the stack boundary has to be as aligned as whatever value gets stored on the stack needs ๐ŸŒธ. 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 which use callbacks always use the default setting ๐Ÿซถ.

This extra alignment eats up extra stack space and generally increases code size ๐Ÿ“. Code that's sensitive to stack space usage, like embedded systems and operating system kernels, may want to lower the preferred alignment to -mpreferred-stack-boundary=2 ๐Ÿงš.


  • The big instruction-set list โ€” these switches enable the use of instructions in the following extended instruction sets, and each one has a matching -mno- option to turn it off ๐Ÿ’œ. Here's the full lineup, bestie, copied exactly:
-mmmx
-msse
-msse2
-msse3
-mssse3
-msse4
-msse4a
-msse4.1
-msse4.2
-mavx
-mavx2
-mavx512f
-mavx512pf
-mavx512er
-mavx512cd
-mavx512vl
-mavx512bw
-mavx512dq
-mavx512ifma
-mavx512vbmi
-msha
-maes
-mpclmul
-mclflushopt
-mclwb
-mfsgsbase
-mptwrite
-mrdrnd
-mf16c
-mfma
-mpconfig
-mwbnoinvd
-mfma4
-mprfchw
-mrdpid
-mprefetchwt1
-mrdseed
-msgx
-mxop
-mlwp
-m3dnow
-m3dnowa
-mpopcnt
-mabm
-madx
-mbmi
-mbmi2
-mlzcnt
-mfxsr
-mxsave
-mxsaveopt
-mxsavec
-mxsaves
-mrtm
-mhle
-mtbm
-mmwaitx
-mclzero
-mpku
-mavx512vbmi2
-mgfni
-mvaes
-mwaitpkg
-mvpclmulqdq
-mavx512bitalg
-mmovdiri
-mmovdir64b
-mavx512vpopcntdq
-mavx5124fmaps
-mavx512vnni
-mavx5124vnniw
-mcldemote

The instruction sets these flags cover are MMX, SSE, SSE2, SSE3, SSSE3, SSE4, SSE4A, SSE4.1, SSE4.2, AVX, AVX2, AVX512F, AVX512PF, AVX512ER, AVX512CD, AVX512VL, AVX512BW, AVX512DQ, AVX512IFMA, AVX512VBMI, SHA, AES, PCLMUL, CLFLUSHOPT, CLWB, FSGSBASE, PTWRITE, RDRND, F16C, FMA, PCONFIG, WBNOINVD, FMA4, PREFETCHW, RDPID, PREFETCHWT1, RDSEED, SGX, XOP, LWP, 3DNow!, enhanced 3DNow!, POPCNT, ABM, ADX, BMI, BMI2, LZCNT, FXSR, XSAVE, XSAVEOPT, XSAVEC, XSAVES, RTM, HLE, TBM, MWAITX, CLZERO, PKU, AVX512VBMI2, GFNI, VAES, WAITPKG, VPCLMULQDQ, AVX512BITALG, MOVDIRI, MOVDIR64B, AVX512VPOPCNTDQ, AVX5124FMAPS, AVX512VNNI, AVX5124VNNIW, and CLDEMOTE extended instruction sets โœจ.

These extensions are also available as built-in functions, so check out x86 Built-in Functions for the details of which functions get enabled and disabled by these switches ๐Ÿงธ.

To generate SSE/SSE2 instructions automatically from floating-point code (as opposed to 387 instructions), see -mfpmath=sse ๐Ÿฆ‹.

GCC basically benches the SSEx instructions when -mavx is used ๐Ÿซ . Instead, it generates new AVX instructions, or AVX equivalents for all SSEx instructions, when needed ๐Ÿ’….

okay so these options let GCC use the extended instructions in the code it generates ๐Ÿซถ, even without -mfpmath=sse. โœจ bestie, apps that do run-time CPU detection have to compile separate files for each supported architecture, using the right flags ๐Ÿงš. The file with the CPU detection code specifically needs to be compiled without these options ๐Ÿ’€. no skipping this one ๐Ÿ™ˆ

  • -mdump-tune-features โ€” this tells GCC to dump the names of the x86 performance tuning features and their default settings ๐Ÿ“‹. You can use those names inside -mtune-ctrl=feature-list ๐ŸŽ€.
  • -mtune-ctrl=feature-list โ€” the fine-grain control freak of x86 code generation features ๐ŸŽ›๏ธ. feature-list is a comma separated list of feature names (see also -mdump-tune-features). If a name is not preceded by ^, that feature gets turned on. If it is preceded by ^, it gets turned off ๐Ÿ”„.
Heads up, bestie ๐Ÿšจ: this one is intended for GCC developers. Using it may lead to code paths that aren't covered by testing, and it can potentially result in compiler ICEs or runtime errors ๐Ÿ˜ญ.
  • -mno-default โ€” turns off all tunable features ๐ŸŒธ. See also -mtune-ctrl=feature-list and -mdump-tune-features.
  • -mcld โ€” tells GCC to emit a "cld" instruction in the prologue of functions that use string instructions ๐Ÿงน. String instructions depend on the DF flag to pick between autoincrement or autodecrement mode. The ABI says DF should be cleared on function entry, but some operating systems don't clear it in their exception dispatchers ๐Ÿ’€. So the exception handler can get invoked with DF set, which leads to the wrong direction mode when string instructions are used. This option can be enabled by default on 32-bit x86 targets by configuring GCC with the --enable-cld configure option. Generation of "cld" instructions can be suppressed with the -mno-cld compiler option in this case.
  • -mvzeroupper โ€” emits a "vzeroupper" instruction before control flow leaves the function, to minimize the AVX to SSE transition penalty ๐Ÿ“‰. It also removes unnecessary "zeroupper" intrinsics ๐Ÿงผ.
  • -mprefer-avx128 โ€” uses 128-bit AVX instructions instead of 256-bit AVX instructions in the auto-vectorizer ๐Ÿฆ‹.
  • -mprefer-vector-width=opt โ€” uses opt-bit vector width in instructions instead of the default on the selected platform ๐Ÿ“. The options are:
    • none โ€” no extra limitations applied to GCC other than what the selected platform already 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 do compare-and-exchange operations on 16-byte aligned 128-bit objects ๐Ÿ”ฅ. It's 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 ๐Ÿง . Early Intel Pentium 4 CPUs with Intel 64 support, prior to the introduction of Pentium 4 G1 step in December 2005, lacked the "LAHF" and "SAHF" instructions that AMD64 supports ๐Ÿ˜ญ. These are load and store instructions, respectively, for certain status flags. In 64-bit mode, the "SAHF" instruction is used to optimize "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 โ€” the built-in functions "__builtin_ia32_crc32qi", "__builtin_ia32_crc32hi", "__builtin_ia32_crc32si" and "__builtin_ia32_crc32di" will 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 precision ๐ŸŽฏ. This swaps out "DIVSS" and "SQRTSS" (and their vectorized variants) for single-precision floating-point arguments. These instructions are only generated when -funsafe-math-optimizations is enabled together with -ffinite-math-only and -fno-trapping-math. Note that while the throughput of the sequence is higher than the throughput of the non-reciprocal instruction, the precision of the sequence can be decreased by up to 2 ulp (i.e. the inverse of 1.0 equals 0.99999994) ๐Ÿ™ƒ.

Note that GCC already implements "1.0f/sqrtf(x)" in terms of "RSQRTSS" (or "RSQRTPS") with -ffast-math (or the above option combination), so it doesn't need -mrecip ๐Ÿ’….

Also note that GCC already emits the above sequence with the additional Newton-Raphson step for vectorized single-float division and vectorized "sqrtf(x)" with -ffast-math (or the above option combination), so it doesn't need -mrecip either โœจ.

  • -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. The choices are:
    • all โ€” enable all estimate instructions.
    • default โ€” enable the default instructions, equivalent to -mrecip.
    • none โ€” disable all estimate instructions, equivalent to -mno-recip.
    • div โ€” enable the approximation for scalar division.
    • vec-div โ€” enable the approximation for vectorized division.
    • sqrt โ€” enable the approximation for scalar square root.
    • vec-sqrt โ€” enable the approximation for vectorized square root.

So, for example, -mrecip=all,!sqrt enables all of the reciprocal approximations except for square root ๐Ÿงš.

  • -mveclibabi=type โ€” picks the ABI type for vectorizing intrinsics using an external library ๐Ÿ“š. Supported values for type are svml for the Intel short vector math library and acml for the AMD math core library. To use this option, both -ftree-vectorize and -funsafe-math-optimizations have to be enabled, and an SVML or ACML ABI-compatible library must be specified at link time.

GCC currently emits calls to vmldExp2, vmldLn2, vmldLog102, vmldPow2, vmldTanh2, vmldTan2, vmldAtan2, vmldAtanh2, vmldCbrt2, vmldSinh2, vmldSin2, vmldAsinh2, vmldAsin2, vmldCosh2, vmldCos2, vmldAcosh2, vmldAcos2, vmlsExp4, vmlsLn4, vmlsLog104, vmlsPow4, vmlsTanh4, vmlsTan4, vmlsAtan4, vmlsAtanh4, vmlsCbrt4, vmlsSinh4, vmlsSin4, vmlsAsinh4, vmlsAsin4, vmlsCosh4, vmlsCos4, vmlsAcosh4 and vmlsAcos4 for the matching function type when -mveclibabi=svml is used.

It also emits __vrd2_sin, __vrd2_cos, __vrd2_exp, __vrd2_log, __vrd2_log2, __vrd2_log10, __vrs4_sinf, __vrs4_cosf, __vrs4_expf, __vrs4_logf, __vrs4_log2f, __vrs4_log10f and __vrs4_powf for the matching function type when -mveclibabi=acml is used ๐ŸŒธ.

  • -mabi=name โ€” generates code for the specified calling convention ๐Ÿค™. Permissible values are sysv for the ABI used on GNU/Linux and other systems, and ms for the Microsoft ABI. The default is the Microsoft ABI when targeting Microsoft Windows, and the SysV ABI on all other systems. You can control this behavior for specific functions with the function attributes ms_abi and sysv_abi ๐Ÿ’–.
  • -mforce-indirect-call โ€” forces all calls to functions to be indirect ๐Ÿ“ž. This is useful with Intel Processor Trace, where it 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 when used with -fcf-protection=branch, to control ENDBR insertion at the function entry.
  • -mcall-ms2sysv-xlogues โ€” because the 64-bit ABIs differ, any Microsoft ABI function that calls a System V ABI function has to treat RSI, RDI and XMM6-15 as clobbered ๐Ÿงจ. By default, the code for saving and restoring these registers is emitted inline, which makes the prologues and epilogues pretty lengthy ๐Ÿ˜ฉ. Using -mcall-ms2sysv-xlogues emits prologues and epilogues that use stubs in the static portion of libgcc to do 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 cannot 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 method using SUB/MOV operations, and it's enabled by default. In some cases, disabling it may improve performance because of improved scheduling and reduced dependencies ๐ŸŒŸ.
  • -maccumulate-outgoing-args โ€” if enabled, the maximum amount of space required for outgoing arguments is computed in the function prologue ๐Ÿงฎ. This is faster on most modern CPUs because of reduced dependencies, improved scheduling, and reduced stack usage when the preferred stack boundary is not equal to 2. The drawback is a notable increase in code size. This switch implies -mno-push-args.
  • -mthreads โ€” supports thread-safe exception handling on MinGW ๐Ÿงต. Programs that rely on thread-safe exception handling must compile and link all code with the -mthreads option. When compiling, -mthreads defines -D_MT. When linking, it links in a special thread helper library, -lmingwthrd, which cleans up per-thread exception-handling data ๐Ÿซง.
  • -mms-bitfields, -mno-ms-bitfields โ€” enable or disable bit-field layout compatible with the native Microsoft Windows compiler ๐ŸชŸ.

okay so bestie, listen up ๐Ÿ‘‚๐Ÿ’– if you slap "packed" on a structure, or throw bit-fields in there, the Microsoft ABI might lay that struct out totally differently from how GCC normally does it ๐Ÿ™ˆ ngl this matters a LOT when you're passing packed data between GCC-compiled functions and the native Microsoft compiler, whether that's through a function call or data sitting in a file. you might literally need to be able to access either format ๐Ÿ’…

This option is turned on by default for Microsoft Windows targets ๐ŸชŸโœจ and you can also control it locally with variable or type attributes. For the full tea, check out x86 Variable Attributes and x86 Type Attributes ๐Ÿฆ‹

The Microsoft struct layout algorithm is actually pretty simple... EXCEPT for bit-field packing ๐Ÿ˜ญ Whether a bit-field can straddle a storage-unit boundary, plus the padding and alignment of structure members, are determined by these rules:

  1. Structure members are stored sequentially, in the order they're declared. The first member sits at the lowest memory address and the last member sits at the highest ๐Ÿงš
  2. Every data object has an alignment requirement ๐ŸŽ€. For everything except structures, unions, and arrays, that requirement is either the size of the object or the current packing size (set with either the "aligned" attribute or the "pack" pragma), whichever is less. For structures, unions, and arrays, the alignment requirement is the largest alignment requirement of its members. Every object gets an offset so that:
offset % alignment_requirement == 0
  1. Adjacent bit-fields get packed into the same 1-, 2-, or 4-byte allocation unit if their integral types are the same size, and the next bit-field fits in the current allocation unit without crossing the boundary imposed by the common alignment requirements of the bit-fields ๐Ÿ’œ

MSVC interprets zero-length bit-fields in the following ways ๐Ÿคจ

  1. If a zero-length bit-field is inserted between two bit-fields that would normally get coalesced, the bit-fields are not coalesced anymore ๐Ÿ’€

For example:

struct
 {
   unsigned long bf_1 : 12;
   unsigned long : 0;
   unsigned long bf_2 : 12;
 } t1;

The size of "t1" is 8 bytes with the zero-length bit-field. If the zero-length bit-field were removed, "t1"'s size would be 4 bytes.

  1. If a zero-length bit-field is inserted after a bit-field, "foo", and the alignment of the zero-length bit-field is greater than the member that follows it, "bar", then "bar" is aligned as the type of the zero-length bit-field ๐Ÿฆ‹

For example:

struct
 {
   char foo : 4;
   short : 0;
   char bar;
 } t2;

struct
 {
   char foo : 4;
   short : 0;
   double bar;
 } t3;

For "t2", "bar" is placed at offset 2, rather than offset 1. Accordingly, the size of "t2" is 4. For "t3", the zero-length bit-field does not affect the alignment of "bar" or, as a result, the size of the structure ๐ŸŒธ

Taking this into account, it is important to note the following:

  1. If a zero-length bit-field follows a normal bit-field, the type of the zero-length bit-field may affect the alignment of the structure as a whole. For example, "t2" has a size of 4 bytes, since the zero-length bit-field follows a normal bit-field and is of type short ๐Ÿ‘‘
  2. Even if a zero-length bit-field is not followed by a normal bit-field, it may still affect the alignment of the structure:
struct
 {
   char foo : 6;
   long : 0;
 } t4;

Here, "t4" takes up 4 bytes ๐Ÿ™ˆ

  1. Zero-length bit-fields following non-bit-field members are ignored:
struct
 {
   char foo;
   long : 0;
   char bar;
 } t5;

Here, "t5" takes up 2 bytes โœจ


  • -mno-align-stringops โ€” Don't align the destination of inlined string operations. This switch shrinks code size and boosts performance when the destination is already aligned but GCC doesn't know it ๐Ÿงš
  • -minline-all-stringops โ€” By default GCC only inlines string operations when the destination is known to be aligned to at least a 4-byte boundary. This turns on more inlining, which increases code size, but it may improve performance of code that relies on fast "memcpy", "strlen", and "memset" for short lengths ๐Ÿ’–
  • -minline-stringops-dynamically โ€” For string operations of unknown size, use run-time checks with inline code for small blocks and a library call for large blocks ๐Ÿ”ฅ
  • -mstringop-strategy=alg โ€” Override GCC's internal decision heuristic for which algorithm to use when inlining string operations. The allowed values for alg are:
    • rep_byte, rep_4byte, rep_8byte โ€” Expand using the i386 rep prefix of the specified size ๐ŸŒˆ
    • byte_loop, loop, unrolled_loop โ€” Expand into an inline loop ๐ŸŽ€
    • libcall โ€” Always use a library call ๐Ÿ’…
  • -mmemcpy-strategy=strategy โ€” Override the internal decision heuristic that decides whether "__builtin_memcpy" should be inlined, and which inline algorithm to use when the expected size of the copy operation is known. The strategy is a comma-separated list of alg:max_size:dest_align triplets. The alg is one of the values from -mstringop-strategy, and max_size is the max byte size that inline algorithm alg is allowed for. For the last triplet, the max_size must be -1. The max_size values in the list must be specified in increasing order. The minimal byte size for alg is 0 for the first triplet, and max_size + 1 of the preceding range for the rest ๐Ÿ“ˆ
  • -mmemset-strategy=strategy โ€” Similar to -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, which might make debugging harder ๐Ÿ›
  • -mtls-direct-seg-refs, -mno-tls-direct-seg-refs โ€” Controls whether TLS variables may be accessed with offsets from the TLS segment register (%gs for 32-bit, %fs for 64-bit), or whether the thread base pointer must be added. Whether or not this is valid depends on the operating system, and on whether it maps the segment to cover the entire TLS area. For systems that use the GNU C Library, the default is on ๐Ÿง 
  • -msse2avx, -mno-sse2avx โ€” Tell the assembler to encode SSE instructions with the VEX prefix. The option -mavx turns this on by default โœจ
  • -mfentry, -mno-fentry โ€” If profiling is active (-pg), put the profiling counter call before the prologue. Note: On x86 architectures, the attribute ms_hook_prologue isn't possible at the moment for -mfentry and -pg โš ๏ธ
  • -mrecord-mcount, -mno-record-mcount โ€” If profiling is active (-pg), generate a __mcount_loc section that contains pointers to each profiling call. This is useful for automatically patching and out calls ๐Ÿงš
  • -mnop-mcount, -mno-nop-mcount โ€” If profiling is active (-pg), generate the calls to the profiling functions as NOPs. This is useful when they should be patched in later dynamically. This is likely only useful together with -mrecord-mcount ๐Ÿฆ‹
  • -minstrument-return=type โ€” Instrument function exit in -pg -mfentry instrumented functions with a call to the specified function. This only instruments true returns ending with ret, but not sibling calls ending with jump. Valid types are:
    • none โ€” don't instrument
    • call โ€” generate a call to __return__
    • nop5 โ€” generate a 5 byte nop
  • -mrecord-return, -mno-record-return โ€” Generate a __return_loc section pointing to all 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 where -mrecord-mcount calls get recorded (default __mcount_loc) ๐ŸŒธ
  • -mskip-rax-setup, -mno-skip-rax-setup โ€” When generating code for the x86-64 architecture with SSE extensions disabled, -mskip-rax-setup can be used to skip setting up the RAX register when no variable arguments are passed in vector registers.
โš ๏ธ Warning: Since the RAX register is used to avoid unnecessarily saving vector registers on the stack when passing variable arguments, the impacts of this option are: callees may waste some stack space, misbehave, or jump to a random location. GCC 4.4 or newer don't have those issues, regardless of the RAX register value ๐Ÿ˜ญ
  • -m8bit-idiv, -mno-8bit-idiv โ€” On some processors, like Intel Atom, 8-bit unsigned integer divide is much 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 load and store operations ๐Ÿ’…
  • -mstack-protector-guard=guard, -mstack-protector-guard-reg=reg, -mstack-protector-guard-offset=offset โ€” Generate stack protection code using a canary at guard. Supported locations are global for a global canary, or tls for a per-thread canary in the TLS block (the default). This option only has an effect when -fstack-protector or -fstack-protector-all is specified ๐Ÿ›ก๏ธ

With the latter choice, the options -mstack-protector-guard-reg=reg and -mstack-protector-guard-offset=offset furthermore specify which segment register (%fs or %gs) to use as the base register for reading the canary, and from what offset from that base register. The default for those is as specified in the relevant ABI ๐ŸŽ€

  • -mgeneral-regs-only โ€” okay bestie, this one is a whole vibe ๐Ÿ’… It tells the compiler to stick to only the general-purpose registers. No floating-point, vector, mask, or bound registers allowed, so it's basically a minimalist era ๐ŸŒธ
  • -mindirect-branch=choice โ€” this one changes how indirect calls and jumps get handled ๐Ÿฆ‹ You pick one of these choices:
    • keep is the default, and it leaves indirect calls and jumps totally unmodified ๐Ÿซถ
    • thunk converts them to call and return thunks โœจ
    • thunk-inline converts them to inlined call and return thunks ๐Ÿงš
    • thunk-extern converts them to external call and return thunks that live in a separate object file ๐Ÿ’œ

You can also control this for one specific function with the function attribute indirect_branch ๐Ÿ‘‘

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 โ€” same energy, but for function returns ๐ŸŒˆ Your options are:
    • keep is the default, and it leaves function returns unmodified ๐Ÿ“
    • 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 a specific function with the function attribute function_return ๐Ÿ’–

Note that -mindirect-return=thunk-extern is compatible with -fcf-protection=branch, since the external thunk can be made to enable control-flow check โœจ

Note 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, no exceptions ๐Ÿ‘‘

These -m switches are supported in addition to the above on x86-64 processors in 64-bit environments ๐Ÿ’…

  • -m32, -m64, -mx32, -m16, -miamcu โ€” these set the code generation environment ๐Ÿซถ
    • -m32 sets int, long, and pointer types to 32 bits, and generates code that runs on any i386 system ๐ŸŒธ
    • -m64 sets int to 32 bits and long and pointer types to 64 bits, and generates code for the x86-64 architecture ๐ŸŒˆ For Darwin only, the -m64 option also turns off the -fno-pic and -mdynamic-no-pic options ๐Ÿ“
    • -mx32 sets int, long, and pointer types to 32 bits, and generates code for the x86-64 architecture ๐Ÿฆ‹
    • -m16 is the same as -m32, except it outputs the .code16gcc assembly directive at the beginning of the assembly output, so the binary can run in 16-bit mode ๐Ÿงš
    • -miamcu generates code that conforms to the Intel MCU psABI, and it requires -m32 to be turned on ๐Ÿ’œ
  • -mno-red-zone โ€” okay so the x86-64 ABI mandates a "red zone," which is a 128-byte area beyond the stack pointer that signal or interrupt handlers don't touch ๐Ÿซง That means you can stash temporary data there without adjusting the stack pointer. This flag disables the red zone, so no more freebies ๐Ÿ™ˆ
  • -mcmodel=small โ€” the small code model, where the program and its symbols must be linked in the lower 2 GB of the address space ๐ŸŒธ Pointers are 64 bits, and programs can be statically or dynamically linked. This is the default code model โœจ
  • -mcmodel=kernel โ€” the kernel code model, where the kernel runs in the negative 2 GB of the address space ๐Ÿ‘‘ This model has to be used for Linux kernel code ๐Ÿ’…
  • -mcmodel=medium โ€” the medium model, where the program is linked in the lower 2 GB of the address space ๐Ÿฆ‹ Small symbols get placed there too. Symbols with sizes larger than -mlarge-data-threshold are put into large data or BSS sections, and those can be located above 2GB. Programs can be statically or dynamically linked ๐ŸŒˆ
  • -mcmodel=large โ€” the large model, which makes no assumptions about addresses and sizes of sections ๐ŸŒ
  • -maddress-mode=long โ€” generates code for long address mode ๐Ÿงš This is only supported for 64-bit and x32 environments, and it's the default address mode for 64-bit environments ๐Ÿ’–
  • -maddress-mode=short โ€” generates code for short address mode ๐Ÿ“ This is only supported for 32-bit and x32 environments, and it's the default address mode for 32-bit and x32 environments ๐Ÿซถ

โœจ x86 Windows Options โœจ

These additional options are available for Microsoft Windows targets ๐ŸชŸ

  • -mconsole โ€” this makes a console application by telling the linker to set the PE header subsystem type for console apps ๐ŸŽ€ It's available for Cygwin and MinGW targets, and it's enabled by default on those targets ๐Ÿ’œ
  • -mdll โ€” available for Cygwin and MinGW targets ๐Ÿฆ‹ It makes a DLL, which is a dynamic link library, and it lets you pick the required runtime startup object and entry point ๐Ÿซถ
  • -mnop-fun-dllimport โ€” available for Cygwin and MinGW targets ๐Ÿ™ˆ It tells the compiler to ignore the dllimport attribute ๐Ÿ’…
  • -mthread โ€” available for MinGW targets ๐Ÿงต It turns on MinGW-specific thread support โœจ
  • -municode โ€” available for MinGW-w64 targets ๐ŸŒˆ It predefines the UNICODE preprocessor macro and picks Unicode-capable runtime startup code ๐Ÿ‘‘
  • -mwin32 โ€” available for Cygwin and MinGW targets ๐ŸŒธ It sets the typical Microsoft Windows predefined macros in the preprocessor, but it doesn't change which runtime library or startup code gets chosen ๐Ÿ“
  • -mwindows โ€” available for Cygwin and MinGW targets ๐ŸชŸ It makes a GUI application by telling the linker to set the PE header subsystem type to match ๐Ÿ’–
  • -fno-set-stack-executable โ€” available for MinGW targets ๐Ÿ”’ It means the executable flag for the stack used by nested functions doesn't get set. This is necessary for binaries running in kernel mode of Microsoft Windows, since the User32 API (which is used to set executable privileges) isn't available there ๐Ÿ˜ญ
  • -fwritable-relocated-rdata โ€” available for MinGW and Cygwin targets ๐Ÿงš It puts relocated data in a read-only section into the .data section. This is necessary for older runtimes that don't support modifying .rdata sections for pseudo-relocation ๐Ÿซง
  • -mpe-aligned-commons โ€” available for Cygwin and MinGW targets ๐Ÿฆ‹ It makes sure the GNU extension to the PE file format, which permits correct alignment of COMMON variables, gets used 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 that work with the simulator ๐ŸŽฎ

โœจ Xtensa Options โœจ

These options are supported for Xtensa targets ๐ŸŒŸ

  • -mconst16, -mno-const16 โ€” enable or disable the use of CONST16 instructions for loading constant values ๐Ÿ’œ The CONST16 instruction isn't 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 isn't available ๐Ÿซถ
  • -mfused-madd, -mno-fused-madd โ€” enable or disable fused multiply/add and multiply/subtract instructions in the floating-point option ๐Ÿ”ฅ This has no effect if the floating-point option isn't also enabled. Turning fused instructions off forces the compiler to use separate instructions for the multiply and the add/subtract operations. That can be handy when strict IEEE 754-compliant results are required, because fused multiply add/subtract instructions don't round the intermediate result, so you get more bits of precision than the IEEE standard specifies ๐Ÿค“ Disabling them also makes sure the program output 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 has to be position-independent code (PIC), this option disables PIC for compiling kernel code ๐ŸŒธ
  • -mtext-section-literals, -mno-text-section-literals โ€” these control how literal pools are treated ๐Ÿ“ฆ The default is -mno-text-section-literals, which places literals in a separate section in the output file. That lets the literal pool sit in data RAM/ROM, and it also lets the linker combine literal pools from separate object files to remove redundant literals and shrink code size โœจ With -mtext-section-literals, literals are interspersed in the text section so they stay as close as possible to their references. This may be necessary for large assembly files. Literals for each function are placed right before that function ๐Ÿฆ‹

-mauto-litpools, -mno-auto-litpools โ€” okay so these two decide how literal pools get handled ๐Ÿงš The default is -mno-auto-litpools, which parks literals in their own separate section of the output file unless -mtext-section-literals is used. With -mauto-litpools, the assembler sprinkles the literals right into the text section instead ๐Ÿ’… The compiler doesn't emit explicit .literal directives. It loads literals into registers with MOVI instead of L32R, so the assembler can handle relaxation and place literals wherever they need to go. This lets the assembler make several literal pools per function, which means it can assemble really huge functions that might not be possible with -mtext-section-literals ๐Ÿ‘‘

-mtarget-align, -mno-target-align โ€” when this is on, GCC tells the assembler to auto-align instructions so branch penalties go down, and the tradeoff is a little less code density ๐Ÿฆ‹ The assembler tries to widen density instructions so branch targets and the instructions after call instructions get lined up. If there aren't enough safe density instructions before a target to line it up, no widening happens. The default is -mtarget-align. These options don't change auto-aligned instructions like LOOP. The assembler always aligns those, either by widening density instructions or by inserting NOP instructions โœจ

-mlongcalls, -mno-longcalls โ€” when enabled, GCC tells the assembler to turn direct calls into indirect calls, unless it can figure out that the target of a direct call is inside the range the call instruction allows ๐ŸŒธ This usually happens for calls to functions in other source files. Specifically, the assembler swaps a direct CALL for an L32R followed by a CALLX. The default is -mno-longcalls. Use this one in programs where the call target could possibly be out of range. It's implemented in the assembler, not the compiler, so the assembly GCC generates still shows direct call instructions. If you want to see what's actually happening, look at the disassembled object code ๐Ÿ”

Heads up: the assembler uses an indirect call for every cross-file call, not just the ones that really are out of range.

zSeries Options

These are listed under


โœจ ENVIRONMENT โœจ

This section covers several environment variables that change how GCC operates ๐Ÿ’– Some of them work by specifying directories or prefixes to search when GCC is hunting for different kinds of files. Others set up other parts of the compilation environment.

Note that you can also specify places to search using options such as -B, -I and -L. These beat environment variables, and environment variables beat whatever GCC's configuration says ๐Ÿ‘‘

  • LANG, LC_CTYPE, LC_MESSAGES, LC_ALL โ€” these control the localization info GCC uses so it can work with different national conventions ๐ŸŒˆ GCC looks at the LC_CTYPE and LC_MESSAGES locale categories if it's been configured to. They can be set to any value your installation supports. A typical value is en_GB.UTF-8, which means English in the United Kingdom encoded in UTF-8.
    • LC_CTYPE sets character classification. GCC uses it to figure out where character boundaries are in a string. That matters for some multibyte encodings that have quote and escape characters, which would otherwise be read as the end of a string or as an escape.
    • LC_MESSAGES sets the language used in diagnostic messages.
    • If LC_ALL is set, it overrides LC_CTYPE and LC_MESSAGES. Otherwise, LC_CTYPE and LC_MESSAGES default to the value of LANG. If none of these are set, GCC falls back to traditional C English behavior ๐Ÿซถ
  • TMPDIR โ€” if set, it specifies the directory for temporary files ๐Ÿฆ‹ GCC uses temp files to hold the output of one stage of compilation that gets used as input to the next. For example, the preprocessor's output is the input to the compiler proper.
  • GCC_COMPARE_DEBUG โ€” setting this is nearly the same as passing -fcompare-debug to the compiler driver. Check that option's documentation for more details ๐Ÿ”
  • GCC_EXEC_PREFIX โ€” if set, it specifies a prefix to use in the names of the subprograms the compiler runs ๐Ÿงš No slash gets added when the prefix is combined with a subprogram's name, but you can end your prefix with a slash if you want one.
    • If GCC_EXEC_PREFIX isn't set, GCC tries to work out a sensible prefix from the pathname it was invoked with.
    • If GCC can't find the subprogram using the specified prefix, it checks the usual places for it.
    • The default value of GCC_EXEC_PREFIX is prefix/lib/gcc/, where prefix is the prefix of the installed compiler. In many cases, prefix is the value of "prefix" you used when you ran the configure script.
    • Other prefixes specified with -B take precedence over this one.
    • This prefix is also used to find files like crt0.o that get used for linking.
    • The prefix also gets used in an unusual way to find the directories that header files live in. For each standard directory whose name normally begins with /usr/local/lib/gcc (more precisely, with the value of GCC_INCLUDE_DIR), GCC tries swapping 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 value of prefix gets replaced by GCC_EXEC_PREFIX when GCC looks for header files ๐Ÿ’…
  • COMPILER_PATH โ€” its value is a colon-separated list of directories, kinda like PATH ๐ŸŒธ GCC tries these directories when searching for subprograms, but only if it can't find them using GCC_EXEC_PREFIX.
  • LIBRARY_PATH โ€” its value is a colon-separated list of directories, kinda like PATH ๐Ÿ“ When GCC is configured as a native compiler, it tries these directories when searching for special linker files, but only if it can't find them using GCC_EXEC_PREFIX. Linking with GCC also uses these directories when hunting for ordinary libraries for the -l option. Directories specified with -L come first, though.
  • LANG โ€” this one passes locale info to the compiler โœจ One thing it's used for is deciding which character set to use when parsing character literals, string literals and comments in C and C++. When the compiler is configured to allow multibyte characters, these values of LANG are recognized:
    • C-JIS โ€” recognizes JIS characters.
    • C-SJIS โ€” recognizes SJIS characters.
    • C-EUCJP โ€” recognizes EUCJP characters.

If LANG isn't defined, or it has some other value, the compiler uses mblen and mbtowc from the default locale to recognize and translate multibyte characters ๐Ÿ™ˆ

Some additional environment variables affect how the preprocessor behaves ๐ŸŽ€

  • CPATH, C_INCLUDE_PATH, CPLUS_INCLUDE_PATH, OBJC_INCLUDE_PATH โ€” each variable's value is a list of directories, separated by a special character, kinda like PATH, where GCC looks for header files ๐Ÿ’œ That special character, PATH_SEPARATOR, depends on the target and gets decided at GCC build time. For Microsoft Windows-based targets it's a semicolon, and for almost every other target it's a colon.
    • CPATH gets searched as if you'd specified the directories with -I, but after any paths given with -I options on the command line. This variable is used no matter which language is being preprocessed.
    • The other three variables only apply when preprocessing their particular language. Each one gets searched as if its directories were specified with -isystem, but after any paths given with -isystem options on the command line.
    • In all of these, an empty element tells the compiler to search its current working directory. Empty elements can 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 is set, its value says how to output Make dependencies based on the non-system header files the compiler processes ๐Ÿซถ System header files get ignored in the dependency output. The value can just be a file name, in which case the Make rules get written to that file, and the target name gets guessed from the source file name. Or the value can take the form file target, in which case the rules get written to file using target as the target name.
    • In other words, this environment variable is equivalent to combining the options -MM and -MF, with an optional -MT switch too ๐Ÿ’–
  • SUNPRO_DEPENDENCIES โ€” this is the same as DEPENDENCIES_OUTPUT, except system header files aren't ignored. So it implies -M rather than -MM. However, the dependence on the main input file is left out ๐ŸŒˆ
  • SOURCE_DATE_EPOCH โ€” if this is set, its value specifies a UNIX timestamp to use in place of the current date and time in the __DATE__ and __TIME__ macros, so the embedded timestamps stay reproducible โฐ
    • The value must be a UNIX timestamp, which is the number of seconds (excluding leap seconds) since 01 Jan 1970 00:00:00, represented in ASCII. It's identical to the output of date +%s on GNU/Linux and other systems that support the %s extension in the date command.
    • The value should be a known timestamp, like the last modification time of the source or package, and the build process should set it ๐Ÿ”ฅ

๐Ÿ› BUGS ๐Ÿ›

For instructions on reporting bugs, see <file:///usr/share/doc/gcc-9/README.Bugs> ๐Ÿ’…

โœจ FOOTNOTES โœจ

  1. okay bestie, this one is the spicy footnote ๐ŸŒถ๏ธ On some systems, gcc -shared needs to build supplementary stub code so constructors actually work ๐Ÿ”ง On multi-libbed systems, gcc -shared has to select the correct support libraries to link against ๐Ÿ“š
๐Ÿ˜ญ Failing to supply the correct flags may lead to subtle defects!! Supplying them when they aren't necessary is innocuous, so no harm done ๐Ÿ’–

โœจ SEE ALSO โœจ

โœจ AUTHOR โœจ

the whole squad of contributors is listed in the Info entry for gcc, or at http://gcc.gnu.org/onlinedocs/gcc/Contributors.html ๐Ÿซถ they're the real MVPs ๐Ÿ‘‘

Copyright (c) 1988-2019 Free Software Foundation, Inc. ๐Ÿงพ

okay the legal bit, but make it cute ๐Ÿ’œ you're totally allowed to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.3 or any later version published by the Free Software Foundation. The Invariant Sections are "GNU General Public License" and "Funding Free Software", the Front-Cover texts are (a) (see below), and the Back-Cover Texts are (b) (see below). A copy of the license is included in the gfdl(7) man page ๐ŸŒธ

(a) The FSF's Front-Cover Text is:

A GNU Manual

(b) The FSF's Back-Cover Text is:

You have freedom to copy and modify this GNU Manual, like GNU software. Copies published by the Free Software Foundation raise funds for GNU development.

and that's the whole tea, bestie ๐Ÿ“โœจ this page came from gcc-9, dated 2022-05-27, and I'm obsessed with how much GCC has going on ๐Ÿ’…๐Ÿงš

๐Ÿ“ฆ where this page comes from