Node:Top, Next:, Previous:(dir), Up:(dir)

Introduction

このマニュアルでは、GNU コンパイラの使い方、インストール方法、移植方法や、新しい機能や互換性の無い部分、それにバグレポートの方法などについて説明している。GNU CC のバージョン 2.95 に対応している。(日本語版ドラフト-17 July 2001)


Node:G++ and GCC, Next:, Previous:Top, Up:Top

C, C++, Objective C, Fortran のコンパイル

C, C++, Objective C, Fortran 毎に分かれていたコンパイラは現在では一つに統合されている。このため我々は「GNU コンパイラ集」(GNU Compiler Collection) という名前を使うことにした。GNU C コンパイラは, C, C++, Objective C, Fortran で書かれたプログラムをコンパイルすることが可能である。Fortran コンパイラについては独立したマニュアルで説明している。

GCC というのは、GNU コンパイラ集(GNU Compiler Collection)のよくある省略形である。我々のコンパイラの最も一般的な名前でもあるし、C 言語のプログラムをコンパイルすることに焦点が置かれている場合に使われる名前でもある(この省略形は以前は "GNU C Compiler" を表していた)。

C++ プログラムのコンパイルについて言うときには、G++ と呼ぶのが普通である。コンパイラ自体は一つしかないので、対象とする言語がなんであれ、GCC と呼ぶのは全く正しい。だが、C++ プログラムをコンパイルするのだということを強調するときは、G++ と呼ぶのが便利である。

我々は、"GCC" をコンパイラシステム全体を指す名前として使う。もう少し正確には、このコンパイラの言語非依存部を指す。例えば、「GCC」の動作に影響する最適化オプションと言ったり、あるいは単に「コンパイラ」と言ったりすることもある。

他の言語フロントエンドとして、Ada 9X, Fortran, Modula-3, Pascal について開発中である。これらのフロントエンドは、C++ と同様、GNU CC のサブディレクトリで構築され、GCC にリンクされる。この結果、統合されたコンパイラが出来上がり、C, C++, Objective C, あるいはユーザがインストールしたフロントエンドの言語がコンパイル出来ることになる。

本マニュアルでは、C、Objective-C、C++ コンパイラのオプションと、GCC の中核部分のオプションについてのみ解説を行う。他の言語で書かれたプログラムをコンパイルする際に使用するオプションについては、その言語のフロントエンドの文書を参照すること。

G++ は本物のコンパイラである。単なるプリプロセッサではない。G++ は、C++ プログラムのソースから直接オブジェクトコードを生成する。中間的な C のコードは作らない。(対照的に、例えば他の実装の中には、C++ ソースから C プログラムを生成するものもある。) C 言語による中間表現を使わないことで、より良いオブジェクトコード、より良いデバッグ情報を得ることができる。GNU デバッガ GDB を使えば、オブジェクトコード中の、このより良いデバッグ情報と合わせて、C++ プログラムのソースコードレベルの編集(デバッグ)機能の恩恵を受けることができる。


Node:Invoking GCC, Next:, Previous:G++ and GCC, Up:Top

GCC コマンド行オプション

GCC を起動すると、普通は、プリプロセス、コンパイル、アセンブル、リンクを行なう。"overall options" を指定することで、この過程を中間の段階で止めることができる。例えば、-c オプションを指定すると、リンカを起動しない。そして、出力はアセンブラの出力であるオブジェクトファイルからなる。

その他のオプションは、上記の過程の一つの段階に受け渡される。プリプロセッサを制御するオプションもあるし、コンパイラ本体を制御するオプションもある。さらに、その他に、アセンブラとリンカを制御するオプションもあるが、ほとんどのオプションは滅多に必要になることはないので、ここでは説明しない。

GCC に指定できるコマンド行オプションは、大部分が C 言語向けである。他の言語(C++ であることが多い)でも使えるオプションについては、明示的にその旨を書くようにしている。ソースプログラムの言語について記述のないオプションは、サポートされている全ての言語に対して使うことができる。

C++ プログラムをコンパイルするときの特別なオプションの要約については、See Compiling C++ Programs.

gcc は、オプションとファイル名を引数として受け付ける。複数の文字からなる名前を持つオプションがたくさんあるので、一文字のオプションをまとめて指定することはできない。例えば、-dr というオプションは、-d -r とは全く異なる指定になる。

オプションとそれ以外の引数を入り混ぜて使うことができる。引数の順序は問題にならない場合が多い。問題になるのは、同じ種類のオプションを重ねて使うときである。例えば、-L オプションを複数回指定すると、指定された順番でディレクトリを検索する。

-f-W で始まる長い名前のオプションがたくさんある。例えば、-fforce-mem-fstrength-reduce-Wformat といったものだ。この種類のオプションは、ほとんどが、肯定形式と否定形式の両方の形式を持つ。例えば、-ffoo の否定形式は -fno-foo になる。このマニュアルでは、二つの形式のうちのどちらかのみ、つまりデフォルトでない方のみを説明する。


Node:Option Summary, Next:, Previous:Invoking GCC, Up:Invoking GCC

オプション要約

以下に全オプションの要約を種類毎に分けて示す。解説は後の節で行なう。

Overall Options
See 出力の種類の制御オプション.
-c  -S  -E  -o file  -pipe  -v  --help  -x language

C 言語オプション
See C 方言を扱うオプション.
-ansi -fstd  -fallow-single-precision  -fcond-mismatch  -fno-asm
-fno-builtin  -ffreestanding  -fhosted  -fsigned-bitfields  -fsigned-char
-funsigned-bitfields  -funsigned-char  -fwritable-strings
-traditional  -traditional-cpp  -trigraphs

C++ 言語オプション
See C++ 方言を扱うオプション.
-fno-access-control  -fcheck-new  -fconserve-space  -fdollars-in-identifiers
-fno-elide-constructors  -fexternal-templates  -ffor-scope
-fno-for-scope  -fno-gnu-keywords  -fguiding-decls  -fhandle-signatures
-fhonor-std -fhuge-objects  -fno-implicit-templates  -finit-priority
-fno-implement-inlines -fname-mangling-version-n  -fno-default-inline
-foperator-names  -fno-optional-diags  -fpermissive -frepo  -fstrict-prototype
-fsquangle  -ftemplate-depth-n  -fthis-is-variable  -fvtable-thunks
-nostdinc++  -Wctor-dtor-privacy -Wno-deprecated -Weffc++
-Wno-non-template-friend
-Wnon-virtual-dtor  -Wold-style-cast  -Woverloaded-virtual
-Wno-pmf-conversions  -Wreorder  -Wsign-promo  -Wsynth

警告オプション
See 警告を要求/抑止するオプション.
-fsyntax-only  -pedantic  -pedantic-errors
-w  -W  -Wall  -Waggregate-return  -Wbad-function-cast
-Wcast-align  -Wcast-qual  -Wchar-subscripts  -Wcomment
-Wconversion  -Werror  -Wformat
-Wid-clash-len  -Wimplicit -Wimplicit-int
-Wimplicit-function-declaration  -Wimport
-Werror-implicit-function-declaration  -Winline
-Wlarger-than-len  -Wlong-long
-Wmain  -Wmissing-declarations  -Wmissing-noreturn
-Wmissing-prototypes  -Wmultichar  -Wnested-externs  -Wno-import
-Wparentheses -Wpointer-arith  -Wredundant-decls
-Wreturn-type -Wshadow  -Wsign-compare  -Wstrict-prototypes
-Wswitch  -Wtraditional
-Wtrigraphs -Wundef  -Wuninitialized  -Wunused  -Wwrite-strings
-Wunknown-pragmas

デバッグオプション
See 読者のプログラムや GCC をデバッグする ためのオプション.
-a  -ax  -dletters  -fdump-unnumbered -fpretend-float
-fprofile-arcs  -ftest-coverage
-g  -glevel  -gcoff  -gdwarf  -gdwarf-1  -gdwarf-1+  -gdwarf-2
-ggdb  -gstabs  -gstabs+  -gxcoff  -gxcoff+
-p  -pg  -print-file-name=library  -print-libgcc-file-name
-print-prog-name=program  -print-search-dirs  -save-temps

最適化オプション
See 最適化オプション.
-fbranch-probabilities  -foptimize-register-moves
-fcaller-saves  -fcse-follow-jumps  -fcse-skip-blocks
-fdelayed-branch   -fexpensive-optimizations
-ffast-math  -ffloat-store  -fforce-addr  -fforce-mem
-fdata-sections -ffunction-sections  -fgcse
-finline-functions -finline-limit-n -fkeep-inline-functions
-fno-default-inline -fno-defer-pop  -fno-function-cse
-fno-inline  -fno-peephole  -fomit-frame-pointer -fregmove
-frerun-cse-after-loop  -frerun-loop-opt -fschedule-insns
-fschedule-insns2  -fstrength-reduce  -fthread-jumps
-funroll-all-loops  -funroll-loops
-fmove-all-movables  -freduce-all-givs -fstrict-aliasing
-O  -O0  -O1  -O2  -O3 -Os

プリプロセッサオプション
See プリプロセッサオプション.
-Aquestion(answer)  -C  -dD  -dM  -dN
-Dmacro[=defn]  -E  -H
-idirafter dir
-include file  -imacros file
-iprefix file  -iwithprefix dir
-iwithprefixbefore dir  -isystem dir -isystem-c++ dir
-M  -MD  -MM  -MMD  -MG  -nostdinc  -P  -trigraphs
-undef  -Umacro  -Wp,option

アセンブラのオプション
See アセンブラに渡されるオプション.
-Wa,option

リンカのオプション
See リンクオプション.
object-file-name  -llibrary
-nostartfiles  -nodefaultlibs  -nostdlib
-s  -static  -shared  -symbolic
-Wl,option  -Xlinker option
-u symbol

ディレクトリに関するオプション
See ディレクトリ検索用オプション.
-Bprefix  -Idir  -I-  -Ldir  -specs=file

ターゲットオプション
See Target Options.
-b machine  -V version

機種依存のオプション
See ハードウェアモデルとコンフィギュレーション.
M680x0 用オプション
-m68000  -m68020  -m68020-40  -m68020-60  -m68030  -m68040
-m68060  -mcpu32 -m5200  -m68881  -mbitfield  -mc68000  -mc68020
-mfpa -mnobitfield  -mrtd  -mshort  -msoft-float
-malign-int

VAX 用オプション
-mg  -mgnu  -munix

SPARC 用オプション
-mcpu=cpu type
-mtune=cpu type
-mcmodel=code model
-malign-jumps=num  -malign-loops=num
-malign-functions=num
-m32  -m64
-mapp-regs  -mbroken-saverestore  -mcypress  -mepilogue
-mflat  -mfpu  -mhard-float  -mhard-quad-float
-mimpure-text  -mlive-g0  -mno-app-regs  -mno-epilogue
-mno-flat  -mno-fpu  -mno-impure-text
-mno-stack-bias  -mno-unaligned-doubles
-msoft-float  -msoft-quad-float  -msparclite  -mstack-bias
-msupersparc  -munaligned-doubles  -mv8

Convex 用オプション
-mc1  -mc2  -mc32  -mc34  -mc38
-margcount  -mnoargcount
-mlong32  -mlong64
-mvolatile-cache  -mvolatile-nocache

AMD29K 用オプション
-m29000  -m29050  -mbw  -mnbw  -mdw  -mndw
-mlarge  -mnormal  -msmall
-mkernel-registers  -mno-reuse-arg-regs
-mno-stack-check  -mno-storem-bug
-mreuse-arg-regs  -msoft-float  -mstack-check
-mstorem-bug  -muser-registers

ARM 用オプション
-mapcs-frame -mno-apcs-frame
-mapcs-26 -mapcs-32
-mapcs-stack-check -mno-apcs-stack-check
-mapcs-float -mno-apcs-float
-mapcs-reentrant -mno-apcs-reentrant
-msched-prolog -mno-sched-prolog
-mlittle-endian -mbig-endian -mwords-little-endian
-mshort-load-bytes -mno-short-load-bytes -mshort-load-words -mno-short-load-words
-msoft-float -mhard-float -mfpe
-mthumb-interwork -mno-thumb-interwork
-mcpu= -march= -mfpe=
-mstructure-size-boundary=
-mbsd -mxopen -mno-symrename
-mabort-on-noreturn
-mno-sched-prolog

Thumb 用オプション
-mtpcs-frame -mno-tpcs-frame
-mtpcs-leaf-frame -mno-tpcs-leaf-frame
-mlittle-endian  -mbig-endian
-mthumb-interwork -mno-thumb-interwork
-mstructure-size-boundary=

MN10200 用オプション
-mrelax

MN10300 用オプション
-mmult-bug
-mno-mult-bug
-mrelax

M32R/D 用オプション
-mcode-model=model type  -msdata=sdata type
-G num

M88K 用オプション
-m88000  -m88100  -m88110  -mbig-pic
-mcheck-zero-division  -mhandle-large-shift
-midentify-revision  -mno-check-zero-division
-mno-ocs-debug-info  -mno-ocs-frame-position
-mno-optimize-arg-area  -mno-serialize-volatile
-mno-underscores  -mocs-debug-info
-mocs-frame-position  -moptimize-arg-area
-mserialize-volatile  -mshort-data-num  -msvr3
-msvr4  -mtrap-large-shift  -muse-div-instruction
-mversion-03.00  -mwarn-passed-structs

RS/6000 と PowerPC 用オプション
-mcpu=cpu type
-mtune=cpu type
-mpower  -mno-power  -mpower2  -mno-power2
-mpowerpc  -mno-powerpc
-mpowerpc-gpopt  -mno-powerpc-gpopt
-mpowerpc-gfxopt  -mno-powerpc-gfxopt
-mnew-mnemonics  -mno-new-mnemonics
-mfull-toc   -mminimal-toc  -mno-fop-in-toc  -mno-sum-in-toc
-maix64  -maix32  -mxl-call  -mno-xl-call  -mthreads  -mpe
-msoft-float  -mhard-float  -mmultiple  -mno-multiple
-mstring  -mno-string  -mupdate  -mno-update
-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
-mcall-aix  -mcall-sysv  -mprototype  -mno-prototype
-msim  -mmvme  -mads  -myellowknife  -memb -msdata
-msdata=opt  -G num

RT 用オプション
-mcall-lib-mul  -mfp-arg-in-fpregs  -mfp-arg-in-gregs
-mfull-fp-blocks  -mhc-struct-return  -min-line-mul
-mminimum-fp-blocks  -mnohc-struct-return

MIPS 用オプション
-mabicalls  -mcpu=cpu type  -membedded-data
-membedded-pic  -mfp32  -mfp64  -mgas  -mgp32  -mgp64
-mgpopt  -mhalf-pic  -mhard-float  -mint64  -mips1
-mips2  -mips3 -mips4 -mlong64  -mlong32 -mlong-calls  -mmemcpy
-mmips-as  -mmips-tfile  -mno-abicalls
-mno-embedded-data  -mno-embedded-pic
-mno-gpopt  -mno-long-calls
-mno-memcpy  -mno-mips-tfile  -mno-rnames  -mno-stats
-mrnames  -msoft-float
-m4650  -msingle-float  -mmad
-mstats  -EL  -EB  -G num  -nocpp
-mabi=32 -mabi=n32 -mabi=64 -mabi=eabi

i386 用オプション
-mcpu=cpu type
-march=cpu type
-mieee-fp  -mno-fancy-math-387
-mno-fp-ret-in-387  -msoft-float  -msvr3-shlib
-mno-wide-multiply  -mrtd  -malign-double
-mreg-alloc=list  -mregparm=num
-malign-jumps=num  -malign-loops=num
-malign-functions=num -mpreferred-stack-boundary=num

HPPA 用オプション
-march=architecture type
-mbig-switch  -mdisable-fpregs  -mdisable-indexing
-mfast-indirect-calls -mgas  -mjump-in-delay
-mlong-load-store  -mno-big-switch  -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
-mno-space-regs  -msoft-float  -mpa-risc-1-0
-mpa-risc-1-1  -mpa-risc-2-0 -mportable-runtime
-mschedule=cpu type  -mspace  -mspace-regs

Intel 960 用オプション
-mcpu type  -masm-compat  -mclean-linkage
-mcode-align  -mcomplex-addr  -mleaf-procedures
-mic-compat  -mic2.0-compat  -mic3.0-compat
-mintel-asm  -mno-clean-linkage  -mno-code-align
-mno-complex-addr  -mno-leaf-procedures
-mno-old-align  -mno-strict-align  -mno-tail-call
-mnumerics  -mold-align  -msoft-float  -mstrict-align
-mtail-call

DEC Alpha 用オプション
-mfp-regs  -mno-fp-regs -mno-soft-float  -msoft-float
-malpha-as -mgas
-mieee  -mieee-with-inexact  -mieee-conformant
-mfp-trap-mode=mode  -mfp-rounding-mode=mode
-mtrap-precision=mode  -mbuild-constants
-mcpu=cpu type
-mbwx -mno-bwx -mcix -mno-cix -mmax -mno-max
-mmemory-latency=time

Clipper 用オプション
-mc300  -mc400

H8/300 用オプション
-mrelax  -mh -ms -mint32  -malign-300

SH 用オプション
-m1  -m2  -m3  -m3e  -mb  -ml  -mdalign -mrelax

System V 用オプション
-Qy  -Qn  -YP,paths  -Ym,dir

ARC 用オプション
-EB  -EL
-mmangle-cpu  -mcpu=cpu  -mtext=text section
-mdata=data section  -mrodata=readonly data section

TMS320C3x/C4x 用オプション
-mcpu=cpu -mbig -msmall -mregparm -mmemparm
-mfast-fix -mmpyi -mbk -mti -mdp-isr-reload
-mrpts=count  -mrptb -mdb -mloop-unsigned
-mparallel-insns -mparallel-mpy -mpreserve-float

V850 用オプション
-mlong-calls -mno-long-calls -mep -mno-ep
-mprolog-function -mno-prolog-function -mspace
-mtda=n -msda=n -mzda=n
-mv850 -mbig-switch

NS32K 用オプション
-m32032 -m32332 -m32532 -m32081 -m32381 -mmult-add -mnomult-add
-msoft-float -mrtd -mnortd -mregparam -mnoregparam -msb -mnosb
-mbitfield -mnobitfield -mhimem -mnohimem

コード生成オプション
See コード生成規約についてのオプション.
-fcall-saved-reg  -fcall-used-reg
-fexceptions -ffixed-reg  -finhibit-size-directive
-fcheck-memory-usage  -fprefix-function-name
-fno-common  -fno-ident  -fno-gnu-linker
-fpcc-struct-return  -fpic  -fPIC
-freg-struct-return  -fshared-data  -fshort-enums
-fshort-double  -fvolatile  -fvolatile-global -fvolatile-static
-fverbose-asm -fpack-struct  -fstack-check
-fargument-alias  -fargument-noalias
-fargument-noalias-global
-fleading-underscore


Node:Overall Options, Next:, Previous:Option Summary, Up:Invoking GCC

出力の種類の制御オプション

コンパイル過程は、四つの段階に分けることができる。プリプロセス、コンパイルそのもの、アセンブル、それにリンクであり、必ずこの順番である。前の三つの段階は個々のソースファイルに対して適用され、オブジェクトファイルの生成で終わる。リンクでは、全てのオブジェクトファイル(新しくコンパイルされ、入力としてしていされたもの)を組み合わせて、一つの実行形式ファイルを作る。

指定された入力ファイル毎に、ファイル名のサフィックスからコンパイル過程のどれが実行されるかが決定される。

file.c
C ソースファイルであり、プリプロセスが必要である。
file.i
C ソースファイルであり、プリプロセスを行なってはいけない。
file.ii
C++ ソースファイルであり、プリプロセスを行なってはいけない。
file.m
Objective-C ソースファイルである。Objective-C のプログラムとして動作させるには、ライブラリ libobjc.a をリンクする必要があることに注意。
file.h
C のヘッダファイル(コンパイルやリンクは行なわれない)。
file.cc
file.cxx
file.cpp
file.C
C++ のソースファイルで、プリプロセスが必要である。.cxx の最後の二文字は字面どおり x でなければならない。同じく、.C は字面どおりの大文字の C である。
file.s
アセンブラソースファイル。
file.S
アセンブラソースファイルで、プリプロセスが必要である。
other
オブジェクトファイルは、そのままリンクフェーズに渡される。認識できないサフィックスを持たないファイル名も同じように扱われる。

-x オプションを指定することで入力の言語を明示的に指定することもできる。

-x language
後続の入力ファイルの言語を(コンパイラに、ファイル名のサフィックスからデフォルトを選択するのをまかせるのではなくて)、明示的に language と指定するこのオプションは、次に -x オプションが現れるまでの入力ファイルに対して適用される。language に指定できる値は以下のとおり。
c  objective-c  c++
c-header  cpp-output  c++-cpp-output
assembler  assembler-with-cpp

-x none
言語を明示的に指定するのを取り止める。これ以降のファイルは、ファイル名のサフィックスに従って(-x オプションが全く指定されなかったのと同じように)処理される。

コンパイル過程の一部分だけ実行したい場合は、-x (またはファイル名サフィックス) を使って開始する段階を指定することが出来る。どの段階で終了するかは、オプション -c-S-E のどれか一つを使って指定する。組合せによっては(例えば、-x cpp-output -E)、gcc は何もしないことがある。

-c
ソースファイルのコンパイルやアセンブルは行なうが、リンクは行なわない。単にリンク段階を行なわないのである。この場合の最終的な出力は、各ソースファイル毎のオブジェクトファイルという形になる。

デフォルトでは、オブジェクトファイル名は、ソースファイル名のサフィックス .c.i.s 等を .o に置き換えたものになる。

認識できない入力ファイルで、コンパイルやアセンブルが要求されないものは無視される。

-S
コンパイル本体の段階で終了する。アセンブルは行なわない。出力は、指定されたアセンブラソースでない各入力ファイルに対して、アセンブラコードファイル形式となる。

デフォルトでは、アセンブラファイル名は、ソースファイル名のサフィックス .c.i 等を .s に置き換えたものになる。

コンパイルを必要としない入力ファイルは無視される。

-E
プリプロセス段階で終了する。コンパイラ本体は実行しない。出力はプリプロセスされたソースコードの形式で、標準出力に出力される。

プリプロセスを必要としない入力ファイルは無視される。

-o file
出力を指定されたファイル file に置く。これは、生成される出力の種類によらない。実行形式ファイルでも、オブジェクトファイルでも、アセンブラフィアルでも、プリプロセス済の C コードでもかまわない。

出力ファイルは一つしか指定できないので、複数の入力ファイルがある場合に-o を指定するのは、実行形式ファイルを出力とする場合しか意味がない。

-o の指定がない場合は、実行形式ファイルは a.out という名前で、source.suffix というソースファイルのオブジェクトファイルは、source.o という名前で、アセンブラファイルはsource.s という名前で作られ、プリプロセスした C のソースは、標準出力に出力される。

-v
コンパイルの各段階で実行されるコマンドを標準エラー出力に表示する。また、コンパイラドライバプログラム、プリプロセッサ、コンパイラ本体のバージョン番号も合わせて表示する。
-pipe
コンパイルの各段階間での情報の受渡しに、一時ファイルではなく、パイプを使う。これはアセンブラがパイプからの読み出しができないシステムでは動作しない。もちろん、GNU アセンブラを使えば問題ない。
--help
gcc が理解するコマンド行オプションの説明を標準出力に表示する。合わせて -v オプションも指定すると、--helpgcc が起動する色々なプロセスにも渡されので、渡されたプロセスは受付可能なコマンド行オプションを表示することができる。-W オプションを一緒に指定すると、説明が用意されていないコマンド行オプションも表示される。


Node:Invoking G++, Next:, Previous:Overall Options, Up:Invoking GCC

C++ プログラムのコンパイル

C++ のソースファイル名は普通はサフィックスが、.C.cc.cpp.c++.cp.cxx のどれかになる。プリプロセス済のファイルは、.ii というサフィックスになる。GCC はこのような名前を持つファイルを認識し、コンパイラを C プログラムをコンパイルする場合と同じ方法で起動しても(gcc という名前を使っても)、C++ のプログラムとしてコンパイルを行なう。

しかし、C++ プログラムは C++ 言語を理解するコンパイラだけではなく、クラスライブラリを必要とすることが多い。また、場合によっては、標準入力から読み込んだプログラムや、C++ プログラムであることを示すサフィックスを持たないファイルにあるプログラムを、C++ プログラムとしてコンパイルしたいこともあるだろう。そのような場合向けに、g++ というプログラムがあり、デフォルトの言語を C++ に設定したうえで GCC を呼び出し、さらにC++ ライブラリを自動的にリンクする。多くのシステムでは、g++ というスクリプトは、c++ という名前でもインストールされる。(訳注: g++ は、現在はスクリプトではなく、実行形式になっている。)

C++ プログラムをコンパイルするときは、他の任意の言語のプログラムをコンパイルするときに使うのと同じコマンド行オプションの多くが使用可能である。あるいは、C とそれに関係する言語で意味のあるコマンド行オプションを指定することもできる。あるいは、C++ プログラムのみで意味を持つオプションを指定することもできる。C に関係する言語向けのオプションの説明は、See Options Controlling C Dialect. C++ プログラムでのみ意味を持つオプションの説明は、See Options Controlling C++ Dialect.


Node:C Dialect Options, Next:, Previous:Invoking G++, Up:Invoking GCC

C 方言を扱うオプション

以下のオプションは、コンパイラが受け付ける、C(あるいは、C++ やObjective C のように C から導出された言語)の方言を制御する。

-ansi
ANSI 規格に則った C プログラムをサポートする。

C モードでは、ANSI C 規格の C プログラムを全てサポートする。C++ モードでは ANSI C++ に合致しない GNU の拡張機能を削除する。

このオプションは、ANSI C 規格(C 言語コードをコンパイルするとき)、あるいは ANSI C++ 規格(C++ 言語のコードをコンパイルするとき) と互換性のない GCC の機能をオフにする。オフになる機能は、キーワード asmtypeof、システムの形式を特定する unixvax 等の定義済マクロ等がある。また、好ましくない、滅多に使われることのない ANSI のトリグラフの機能を有効にする。C コンパイラの場合は、C++ 形式の // によるコメントやキーワード inline を無効にする。C++ コンパイラの場合は、-foperator-names が有効になる。

-ansi を指定しても、別の形のキーワード __asm____extension____inline____typeof__ は使用可能である。もちろん、こういったキーワードを ANSI C プログラムで使うことはないだろうが、-ansi つきで行なわれるコンパイルの際にインクルードされる可能性のあるヘッダファイルで使うと便利である。別の形の定義済マクロ、__unix____vax__ が、-ansi の有無に関わらず、使用可能である。

-ansi オプションを指定しただけでは、非 ANSI プログラムをいわれなく拒絶することはない。拒絶するには、-ansi に加えて-pedantic を指定する必要がある。See Warning Options.

-ansi オプションを指定すると、マクロ __STRICT_ANSI__ が定義済となる。ヘッダファイルの中には、このマクロが定義されていると、ANSI 規格では使用しない関数の宣言やマクロの定義をしないようにするものもある。これは、そのような関数やマクロの名前を別のものに使っているかもしれないプログラムとの干渉を避けるためである。

関数 allocaabortexit_exit-ansi が指定されると組み込み関数ではなくなる。

-flang-isoc9x
C9X 規格にある機能のサポートを有効にする。特に、C9X のキーワード restrict のサポートを有効にする。
-fstd=
言語規格を指定する。このオプションには値を指定しなければならない。指定できる値は以下の通り。

このオプションが指定されていない場合でも、以前の C 規格と矛盾しない限り、より新しい規格の幾つかの機能を使うことが可能である。例えば、-fstd=c9x が指定されていない場合でも__restrict__ を使って良い。

-fno-asm
asminlinetypeof をキーワードとして認識しない。これらの名前は識別子として使用可能になる。替わりに、__asm____inline____typeof__ がキーワードとして使える。-ansi を指定すると -fno-asm も有効になる。

C++ では、このオプションはキーワード typeof にだけ影響がある。C++ では、asminline は、規格にあるキーワードだからである。キーワード typeof を認識しないようにするには代わりに-fno-gnu-keywords オプションを使っても良い。その場合は、typeof の他に、headof の様な C++ に固有の拡張キーワードも認識しないようになる。

-fno-builtin
組み込み関数のうち、名前のプレフィックスが __builtin_ で始まっていないものを認識しないようにする。現在、影響を受ける関数は、abortabsallocacosexitfabsffslabsmemcmpmemcpysinsqrtstrcmpstrcpystrlen である。

GCC は、通常、いくつかの組み込み関数をより効率良く扱うような特別なコードを生成する。例えば、alloca の呼び出しはスタックを直接調整する一個の命令で置き換えられたり、memcpy の呼びだしがコピーを行なうループにインライン展開されることもある。生成されるコードは、小さく高速であることが多いが、関数呼び出しはもはや現れないので、こういう呼びだしにブレークポイントを設定できなくなったり、別のライブラリをリンクすることでその関数の動作を変えることができなくなったりする。

-ansi オプションを指定すると、allocaffs は組み込み関数ではなくなる。これらの関数は ANSI 規格では規定されていないからである。

-fhosted

ホスト環境でコンパイルが行なわれていることをアサートする。これにより、-fbuiltin も暗黙に指定される。ホスト環境とは、そこで全標準ライブラリが利用可能であり、main の戻り値型が int であるような環境である。例としては、OS のカーネル以外はほとんどなんでも当てはまる。このオプションは、-fno-freestanding と等価である。

-ffreestanding

孤立した環境でコンパイルが行なわれていることをアサートする。孤立した環境とは、標準ライブラリがない可能性があり、プログラムの起動が必ずしも main から始まらない可能性がある環境である。最もわかりやすい例は、OS のカーネルである。このオプションは、-fno-hosted オプションと等価である。

-trigraphs
ANSI C のトリグラフ機能をサポートする。トリグラフについては問題が多い機能なので、ユーザは詳細を知る必要はないと思う。-ansi を指定すると、-trigraphs が有効になる。
-traditional
旧来の C のコンパイラの機能をいくつかサポートする。特に以下の機能がサポートされる。

自分のプログラムで、通常は GNU C の組み込み関数である名前をそのプログラム固有の別の目的で使っている場合は、-traditional の他に -fno-builtin を使う必要があるかもしれない。

ANSI C の機能を使っているヘッダファイルをインクルードする場合は、-traditional を使うことはできない。いくつかのベンダは、ANSI C ヘッダファイルを入れたシステムを出荷し始めているので、そういうシステムでは、システムのヘッダを一つでもインクルードしているファイルをコンパイルするときには、-traditional は使えないのである。

-traditional オプションを指定すると -traditional-cpp も有効になる。これについては次で説明する。

-traditional-cpp
旧来の C プリプロセッサの機能のいくつかをサポートする。特に以下の機能をサポートする。
-fcond-mismatch
3項演算子式で、二番目と三番目の引数の型が違っても許す。そういう式の値は void である。
-funsigned-char
char 型を、unsigned char のように符号なしとする。

各機種により、char のデフォルトがどうあるべきかが決まっている。デフォルトでは、unsigned char のようになるか、signed char のようになるかのどちらかである。

理想的には、移植性の良いプログラムにするなら、オブジェクトの符号の意味によって、必ず signed charunsigned char のどちらかを使うべきである。だが、たくさんのプログラムが単なる char 型を使って書かれており、それが書かれたマシンに依存して、符号付きか、符号なしかであるかを想定している。このオプションと、これの逆のオプションにより、デフォルトが反対になっているマシンでプログラムを動作させることができる。

char 型は常に signed char とも unsigned char とも異なる型である。たとえ、動作が必ずどちらか一方と同じであっても。

-fsigned-char
char 型を、signed char のように符号つきとする。

これは、-fno-unsigned-char と同じであり、-funsigned-char の否定形である。同様に、-fno-signed-char-funsigned-char と同じである。

-fsigned-bitfields
-funsigned-bitfields
-fno-signed-bitfields
-fno-unsigned-bitfields
これらのオプションは、ビットフィールドの宣言に signedunsigned も使っていないときに、そのビットフィールドが符号付きとなるか符号なしとなるかを制御する。デフォルトでは、そのようなビットフィールドは符号付きである。何故なら、そうすると首尾一貫するからである。int のような基本整数型は符号付きの型である。

だが、-traditional を指定すると、ビットーフィールドは何があろうと全て符号なしになる。

-fwritable-strings
文字列定数を書き込み可能なデータセグメントに格納し、一意化しない。これは、文字列定数に書き込みが可能であると仮定している古いプログラムとの互換性を取るためにある。-traditional オプションを指定してもこの機能が有効になる。

文字列定数に書き込もうとするのは全くの間違いである。「定数」は定数であるべきなのだ。

-fallow-single-precision
-traditional を指定してコンパイルした場合でも、単精度の数学演算を倍精度に格上げしない

K&R C では、オペランドのサイズに関わらずに、全ての浮動小数点演算を倍精度に格上げする。アーキテクチャによっては、単精度の方が倍精度より速いことがある。-traditional オプションを使わなければならない場合で、かつ、オペランドが単精度の場合には単精度の演算を使用したければ、このオプションを指定すれば良い。このオプションは ANSI または GNU C の規約(デフォルト)でコンパイルする場合には、動作に影響はない。


Node:C++ Dialect Options, Next:, Previous:C Dialect Options, Up:Invoking GCC

C++ 方言を扱うオプション

この節では、C++ プログラムの場合にのみ意味のあるコマンド行オプションを説明する。だが、GNU コンパイラのオプションの大部分は、プログラムの言語が何であるかに関わらず使うことができる。例えば、firstClass.C というファイルを以下のようにコンパイル出来る。

g++ -g -frepo -O -c firstClass.C

この例では、-frepo だけが、C++ プログラムの場合にだけ意味を持つオプションである。他のオプションは、GCC がサポートしているどの言語でも使用できる。

以下のリストは、C++ プログラムをコンパイルする場合にのみ意味のあるオプションである。

-fno-access-control
全てのアクセス検査を行なわない。これは、主にアクセス制御コードのバグを回避するためにある。
-fcheck-new
operatr new により返されるポインタがヌルでないことを、確保した領域を変更する前に、検査する。最新の ANSI C++ の "Working Paper" では、operator new は決してヌルポインタを返さないことを要求しているので、この検査は普通は必要でない。

このオプションの代わりとなる方法としては、自作の operator new がなんら例外を投げないと指定する方法がある。throw() と宣言すると、g++ は戻り値を検査する。new (nothrow) も参照のこと。

-fconserve-space
非初期化、あるいは実行時初期化グローバル変数を C の場合のように、コモンセグメントに置く。これは、二重定義を検査しないというコストを払ったうえで、実行形式中のスペースを節約する。このオプションをつけてコンパイルしたプログラムが、main() の終了後に、不可解にも異常終了したなら、二つの定義がマージされたために二回破壊されるオブジェクトが存在する可能性がある。

このオプションはもはやほとんどのターゲットで意義がなくなっている。変数を、コモンにすることなく BSS に置く方法がサポートされているからである。

-fdollars-in-identifiers
識別子中に $ を使うことを許す。-fno-dollars-in-identifiers オプションを使って、$ を明示的に使用禁止にすることも可能である。(GNU C は、ほとんどのターゲットでデフォルトで $ を許すが、2,3 の例外がある。) 旧来の C は、識別子の一部に $ を使うことを許している。しかし、ANSI C と C++ は、識別子中の $ を禁止している。
-fno-elide-constructors
C++ 規格は、同じ型の別のオブジェクトを初期化するのにしか使われない一時オブジェクトを作るのを省略する実装を許している。このオプションを指定すると、その最適化を無効にし、g++ が全ての場合にコピー・コンストラクタを呼ぶようにする。
-fexternal-templates
テンプレートの実体化を #pragma interfaceimplementation に従わせる。テンプレートの実体が生成されるか、テンプレート定義の位置には従わない。詳細については See Template Instantiation

このオプションは廃止要求が出ている。

-falt-external-templates
-fexternal-templates と同様だが、テンプレートの実体は生成されるか、最初に実体化された場所には従わない。詳細については See Template Instantiation

このオプションは廃止要求が出ている。

-ffor-scope
-fno-for-scope
-ffor-scope が指定されると、for 文の初期化文で宣言された変数の有効範囲は、その for ループ自体に限られる。これは、C++ 規格のドラフトで規定されている動作である。-fno-for-scope が指定された場合は、for 文の初期化文で宣言された変数の有効範囲は、for 文を囲む有効範囲の最後までとなる。これは、gcc の古いバージョンや、他の(古い) C++ の実装での動作である。

どちらのオプションも指定されない場合のデフォルトは規格に従うが、無効であったり、異なる動作にならない限り、古い形式のコードも警告がでるが許される。

-fno-gnu-keywords
classofheadofsignaturesigoftypeof をキーワードとして認識せず、識別子として使えるようにする。その場合、代わりに__classof____headof____signature____sigof____typeof__ を使うことができる。-ansi-fno-gnu-keywords を含む。
-fguiding-decls
潜在的な関数テンプレートの実体化と同じ型を持つ関数の宣言があったとき、それを普通の関数としてではなく、あたかも実体化を宣言しているかのように扱う。その関数の定義が、同じ翻訳単位の後ろで与えられていれば(あるいは、ターゲットにウィークシンボルがあれば、別の翻訳単位でも良い)、その定義が使われる。定義がければ、そのテンプレートは実体化される。この動作は、1996年9月以前の C++ 言語仕様を反映したものであり、この後、案内宣言(guiding declaration)が仕様から削除された。

このオプションを指定すると、-fname-mangling-version-0 も指定したことになるので、これ以外の名前のエンコード版(name mangling version) と一緒には使えない。ABI を変更する全てのオプション同様、libgcc.a を含む全ての C++ コードをこのオプションの設定を同一にして構築しなければならない。

-fhandle-signatures
抽象型を指定するキーワード、 signaturesigof を認識する。デフォルト(-fno-handle-signatures) では認識しない。
-fhonor-std
namespace std をネームスペースとして、無視せずに取り扱う。g++ の昔のバージョンとの互換性のために、GCC はデフォルトでは namespace-declarationsusing-declarationsusing-declarationsusing-directivesnamespace-names が、std を含んでいれば、それを無視する。
-fhuge-objects
short int で表現可能な大きさを越えるオブジェクトについて仮想関数呼び出しをサポートする。ユーザはデフォルトではこのオプションを使うべきでない。このオプションを使う必要があるときは、コンパイラが知らせてくれる。

このオプションは、-fvtable-thunks を使ってコンパイルした場合には役に立たない。

ABI を変更する全てのオプション同様、libgcc を含む全ての C++ コードをこのオプションの設定を同一にして構築しなければならない。

-fno-implicit-templates
暗黙に(すなわち、使うことにより)実体化される非インラインのテンプレート用のコードを生成しない。明示的な実体化に対してのみコードを生成する。より詳細については、See Template Instantiation
-fno-implicit-inline-templates
インラインテンプレートの暗黙の実体化についてのコードも生成しない。デフォルトはインラインを違ったやり方で取扱うので、最適化ありでもなしでも、コンパイラは明示的な実体化の同じセットが必要になる。
-finit-priority
__attribute__ ((init_priority (n))) をサポートし、ファイルスコープのオブジェクトの初期化順序を制御できるようにする。ELF ターゲットでは、このためには GNU ld 2.10 以降が必要である。
-fno-implement-inlines
スペースの節約のために、#pragma implementation により制御されるインライン展開関数の展開コードのコピーを生成しない。こうすると、インライン展開関数が、どの呼び出し個所でもインライン展開されないと、リンク時のエラーになる。

このオプションは、C++ リンケージの宣言には影響しない。

-fname-mangling-version-n
名前のマングル方法を制御する。バージョン 0 は、2.8 以前の g++ のバージョンと互換である。バージョン1がデフォルトである。バージョン1 は、関数テンプレートの正しいマングルが可能である。例えば、バージョン 0 のマングルでは、foo<int, double> をマングルせず、foo<int, char> は以下の宣言になる。
template <class T, class U> void foo(T t);

ABI を変更する全てのオプション同様、libgcc を含む全ての C++ コードをこのオプションの設定を同一にして構築しなければならない。

-foperator-names
演算子名キーワード、andbitandbitorcomplnotorxor をそれらが参照する記号の別名として認識する。-ansi には -foperator-names が含まれる。
-fno-optional-diags
規格がコンパイラが発行する必要はないと規定している診断メッセージを出さないようにする。現在、g++ が発行する診断メッセージで該当するのは、ある名前があるクラス内で複数の意味を持っているというものに対するものである。
-fpermissive
規格に準拠していないコードについてのメッセージをエラーから警告に格下げする。デフォルトでは、g++ は -pedantic を指定しない場合は実質的に -pedantic-errors を指定している。このオプションはそれを逆にする。この動作とオプションは、-pedantic により打ち消される。-pedatnic は GNU C の場合と同様の動作になる。
-frepo
自動的なテンプレートの実体化を有効にする。このオプションは、暗黙に -fno-implicit-templates も設定する。もっと詳しいことについては、 See Template Instantiation
-fno-rtti
C++ の実行時型識別機能(dynamic_casttypeid)で使われる情報を生成しない。C++ 言語のこれらの機能(あるいは、dynamic_cast を内部的に使っている例外処理)を使わないのであれば、このオプションを指定することでスペースをいくらか節約できる。
-fstrict-prototype
リンケージ指定 extern "C" の中で、引数なしの関数宣言、例えば int foo (); を、引数を取らない関数の宣言として扱う。普通 C では、そのような宣言は関数 foo はどんな引数の組合せでも取ることができることを意味する。-pedantic は、-fno-strict-prototype が指定されていない限り、-fstrict-prototype も有効にする。

このオプションを指定すると、暗黙の関数宣言も抑制する。

このオプションは、C++ リンケージを持つ宣言には、もはや影響しない。

-fsquangle
-fno-squangle
-fsquangle を指定すると、識別子の名前のマングリングの圧縮形を有効にする。これは、特に、複数回現れる型名とクラス名を認識し、特別に短い ID コードで置き換えることで、非常に長い名前を短くするのを助ける。このオプションを指定するなら、一緒に使うどの C++ ライブラリも同様にこのオプションを指定してコンパイルする必要がある。デフォルトで無効になっている(-fno-squangle を指定したのと同じ)。

ABI を変更するような全てのオプション同様、libgcc.a を含む 全ての C++ コードを、このオプションについて同じ設定で構築しなければならない。

-ftemplate-depth-n
テンプレートクラスの実体化の最大の深さを n にする。テンプレート実体化の深さは、テンプレートクラス実体化の際に無限に再帰が起こるのを検出するのに必要である。ANSI/ISO C++ に適合するプログラムは、17 より大きい最大の深さに頼ってはならない。
-fthis-is-variable
this への代入を許す。ユーザ定義のフリーストア管理を C++ に取り込んだことにより、this への代入は時代遅れになった。このため、デフォルトではクラスのメンバ関数内で this に代入することは無効である。すなわち、GNU C++ は、クラス X のメンバ関数中の thisX * 型の非左辺値として取り扱う。しかし、以前との互換性のために、-fthis-is-variable を指定することで有効とすることができる。
-fvtable-thunks=thunks-version
サンク を使って仮想関数のディスパッチテーブル(vtable)を実装する。vtable を実装する旧来の方法(cfrontの方法)では、仮想関数へのポインタと、呼び出し側で this ポインタを調整するための二つのオフセットを格納していた。新しい実装方法では、あるサンク関数への一個のポインタを格納する。そのサンク関数が必要な調整を行ったうえで目的の関数を呼び出す。

サンクの最初の実装(バージョン1)には、仮想基底クラスに関するバグがあった。このバグは、サンクの実装のバージョン 2 で修正されている。バージョンを 2 に指定すると、バージョン 1 のサンクとの互換性が保たれるが、余分な機械語コードがかかる。バージョン 3 にはこの互換性はない。

このオプションはまた、発見的方法を使って、仮想関数テーブルの生成を制御する。あるクラスに一つでも非インライン仮想関数があれば、その非インライン関数のうちの先頭の一つを含む翻訳単位に、vtable が射出される。

ABI を変更する全てのオプション同様、libgcc.a を含む全ての C++ コードをこのオプションの設定を同一にして構築しなければならない。バージョン 1 とバージョン 2 も非互換である(仮想関数を定義している仮想基底をもつクラスについて)、全てのコードを同じバージョンでコンパイルしなければならない。

このバージョンの gcc では、バージョン 2 のサンクがデフォルトになっているターゲットはない。全てのターゲットで、オプションを指定しないと旧来の実装を使い、-fvtable-thunks を指定するとバージョン 2 のサンクを生成する。

-nostdinc++
ヘッダファイルを、C++ 固有の標準ディレクトリから探さない。だが、他の標準ディレクトリに対しては検索を行なう。(このオプションは、GNU の C++ ライブラリを構築するときに使われる。)

さらに、以下の最適化、警告、コード生成に関するオプションはC++ プログラムの場合にのみ意味を持つ。

-fno-default-inline
クラススコープ内で定義されている関数に inline を仮定しない。See Options That Control Optimization. こういう関数はインライン関数と似たリンケージを持つ。単にデフォルトではインライン展開されないのである。
-Wctor-dtor-privacy (C++ のみ)
クラスが使用不可能だと思える場合に警告を出す。これは、クラスの全てのコンストラクタまたはデストラクタが private であり、friend や public static のメンバ関数が無いときである。
-Wnon-virtual-dtor (C++ のみ)
クラスが、おそらく virtual でなくてはいけないデストラクタを非 virtual と宣言しているときに警告を出す。多相的に使われるであろうクラスに見えるからである。
-Wreorder (C++ のみ)
コードで示されたメンバの初期化順序と、実際に実行するときに従わなければならない順序が一致しないときに、警告する。例えば、以下のコードを考える。
struct A {
  int i;
  int j;
  A(): j (0), i (1) { }
};

ここでコンパイラは、ij についてのメンバ初期化が、メンバの宣言順序に一致するように並べ変えられるという警告を出す。

以下の -W... オプションは -Wall には影響されない。

-Weffc++ (C++ のみ)
Scott Meyers の「Effective C++」で述べられているスタイルの指針から外れている様々なものについて警告する。このオプションを使う場合は、標準ライブラリヘッダがこれらの指針の全てには従っていないという点に注意する必要がある。grep -v を使って、そういう警告を取り除く事ができる。
-Wno-deprecated (C++ のみ)
廃止要求が出ている機能を使った場合の警告を出さない。See Deprecated Features.
-Wno-non-template-friend (C++ のみ)
テンプレート化されていないフレンド関数がテンプレート内で宣言されている時の警告を出さないようにする。明示的なテンプレート指定が g++ でサポートされたことにより、そのフレンドの名前が修飾子無しの識別子(例えば、friend foo(int)) なら、C++ 言語規格ではそのフレンドが通常の、非テンプレート関数を宣言するか定義することを要求している。(14.5.3節。) g++ が明示的な規定を実装する前は、修飾子無しの識別子は、テンプレート化された関数の特定の特殊化と解釈可能であった。この規格に合致しない動作はもはや g++ のデフォルトの動作ではないので、-Wnon-teplate-friend を指定すると GCC は既存のコードの中から潜在的に問題になりそうなところを検査する。これはデフォルトで有効になっている。この新しい動作は -fguiding-decls オプションでも無効にすることができる。このオプションは、昔の、指定無しのコンパイラのコードを有効にする。あるいは、-Wno-non-template-friend を指定すると、規格に準拠したコンパイラのコードを保持するが、役に立つ警告は出なくなる。
-Wold-style-cast (C++ のみ)
C++ プログラムで古い形式(C言語形式)のキャストが使われている場合、警告を出す。新しい形式のキャスト(static_castreinterpret_castconst_cast) は、予期しない効果を受けにくい。
-Woverloaded-virtual (C++ のみ)
導出クラスの関数宣言が仮想関数の定義でエラーになりうる場合に警告する。導出クラスでは、仮想関数の定義は、基底クラスの仮想関数宣言の型シグネチャに一致しなければならない。このオプションを指定すると、コンパイラは、仮想関数と同じ名前だが、型シグネチャが基底クラスのどの宣言にも一致しない関数を定義すると警告を出す。
-Wno-pmf-conversions (C++ のみ)
メンバ関数へ結び付いたポインタを普通のポインタに変換するときの診断メッセージを無効にする
-Wsign-promo (C++ のみ)
多重定義の解決の際に、unsigned 型または列挙型から signed 型への格上げが、同じ大きさの unsigned 型への変換を越えて選択されたときに警告を出す。以前のバージョンの g++ は、unsigned 性を保存することを試みていたが、規格が現在の動作を要求しているのである。
-Wsynth (C++ のみ)
g++の合成の振るまいが cfront のものと一致しない場合に警告する。例えば、
struct A {
  operator int ();
  A& operator = (int);
};

main ()
{
  A a,b;
  a = b;
}

という例では、g++ はデフォルトの A& operator = (const A&); を合成するが、cfront はユーザ定義の operator = を使う。


Node:Warning Options, Next:, Previous:C++ Dialect Options, Up:Invoking GCC

警告を要求/抑止するオプション

警告とは診断メッセージであり、本来のエラーではないが、潜在的な危険性があったり、誤りが存在する可能性のある構文について報告する。

-W で始まるオプションを指定することで、多くの特定の警告を要求することができる。例えば、-Wimplicit は、暗黙の宣言についての警告を出すよう要求する。これらの特定の警告オプションには、警告を抑止する、-Wno- で始まる否定形がある。例えば、-Wno-implicit というのがある。このマニュアルでは、二つの形式のうちの、デフォルトでは無い方だけを列挙する。

以下のオプションは、GCC により生成される警告の量と種類を制御する。

-fsyntax-only
文法チェックのみを行ない、それ以上のことは一切行なわない。
-pedantic
ANSI C と ISO C++ に厳密に準拠した場合に要求される警告を全て発する。また、禁じられている拡張を使っているプログラムを全て拒絶する。

ANSI C と ISO C++ に則ったプログラムは、このオプションを指定してもしなくても、正しくコンパイルが行なわれる(まれに、-ansi をオプションを必要とする場合もあるが)、しかし、このオプションを指定しない場合は、GNU の拡張機能と古い形式の C と C++ の機能もサポートされる。このオプションを指定するとそれらは拒絶される。

-pedantic は、先頭と末尾が __ である名前を持つ別キーワードを使う分には警告メッセージを出さない。「衒学的」(pedantic)な警告は、__extension__ に続く式についても抑止される。しかし、このような抜け道を使うのはシステムのヘッダファイルにとどめるべきであり、アプリケーションプログラムは使わないようにしたほうが良い。See Alternate Keywords.

このオプションは役に立つことを目的としていない。単に、これがないと、GCC が ANSI 標準をサポートしていないと文句を言い立てる輩を満足させるためだけのものである。

読者の中には、-pedantic を使って、プログラムが厳密に ANSI C に適合しているかどうかを検査してみる人がいるかもしれない。でもすぐに、期待通りというわけではないことが分かるだろう。-pedantic は、非 ANSI 的な構文のうちの幾つかを見つけるだろう。だが、全部ではない。ANSI C が診断メッセージを要求しているものだけなのである。

ANSI C に適合しない点についてはどんなまのでも報告する機能は場合によっては有用かもしれないが、相当の作業量を必要とするし、-pedantic とは全く異なったものになるだろう。我々は近い将来このような機能をサポートする計画はない。

-pedantic-errors
-pedantic と同様だが、警告の代わりにエラーとする。
-w
全ての警告メッセージを抑止する。
-Wno-import
#import の使い方に関する警告を抑止する。
-Wchar-subscripts
配列の添え字の型が char なら警告を出す。これは良くある間違いの元となる。プログラマは、この型がマシンによっては符号付きになることを良く忘れるからである。
-Wcomment
コメント開始文字列 /*/* 形式のコメント中に現れたり、バックスラッシュ-改行が // 形式のコメントに現れた場合に警告を出す。
-Wformat
printfscanf 等の関数の呼びだしを検査し、指定された引数の型が、フォーマット文字列で指定されたものとあっているかどうかを調べる。
-Wimplicit-int
宣言に型指定がない場合に警告をだす。
-Wimplicit-function-declaration
-Werror-implicit-function-declaration
関数が宣言される前に使われている場合に警告(あるいはエラー)を出す。
-Wimplicit
-Wimplicit-int-Wimplicit-function-declaration に同じ。
-Wmain
main の型に不備がある場合に警告を出す。main は、外部リンケージで、int を返し、適切な型の引数をゼロ個か、二個か、三個を取る関数とすべきである。
-Wmultichar
複数文字からなる文字定数('FOOF' が使われた場合に警告を出す。こういうものは普通はユーザのコードのタイポを示しており、実装定義の値になるので、可搬なコードでは使うべきではないからである。
-Wparentheses
特定の文脈において括弧が省略されている場合に警告を出す。そのような文脈としては、真偽値が期待されている文脈で代入を行なっていたり、優先順位を良く間違える人が多いような演算子が入れ子になっている場合等である。

また、ある else 文がどの if 文に属するか混乱する可能性のある構文についても警告する。以下にその例を挙げる。

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

C では、どの else 文も可能なうちで最も内側の if 文に所属する。これは、プログラマが期待するものと違うことが良くある。上の例では、プログラマが期待するものは字下げで示されているものである。このような混乱の可能性がある場合は、GNU C は、このオプションを指定している場合には、警告を出す。警告を出さない用にするには、最も内側の if 文を括弧で明示的に括って、else が外側の if には属する術が無いことを知らせる。それを反映したコードは以下のようになる。

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

-Wreturn-type
関数定義で、戻り値型の指定がなくデフォルトの int 型になる関数について警告を出す。また、戻り値型が void でない関数内で、戻り値なしの return 文があったら警告を出す。
-Wswitch
switch 文のインデックスが列挙型であり、その列挙型の列挙定数のうち、一個以上について case が欠けている場合に、警告を出す。(ラベル default があれば、この警告はでない。) 列挙値の範囲外の case ラベルがある場合も、このオプションが指定されていれば、この警告が出される。
-Wtrigraphs
トリグラフを見つけたら警告を出す(トリグラフが有効になっている場合)。
-Wunused
変数が、宣言以外の所で使われていない場合、関数が static として宣言されているが定義されていない場合、ラベルが宣言されているが使われていない場合、それに明示的には使われない結果を計算している文がある場合に警告を出す。

使われていない関数の仮引数についての警告を出すには、-W-Wunused を両方指定しなければならない。

ある式について、この警告を出さないようにするには、単にその式をvoid にキャストする。変数と仮引数、ラベルについてこの警告を出さないようにするには、unused 属性を使う(see Variable Attributes)。

-Wuninitialized
自動変数が、最初に初期化する前に使われている場合に警告をだす。

この警告は、最適化を伴うコンパイルの場合にのみ発生する。なぜなら、この警告を出すには、最適化を行なった場合にのみ計算される、データフロー情報を必要とするからである。-O を指定しない場合には、単にこの警告が出ないだけである。

この警告は、レジスタ割当の候補となる変数に対してだけ出される。このため、volatile と宣言されていたり、アドレスを取っていたり、サイズが 1、2、4、8 バイト以外の変数に対してのみ発生する。また、構造体、共用体、配列についても、たとえそれらがレジスタに置かれていても警告はでない。

それ自身決して使われることのない値を計算するのにだけ使われる変数については警告が出ないことに注意。そういう計算自体が、警告が出力される前のデータフロー解析で削除されるからである。

これらの警告がデフォルトではなくてオプションになっているのは、そのコードにエラーがあるように見えるのに、正しいかもしれないという理由が全て分かるほど GCC は賢くないからである。以下に、どういうふうに発生するかの例を一つ示す。

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

y の値が常に 1、2、3 のどれからなら、x は常に初期化される。だが、GCC はそのことを知らない。次の例はもう一つの良くあるケースである。

{
  int save_y;
  if (change_y) save_y = y, y = new_y;
  ...
  if (change_y) y = save_y;
}

この場合は、save_y が使われるのは、値が設定されている場合のみだから問題はない。

使っている関数のうち、決して戻らない関数を全て noreturn と宣言すると、幾つかの見せ掛けの警告を回避することができる。

-Wunknown-pragmas
GCC が知らない #pragma 命令に出会った場合に警告を出す。このコマンド行オプションを指定すると、システムヘッダファイルの中に知らない pragma があった場合にも警告を出す。これは、警告がコマンド行オプション -Wall によってのみ有効になる場合ではない。
-Wall
上記の全ての -W オプションを組み合わせる。これにより、ユーザによっては疑問に思うような構文のうち、回避したり抑止するよう修正するのが簡単なものついては、それがマクロを使っているものであっても、全てについて警告を出す。

以下の -W... オプションは、-Wall には含まれない。この中の幾つかは、一般にはユーザが問題とは考えないことが多い構文に関して警告するが、検査したくなることも時々あるような問題でもある。その他のものは、ある場合には回避することが必要だったり、あるいは回避することが難しい構文について警告する。これらの警告は、出さないようにするためのコードの簡単な修正方法がないものである。

-W
以下の出来事に対して追加で警告メッセージを出力する。
-Wtraditional
旧来の C と ANSI C で動作が異なる構文について警告する。
-Wundef
未定義の識別子が、#if 制御子の中で評価される場合に警告を出す。
-Wshadow
あるローカル変数が別のローカル変数を覆い隠す時に警告を出す。
-Wid-clash-len
二つの異なる識別子の最初の len 文字が一致するときに警告する。これは、プログラムをある種の古い、腐ったコンパイラでコンパイルが通るようにするときに役に立つであろう。
-Wlarger-than-len
len バイトより大きなオブジェクトが定義された場合に警告を出す。
-Wpointer-arith
関数型や void 型の「大きさ」に依存しているもの全てについて警告する。GNU C は、void * ポインタと関数へのポインタの計算に便利なように、これらの型の大きさに 1 を割り当てている。
-Wbad-function-cast
関数呼び出しが、マッチしない型にキャストされた時に警告する。例えば、int malloc()anything * にキャストされると警告を出す。
-Wcast-qual
ポインタが、それが指す型から型修飾子を取り除いた型にキャストされると警告を出す。例えば、const char *char * にキャストすると警告を出す。
-Wcast-align
ポインタが、その指す型に必要とされるアラインメントが大きくなるようにキャストされると警告を出す。例えば、整数は2バイトまたは4バイト境界でしかアクセスできない機種で、char *int * にキャストすると警告が出る。
-Wwrite-strings
文字列定数の型を const char[length] とし、その文字列のアドレスを非constchar * 型のポインタにコピーしたときに警告を出させるようにする。この警告は、文字列定数に書き込む可能性のあるコンパイル時コードを見つける助けとなる。ただし、宣言とプロトタイプで const を注意深く使わなければならない。そうしないと、単に邪魔になるだけである。このため、-Wall ではこの警告を出さないようにしている。
-Wconversion
プロトタイプ宣言のために、プロトタイプ宣言がない場合に同じ引数が受けるのとは異なる型変換が起こる場合に警告を出す。これは、固定小数点と浮動小数点間の変換を含み、デフォルトの格上げと同じになる場合を除いて、固定小数点引数の幅や符号を変える変換も含む。

また、負の整数定数式が暗黙に符号なし型に変換されるときも警告を出す。例えば、x が符号なしであれば、x = -1 という代入に警告を出す。しかし、(unsigned) -1 のような明示的なキャストには警告を出さない。

-Wsign-compare
符号付きの値と符号なしの値を比較するとき、符号付きの値が符号なしに変換されると間違った結果になるときに警告を出す。この警告は -W によっても有効になる。-W が出す他の警告を、この警告を出さずに得るには、-W -Wno-sign-compare を使う。
-Waggregate-return
構造体や共用体を返す関数が定義されているか呼び出されていると警告する。(配列を返せる言語でも、警告を引き出す。)
-Wstrict-prototypes
関数が、引数の型指定なしで宣言されていたり、定義されていると警告を出す。(古い形式の関数定義は、引数の型を指定する宣言が事前にあれば、許され、警告は出ない。)
-Wmissing-prototypes
グローバルな関数が事前のプロトタイプ宣言なしで定義された場合に警告を出す。この警告は、関数の定義自身がプロトタイプ宣言を提供している場合でも発行される。目的は、ヘッダファイルで宣言されていないグローバルな関数を検出することにある。
-Wmissing-declarations
グローバルな関数が事前の宣言なしで定義された場合に警告を出す。関数の定義自身がプロトタイプ宣言を提供している場合でも警告が出る。このオプションを使って、ヘッダファイルで宣言されていないグローバルな関数を検出する。
-Wmissing-noreturn
属性 noreturn の候補になる可能性のある関数について警告する。これらはあくまで候補であって、絶対的なものではないことに注意。noreturn 属性を追加する前に、関数が実際に決して戻らないことを自分で注意深く検証する必要がある。そうしないと、微妙なコード生成のバグが持ち込まれる可能性がある。
-Wredundant-decls
同じスコープ内で複数回宣言されているものがあれば警告する。これは、複数回宣言することが有効であり、何も変えない場合でも該当する。
-Wnested-externs
extern 宣言が関数内にあると警告する。
-Winline
関数が inline 宣言されているか、-finline-functions オプションが指定されているときに、インライン展開できない関数があれば警告を出す。
-Wlong-long
long long 型が使われていると警告を出す。これはデフォルトである。この警告メッセージを出さないようにするには、-Wno-long-long を指定する。-Wlong-long-Wno-long-long オプションは、-pedantic オプションが指定されている場合にのみ、考慮される。
-Werror
全ての警告をエラーに変える。


Node:Debugging Options, Next:, Previous:Warning Options, Up:Invoking GCC

読者のプログラムや GCC をデバッグするためのオプション

GCC には色々特別なオプションがあって、ユーザのプログラムや GCC 自体をデバッグするのに使われる。

-g
デバッグ情報をオペレーティングシステム固有の形式(stabs、 COFF、 XCOFF、あるいは DWARF)で生成する。GDB は、このデバッグ情報を使うと動作するようになる。

stabs 形式を使っているほとんどのシステムで、-g を指定すると、GDB だけが使うことのできる特別のデバッグ情報を使うようになる。この特別な情報は GDB の場合にはデバッグをしやすくするが、他のデバッガを使う場合は、おそらく、デバッガが落ちたり、プログラムを読み込めなくなってしまうだろう。特別な情報を生成するかどうかをある程度制御したい場合は、-gstabs+-gstabs-gxcoff+-gxcoff-gdwarf-1+-gdwarf-1 を使うこと(後述参照)。

他の多くの C コンパイラと違って、GCC では -g-O と一緒に使うことができる。最適化されたコードによるショートカットのため、以下のように、驚くような結果が時々出るが。宣言したはずの変数が全く存在しないことがある。制御の流れが、簡単に言えば、予想していない場所に移動してしまうことがある。文の中には実行されないものも出てくる。それらの文が、既に入手済みの一定の結果や値を計算しているからである。文の中には別の場所で実行されるものもある。ループの外に移動したからである。

それにもかかわらず、最適化された出力をデバッグすることは可能である。このため、バグがあるかもしれないプログラムを最適化することが妥当なことになる。

GCC が複数のデバッグ情報を扱えるように生成されているときは以下のオプションが役に立つ。

-ggdb
GDB で使用するデバッグ情報を生成する。これは、利用可能な形式のうち最も表現力のあるものを使うということを意味する。これには、可能な限りの GDB 向け拡張も含まれる。
-gstabs
stabs 形式のデバッグ情報(サポートされていれば)を GDB 向け拡張なしで生成する。この形式が、ほとんどの BSD システムの DBX で使われるものである。MIPS、Alpha、System V Release 4 のシステムでは、このオプションは、DBX や SDB が理解できない形式の stabs デバッグ情報を生成する。System V Release 4 のシステムでこのオプションを使うにはGNU assembler が必要である。
-gstabs+
stabs 形式のデバッグ情報(サポートされていれば)を、GNU debugger (GDB) だけが理解できる GNU 拡張付きで生成する。この拡張を使うと、他のデバッガは落ちたり、プログラムを読み込めなくなったりする。
-gcoff
デバッグ情報を COFF 形式(サポートされていれば)で生成する。これは、System V Release 4 以前の System V 上の SDB で使われていた形式である。
-gxcoff
デバッグ情報を XCOFF 形式(サポートされていれば)で生成する。これは、IBM の RS/6000 システム上の DBX デバッガで使われている形式である。
-gxcoff+
デバッグ情報を XCOFF 形式(サポートされていれば)で、GNU デバッガ(GDB) だけが理解できる GNU の拡張付きで生成する。この拡張を使うと、他のデバッガは落ちたり、プログラムを読み込めなくなったりする。また、GNU assembler (GAS) 以外のアセンブラだとエラーが出て失敗する。
-gdwarf
デバッグ情報を DWARF のバージョン1の形式(サポートされていれば)で生成する。これは、System V Release 4 のシステム上の SDB で使われている形式である。
-gdwarf+
デバッグ情報を DWARF のバージョン1の形式(サポートされていれば)で、GNU debugger (GDB) だけが理解できる GNU の拡張付きで生成される。この拡張を使うと、他のデバッガは落ちたり、プログラムを読み込めなくなったりする。
-gdwarf-2
デバッグ情報を DWARF のバージョン2の形式(サポートされていれば)で生成する。これは、IRIX 6 上の DBX で使われている形式である。
-glevel
-ggdblevel
-gstabslevel
-gcofflevel
-gxcofflevel
-gdwarflevel
-gdwarf-2level
デバッグ情報を出すことを要求し、かつ、 level でどれぐらいの情報を出すかを指定する。デフォルトのレベルは 2 である。

レベル 1 は、デバッグする予定のないプログラムの一部のバックトレースが取れるぐらいの、最小限の情報を生成する。この情報には、関数と外部変数の記述が含まれるが、ローカル変数と行番号についての情報は含まれない。

レベル 3 は余分の情報を含める。例えば、プログラムに存在する全てのマクロ定義などが含まれる。デバッガの中には、-g3 を使った場合にマクロの展開をサポートするものもある。

-p
prof プログラムによる解析に適したプロファイル情報を書き出す余分のコードを生成する。このオプションは、データを必要とするソースファイルをコンパイルするときに指定しなければならない。また、リンク時にも指定しなければならない。
-pg
gprof プログラムによる解析に適したプロファイル情報を書き出す余分のコードを生成する。このオプションは、データを必要とするソースファイルをコンパイルするときに指定しなければならない。また、リンク時にも指定しなければならない。
-a
基本ブロックに関するプロファイル情報を書き出す余分のコードを生成する。このコードは、各基本ブロックが実行された回数、基本ブロックの開始アドレス、その基本ブロックを含む関数名を記録する。-g が指定されていると、基本ブロックの開始点の行番号とファイル名も記録される。マシン記述で上書きされていない限り、デフォルトの動作はテキストファイル bb.out に追加することである。

このデータは、tcov のようなプログラムで解析することができる。だが、このデータの形式は tcov が想定しているものでないことに注意すること。将来的には GNU gprof を、このデータを処理できるように拡張する必要があるだろう。

-Q
各関数のコンパイルが終わる毎にその関数名を出力し、各パスが終了したときにそのパスについての統計情報を出力する。
-ax
基本ブロックプロファイル用の余分なコードを生成する。実行形式を実行すると、-a が指定されたときに生成されるもののスーパーセットが出力される。出力に付け加わるのは、ジャンプが起きたところの基本ブロックのジャンプ元とジャンプ先のアドレスと、ジャンプの実行回数、それにオプションで実行される基本ブロックの完全な列である。出力は、ファイル bb.out に追加される。

再コンパイルしなくても異なるプロファイリングの面を試すことができる。実行形式ファイルは、ファイル bb.in から関数名のリストを読み込む。プロファイリングは、リストにある関数に入った時点で開始し、その関数の実行が終わった点で終了する。プロファリングから関数を除外する場合は、その名前の前に `-' を付ける。関数名が一意的でない場合は、/path/filename.d:functionname という形式で書くことで区別できる。実行形式ファイルの実行により、利用可能なパス名とファイル名がファイル bb.out に書き出される。

幾つかの関数名には特別な意味がある。

__bb_jumps__
ジャンプ元、ジャンプ先、ジャンプの頻度をファイル bb.out に書き出す。
__bb_hidecall__
頻度の計数から関数呼び出しを除外する。
__bb_showret__
頻度の計数に関数からの戻りを含める。
__bb_trace__
実行された基本ブロックの列をファイル bbtrace.gz に書き出す。このファイルは gzip プログラムを使って圧縮されるので、gzipPATH に入っていなければならない。popen 関数のないシステムでは、このファイルは bbtrace という名前になり、圧縮は行なわれない。そういうシステムでは、ほんの数秒のプロファイリングでも、非常に巨大なファイルができる。 注意: __bb_hidecall____bb_showret__bbtrace.gz に書き出される列には影響しない。

以下に、ファイル bb.in で異なるプロファイリングパラメータを使った短い例を示す。関数 foo には、基本ブロック 1 と 2 があり、関数 main のブロック 3 から二回呼び出されるとする。その呼び出しの後、ブロック 3 は制御を main のブロック 4 に移す。

__bb_trace__main をファイル bb.in に入れておくと、0 3 1 2 1 2 4 というブロック列がファイル bbtrace.gz に書き出される。ブロック 2 からブロック 3 へ戻るのは示されていない。これは、ブロックの中のある点へ戻るためで最上位に戻るのではないからである。ブロックアドレス 0 は常に、制御が測定した関数のどこか外側から、トレースに移ったことを意味する。-foobb.in に入れると、関数 foo のブロックはトレースから除かれるので、0 3 4 だけが残る。

__bb_jumps__main をファイル bb.in に入れると、ジャンプの頻度がファイル bb.out に書き出される。頻度は、ブロックのトレースを構成し、トレース中の隣り合わせのブロックの対毎にカウンタをインクリメントすることで得られる。トレース 0 3 1 2 1 2 4 は以下の列を表示する。

Jump from block 0x0 to block 0x3 executed 1 time(s)
Jump from block 0x3 to block 0x1 executed 1 time(s)
Jump from block 0x1 to block 0x2 executed 2 time(s)
Jump from block 0x2 to block 0x1 executed 1 time(s)
Jump from block 0x2 to block 0x4 executed 1 time(s)

__bb_hidecall__ を置くと、呼出し命令による制御の移動はトレースから取り除かれる。すなわち、トレースは三つの部分に分けられる。0 3 4 と 0 1 2、それに 0 1 2 である。__bb_showret__ を置くと、リターン命令による制御の移動がトレースに追加される。トレースは、0 3 1 2 3 1 2 3 4 になる。このトレースは、bbtrace.gz に書き出される列とは同じでないことに注意。これは、ジャンプの頻度を数えるのにしか使われない。

-fprofile-arcs
コンパイル中に 弧(arc) を操作する。プログラムの関数毎に GCC は、一個のプログラムの流れのグラフを作り、そのグラフのスパニング・ツリーを探す。スパニング・ツリー上にない弧だけが操作される。GCC は、そういう弧が実行される回数を数えるコードを追加する。ある弧が、あるブロックに対する出口にしかなっていないか、あるいは入り口にしかなっていない場合は、操作を行なうコードをそのブロックに追加することが可能である。その他の場合は、新しい基本ブロックを作り、操作を行なうコードを保持しなければならない。

プログラム中のあらゆる弧が操作されるわけではないので、このオプションを使ってコンパイルしたプログラムは、-a でコンパイルしたプログラムよりは高速である。-a を付けると、プログラム中のあらゆる基本ブロックに操作コードを追加する。トレードオフがある。gcov は、全ての分岐について実行回数を数えている訳ではないので、操作された分岐の実行回数から始めて、プログラムの流れのグラフについて、全グラフが解決するまで繰り返し行なう。このため、gcov は、-a で得られる情報を使うプログラムよりは、いくらか遅くなる。

-fprofile-arcs を指定すると、分岐確率を見積もったり、基本ブロックの実行回数を計算することも可能になる。一般に、基本ブロックの実行回数だけでは、全ての分岐確率を見積もることが出来るだけの情報は得られない。コンパイルしたプログラムが終了するとき、弧の実行回数を sourcename.da というファイルにセーブする。オプション -fbranch-probabilities (see Options that Control Optimization) を指定して再コンパイルして、見積もった分岐確率を使って最適化を行なう。

-ftest-coverage
コードカバレージプログラム gcov 用のデータファイルを作る(see gcov: a GCC Test Coverage Program). このデータファイル名は、ソースファイル名で始まる。
sourcename.bb
基本ブロックと行番号の対応表である。gcov が行番号毎に基本ブロックの実行回数を対応させるのに使う。
sourcename.bbg
プログラムのフローグラフにおける、全ての弧のリストである。これにより gcov がプログラムのフローグラフを再構築することで、sourcename.da ファイルにある情報から、全ての基本ブロックと弧の実行回数を計算できるようになる。(sourcename.da は、-fprofile-arcs の出力である。)

-Q
各関数がコンパイルされるときにその関数名を出力し、コンパイルの各パスについて、それが終わったときに統計情報を出力する。
-dletters
letters で指定されるコンパイル過程のデバッグ出力を行なう。これは GCC のデバッグに使われる。デバッグ出力のファイル名は、ほとんどが、ソースファイル名にある単語を追加して作られる(例えば、foo.c.rtlfoo.c.jump 等)。以下に letters に指定できる文字とその意味を示す。
b
分岐確率計算後に、file.bp に出力する。
c
命令組合せ後に、ファイル file.combine にダンプする。
d
遅延分岐スケジューリング後に、file.dbr にダンプする。
D
通常の出力に加えて、全てのマクロ定義を前処理の最後にダンプする。
r
RTL 生成後、file.rtl にダンプする。
j
最初のジャンプ最適化後に、file.jump にダンプする。
F
ADDRESSOF の削除後に、file.addressof にダンプする。
f
フロー解析後に、file.flow にダンプする。
g
グローバルレジスタ割当後に、file.greg にダンプする。
G
GCSE 後に、file.gcse にダンプする。
j
最初のジャンプ最適化後に、file.jump にダンプする。
J
最後のジャンプ最適化後に、file.jump2 にダンプする。
k
レジスタからスタックへの変換後に、file.stack にダンプする。
l
ローカルレジスタ割当後に、file.lreg にダンプする。
L
ループ最適化後に、file.loop にダンプする。
M
機種依存の再構成パス後に、file.mach にダンプする。
N
レジスタ移動パス後に、file.regmove にダンプする。
r
RTL 生成後に、file.rtl にダンプする。
R
二回目の命令スケジューリング・パス後に、file.sched2 にダンプする。
s
CSE(時々 CSE に続くジャンプ最適化を含む)後に、file.cse にダンプする。
S
一回目の命令スケジューリング・パス後に、file.sched にダンプする。
t
二回目のCSE(時々 CSE に続くジャンプ最適化を含む)後に、file.cse2 にダンプする。
a
上記のダンプを全て生成する。
m
メモリ使用状況の統計を、最後に標準出力に出力する。
p
アセンブラ出力に、どのパターンと選択肢が使われたかを示すコメントで注釈を付ける。各命令の長さも表示される。
x
関数をコンパイルするのではなく、単に RTL を生成する。普通、r と一緒に使う。
y
構文解析中にデバッグ情報を標準エラー出力にダンプする。
A
アセンブラ出力に色々なデバッグ情報で注釈を付ける。

-fdump-unnumbered
デバッグダンプを出力するとき(上の -d オプションを参照のこと)、命令番号と行番号ノートを出力しない。これにより、別のオプションを指定して起動したコンパイルのデバッグダンプに diff を使いやすくなる。特に -g のありなしで有効である。
-fpretend-float
クロスコンパイラを実行する際に、ターゲット機種がホスト機種と同じ浮動小数点形式を使っている振りをさせる。こうすると、実際の浮動小数点定数としては正しくない出力を行なうが、実際の命令列は、GCC をターゲット機種で実行させたとき生成する命令列とおそらく同じである。
-save-temps
通常「一時的」な中間ファイルを保存する。中間ファイルをカレントディレクトリに置き、ソースファイル名に基づいた名前を付ける。つまり、foo.c-c -save-temps を付けてコンパイルすると、foo.o の他に、foo.ifoo.s というファイルができる。
-print-file-name=library
リンク時に使われるライブラリファイル library の絶対パス名を出力し、他には何も行なわない。このオプションを指定すると、GCC はコンパイルやリンクは一切行なわない。単にファイル名を出力するだけである。
-print-prog-name=program
-print-file-name と似ていて、cpp のようなプログラムを検索する。
-print-libgcc-file-name
-print-file-name=libgcc.a と同じ。

これは、-nostdlib-nodefaultlibs を使いたいが、libgc.a はリンクしたいというときに便利である。それには以下のようにすれば良い。

gcc -nostdlib files... `gcc -print-libgcc-file-name`

-print-search-dirs
コンフィギュレーションで指定したインストール先ディレクトリ名と、GCC がプログラムとライブラリを検索するディレクトリのリストを表示する。その他の事は何も行なわない。

これは gcc が installation problem, cannot exec cpp: No such file or directory というエラーメッセージを出したときに役に立つ。このエラーが出たときには、cpp とその他のコンパイラのサブプログラムをgcc があると想定している場所に置くか、あるいはそれらをインストールしたディレクトリを環境変数 GCC_EXEC_PREFIX で指定する必要がある。ここで指定するディレクトリ名には最後に '/' を付けなければならないことに注意して欲しい。See Environment Variables.


Node:Optimize Options, Next:, Previous:Debugging Options, Up:Invoking GCC

最適化オプション

以下のオプションは色々な種類の最適化を制御する。

-O
-O1
最適化を行なう。最適化を行なうコンパイルには幾らか余計に時間がかかり、大きな関数についてはたくさんのメモリを余計に使う。

-O を指定しない場合は、コンパイラの目標はコンパイルのコストを小さくすることとデバッグが期待どおりの結果にすることである。各文は独立している。文と文の間にブレークポイントを設定してプログラムを止めたとき、どの変数にも新たな値を代入できるし、プログラムカウンタを変更して、その関数内の他のどの文にも飛ばすことができ、そしてソースコードから期待できる結果と全く同じものが得られる。

-O を指定しないと、register 宣言した変数しかレジスタに割り当てない。コンパイル結果のコードは、-O なしの PCC で作られるよりもやや悪い。

-O を指定すると、コードサイズと実行時間を小さくしようとする。

-O を指定すると、全機種で -fthread-jumps-fdefer-pop を有効にする。遅延スロットのある機種では-fdelayed-branch をオンにし、フレームポインタなしでもデバッグをサポートできる機種では -fomit-frame-pointer をオンにする。機種によっては、他のオプションをオンにするものもある。

-O2
さらなる最適化を行なう。GCC は、スペース-速度のトレードオフを含まないほとんど全ての最適化を実行する。-O2 を指定した場合は、ループ展開や関数のインライン展開を行なわない。-O と比べると、このオプションはコンパイル時間が増え、生成コードの効率が良くなる。

-O2 を指定すると、ループ展開と関数のインライン展開、それに厳密なエイリアシングを除いた全ての最適化が有効になる。また、全ての機種で -fforce-mem オプションを付け、デバッグと干渉しない機種ではフレームポインタの削除を行なう。

-O3
さらに最適化を行なう。-O3-O2 で指定される全ての最適化を行ない、かつ inline-functions オプションを行なう。
-O0
最適化を行なわない。
-Os
サイズについて最適化する。-Os を指定すると、普通はコードサイズを大きくしない -O2 の最適化を全て有効にする。また、コードサイズを小さくするよう設計されたさらなる最適化を実行する。

-O オプションを複数指定した場合は、最適化レベルの数字が付いていてもいなくても、最後に指定したオプションが有効になる。

-fflag という形のオプションは機種独立のフラグを指定する。ほとんどのフラグには、肯定形と否定形がある。-ffoo の否定形は -fno-foo である。以下の表では、どちらか一方の形しか列挙していない。デフォルトでないほうを列挙している。もう一方の形式は、no- を取り除くか、追加すれば良い。

-ffloat-store
浮動小数点変数をレジスタにストアせず、浮動小数点値をレジスタかメモリから取り出すかどうかを変更する可能性のあるオプションを禁じる。

このオプションを指定すると、68000 の様な機種で、好ましくない余分な精度を使わないようになる。68000 では、(68881 の)浮動小数点レジスタは、double が持つと想定されているよりも余分の精度を保持している。x86 アーキテクチャについても同様である。ほとんどのプログラムにとっては、精度が余分に高いのは利点が加わるだけであるが、幾つかのプログラムはIEEE 浮動小数点の厳密な定義を想定している。そういうプログラムに対しては、適当な中間計算結果を全て変数に格納するようにプログラムを修正しておいて、-ffloat-store を使うこと。

-fno-default-inline
メンバ関数を、それが単にクラススコープで定義されているからといってインライン展開しない(C++ のみ)。これを指定しないと、-O 付きでコンパイルした場合、クラススコープ内で定義されているメンバ関数はデフォルトでインライン展開される。すなわち、メンバ関数名の前に inline を付ける必要がないのである。
-fno-defer-pop
関数呼び出しの度に常に、その関数から戻るとすぐ引数をポップする。関数呼び出しの後に引数をポップしなければならない機種では、GCC は普通は複数の関数呼び出しについてスタックに引数を蓄積し、それらを全て一度にポップする。
-fforce-mem
メモリオペランドについて算術演算を行なう前に、そのメモリオペランドをレジスタに強制的にコピーさせる。この結果、全てのメモリ参照を潜在的な共通部分式とすることにより、生成コードが良くなる。これらのメモリ参照が共通部分式でない場合は、命令組合せフェーズが独立したレジスタへのロードを削除する必要がある。-O2 を指定するとこのオプションが有効になる。
-fforce-addr
メモリ中のアドレス定数を、それについて算術演算を行なう前にレジスタにコピーすることを強制する。これは、-fforce-mem と同程度に良いコードを生成する。
-fomit-frame-pointer
フレームポインタを必要としない関数については、フレームポインタをレジスタに保持しないようにする。これにより、フレームポインタをセーブ、設定、リストアする命令をなくすことができる。また、多くの関数で利用可能なレジスタが一つ増える。また、機種によってはデバッグが不可能になる。

機種によっては、Vax のように、このオプションの効果がないものもある。標準の呼び出しシーケンスが自動的にフレームポインタを取扱うので、フレームポインタが存在しない振りをしても何もセーブされないからである。マシン記述マクロ FRAME_POINTER_REQUIRED が、ターゲット機種でこのオプションが使えるかどうかを決定する。See Registers.

-fno-inline
キーワード inline に注意を払わない。普通このオプションは、関数のインライン展開を一切行なわせないために使われる。最適化を行なわない場合には、どの関数もインライン展開されることはないことに注意して欲しい。
-finline-functions
単純な関数を全て呼びだし元に統合する。GCC は、どの関数がこの方法で統合するのに充分単純かを発見的に決定する。

ある関数に対する全ての呼び出しが統合される場合、その関数がstatic と宣言されていれば、普通はその関数はアセンブラコードとしては出力されない。

-finline-limit-n
デフォルトでは、GCC はインライン展開可能な関数の大きさを制限している。このオプションを指定すると、明示的にインライン展開を行うと印を付けられている(すなわち、キーワード inline を指定されているか、C++ のクラス定義の中で定義されている)関数に対するこの制限を調整できるようになる。n は、インライン展開可能な関数の大きさを疑似命令の数で表したものである(パラメータの取扱いは数えない)。デフォルトの n の値は、10000 である。この値を大きくすると、インライン展開されたコードが多くなり、コンパイル時間とメモリ消費量が余計にかかるようになる。この値を小さくすると、普通はコンパイル時間が速くなり、インライン展開されるコードが少なくなる(これは、恐らくプログラムが遅くなることを意味するだろう)。このオプションが特に有効なのは、C++ の再帰的テンプレートに基づくような、インライン展開を非常にたくさん使っているプログラムである。

注意。疑似命令は、今のこの特定の文脈においては、関数の大きさの抽象的な尺度を表す。アセンブリ命令数を表し、その意味はあるリリースと別のリリースで変わる可能性がある。

-fkeep-inline-functions
ある関数に対する呼び出しが全部統合され、その関数が static と宣言されている場合でも、実行時に呼び出し可能な版の関数を別個に出力する。このオプションは extern inline 宣言された関数には影響しない。
-fkeep-static-consts
最適化を実行しないときに、static const と宣言されている変数が参照されていなくても、その変数を出力する。

GCC はこのオプションをデフォルトで有効にする。最適化の有無に関わらずに、GCC に変数が参照されているかどうかを検査させたい場合は、-fno-keep-static-consts オプションを使えば良い。

-fno-function-cse
関数のアドレスをレジスタに置かないようにする。ある一定の関数を呼び出す命令は一々その関数のアドレスを明示的に保持するようにする。

このオプションを指定するとコードの効率が悪くなるが、アセンブラの出力を変にいじったような場合、このオプションを指定しないと実行される最適化処理が混乱させられる可能性がある

-ffast-math
このオプションを指定すると、実行速度を最適化するという観点から、ある面で ANSI や IEEE の規則や仕様を破ることを GCC に許す。例えば、このオプションを指定すると、GCC は、sqrt 関数の引数が負にならないとか、浮動小数点値がNaN になることはないという仮定を行なう。

このオプションは、どの -O オプションを指定しても有効になることはない。何故なら、IEEE や ANSI の数学関数の規則/仕様に厳密に基づいて実装されているプログラムの場合は、出力が正しくなくなる可能性があるからである。

以下のオプション群は、特定の最適化を制御する。-O2 オプションは、-funroll-loops-funroll-all-loops-fstrict-aliasing オプションを除く、全ての最適化を実行する。多くの機種では、-O オプションを指定すると、-fthread-jumps-fdelayed-branch オプションを有効にするが、特定の機種では別の扱いをする。

以下のオプションは、高度な最適化を行ないたいという場合に使うことができる。

-fstrength-reduce
ループの強度削減と繰り返し変数の削除の最適化を実行する。
-fthread-jumps
あるジャンプの分岐先に、別のもう一つの比較があり、その比較が最初の比較に包括されるものかどうかを検査する最適化を実行する。もし包括されるものなら、最初の分岐の分岐先は、二番目の分岐の分岐先かその直後の地点のどちらかに、二番目の比較条件の真偽が既知かどうかに従って、変更される。
-fcse-follow-jumps
共通部分式削除(CSE)の際に、ジャンプ命令のうち、そのジャンプ先に他の経路を通って到達することがないものを探し出す。例えば、CSE がelse 節つきの if 文を見つけると、テストされた条件が偽のときのジャンプに従う。
-fcse-skip-blocks
これは -fcse-follow-jumps に良く似ているが、CSE は条件的にブロックを飛び越すジャンプに従う。CSE が else 節のないif 文を見つけると、if 節の本体のまわりのジャンプに従う。
-frerun-cse-after-loop
ループ最適化の実行後に共通部分式の削除をもう一度実行する。
-frerun-loop-opt
ループ最適化を二回実行する。
-fgcse
グローバル共通部分式削除パスを実行する。このパスは、グローバルな定数とコピーの伝播も実行する。
-fexpensive-optimizations
比較的コストがかかる、マイナーな最適化を幾つか行なう。
-foptimize-register-moves
-fregmove
移動命令中のレジスタ番号を他の単純な命令のオペランドとして再割当を行い、レジスタ結合の量を最大にすることを試みる。これは、とりわけ二オペランド命令の機種で役に立つ。GCC は、-O2 以上が指定されたときはデフォルトでこの最適化を有効にする。

なお、-fregmove-foptimize-register-moves は同じ最適化である。

-fdelayed-branch
ターゲット機種でサポートされていれば、遅延分岐命令後の利用可能な命令スロットを利用するように命令の並べ替えを試みる。
-fschedule-insns
ターゲット機種でサポートされていれば、必要とされるデータが利用不可能なために起こる実行のストールをなくように命令の並べ替えを試みる。これにより、浮動小数点命令やメモリからのロード命令が遅い機種で、ロード命令や浮動小数点命令の結果が必要になるまでの間、他の命令を発行することが出来るようになる。
-fschedule-insns2
-fschedule-insns とほぼ同じで、違いはレジスタ割当が完了した後にもう一度命令スケジューリングのパスを行なうことである。これがとりわけ役に立つのは、レジスタ数が比較的少なく、メモリからのロード命令が複数サイクルかかるような機種の場合である。
-ffunction-sections
-fdata-sections
ターゲットが任意個数のセクションを使えるなら、各関数やデータ項目をそれぞれ専用のセクションに入れた出力ファイルを作る。関数名やデータ項目名から、出力ファイルでのセクション名が決まる。

リンカに命令空間の参照の局所性を改善する最適化を行なう機能があるシステムでは、これらのオプションを使うと良いだろう。HP-UX の稼働する HPPA プロセッサと Solaris 2 の稼働する SPARC プロセッサにはこのような最適化機能のあるリンカが存在する。ELF オブジェクトファイル形式を使っている他のシステムや、 AIX も将来この最適化機能が加わる可能性がある。

これらのオプションを使うのは、使うことによって著しい御利益がある場合に限ること。これらのオプションを使うと、アセンブラとリンカが作る、オブジェクトファイルや実行形式ファイルが大きくなり、そのために遅くなることもある。このオプションを指定すると、全てのシステムでgprof が使えなくなる。また、-g と共に指定すると、デバッグ時に問題が生じる可能性がある。

-fcaller-saves
関数呼び出しにより破壊されるレジスタに値を割り当てることを可能にする。このために、命令を余分に生成し、呼び出しの前後でレジスタのセーブとリストアを行なう。このような割当が行なわれるのは、他の方法を取るよりも結果的に良いコードが生成される見込みのある場合だけである。

いくつかの機種ではこのオプションが常にデフォルトで有効になっている。そういう機種には、代わりに使うべき、呼び出し時保存レジスタが普通ないのである。

全ての機種で、最適化レベルを 2 以上にするとこのオプションがデフォルトで有効になる。

-funroll-loops
ループ展開最適化を実行する。これは、コンパイル時か実行時に繰り返し回数が決められるループにしか行なわれない。-funroll-loops は、-fstrength-reduce-frerun-cse-after-loop を含む。
-funroll-all-loops
ループ展開最適化を実行する。これは、全てのループに対して行なわれ、普通はプログラムの実行を遅くする。-funroll-all-loops は、-fstrength-reduce-frerun-cse-after-loop を含む。
-fmove-all-movables
ループ中の不変な計算を全てループの外に移動する。
-freduce-all-givs
ループ中の一般誘導変数を全て強度削減する。

注意。Fortran で書かれたプログラムをコンパイルするときは-fmove-all-movables-freduce-all-givs は、最適化を行うとデフォルトで有効になる。

これらのオプションで、生成されるコードがよくなることもあるし、悪くなることもある。結果は、ソースコードでのループに構造に強く依存する。

この二つのオプションは、ループ最適化を改良する色々な方法の有効性を知る役目が終わったなら、いつか削除する予定である。

これらのオプションを使うと、読者のコードの性能にどれぐらい効果があったかを、我々(gcc@gcc.gnu.orgfortran@gnu.org) に知らせて欲しい。これらのオプションが有効になっているときに遅くなったコードに我々は非常に興味がある。

-fno-peephole
機種固有の覗き穴最適化を無効にする。
-fbranch-probabilities
-fprofile-arcs (see Options for Debugging Your Program or gcc)を付けてコンパイルしたプログラムを実行した後、二回目は -fbranch-probabilities を付けてコンパイルすると、分岐が起こる経路の推測に基づく最適化を改良する。

-fbranch-probabilities を指定すると、GCC は REG_EXEC_COUNT というノートを各基本ブロックの最初の命令に付け、REG_BR_PROB というノートを各 JUMP_INSNCALL_INSN に付ける。これらを使って最適化を向上させることができる。現在、これらは一箇所でしか使われていない。reorg.c で、ある分岐がどちらの方向に起こりそうかを推測する代わりに、REG_BR_PROB の値を使ってより分岐する頻度が高い方向を正確に決定する。

-fstrict-aliasing
GCC に、コンパイルされる言語に取りうる最も厳密な別名規則を取らせる。C(それに C++)の場合は、これにより式の型にもとづく最適化が有効になる。特に、一つの型のあるオブジェクトは、同じアドレスに異なる型のオブジェクトが存在することは、それらの型がほとんど同じでない限り、決してないと仮定する。例えば、unsigned intint の別名になりうるが、void*double の別名にはなりえない。文字型は他のどんな型の別名にもなりうる。

以下のようなコードには特別に注意が必要である。

union a_union {
  int i;
  double d;
};

int f() {
  a_union t;
  t.d = 3.0;
  return t.i;
}
共用体の、一番最後に書き込みが行われたメンバとは異なるメンバの値を呼び出すという手法(「型もじり」、type-punning と呼ばれる)は良く行われている。-fstrict-aliasing を指定しても、型もじりは許されるので、メモリは共用体型を通じて参照される。このため、上記のコードは期待どおりに動作する。だが、次のコードは期待どおりにならない。
int f() {
  a_union t;
  int* ip;
  t.d = 3.0;
  ip = &t.i;
  return *ip;
}

言語固有の別名解析を実行したい言語があれば、ある tree ノードが与えられた場合に、そのノードの別名セットを計算する関数を定義する必要がある。例えば、C 言語のフロントエンドの関数 c_get_alias_set を参照のこと。


Node:Preprocessor Options, Next:, Previous:Optimize Options, Up:Invoking GCC

プリプロセッサオプション

以下のオプションは C プリプロセッサを制御する。C プリプロセッサは、各 C のソースファイルに対して、実際のコンパイルの前に実行される。

-E オプションを指定すると、前処理以外のことはやらない。以下のオプションのうち幾つかは、-E と組み合わせたときにだけ意味を持つ。何故なら、それらはプリプロセッサの出力を実際のコンパイルには適さないものにするからである。

-include file
正規の入力ファイルを処理する前に、file を入力として処理する。事実上、file の内容が先にコンパイルされる。コマンド行で指定した -D オプションと -U オプションはどれも、-include file の前に必ず処理される。これは、コマンド行に書かれた順番には関係しない。全ての -include オプションと -imacros オプションは、書かれた順に処理される。
-imacros file
入力として file を処理し、その結果の出力は捨て去った後で、正規の入力ファイルの処理に取りかかる。file から生成される出力は捨てられるので、-imacros file の唯一の効果は、file でマクロを定義し、正規の入力でそれを使えるようにすることである。

コマンド行で指定した -D オプションと -U オプションはどれも、-imacros file の前に必ず処理される。これは、コマンド行に書かれた順番には関係しない。全ての -include オプションと -imacros オプションは、書かれた順に処理される。

-idirafter dir
ディレクトリ dir を第二のインクルードパスに加える。第二のインクルードパスにあるディレクトリは、ヘッダファイルが第一のインクルードパス(-I が加えたもの)にあるディレクトリには見つからないときに、検索される。
-iprefix prefix
prefix を、後続の -iwithprefix オプションのプレフィックスとして指定する。
-iwithprefix dir
ディレクトリを一個、第二のインクルードパスに追加する。そのディレクトリの名前は、prefixdir を連結することで作られる。ここで prefix は既出の -iprefix で指定されたものである。プレフィックスをまだ指定していなければ、コンパイラのインストールされたパスを含むディレクトリがデフォルトとして使われる。
-iwithprefixbefore dir
主となるインクルードパスにディレクトリを追加する。追加するディレクトリ名は、-iwithprefix の場合と同じように、prefixdir をつなげて作られる。
-isystem dir
ディレクトリを一個、第二のインクルードパスの先頭に追加し、それをシステムのディレクトリとして印を付け、標準のシステムディレクトリが受けるのと同じ特別な扱いを受けられるようにする。
-nostdinc
システム標準のディレクトリにあるヘッダファイルを検索しない。-I で指定したディレクトリ(と、適切であればカレントディレクトリ) だけを検索する。-I については See Directory Options

-nostdinc-I- を両方使うと、インクルードファイルの検索パスを明示的に指定したディレクトリにだけ限定することができる。

-undef
非標準マクロは何も定義済としない。(アーキテクチャを知らせるフラグも含む。)
-E
C プリプロセッサのみを実行する。指定された全ての C ソースファイルをプリプロセスし、結果を標準出力か指定された出力ファイルに出力する。
-C
プリプロセッサにコメントを除去しないように指示する。-E オプションと合わせて使われる。
-P
プリプロセッサに #line 制御子を生成しないように指示する。-E オプションと合わせて使われる。
-M
各オブジェクトファイルの依存ファイルを記述する make のルールに適した出力を行なうようプリプロセッサに指示する。プリプロセッサは、各ソースファイル毎に make のルールを一つ出力する。そのルールのターゲットは、ソースファイルに対応するオブジェクトファイル名であり、依存ファイルはそのソースファイルが#include している全てのヘッダファイルである。このルールは一行でも良いし、長ければ \-改行 で継続しても良い。ルールのリストは、前処理済みの C プログラムではなく、標準出力に出力される。

-M には -E が含まれる。

make のルールの出力を指定するもう一つの方法は、環境変数 DEPENDENCIES_OUTPUT を設定することである(see Environment Variables)。

-MM
-M と同様だが、#include "file" の形式でインクルードされるファイルだけを出力する。#include <file> の形式でインクルードされるシステムのヘッダファイルは除かれる。
-MD
-M と同様だが、依存関係情報は、入力ファイル名の最後の ".c" を".d" に置き換えたファイルに出力される。これは、指定されたファイルをコンパイルしたうえで行なわれる。-M は通常のコンパイルは行なわないが、-MD は行なう。

Mach では、md というユーティリティを使って、複数の依存関係ファイルを一個の依存関係にマージすることができ、make コマンドで使うのに適したものになる。

-MMD
-MD と同様だが、ユーザのヘッダファイルのみを出力し、システムのヘッダファイルは出力しない。
-MG
見当たらないヘッダファイルは生成されたファイルとして扱い、ソースファイルと同じディレクトリにあると仮定する。-MG を指定するなら、-M-MM のどちらかも指定しなければならない。-MG は、-MD-MMD と組み合わせるのはサポートされていない。
-H
通常の処理に加えて、使われている各ヘッダファイル名を表示する。
-Aquestion(answer)
question に対する回答 answer を表明する。それは、#if #question(answer) のような前処理の条件文でテストすることができる。-A- は、普通ターゲット機種を記述する標準の表明を無効にする。
-Dmacro
マクロを macro を定義し、文字列 1 をその定義とする。
-Dmacro=defn
マクロ macrodefn として定義する。コマンド行に現れる全ての -D は、どの -U オプションよりも前に処理される。
-Umacro
マクロ macro を未定義にする。-U オプションは、全ての -D オプションの後で、-include-imacros オプションの前に評価される。
-dM
プリプロセッサに対し、前処理の終了段階で有効なマクロ定義の一覧だけを出力することを指示する。-E と組み合わせて使う。
-dD
プリプロセッサに対し、全てのマクロ定義を出力することを指示する。マクロ定義は、それ以外の出力中に元々の順番で現れる。
-dN
-dD と同様だが、マクロ引数と展開内容が省略される。#define name だけ出力する。
-trigraphs
ANSI C のトリグラフをサポートする。-ansi オプションを指定してもこの効果がある。
-Wp,option
option をプリプロセッサへのオプションとして渡す。option にカンマが入っていると、カンマのところで複数のオプションに分割される。


Node:Assembler Options, Next:, Previous:Preprocessor Options, Up:Invoking GCC

アセンブラに渡されるオプション

以下のようにして、アセンブラにオプションを渡すことが可能である。

-Wa,option
option をアセンブラにオプションとして渡す。option がコンマを含んでいるなら、コンマで複数のオプションに分割される。


Node:Link Options, Next:, Previous:Assembler Options, Up:Invoking GCC

リンクオプション

以下のオプションは、コンパイラがオブジェクトファイルを実行形式ファイルにリンクするときに関係してくる。コンパイラがリンクの段階を行なわないなら、これらは意味がない。

object-file-name
特別に認識されるサフィックスで終わっていないファイル名は、オブジェクトファイルかライブラリを示すものと考えられる。(オブジェクトファイルは、ファイルの内容に従って、リンかによりライブラリと区別される。)リンクが行なわれると、これらのオブジェクトファイルはリンカへの入力として使われる。
-c
-S
-E
これらのオプションのどれかが指定されると、リンカは起動されない。また、オブジェクトファイル名は引数として与えるべきではない。See Overall Options.
-llibrary
リンク時に library という名前のライブラリを検索する。

このオプションをコマンド行のどこに置いたかで違いが出てくる。リンカは、ライブラリとオブジェクトファイルを指定された順番に検索し、処理する。すなわち、foo.o -lz bar.o とした場合、ライブラリ z は、ファイル foo.o の後で、bar.o の前に検索される。もし bar.oz 内の関数を参照していても、その関数はロードされない。

リンカは、標準のディレクトリのリストからライブラリを探す。次に、見つけたファイルを、正確な名前で指定されたかのように使う。

検索されるディレクトリには、幾つかの標準のシステムディレクトリにの他に、-L で指定したディレクトリが加わる。

普通こうして見つかるファイルはライブラリファイル、すなわちオブジェクトファイルをメンバとするアーカイブファイルである。リンカのアーカイブファイルの扱い方は、アーカイブファイルを走査して、これまでに参照されているが定義はされていないシンボルを定義しているメンバオブジェクトファイルを探す。だが、こうして見つけたファイルが通常のオブジェクトファイルだった場合は、普通にリンクされる。-l オプションを使うのとファイル名を指定するのとの違いは、-llibrary の前後にlib.a を付けて、色々なディレクトリを検索するという点にある。

-lobjc
この特別な -l オプションは、Objective C のプログラムをリンクするのに必要である。
-nostartfiles
リンク時にシステム標準の起動ファイルを使わない。システムの標準ライブラリの方は、-nostdlib-nodefaultlibs を指定しない限り、普通は使われる。
-nodefaultlibs
リンク時にシステム標準のライブラリを使わない。明示的に指定したライブラリだけがリンカに渡される。-nostartfiles を指定しない限り、標準の起動ファイルが普通は使われる。GCC は System V (それに ANSI C) の環境向けにはmemcmp、memset、memcpy の呼出しを生成し、BSD 環境向けには bcopy と bzero の呼出しを生成するだろう。これらのエントリは通常 libc 内のエントリで解決される。これらのエントリ・ポイントは、このオプションが指定された時には、何か他の仕組みによって提供される必要がある。
-nostdlib
リンク時に、システム標準の起動ファイルやライブラリを使わない。リンカには、起動ファイルは渡されず、ライブラリは明示的に指定したものだけが渡される。GCC は System V (それに ANSI C) の環境向けにはmemcmp、memset、memcpy の呼出しを生成し、BSD 環境向けには bcopy と bzero の呼出しを生成するだろう。これらのエントリは通常 libc 内のエントリで解決される。これらのエントリ・ポイントは、このオプションが指定された時には、何か他の仕組みによって提供される必要がある。

-nostdlib-nodefaultslibs に影響を受けない標準ライブラリの一つに libcc.a がある。これは、GCC が内部的に使うサブルーチンライブラリであり、特定の機種の機能の不足や、幾つかの言語で特別に必要になる機能を提供するものである。(libgcc.a についてのさらに詳しい議論については、See Interfacing to GCC Output.) ほとんどの場合、他の標準ライブラリを使いたくないときでも libgcc.a は必要になる。言い換えると、-nostdlib-nodefaultlibs を指定するときには、普通は -lgcc も指定すべきである。これにより、GCC 内部のライブラリサブルーチンに対する未解決参照がなくなることを保証する。(例えば、__main は、C++ のコンストラクタが呼ばれることを保証するのに使われる。see collect2。)

-s
実行形式から、シンボルテーブルと再配置情報を全て削除する。
-static
ダイナミックリンクをサポートしているシステムでは、このオプションを指定すると共有ライブラリとリンクするのを防ぐ。他のシステムでは、このオプションは何の効果もない。
-shared
他のオブジェクトとリンクして実行形式を作ることが可能な共有オブジェクトを生成する。このオプションは全てのシステムではサポートされていない。システムによっては、このオプションを指定するときには、-fpic-fPIC を指定しなければならない。
-symbolic
共有オブジェクトを構築する際に、グローバルシンボルに対する参照を結合する。未解決の参照については警告を出す(ただし、リンクエディタのオプション -Xlinker -z -Xlinker defs が指定されていない場合)。このオプションをサポートしているシステムは、二、三種類しかない。
-Xlinker option
option をリンカへのオプションとして渡す。これを使うと、GCC には認識する方法が分からない、システム固有のリンカオプションを指定することができる。

引数を取るオプションを渡したい場合は、-Xlinker を二回指定しなければならない。一つはそのオプション用で、もう一つは引数用である。例えば、-assert definitions を渡すには、-Xlinker -assert -Xlinker definitions と書かなければならない。-Xlinker "-assert definitions" と書いたのではうまくいかない。何故なら、これは文字列全体を一個の引数として渡すので、リンカが期待しているのとは違ってしまうからである。

-Wl,option
option をリンカへのオプションとして渡す。option にカンマが含まれていると、コンマのところで複数のオプションに分割される。
-u symbol
シンボル symbol を未定義とし、そのシンボルを定義しているライブラリモジュールを強制的にリンクする。-u をオプションを複数、異なるシンボルに対して使うと、追加でライブラリモジュールを強制的にロードできる。


Node:Directory Options, Next:, Previous:Link Options, Up:Invoking GCC

ディレクトリ検索用オプション

以下のオプションは、ヘッダファイルやライブラリや GCC の構成部分を検索するディレクトリを指定する。

-Idir
ディレクトリ dir をヘッダファイルを検索するディレクトリのリストの先頭に追加する。このオプションを使うことにより、システムのヘッダファイルを読者自身のバージョンで置き換えることができる。というのは、ここで指定したディレクトリはシステムのヘッダファイルディレクトリよりも前に検索されるからである。-I オプションを複数回指定した場合、ディレクトリは左から右へ検索される。システム標準のディレクトリはその後に検索される。
-I-
-I- オプションの前で -I オプションで指定したディレクトリは、#include "file" の形式の場合しか検索されない。#include <file> に対しては検索されないのである。

-I- の後で -I で追加でディレクトリが指定されたら、これらのディレクトリはすべての #include 文で検索される。(通常は、-I で指定されたディレクトリは全て、このように使われる。)

さらに、-I- オプションを指定すると、#include "file" に対して最初に検索するディレクトリとしてカレントディレクトリ(これは現在の入力ファイルがあるところである)を使うのを禁ずる。-I- のこの効果を変える方法はない。-I. を指定すると、コンパイラが起動したときのカレントディレクトリを検索ディレクトリに指定することができる。これは、プリプロセッサがデフォルトで行なう処理と正確に同じではないが、充分なことが多い。

-I- は、システム標準のヘッダファイルのあるディレクトリを使うことは妨げない。つまり、-I--nostdinc は独立である。

-Ldir
-l オプションで指定されたライブラリを検索するディレクトリのリストにディレクトリ dir を追加する。
-Bprefix
このオプションは、GCC 自身が使用する実行形式ファイル、ライブラリファイル、インクルードファイル、それにデータファイルを探す場所を指定する。

GCC のドライバプログラムは、サブプログラム cppcc1asld の少なくとも一つを実行する。prefix を実行を試みる各プログラムのプレフィックスとして試す。この時、machine/version/ (see Target Options) を付けるのと付けないのを両方試す。

実行すべきサブプログラム毎に、GCC のドライバは、指定されていればまず -B によるプレフィックスを試す。その名前が見つからなかったり、-B が指定されていない場合は、ドライバは標準的なプレフィックスを二つ試す。/usr/lib/gcc//usr/local/lib/gcc-lib/ である。このどちらを使ってもファイル名が見つからない場合は、プログラム名をそのまま使って、環境変数 PATH で指定されたディレクトリを検索する。

-B によるプレフィックスは、リンカがリンクするライブラリにも適用されるディレクトリ名を指定する。これは GCC がこのオプションをリンカ用の -L オプションに変換するからである。またプリプロセッサがインクルードするファイルにも適用される。GCC がこのオプションをプリプロセッサ用の -isystem オプションに変換するからである。この場合、GCC は include をプレフィックスに追加する。

実行時サポートファイル libgcc.a も、必要であれば -B によるプレフィックスを使って検索することが可能である。-B で指定した場所に見つからなかった場合には、上述の二つの標準プレフィックスが試される。さらなる検索は行なわれない。これらの手段で見つからなかったファイルは、リンク時にそのまま残される。

-B によるプレフィックス指定と良く似たもう一つのプレフィックス指定方法として環境変数 GCC_EXEC_PREFIX を使う方法がある。See Environment Variables

-specs=file
GCC が標準の specs ファイルを読み込んだ後にfile を処理し、ドライバプログラムである gcc が、cc1cc1plusasld 等に渡すべきオプションを決定するときに使うデフォルトを変更する。-specs=file はコマンド行で複数指定することができ、その場合、左から右へ順に処理される。


Node:Target Options, Next:, Previous:Directory Options, Up:Invoking GCC

ターゲット機種とコンパイラバージョンの指定

デフォルトでは、GCC は、読者が使っているのと同じタイプの機種用にコードをコンパイルする。だが、クロスコンパイラとしてインストールすることもでき、何か他のタイプの機種用にコンパイルすることも可能である。実際、色々なコンフィギュレーションの GCC を、色々な対象機種に対して、同じにインストールすることが可能である。そのどれを使うかは、-b オプションで指定する。

さらに、GCC の旧版と新版も同じにインストールすることができる。そのうちの一つ(おそらく最新版)がデフォルトになるが、別の版を使いたいときもあるだろう。

-b machine
引数 machine は、コンパイルの対象となる機種を指定する。GCC をクロスコンパイラとしてインストールしたときに便利である。

machine の値は、GCC をクロスコンパイラとしてコンフィギュレーションしたときに指定したのと同じ機種になる。例えば、クロスコンパイラがconfigure i386v としてコンフィギュレーションされているなら、これは System V の稼働する 80386 マシン向けにコンパイルすることを意味し、このコンフィギュレーション向けのコンパイラを実行するには-b i386v と指定する。

-b を指定しないときは、普通は読者が使っているのと同じ型の機種用にコンパイルすることになる。

-V version
引数 version は、実行する GCC のバージョンを指定する。これは複数のバージョンがインストールされているときに役に立つ。例えば、version2.0 なら、GCC のバージョン 2.0 を実行することを意味する。

-V を指定しない場合の、デフォルトのバージョンは、インストールされている GCC のうち最新版になる。

-b-V オプションの実際の仕組みは、コンパイルに使う実行形式ファイルとライブラリファイル名の一部を変えることで行なわれる。GCC のバージョンとターゲット機種が指定されていると、/usr/local/lib/gcc-lib/machine/version というディレクトリに通常置かれている。

このため、読者のサイトで、-b-V の効果をカスタマイズするには、これらのディレクトリ名を変えたり、別の名前(あるいはシンボリックリンク)を追加したりすれば良い。ディレクトリ /usr/local/lib/gcc-lib/ で、80386 というファイルが、i386v というファイルへのリンクになっていると、-b 80386 は、-b i386v のもう一つの指定方法になる。

見方によっては、-b-V を指定したからと言って、完全に別なコンパイラに変わるわけではない。最初に起動した最上位のドライバプログラム gcc はそのまま動き続け、実際の仕事を行なう他の実行形式(プリプロセッサ、コンパイラ本体、アセンブラ、リンカ)を起動するのである。しかし、ドライバプログラムは実際の仕事は何もしないので、ドライバプログラムが、指定したターゲットとバージョン向けのものでなくても普通は問題はない。

ドライバプログラムがターゲット機種に関わってくる唯一の点は、機種固有の特別なオプションのパースと取扱いである。しかし、これも他の実行形式ファイル同様、指定したバージョンとターゲット機種用のディレクトリに置かれているファイルにより制御されるのである。結局、ドライバプログラムが一個インストールしてあれば、どのターゲット機種やバージョンを指定しても適合するのである。

ただし、ドライバプログラムの実行形式は、一つ重要な点を取り扱う。デフォルトのバージョンとターゲット機種である。このため、ドライバプログラムの実体を、異なるターゲットとバージョン向けに別々にコンパイルして、別の名前でインストールしても良い

たとえば、バージョン 2.0 用のドライバを ogcc としてインストールし、バージョン 2.1 用のを gcc としてインストールしておくと、gcc というほうのコマンドはデフォルトでバージョン 2.1 を使い、ogcc のデフォルトは 2.0 になる。しかし、どちらのコマンドを使っても、-V オプションを使えばどちらのバージョンでも指定できるのである


Node:Submodel Options, Next:, Previous:Target Options, Up:Invoking GCC

ハードウェアモデルとコンフィギュレーション

以前、標準のオプション -b について議論した。-b は、全く異なるターゲット機種、例えば、Vax と 68000 と 80386 用の、インストール済みコンパイラの中から選ぶ。

加えて、各ターゲット機種には -m で始まる、機種固有の特別なオプションがあり、例えば、68010 か 68020 かといった、色々なハードウェアのモデルやコンフィギュレーションから選択することができる。GCC が一つインストールされていれば、指定したオプションに従って、どのモデルやコンフィギュレーションに対してもコンパイルが可能である。

GCC のあるコンフィギュレーションでは、追加で特別なオプションをサポートしているものもある。これは、普通は、同じプラットフォーム上の他のコンパイラとの互換性のためにある。

これらのオプションは、マシン記述中のマクロ TARGET_SWITCHES で定義されている。そのオプションのデフォルト値も同じマクロで定義されているので、デフォルト値を変更することができるようになっている。


Node:M680x0 Options, Next:, Previous:Submodel Options, Up:Submodel Options

M680x0 オプション

以下の -m オプションが 68000 シリーズ向けに定義されている。これらのオプションのデフォルト値は、コンフィギュレーション時に68000 のどの形式が選択されたかに依る。最も共通する選択のデフォルトは以下の通り。

-m68000
-mc68000
68000 用の出力を生成する。これは、コンパイラが68000 ベースのシステム向けにコンフィギュレーションされた場合のデフォルトである。

このオプションは、68000 や EC000 のコアを持つマイクロコントローラ、68008、68302、68306、68307、68322、68328、68356 等に対して使う。

-m68020
-mc68020
68020 用の出力を生成する。これは、コンパイラが68020 ベースのシステム向けにコンフィギュレーションされた場合のデフォルトである。
-m68881
浮動小数点数向けの 68881 の命令を含む出力を生成する。これは、-nfp がコンフィギュレーション時に指定されない限り、ほとんどの 68020 のシステムのデフォルトである。
-m68030
68030 用の出力を生成する。これは、コンパイラが68030 ベースのシステム向けにコンフィギュレーションされた場合のデフォルトである。
-m68040
68040 用の出力を生成する。これは、コンパイラが68040 ベースのシステム向けにコンフィギュレーションされた場合のデフォルトである。

このオプションは、68040 ではソフトウェアでエミュレートしなければならない 68881/68882 の命令を禁止する。読者の 68040 システムにこれらの命令をエミュレートしなければならないようなコードがなければ、このオプションを使うこと。

-m68060
68060 用の出力を生成する。これは、コンパイラが68060 ベースのシステム向けにコンフィギュレーションされた場合のデフォルトである。

このオプションは、68060 ではソフトウェアでエミュレートしなければならない 68881/68882 の命令を禁止する。読者の 68060 システムにこれらの命令をエミュレートしなければならないようなコードがなければ、このオプションを使うこと。

-mcpu32
CPU32 向けの出力を生成する。これは、GCC が CPU32 ベースのシステム向けにコンフィギュレーションされたときのデフォルトである。

このオプションは、CPU32 や CPU32+ のコアを持つマイクロコントローラ、68330、68331、68332、68333、68334、68336、68340、68341、68349、68360 等に対して使う。

-m5200
520X 「コールドファイア」シリーズの CPU 用にコードを生成する。GNU C コンパイラが 520X ベースのシステム用にコンフィギュレーションされた場合のデフォルトになる。

このオプションは、5200 のコアを持つマイクロコントローラ、MCF5202、MCF5203、MCF5204、MCF5202 等に使う。

-m68020-40
68040 用に出力を生成するが、新しい命令は何も使わない。この結果、68020/68881 や 68030、68040 のどれでも比較的効率の良いコードが生成される。生成されたコードでは、68881 の命令を使っており、68040 ではエミュレートされる。
-m68020-60
68060 用に出力を生成するが、新しい命令は何も使わない。この結果、68020/68881 や 68030、68040 のどれでも比較的効率の良いコードが生成される。生成されたコードでは、68881 の命令を使っており、68060 ではエミュレートされる。
-mfpa
Sun の FPA 浮動小数点命令を含むコードを生成する。
-msoft-float
浮動小数点演算に関するライブラリ呼出しを含む出力を生成する。警告必要となるライブラリは、全ての m68k のターゲットで利用可能な訳ではない。普通はその機種で標準の C コンパイラの機能が使われるが、これはクロスコンパイルの場合は直接は使えない。クロスコンパイルの場合は、適切なライブラリ関数が提供できるよう読者自身で調整を行なわなければならない。組み込みターゲットのm68k-*-aoutm68k-*-coff では、ソフトウェアによる浮動小数点演算をサポートしている。
-mshort
int 型を short int と同じ 16 ビット長とする。
-mnobitfield
ビットフィールド命令を使わない。-m68000-mcpu32-m5200 オプションは、-mnobitfield を暗黙に含む。
-mbitfield
ビットフィールド命令を使う。-m68020 オプションは、-mbitfield を暗黙に含む。68020 向けのコンフィギュレーションを使う場合のデフォルトである。
-mrtd
別の関数呼び出し規約を使う。その規約では、引数の数が固定している関数は、rtd 命令で戻る。この命令は戻る際に引数をポップする。これにより、呼び出し側では、引数をポップする必要がないので命令を一個節約できる。

この呼び出し規約は、Unix で通常使われているものと互換性がない。このため、Unix のコンパイラでコンパイルされたライブラリを呼び出す必要があるときには使えない。

また、可変個数の引数を取る全ての関数(printf を含む)について関数プロトタイプを用意しなければならない。そうしないと、これらの関数に対する呼び出しコードが正しく生成されないからである。

さらに、あまりたくさん引数をつけて関数を呼び出すと全く正しくないコードが生成される。(普通は、余分な引数は無視され害がない。)

rtd 命令は、68010、68020、68030、68040、68060、CPU32 といったプロセッサにあるが、68000 や 5200 にはない。

-malign-int
-mno-align-int
GCC が intlonglong longfloatdoublelong double の変数を 32ビット境界に置く(-malign-int) か、16ビット境界に置く(-mno-align-int)かを制御する。変数を 32 ビット境界に整列させると、32ビットバスのプロセッサではいくらか高速になるコードを生成するが、メモリを余分に消費する。

注意: -malign-int オプションを指定すると、GCC は上で列挙した型を含む構造体を、m68k 用の、公表されているほとんどのアプリケーション・バイナリ・インターフェース仕様とは異なるアライメントを取るように置く。


Node:VAX Options, Next:, Previous:M680x0 Options, Up:Submodel Options

VAX オプション

以下の -m オプションが Vax 用に定義されている。

-munix
特定のジャンプ命令群(aobleq 等)を出力しない。これらの命令は、Vax 用の Unix アセンブラが長い範囲を越えて扱うことが出来ないものである。
-mgnu
GNU アセンブラを使ってアセンブルを行なうという想定のもとに、上記のジャンプ命令群を出力する。
-mg
浮動小数点形式として、d 形式の代わりに g 形式で出力する。


Node:SPARC Options, Next:, Previous:VAX Options, Up:Submodel Options

SPARC オプション

以下の -m オプションが SPARC ではサポートされている。

-mno-app-regs
-mapp-regs
-mapp-regs を指定するとグローバルレジスタの 2 〜 4 を使うコード生成を行なう。グローバルレジスタの 2 〜 4 は SPARC SVR4 ABI がアプリケーション用に予約している。これがデフォルトである。

完全に SVR4 ABI に準拠するには、幾らか効率が落ちるが、-mno-app-regs を指定する。ライブラリとシステムソフトウェアをこのオプションでコンパイルする必要がある。

-mfpu
-mhard-float
浮動小数点命令を含んだ出力を生成する。これはデフォルトである。
-mno-fpu
-msoft-float
浮動小数点用ライブラリ呼び出しを含む出力を生成する。警告: 必要となるライブラリは全ての SPARC ターゲットで利用可能であるわけではない。普通はその機種の通常の C コンパイラの機能が使われるが、クロスコンパイルの場合はこれをそのまま行なうことはできない。クロスコンパイルの場合は、適切なライブラリ関数を自分で用意しなければならない。組み込みターゲット sparc-*-aoutsparclite-+-+ では、ソフトウェアによる浮動小数点サポートを提供している。

-msoft-float を指定すると、出力ファイル中の呼び出し規約が変わる。このため、プログラム全体をこのオプションでコンパイルしないといけない。特に、GCC 付属のライブラリである、libgcc.a をコンパイルするときに、-msoft-float を指定してコンパイルしないとこのライブラリが正しく動作しない。

-mhard-quad-float
4倍精度(long double)の浮動小数点命令を含むコードを生成する。
-msoft-quad-float
4倍精度(long double)の浮動小数点命令に対して、ライブラリ呼びだしを行なうコードを生成する。呼び出される関数は、SPARC ABI で規定されているものである。これはデフォルトになっている。

このマニュアルを執筆している時点では、4倍精度浮動小数点命令をハードウェアでサポートしている SPARC の実装は存在しない。全ての実装で、これらの命令のうちの一つに対してはトラップハンドラを起動し、そのトラップハンドラでその命令の効果をエミュレートしている。トラップハンドラのオーバーヘッドにより、ABI のライブラリルーチンを呼び出すよりもずっと遅くなる。このため、-msoft-quad-float オプションがデフォルトになっている。

-mno-epilogue
-mepilogue
-mepilogue を指定すると(デフォルトで指定される)、GCC は、各関数の最後に必ず関数の出口用のコードを生成する。関数の途中での出口(例えば、C 言語の return 文)に対しては、関数の最後の出口コードへのジャンプを生成する。

-mno-epilogue を指定すると、GCC は関数の出口毎に出口コードを展開する。

-mno-flat
-mflat
-mflat を指定すると、GCC はセーブ/リストアを行なう命令群を生成せず、「平らな」あるいは、一個のレジスタウィンドウ呼出し規約を使う。この方式では、%i7 をフレームポインタとして使い、通常のレジスタウィンドウ方式と互換性がある。どちらのコードもお互いに混ぜて使うことができる。ローカルレジスタと入力レジスタ(0-5)は、以前として呼出し時セーブレジスタとして取り扱われ、必要に応じてスタックにセーブされる。

-mno-flat を指定すると(デフォルト)、GCC はセーブ/リストア命令群を生成し(末端関数は除く)、通常の操作モードになる。

-mno-unaligned-doubles
-munaligned-doubles
double は 8 バイト境界に整列されると仮定する。これがデフォルトである。

-munaligned-doubles を指定すると、double 型が 8 バイト境界に整列させられるのは、別の型に含まれている場合や、絶対アドレスを持つ場合に限られる。その他の場合は、4 バイト境界に整列される。このオプションを指定すると、滅多にないことだが、他のコンパイラで生成したコードとの互換性の問題を回避できる。これはデフォルトにはなっていない。性能が、とりわけ浮動小数点コードの場合に悪くなるからである。

-mv8
-msparclite
この二つのオプションは、SPARC アーキテクチャの版のうちの一つを選択する。

デフォルトでは(富士通の SPARClite 用にコンフィギュレーションを行なわない限り)、GCC は、SPARC アーキテクチャの v7 用のコードを生成する。

-mv8 を指定すると、SPARC v8 用のコードを生成する。v7 との違いは、v7 にはないが v8 には存在する整数乗算と整数除算命令を生成する点にある。

-msparclite を指定すると SPARClite 用のコードを生成する。これは、整数乗算と整数除算、スキャン(ffs)命令を追加する。これらの命令は、v7 にはないが SPARClite に存在する。

これらのオプションは廃止要求が出ており、将来の GCC のリリースで削除される予定である。これらは、-mcpu=xxx に置き換えられることになる。

-mcypress
-msupersparc
この二つのオプションは、どのプロセッサ向けに最適化を行なうかを選択する。

-mcypress を指定すると(これがデフォルトである)、GCC は Cypress CY7C602 というチップ向けにコードを最適化する。このチップは、SPARCstation/SPARCserver 3xx シリーズで使われているものである。このオプションは、古目の SPARCstation 1、2、IPX 等にも適している。

GCC は SuperSPARC チップ向けにコードを最適化する。このチップは、SPARCstation 10、1000、2000 シリーズで使われているものである。このオプションは、完全な SPARC v8 命令セットにも適している。

これらのオプションは廃止要求が出ており、将来の GCC のリリースで削除される予定である。これらは、-mcpu=xxx に置き換えられることになる。

-mcpu=cpu_type
機種型 cpu_type 用に、命令セット、レジスタセット、命令スケジューリングのパラメータを設定する。cpu_type の値として使えるのは、v7cypressv8supersparcsparclitehypersparcsparclite86xf930f934sparclettsc701v9ultrasparc である。

デフォルトの命令スケジューリングパラメータは、アーキテクチャを選択する値に対して使われるのであって、実装に対して使われるのではない。これらは、v7v8sparclitesparcletv9 である。

サポートされているアーキテクチャとそれに対応するサポートされている実装のリストを以下に示す。

    v7:             cypress
    v8:             supersparc, hypersparc
    sparclite:      f930, f934, sparclite86x
    sparclet:       tsc701
    v9:             ultrasparc

-mtune=cpu_type
機種 cpu_type に対する命令スケジューリングのパラメータを設定する。ただし、-mcpu=cpu_type が行なうような命令セットやレジスタセットの設定は行なわない。

-mcpu=
cpu_type に使えるのと同じ値が -mtune=cpu_type に対しても使える。ただし意味のある値は、特定の CPU の実装を選ぶものだけである。それは次の通り。cypresssupersparchypersparcf930f934sparclite86xtsc701ultrasparc

-malign-loops=num
ループを 2 の num 乗バイト境界に整列させる。-malign-loops が指定されていない場合のデフォルトは 2 である。
-malign-jumps=num
ジャンプ先の命令のみを 2 の num 乗境界に整列させる。-malign-jumps が指定されていない場合のデフォルトは 2 である。
-malign-functions=num
関数の開始位置を 2 の num 乗境界に整列させる。-malign-functions が指定されていない場合のデフォルトは、32 ビットの SPARC の場合は 2 で、64 ビットの SPARC の場合は 5 である。

SPARCLET プロセッサでは、以下の -m オプションが上記に加えてサポートされている。

-mlittle-endian
リトルエンディアン・モードで動作するプロセッサ用のコードを生成する。
-mlive-g0
レジスタ %g0 を普通のレジスタとして取り扱う。GCC は必要に応じて、引き続き、このレジスタを上書きするが、常に 0 を読み出すという想定は行なわない。
-mbroken-saverestore
save 命令と restore 命令の自明でない形を使わないコードを生成する。SPARCLET プロセッサの初期のバージョンは、引数付きのsave 命令と restore 命令を正しく扱えない。引数なしなら正しく扱うことができる。引数なしの save 命令は、現在のウィンドウポインタをインクリメントするが、新しいスタックフレームは割り当てない。ウィンドウのオーバフローのトラップハンドラが、この場合を、割り込みハンドラと同じように正しく扱うことを想定している。

64ビット環境の SPARC V9 プロセッサでは上記に加えて以下のオプションがサポートされている。

-mlittle-endian
リトルエンディアン・モードで動作するプロセッサ用のコードを生成する。
-m32
-m64
32ビットまたは64ビット環境用のコードを生成する。32ビット環境は、int と long、ポインタを 32ビットに設定する。64ビット環境は、int を 32ビットに、long とポインタを 64ビットに設定する。
-mcmodel=medlow
Medium/Low コードモデル向けにコードを生成する。このモデルでは、プログラムはアドレス空間の下位 32 ビット内でリンクしなければならない。ポインタは 64 ビットである。プログラムは、静的にも動的にもリンク可能である。
-mcmodel=medmid
Medium/Middle コードモデル向けにコードを生成する。このモデルでは、プログラムはアドレス空間の下位 44 ビット内でリンクしなければならず、テキストセグメントは 2G バイト以下でなければならず、データセグメントは 2Gバイトのテキストセグメント内に一緒に入れなければならない。ポインタは 64 ビットである。
-mcmodel=medany
Medium/Anywhere コードモデル向けにコードを生成する。このモデルでは、プログラムはアドレス空間のどこにリンクしても良く、テキストセグメントは 2G バイト以下でなければならず、データセグメントは 2Gバイトのテキストセグメント内に一緒に入れなければならない。ポインタは 64 ビットである。
-mcmodel=embmedany
組み込みシステム用の Medium/Anywhere コードモデル向けにコードを生成する。このモデルでは、テキストセグメントとデータセグメントは 32 ビットの大きさであり、どちらも任意の位置(リンク時に決定される)から開始可能である。レジスタ %g4 が、データセグメントの基底を指す。ポインタは依然として 64 ビットである。
-mstack-bias
-mno-stack-bias
-mstack-bias を指定すると、GCC はスタックポインタと、それにもしあればフレームポインタは、スタックフレームの参照を作るときに、オフセットに -2047 を加えなければならないと想定する。


Node:Convex Options, Next:, Previous:SPARC Options, Up:Submodel Options

Convex オプション

Convex 向けには以下の -m オプションが定義されている。

-mc1
C1 用の出力を生成する。これで生成したコードは Convex のどの機種でも動作する。プリプロセッサ用シンボル __convex__c1__ が定義される。
-mc2
C2 用の出力を生成する。C1 には存在しない命令を使う。スケジューリング、それにその他の最適化は、C2 で最大の性能を発揮するように選ばれる。プリプロセッサ用シンボル __convex__c2__ が定義される。
-mc32
C32xx 用の出力を生成する。C1 には存在しない命令を使う。スケジューリング、それにその他の最適化は、C32 で最大の性能を発揮するように選ばれる。プリプロセッサ用シンボル __convex__c32__ が定義される。
-mc34
C34xx 用の出力を生成する。C1 には存在しない命令を使う。スケジューリング、それにその他の最適化は、C34 で最大の性能を発揮するように選ばれる。プリプロセッサ用シンボル __convex__c34__ が定義される。
-mc38
C38xx 用の出力を生成する。C1 には存在しない命令を使う。スケジューリング、それにその他の最適化は、C38 で最大の性能を発揮するように選ばれる。プリプロセッサ用シンボル __convex__c38__ が定義される。
-margcount
各引数リストの前に、引数の個数の入ったワードを置くようにコードを生成する。こうすると普通の CC と互換性があり、引数個数のワードを必要とするプログラムが幾つかある。GDB やそのたのソースコードレベルのデバッガは引数個数のワードを必要としない。引数の個数情報は、シンボルテーブルに入っているからである。
-mnoargcount
引数個数のワードを省略する。これがデフォルトである。
-mvolatile-cache
揮発性の参照をキャッシュする。これがデフォルトである。
-mvolatile-nocache
揮発性参照について、データキャッシュを迂回させ、全てメモリを見に行かせる。これは、標準の同期命令を使わない、マルチプロセッサコードの場合にのみ必要になる。揮発性の位置に対する非揮発性の参照を作るのは、動作する必要はない。
-mlong32
long 型を int 型と同じ 32 ビットにする。これがデフォルトである。
-mlong64
long 型を long long 型と同じ 64 ビットにする。このオプションは、サポートするライブラリが存在しないので、使えない


Node:AMD29K Options, Next:, Previous:Convex Options, Up:Submodel Options

AMD29K オプション

以下の -m オプションが AMD Am29000 用に定義されている。

-mdw
DW ビットが立っている、すなわちバイト演算と半語演算がハードウェアにより直接サポートされていることを想定したコードを生成する。これがデフォルトである。
-mndw
DW ビットが立っていないことを想定したコードを生成する。
-mbw
システムが、バイトと半語の書き込み演算をサポートしていることを想定したコードを生成する。これがデフォルトである。
-mnbw
システムが、バイトと半語の書き込み演算をサポートしていないことを想定したコードを生成する。-mnbw-mndw を含む。
-msmall
スモール・メモリ・モデルを使う。このモデルでは、関数のアドレスは全て一個の 256KB のセグメント内にあるか、256k より小さい絶対アドレスにあることを想定する。これにより、call 命令が、constconsthcalli という命令列の代わりに使われる。
-mnormal
ノーマル・メモリ・モデルを使う。呼出し側関数が同一ファイル内にあるときのみcall 命令を生成し、それ以外の場合は calli 命令を生成する。これは、各ファイルが 256 KB 未満であれば動作する。この場合、実行形式全体は 256KB より大きくても良い。これがデフォルトである。
-mlarge
常に calli 命令を使う。一個のファイルをコンパイルしたときに256KB より大きなコードになりそうなら、このオプションを指定する。
-m29050
Am29050 用のコードを生成する。
-m29000
Am29000 用のコードを生成する。これがデフォルトである。
-mkernel-registers
レジスタ gr96-gr127 への参照の代わりに、レジスタ gr64-gr95 への参照を生成する。このオプションは、ユーザモードのコードで使われるものとは分離したグローバルレジスタのセットを必要とするカーネルコードをコンパイルするときに使うことができる。

このオプションを使うときは、-f オプションで指定するレジスタ名は、通常のユーザモードの名前を使わなければならない。

-muser-registers
通常のグローバル・レジスタのセットである、gr96-gr127 を使う。これがデフォルトである。
-mstack-check
-mno-stack-check
各スタック調整の後に、__msp_check への呼出しを挿入する(挿入しない)。これはカーネルコードで良く使われる。
-mstorem-bug
-mno-storem-bug
-mstorem-bug を指定すると、mstrim 命令と storem 命令を分離して扱えない 29k プロセッサ(29050 を除く、現時点でのほとんどの 29000 チップ)を取り扱う。
-mno-reuse-arg-regs
-mreuse-arg-regs
-mno-reuse-arg-regs を指定すると、入力引数レジスタは引数をそのままコピーするためにしか使わないようにする。これは、宣言されたものよりも少ない引数で関数を呼び出しているのを検出する手助けになる。
-mno-impure-text
-mimpure-text
-mimpure-text を、-shared に加えて指定すると、享有オブジェクトをリンクするときにリンカに -assert pure-text オプションを渡さないようにする。
-msoft-float
浮動小数点用ライブラリ呼び出しを含む出力を生成する。警告: 必要となるライブラリは GCC の一部ではない。普通はその機種の通常の C コンパイラの機能が使われるが、クロスコンパイルの場合はこれをそのまま行なうことはできない。クロスコンパイルの場合は、適切なライブラリ関数を自分で用意しなければならない。
-mno-multm
multm 命令や multmu 命令を生成しない。これは、これらの命令向けにトラップ・ハンドラを持たない幾つかの組み込みシステムで有用である。


Node:ARM Options, Next:, Previous:AMD29K Options, Up:Submodel Options

ARM オプション

以下のオプションが、Advanced RISC Machines (ARM) アーキテクチャ用に定義されている

-mapcs-frame
コードを正しく実行するには必ずしも必要でなくても、全ての関数に対し、ARM Procedure Call Standard に準拠したスタックフレームを生成する。このオプションと合わせて -fomit-frame-pointer を指定すると、末端関数に対してはスタックフレームが生成されなくなる。デフォルトは -mno-apcs-frame である。
-mapcs
これは -mapcs-frame の別名である。
-mapcs-26
プログラムカウンタが 26 ビットのプロセッサ用で、APCS 26 ビットオプション用の関数呼出し規約に準拠するコードを生成する。このオプションは、GCC の以前のリリースの -m2 オプションと-m3 オプションを置き換えるものである。
-mapcs-32
プログラムカウンタが 32 ビットのプロセッサ用で、APCS 32 ビットオプション用の関数呼出し規約に準拠するコードを生成する。このオプションは、GCC の以前のリリースの -m6 オプションを置き換えるものである。
-mapcs-stack-check
あらゆる関数(実際に少しでもスタックスペースを使うもの)の入り口点で、利用可能なスタックスペースの量を検査するコードを生成する。利用できるスタックスペースが足りなければ、関数 __rt_stkovf_split_small__rt_stkovf_split_big のどちらかが呼ばれる。どちらが呼ばれるかは必要とするスタックスペース量による。実行時システムはこれらの関数を提供する必要がある。デフォルトは、-mno-apcs-stack-check である。生成されるコードが小さいからである。
-mapcs-float
浮動小数点引数を浮動小数点レジスタを使って渡す。これは APCS の変種の一つである。このオプションは、ターゲットハードウェアが浮動小数点ユニットを持っている場合や、浮動小数点算術演算を大量に実行する場合にお勧めである。デフォルトは -mno-apcs-float である。整数しか含まないコードは、-mapcs-float を指定するとわずかにサイズが大きくなるためである。
-mapcs-reentrant
再入可能な位置独立コードを生成する。これは、-fpic オプションを指定するのに等価である。デフォルトは、-mno-apcs-reentrant である。
-mthumb-interwork
ARM と THUMB の命令セット間での呼びだしをサポートするコードを生成する。このオプションを指定しないと、二つの命令セットを一つのプログラムの中で使用するのは信頼性に欠けることになる。デフォルトは、、-mno-thumb-interwork である。-mthumb-interwork を指定するとわずかにコードが大きくなるためである。
-mno-sched-prolog
関数プロローグ内の命令並べ替えや、関数プロローグの命令と関数本体の命令の混合を抑止する。これは、全ての関数がある見分けの付く命令のセットで始まる(あるいは、実際には、異なる関数プロローグの幾つかのセットから一つ選んだもので始まる)ということを意味する。この情報を使って、関数が実行可能なコード断片の中にあるときにその関数の開始位置を見つけることが出来る。デフォルトは、-sched-prolog である。
-mhard-float
浮動小数点命令を含む出力を生成する。これがデフォルトである。
-msoft-float
浮動小数点用ライブラリ呼び出しを含む出力を生成する。警告: 必要となるライブラリは全ての ARM ターゲットで利用可能であるわけではない。普通はその機種の通常の C コンパイラの機能が使われるが、クロスコンパイルの場合はこれをそのまま行なうことはできない。クロスコンパイルの場合は、適切なライブラリ関数を自分で用意しなければならない。

-msoft-float を指定すると、出力ファイル中の呼び出し規約が変わる。このため、プログラム全体をこのオプションでコンパイルしないといけない。特に、GCC 付属のライブラリである、libgcc.a をコンパイルするときに、-msoft-float を指定してコンパイルしないとこのライブラリが正しく動作しない。

-mlittle-endian
リトル・エンディアンモードで動作するプロセッサ向けのコードを生成する。これが、全ての標準のコンフィギュレーションのデフォルトである。
-mbig-endian
ビッグ・エンディアンモードで動作するプロセッサ向けのコードを生成する。デフォルトは、リトル・エンディアンのプロセッサ向けのコードをコンパイルするものである。
-mwords-little-endian
このオプションは、ビッグ・エンディアンのプロセッサ用のコードを生成する時にのみ適用される。語に関してはリトル・エンディアンだが、バイトに関してはビッグ・エンディアンのコードを生成する。すなわち、バイト順は 32107654 という形である。このオプションを使うのは、ビッグ・エンディアンの ARM プロセッサ用のコードで、GCC の 2.8 以前のバージョンで生成されたものとの互換性が必要な場合だけにすべきである。
-mshort-load-bytes
半語(例えば short型)をロードするのに、整列していないアドレスから語をロードすることで行なうことをしない。ターゲットの中には、MMU が、整列していないアドレスからのロードをトラップするよう設定されているものがある。このオプションを使って、そういう環境でも安全なコードを生成する。
-mno-short-load-bytes
半語(short型等)をロードするのに、整列していないアドレスから語をロードすることで行なう。このオプションを使うと、効率の良いコードが得られるが、MMU はこれらの命令をトラップするように設定されていることがある。
-mshort-load-words
これは -mno-short-load-bytes の別名である。
-mno-short-load-words
これは、-mshort-load-bytes の別名である。
-mbsd
このオプションは RISC iX にのみ使える。ネイティブの BSD モードのコンパイラをエミュレートする。これは、-ansi が指定されない場合のデフォルトである。
-mxopen
このオプションは RISC iX にのみ使える。ネイティブの X/Open モードのコンパイラをエミュレートする。
-mno-symrename
このオプションは RISC iX にのみ使える。アセンブラの後処理プログラム symrename を、コードがアセンブルされた後で実行しない。普通は、RISC iX C ライブラリとリンクするための下準備として、標準のシンボルをいくらか修正する必要がある。このオプションはその修正過程を抑止する。後処理プログラムは、GCC がクロスコンパイラとして構築された場合には決して実行されない。
-mcpu=<name>
-mtune=<name>
これは、ターゲットの ARM プロセッサ名を指定する。GCC はこの名前を使って、アセンブリコードを生成するときに使える命令の種類を決定する。指定できる名前は次の通り。arm2、arm250、arm3、arm6、arm60、arm600、arm610、arm620、arm7、arm7m、arm7d、arm7dm、arm7di、arm7dmi、arm70、arm700、arm700i、arm710、arm710c、arm7100、arm7500、arm7500fe、arm7tdmi、arm8、strongarm、strongarm110、strongarm1100、arm8、arm810、arm9、arm9tdmi。-mtune=-mcpu= の別名であり、古いバージョンの GCC をサポートするためある。
-march=<name>
これは、ターゲットの ARM のアーキテクチャ名を指定する。GCC はこの名前を使って、アセンブリコードを生成するときに使える命令の種類を決定する。このオプションは、-mcpu= オプションと組み合わせて、あるいは-mcpu= オプションの代わりに使うことが出来る。指定できる名前は、armv2、armv2a、armv3、armv3m、armv4、armv4t である。
-mfpe=<number>
-mfp=<number>
これは、ターゲットで利用可能な浮動小数点エミュレーションのバージョンを指定する。指定できる値は 2 と 3 である。-mfp=-mfpe= の別名であり、古いバージョンの GCC をサポートするためにある。
-mstructure-size-boundary=<n>
全ての構造体と共用体の大きさを、このオプションで指定するビット数の倍数に切り上げる。指定可能な値は 8 と 32 である。デフォルト値は、ツール・チェーンが異なると変わってくる。COFF 向けのツールチェーンに対してはデフォルト値は 8 である。大きい数を指定すればそれだけ高速で効率の良いコードが得られるが、プログラムのサイズも大きくなる。指定できる二つの値は、潜在的には互換性がない。一方の値でコンパイルしたコードは、もう一方の値でコンパイルしたコードやライブラリと合わせたとき、それが構造体や共用体を使った情報を交換している場合には、動作するとは必ずしも期待できない。プログラマの皆さんには 32 という値を使うことをお勧めする。ツールチェーンの将来のバージョンでは、デフォルトがこの値になる可能性があるからである。
-mabort-on-noreturn
noreturn 関数の最後に関数 abort の呼出しを生成する。これは関数が戻ろうとしたときに実行される。


Node:Thumb Options, Next:, Previous:ARM Options, Up:Submodel Options

Thumb オプション


-mthumb-interwork
THUMB と ARM の命令セット間での呼びだしをサポートするコードを生成する。このオプションを指定しないと、二つの命令セットを一つのプログラムの中で使用するのは信頼性に欠けることになる。デフォルトは、、-mno-thumb-interwork である。このオプションを指定するとわずかにコードが小さくなるためである。
-mtpcs-frame
全ての末端でない関数に対し、Thumb Procedure Call Standard に準拠するスタックフレームを生成する。(末端関数とは、他の関数を全くよばない関数である。) デフォルトは -mno-tpcs-frame である。
-mtpcs-leaf-frame
全ての末端関数に対し、Thumb Procedure Call Standard に準拠するスタックフレームを生成する。(末端関数とは、他の関数を全くよばない関数である。) デフォルトは -mno-tpcs-leaf-frame である。
-mlittle-endian
リトル・エンディアンモードで動作するプロセッサ向けのコードを生成する。これは、全ての標準のコンフィギュレーションのデフォルトである。
-mbig-endian
ビッグ・エンディアンモードで動作するプロセッサ向けのコードを生成する。
-mstructure-size-boundary=<n>
全ての構造体と共用体の大きさを、このオプションで指定するビット数の倍数に切り上げる。指定可能な値は 8 と 32 である。デフォルト値は、ツール・チェーンが異なると変わってくる。COFF 向けのツールチェーンに対してはデフォルト値は 8 である。大きい数を指定すればそれだけ高速で効率の良いコードが得られるが、プログラムのサイズも大きくなる。指定できる二つの値は、潜在的には互換性がない。一方の値でコンパイルしたコードは、もう一方の値でコンパイルしたコードやライブラリと合わせたとき、それが構造体や共用体を使った情報を交換している場合には、動作するとは必ずしも期待できない。プログラマの皆さんには 32 という値を使うことをお勧めする。ツールチェーンの将来のバージョンでは、デフォルトがこの値になる可能性があるからである。


Node:MN10200 Options, Next:, Previous:Thumb Options, Up:Submodel Options

MN10200 オプション

以下の -m オプションが Matushita MN10200 アーキテクチャ向けに定義されている。


-mrelax
リンカに対し、緩和最適化パスを実行して分岐、呼出し、絶対メモリアドレスを短くする。このオプションは、最終的なリンク段階のコマンド行で使った場合にだけ効果がある。

このオプションを使うと、シンボリックデバッグができなくなる。


Node:MN10300 Options, Next:, Previous:MN10200 Options, Up:Submodel Options

MN10300 オプション

以下の -m オプションが松下 MN10300 アーキテクチャ用に定義されている。

-mmult-bug
MN10300 プロセッサの乗算命令のバグを回避するようにコードを生成する。これはデフォルトである。
-mno-mult-bug
MN10300 プロセッサの乗算命令のバグを回避するようなコードを生成しない。
-mrelax
リンカに対し、緩和最適化パスを実行して分岐、呼出し、絶対メモリアドレスを短くする。このオプションは、最終的なリンク段階のコマンド行で使った場合にだけ効果がある。

このオプションを使うと、シンボリックデバッグができなくなる。


Node:M32R/D Options, Next:, Previous:MN10300 Options, Up:Submodel Options

M32R/D オプション

以下の -m オプションが三菱 M32R/D アーキテクチャ用に定義されている。

-mcode-model=small
全てのオブジェクトが下位 16MB の範囲のメモリに収まり(そうなっているとアドレスが ld24 命令でロード可能である)、全てのサブルーチンは、bl 命令で到達可能であると想定する。これはデフォルトである。

特定のオブジェクトのアドレス可能性は、model 属性で設定可能である。

-mcode-model=medium
オブジェクトは 32 ビットのアドレス空間のどこにあっても良く(GCC はそれらのアドレスをロードするのに seth/add3 命令を生成する)、全てのサブルーチンは、bl 命令で到達可能であると想定する。
-mcode-model=large
オブジェクトは 32 ビットのアドレス空間のどこにあっても良く(GCC はそれらのアドレスをロードするのに seth/add3 命令を生成する)、サブルーチンは、bl 命令では到達できない可能性があると想定する(GCC は、さらに遅い seth/add3/jl 命令列を生成する)。
-msdata=none
小データ領域を使わないようにする。変数は .databss.rodata のどれか一つに置かれる(section 属性が指定されればその限りではない)。これはデフォルトである。

小データ領域は、セクション .sdata.sbss からなる。section 属性でこのどちらかのセクションを指定すれば、オブジェクトを小データ領域に明示的に置くことができる。

-msdata=sdata
小さいグローバルなデータと静的なデータを小データ領域に置きはするが、それらを参照するために特別なコードは生成しない。
-msdata=use
小さいグローバルなデータと静的なデータを小データ領域に置き、それらを参照するために特別なコードを生成する。
-G num
num バイト以下の大きさのグローバルなオブジェクトと静的なオブジェクトを、普通のデータセクションや bss セクションではなく、小データセクションや小 bss セクションに置く。num のデフォルト値は 8 である。このオプションを有効にするためには、-msdata オプションでsdatause のどちらかを指定しなければならない。

全てのモジュールは、-G num で同じ値を指定してコンパイルする必要がある。num の値が違っていると、正しく動作するかどうかわからない。動作しない場合は、リンカがエラーメッセージを出すはずである。正しくないコードは生成されない。


Node:M88K Options, Next:, Previous:M32R/D Options, Up:Submodel Options

M88K オプション

以下の -m オプションが Motorola 88k アーキテクチャ用に定義されている。

-m88000
m88100 と m88110 の両方で正しく動作するコードを生成する。
-m88100
m88100 で最も良く動作するが、m88110 でも動作はするコードを生成する。
-m88110
m88110 で最も良く動作し、m88100 では動作しない可能性があるコードを生成する。
-mbig-pic
次期バージョンで削除予定の古いオプションである。-fPIC を使おう。
-midentify-revision
アセンブラ出力に ident 疑似命令を入れて、ソースファイル名、コンパイラ名とそのバージョン、タイムスタンプ、コンパイラへのオプションを記録する。
-mno-underscores
アセンブラ出力で、シンボル名の先頭にアンダースコアを付けずにその名前を出力する。デフォルトでは、それぞれの名前の前にアンダースコアが付く。
-mocs-debug-info
-mno-ocs-debug-info
88open Object Compatibility Standard, "OCS" で規定されている追加のデバッグ情報(各スタックフレームでのレジスタの使用状況)を出力する(出力しない)。この追加デバッグ情報があると、フレームポインタが削除されたコードをデバッグできる。DG/UX、SVR4、Delta 88 SVR3.2 の場合のデフォルトは、この情報を含める。他の 88k のコンフィギュレーションではデフォルトではこの情報を省略する。
-mocs-frame-position
自動変数、それにスタック上に格納される引数に対する COFF 形式デバッグ情報を出力するとき、正規のフレームアドレス、つまり関数の入り口点でのスタックポインタ(レジスタ 31)からのオフセットを使う。DG/UX、SVR4、Delta88 SVR3.2、BCS のコンフィギュレーションでは-mocs-frame-position を使っている。他の 88k のコンフィギュレーションでは、デフォルトは -mno-ocs-frame-position である。
-mno-ocs-frame-position
自動変数、それにスタック上に格納される引数に対する COFF 形式デバッグ情報を出力するとき、フレームポインタ(レジスタ 30)からのオフセットを使う。このオプションが有効になっていると、デバッグ情報が -g オプションで選択されているときフレームポインタは削除されない。
-moptimize-arg-area
-mno-optimize-arg-area
関数の引数がスタックフレームにどのように格納されるかを制御する。-moptimize-arg-area を指定すると最適化により使用メモリを節約する。だが、このオプションは 88open の仕様に反する。その反対のオプション -mno-optimze-arg-area は、88open 規格に一致する。デフォルトでは、引数領域の最適化は行なわない。
-mshort-data-num
データへの参照をより小さくするために、それらをr0 相対にする。これにより、値をロードするのが一個の命令でできるようになる(普通は命令二個必要である)。どのデータ参照が影響を受けるかは、このオプションで指定する num で調整できる。例えば、-mshort-data-512 と指定すると、影響を受けるデータ参照は512 バイト未満の変位を含むものである。-mshort-data-num は、num が 64k より大きいと効果がない。
-mserialize-volatile
-mno-serialize-volatile
逐次的な揮発性メモリ参照の一貫性を保証するコードを生成する、あるいは生成しない。デフォルトでは一貫性は保証される。

MC88110 プロセッサによりなされるメモリ参照の順序は、その参照を必要とする命令の順序には必ずしも一致しない。特に、ロード命令は先行するストア命令よりも先に実行される可能性がある。このような並べ替えは、逐次的な揮発性メモリ参照の一貫性を、マルチプロセッサの場合には破る。一貫性が保証されなければならない場合は、GNU C は必要に応じて特別な命令を生成し、強制的に適切な順序で実行させるようにする。

MC88100 プロセッサはメモリ参照の並べ替えを行なわないので、常に逐次的な一貫性を提供する。だが、GNU C はデフォルトでは、 -m88100 を指定した場合でも、特別な命令を生成し、一貫性を保証するので、その生成コードは M88110 プロセッサでも実行可能である。M88100 プロセッサでしか実行しないつもりなら、-mno-serialize-volatile を指定することができる。

一貫性を保証するために生成された余分のコードは、読者のアプリケーションの実行速度に影響を及ぼす可能性がある。保証しなくても大丈夫であることが判っているなら、-mno-serialize-volatile を指定することができる。

-msvr4
-msvr3
SVR4 に関係した拡張機能をオンにしたり(-msvr4)、オフにする(-msvr3。これは以下の事項を制御する。

  1. どのアセンブラ構文の変種を使うか。
  2. -msvr4 を指定すると、C プリプロセッサが、SVR4 で使われている#pragma weak を認識するようになる。
  3. -msvr4 を指定すると、GCC は SVR4 で使われている追加の宣言制御子を発行する。

-msvr4 は、m88k-motorola-sysv4 と m88k-dg-dgux という m88k のコンフィギュレーションではデフォルトになっている。-msvr3 は、その他の全ての m88k のコンフィギュレーションでデフォルトになっている。

-mversion-03.00
このオプションは廃れており、無視される。
-mno-check-zero-division
-mcheck-zero-division
整数のゼロによる除算が検出されることを保証するコードを生成するかどうかを指定する。デフォルトでは検出されることが保証される。

MC88100 プロセッサの幾つかのモデルでは、特定の条件下でゼロによる整数除算をトラップできないことがある。デフォルトでは、そういうプロセッサで実行される可能性があるコードをコンパイルするときは、GCC はゼロになる除数を明示的に検査し、検出された場合には例外番号 503 でトラップするコードを生成する。-mno-check-zero-division を使うと、MC88100 プロセッサで実行するように生成されたコードに対し、この様な検査を行なわない。

GNU C は、MC88110 プロセッサが、ゼロによる整数除算が起こった場合全てを正しく検出できることを想定している。-m88110 を指定したときは、-mcheck-zero-division-mno-check-zero-division もどちらも無視され、除数がゼロになるかどうかを明示的に検査するコードは生成されない。

-muse-div-instruction
MC88100 プロセッサでの符号付き整数除算に対し、div 命令を使う。デフォルトでは、div 命令は使われない。

MC88100 プロセッサでは、符号付きの整数除算命令(div)は、オペランドが負の場合は OSへのトラップを発生する。OS は透過的に演算を完了することができるが、実行時間が非常にかかることになる。デフォルトでは、MC88100 プロセッサで実行される可能性があるコードをコンパイルするときは、GCC は符号付き整数除算を、符号なし整数除算命令(divu)を使ってエミュレートする。これにより、OS へのトラップという大きなペナルティを回避している。このエミュレーションのコストは、実行時間とコードサイズの両面で小さくなっている。読者のプログラムで、重要な符号付き整数除算が二つの負でないオペランドに対して実行される範囲なら、div 命令を直接使うのが望ましい。

MC88110 プロセッサの場合は、div 命令(divs 命令としても知られている)は、OS へのトラップを発生することなく、負のオペランドを処理する。-m88110 が指定されたときは、-muse-div-instruction は無視され、div 命令が符号付き整数除算に使われる。

INT_MIN を -1 で割った結果は未定義であることに注意して欲しい。特に、このような割り算の動作は、-muse-div-instruction の有無で変わってくる。

-mtrap-large-shift
-mhandle-large-shift
シフトビット数が 31 ビットを越えるものを検出するコードを挿入する。これらのオプションは、それぞれ、そのようなシフト命令をトラップするか、正しく取り扱うコードを生成する。デフォルトでは、GCC はシフトのビット数が大きくても特に何もしない。
-mwarn-passed-structs
関数が引数や戻り値として構造体を渡したときに警告する。構造体の渡し方の規約は、C 言語が進化するにつれて変わってきており、移植上の問題の元になることが多い。デフォルトでは、GCC はこの警告は出さない。


Node:RS/6000 and PowerPC Options, Next:, Previous:M88K Options, Up:Submodel Options

IBM RS/6000 と PowerPC オプション

以下の -m オプションが IBM RS/6000 と PowerPC 用に定義されている。

-mpower
-mno-power
-mpower2
-mno-power2
-mpowerpc
-mno-powerpc
-mpowerpc-gpopt
-mno-powerpc-gpopt
-mpowerpc-gfxopt
-mno-powerpc-gfxopt
-mpowerpc64
-mno-powerpc64
GCC は、RS/6000 と PowerPC について、二つの関係のある命令セットをサポートしている。POWER 命令セットは、最初の RS/6000 システムで使われていたrios チップセットでサポートされていた命令セットである。PowerPC 命令セットは、モトローラのマイクロプロセッサ MPC5xx、MPC6xx、MPC8xx と IBM のマイクロプロセッサ 4xx のアーキテクチャである。

どちらのアーキテクチャも他方のサブセットにはなっていない。しかし、両方でサポートされている共通の命令の大きなサブセットがある。POWER アーキテクチャをサポートするプロセッサには MQ レジスタが含まれている。

これらのオプションを使って、自分のプロセッサで利用可能な命令を指定することができる。これらのオプションのデフォルト値は、GCC のコンフィギュレーション時に決定される。-mcpu=cpu_type を指定すると、これらのオプションの指定を上書きする。上に列挙したオプションではなく、-mcpu=cpu_type オプションを使うことをお勧めする。

-mpower オプションを指定すると、POWER アーキテクチャにのみ存在する命令を生成したり、MQ レジスタを使うことを GCC に許す。-mpower2 を指定すると、-power を含んだうえに、POWER2 アーキテクチャには存在するが、元々の POWER アーキテクチャには存在しない命令を生成することを GCC に許す。

-mpowerpc オプションを指定すると、PowerPC アーキテクチャの32ビット版のサブセットにのみ存在する命令の生成を GCC に許す。-mpowerpc-gpopt を指定すると、-mpowerpc を含んだうえに、PowerPC アーキテクチャの General Purpose グループのオプションの命令を使うことができるようになる。これには、浮動小数点平方根命令も含まれる。-mpowerpc-gfxopt を指定すると、-mpowerpc を含んだうえに、PowerPC アーキテクチャの Graphics グループのオプションの命令を使うことができるようになる。これには浮動小数点選択命令も含まれる。

-mpowerpc64 オプションを指定すると、GCC は完全な PowerPC64 アーキテクチャにある 64 ビット命令を追加で生成し、GPR を 64 ビットの倍語量として取り扱う。デフォルトは -mno-powerpc64 である。

-mno-power-mno-powerpc の両方を指定すると、GCC は両方のアーキテクチャに共通する命令サブセットに加えて幾つかの特別なAIX 共通モード呼出し命令のみを使い、MQ レジスタは使わないようになる。-mpower-mpowerpc を両方指定すると、どちらのアーキテクチャのどの命令でも使うことが可能になり、MQ レジスタも使うようになる。Motorola MPC601 にはこの両方を指定すること。

-mnew-mnemonics
-mold-mnemonics
どのニーモニックを生成されるアセンブラコードで使うかを選ぶ。-mnew-mnemonisc を指定すると、PowerPC アーキテクチャ向けに定義されたアセンブラニーモニックを使って出力する。一方、-mold-mnemonisc を指定すると、POWER アーキテクチャ用に定義されたアセンブラニーモニックを使用する。一つのアーキテクチャでしか定義されていない命令は、ニーモニックは一種類しかない。GCC は、一種類しかないニーモニックは、どのオプションが指定されたかに関係なく、それを使う。

GCC では使われているアーキテクチャに適したニーモニックをデフォルトで使う。-mcpu=cpu_type を指定すると、これらのオプションの値が変わることもある。クロスコンパイラを作るのでない限り、普通は -mnew-mnemonics-mold-mnemonics を指定するのではなく、代わりにデフォルトを受け入れるようにすべきである。

-mcpu=cpu_type
アーキテクチャ型、レジスタ使用法、ニーモニックの選択、命令スケジューリングのパラメータを、機種 cpu_type 用に設定する。cpu_type として使えるのは、rs6000rios1rios2rsc601602603603e604604e620740750powerpower2powerpc403505801821823860common である。-mcpu=power-mcpu=power2-mcpu=powerpc は、POWER、POWER2、それに純粋な PowerPC(つまり、MPC601 は含まない) アーキテクチャの汎用の機種を指定する。スケジューリング用には、適切な汎用プロセッサモデルを想定する。

オプション -mcpu=rios1-mcpu=rios2-mcpu=rsc-mcpu=power-mcpu=power2 のどれかを指定すると、-mpower オプションが有効になり、-mpowerpc オプションが無効になる。-mcpu=601 を指定すると、-mpower-mpowerpc の両方が有効になる。-mcpu=602-mcpu=603, -mcpu=603e-mcpu=604-mcpu=604e, -mcpu=620-mcpu=403-mcpu=505-mcpu=801, -mcpu=821-mcpu=823-mcpu=860-mcpu=powerpc のどれかを指定すると、-mpowerpc オプションを有効にし、-mpower オプションを無効にする。全く同様に、-mcpu=403-mcpu=505-mcpu=821-mcpu=860-mcpu=powerpc を指定すると、-mpowerpc を有効にし、-mpower を無効にする。-mcpu=common は、-mpower-mpowerpc の両方を無効にする。

AIX バージョン 4 以降は、デフォルトで -mcpu=common を選択し、コードがRS/6000 と PowerPC 一族の全メンバで動作するようになっている。その場合、GCC は両方のアーキテクチャに共通のサブセットに、幾つかの特別な AIX 共通モード呼び出しを加えたものだけを使い、MQ レジスタは使わない。GCC は、スケジューリングの際には汎用のプロセッサモデルを想定する。

-mcpu=rios1-mcpu=rios2-mcpu=rsc-mcpu=power-mcpu=power2 のどれかを指定することでも、new-mnemonics オプションを無効にする。-mcpu=601-mcpu=602-mcpu=603-mcpu=603e-mcpu=604620403-mcpu=powerpc のどれかを指定することでも、new-mnemonics オプションを有効にする。

-mcpu=403-mcpu=821-mcpu=860 のどれかを指定することでも -msoft-float オプションを有効にする。

-mtune=cpu_type
命令スケジューリングのパラメータを機種 cpu_type 用に設定する。しかし、アーキテクチャ型、レジスタ使用法、ニーモニックの選択といった、 -mcpu=cpu_type がやる設定は行なわない。cpu_type の値としては、-mcpu=cpu_type に使ったのと同じものを、-mtune=cpu_type に対して使う。-mtune=cpu_type オプションは、-mcpu=cpu_type オプションが設定したものを、命令スケジューリングのパラメータで上書きする。
-mfull-toc
-mno-fp-in-toc
-mno-sum-in-toc
-mminimal-toc
TOC(Table Of Contents) の生成の仕方を変える。TOC は各実行形式ファイル毎に作られる。-mfull-toc オプションがデフォルトで選ばれている。その場合、GCC は、プログラム内の一意的で自動変数でない変数の参照一つ毎に、少なくとも一つのTOC エントリを割り当てる。GCC は、浮動小数点定数も TOC に置く。だが、TOC に入れられるエントリ数は、16,384 しかない。

リンカが、利用可能な TOC 空間が溢れたというエラーメッセージを出した場合は、TOC の使用量を -mno-fp-in-toc オプションや-mno-sum-in-toc オプションで減らすことができる。-mno-fp-in-toc を指定すると、浮動小数点定数を TOC に置くのを止める。-mno-sum-in-toc を指定すると、あるアドレスとある定数の和を TOC に置く変わりに、実行時にその和を計算するコードを生成する。この二つのオプションは、どちらか指定しても良いし、両方指定しても良い。どちらも、TOC 空間を保存することの代償として、ほんのちょっとだけ、コードが遅く、大きくなる。

両方指定してもまだ TOC が足りないという場合は、代わりに-mminimal-toc を指定すること。このオプションを指定すると、GCC は、各ファイルに一つしか TOC エントリを作らない。このオプションを指定すると、遅く、大きなコードを生成するが、TOC 空間は非常にわずかしか使わない。このオプションを使うのは、あまり頻繁に実行されないコードしか入っていないファイルに限るのが良いだろう。

-maix64
-maix32
AIX の 64 ビット ABI と呼出し規約を有効にする。すなわち、64ビットポインタ、64ビット long 型、それにそれらをサポートするのに必要なインフラストラクチャが有効になる。-maix64 を指定すると、-mpwoerpc64-mpowerpc も暗に指定される。一方、-maix32 を指定すると 64ビット ABI を無効にし、暗に -mno-powerpc64 を指定する。GCC のデフォルトは-maix32 である。
-mxl-call
-mno-xl-call
AIX で、プロトタイプ付きの関数に対する浮動小数点引数を、引数用 FPR に加えて、レジスタセーブ領域(register save area, RSA) を越えてスタックに渡される。AIX の呼出し規約は、引数のアドレスをとり、宣言されたよりも少ない引数しか渡さない関数を呼び出す、K&R の曖昧な場合を扱うように拡張されているが、最初はドキュメントにその記述がなかった。AIX XL コンパイラは、RSA に収まらない浮動小数点引数は、最適化なしでサブルーチンが最適化なしでコンパイルされたときは、スタックからアクセスする。浮動小数点引数を常にスタックに格納するのは効率が悪いし、滅多に必要にならない。このため、このオプションはデフォルトでは有効になっていない。必要になるのは、AIX XL コンパイラで最適化なしでコンパイルしたサブルーチンを呼び出すときだけである。
-mthreads
AIX Threads をサポートする。pthreads を使って書かれたアプリケーションを、特別なライブラリとスタートアップコードにリンクして、アプリケーションの実行を可能にする。
-mpe
IBM RS/6000 SPParallel Environment (PE) をサポートする。メッセージパッシングを使うように書かれているアプリケーションは、特別なスタートアップコードとリンクして、そのアプリケーションが正しく動作するようにする。システムには PE が標準の位置(/usr/lpp/ppe.poe/)にインストールされていなければならない。標準の位置にない場合は、-specs= オプションで適切なディレクトリ位置を指定するように specs ファイルを上書きする必要がある。Parallel Environment はスレッドをサポート指定位なので、-mpe オプションと -mthreads オプションは互換性がない。
-msoft-float
-mhard-float
浮動小数点レジスタセットを使わない(使う)コードを生成する。-msoft-float オプションを指定した場合、ソフトウェア浮動小数点エミュレーションが提供されており、このオプションがリンク時に GCC に渡される。
-mmultiple
-mno-multiple
複数語のロード命令とストア命令を使う(使わない)コードを生成する。これらの命令は、POWER システムではデフォルトで生成され、PowerPC システムでは生成されない。リトルエンディアンを使用している PowerPC システムでは -mmultiple を使わないこと。これらの命令はリトルエンディアンモードでは正しく動作しないからである。例外は PPC740 と PPC750 で、これらの命令をリトルエンディアンモードで使うことを許している。
-mstring
-mno-string
ロード・ストリング命令とストア・ストリング命令を使って、複数レジスタをセーブし、小さなブロック移動を行なうコードを生成する。これらの命令は、POWER のシステムではデフォルトで生成され、PowerPC のシステムでは生成されない。リトル・エンディアンのPowerPC システムでは -mstring オプションを使わないこと。これらの命令は、リトル・エンディアン・モードのプロセッサでは動作しないからである。例外は PPC740 と PPC750 で、これらの命令をリトルエンディアンモードで使うことを許している。
-mupdate
-mno-update
ベースレジスタを計算後のメモリアドレスに更新するロード命令あるいはストア命令を使う(使わない)コードを生成する。これらの命令はデフォルトで生成される。-mno-upate を指定すると、スタックポインタが更新されるのと直前のフレームのアドレスが更新されるのと間に間があき、割り込みやシグナルを越えてスタックフレームを歩き回るコードがあると、正しくないデータを受け取る可能性がある。
-mfused-madd
-mno-fused-madd
浮動小数点積和命令を使う(使わない)コードを生成する。これらの命令は、ハードウェアによる浮動小数点演算が使われる場合はデフォルトで生成される。
-mno-bit-align
-mbit-align
System V.4 と組み込み PowerPC システムで、ビットフィールドを含む構造体や共用体を、ビットフィールドの基本型に強制的に整合させる(整合させない)

例えば、長さが 1 の unsigned のビットフィールド 8 個だけしか含まない構造体は、デフォルトでは、4バイト境界に整合され、大きさが4バイトになる。-mno-bit-align を使うと、この構造体は 1 バイト境界に整合されるようになり、大きさも 1 バイトになる。

-mno-strict-align
-mstrict-align
System V.4 と組み込み PowerPC システムで、整合のとれていないメモリ参照がシステムにより取り扱われると仮定しない(仮定する)。
-mrelocatable
-mno-relocatable
組み込み PowerPC システムで、実行時に異なるアドレスに再配置されるコードを生成することを許す(許さない)。モジュールを一個でも-mrelocatable を指定してコンパイルしたなら、一緒にリンクするオブジェクトは全て -mrelocatable-mrelocatable-lib を指定してコンパイルしなければならない。
-mrelocatable-lib
-mno-relocatable-lib
組み込み PowerPC システムで、実行時に異なるアドレスに再配置されるコードを生成することを許す(許さない)。-mrelocatable-lib を指定してコンパイルしたモジュールは、-mrelocatable-mrelocatable-lib なしでコンパイルしたモジュールでも、-mrelocatable 付きでコンパイルしたモジュールでもリンク可能である。
-mno-toc
-mtoc
System V.4 と組み込み PowerPC システムで、レジスタ 2 が、プログラムで使われるアドレス群を指すグローバル領域へのポインタであることを想定しない(想定する)。
-mlittle
-mlittle-endian
System V.4 と組み込み PowerPC システムでは、リトルエンディアンモードにあるプロセッサ向けに、コードをコンパイルする。-mlittle-endian オプションは -mlittle オプションと同じである。
-mbig
-mbig-endian
System V.4 と組み込み PowerPC システムでは、ビッグエンディアンモードにあるプロセッサ向けに、コードをコンパイルする。-mbig-endian オプションは -mbig オプションと同じである。
-mcall-sysv
System V.4 と組み込み PowerPC システムでは、「System V Application Binary Interface, PowerPC processor supplement」の 1995年3月版ドラフトに従った呼び出し規約を使って、コードをコンパイルする。GCC を powerpc-*-eabiaix でコンフィギュレーションしない場合は、これがデフォルトになる。
-mcall-sysv-eabi
-mcall-sysv-meabi の両方のオプションを指定する。
-mcall-sysv-noeabi
-mcall-sysv-mno-eabi の両方のオプションを指定する。
-mcall-aix
System V.4 と組み込み PowerPC システムでは、AIX で使われている呼び出し規約に類似の呼び出し規約を使ってコードをコンパイルする。GCC を powerpc-*-eabiaix でコンフィギュレーションした場合は、これがデフォルトになる。
-mcall-solaris
System V.4 と組み込み PowerPC システムでは、Solaris オペレーティングシステム向けにコードをコンパイルする。
-mcall-linux
System V.4 と組み込み PowerPC システムでは、Linux ベースの GNU システム向けにコードをコンパイルする。
-mprototype
-mno-prototype
System V.4 と組み込み PowerPC システムでは、全ての可変数引数関数への呼出しは、正しくプロトタイプ宣言されていると想定する。想定しない場合は、GCC は、プロトタイプ宣言なしの呼出し毎にその直前に命令を一個挿入して、関数が可変数引数を取る場合、浮動小数点値が浮動小数点レジスタで渡されたかどうかを指示するために、条件コードレジスタ(CR)のビット 6 を立てるか落とすかしなければならない。-mprototype を指定すると、プロトタイプ宣言された可変数引数関数への呼出しでのみ、ビット 6 を立てたり落としたりする。
-msim
組み込み PowerPC システムで、起動モジュールが sim-crt0.o であり、標準 C ライブラリは libsim.alibc.a であることを仮定する。これは、powerpc-*-eabisim のデフォルトである。
-mmvme
組み込み PowerPC システムで、起動モジュールが crt0.o であり、標準 C ライブラリは libmvmem.alibc.a であることを仮定する。
-mads
組み込み PowerPC システムで、起動モジュールが crt0.o であり、標準 C ライブラリは libads.alibc.a であることを仮定する。
-myellowknife
組み込み PowerPC システムで、起動モジュールが crt0.o であり、標準 C ライブラリは libyka.alibc.a であることを仮定する。
-memb
組み込み PowerPC システムで、ELF フラグヘッダの PPC_EMB ビットを立てることで、eabi 拡張再配置情報が使われることを指示する。
-meabi
-mno-eabi
System V.4 と組み込み PowerPC システムで、組み込みアプリケーション・バイナリ・インターフェース(Embedded Applications Binary Interface (eabi)) を遵守する(遵守しない)。eabi は、System V.4 の仕様に対する一群の修正である。-meabi を選ぶと、スタックは 8 バイト境界に整合が行なわれ、関数 __eabimain から呼び出され、eabi 環境の設定が行なわれ、さらに -msdata オプションを使った場合、r2r13 の両方を使い、二つの小さなデータ領域を指すことができるようになる。-mno-eabi を選ぶと、スタックは 16 バイト境界に整合が行なわれ、main から初期化関数を呼び出さず、-msdata オプションを指定しても、r13 だけが使われ、小さなデータ領域を一個しか指さない。-meabi オプションは、GCC を powerpc*-*-eabi* オプションのどれか一つを使ってコンフィギュレーションした場合は、デフォルトで有効になる。
-msdata=eabi
System V.4 と組み込み PowerPC システムでは、小さな初期化済みでconst のグローバルデータと静的データをセクション .sdata2 に置く。.sdata2 セクションはレジスタ r2 が指す。小さな初期化済みで非 const のグローバルデータと静的データをセクション .sdata に置く。.sdata セクションはレジスタ r13 が指す。小さな非初期化グローバルデータと静的データをセクション .sbss セクションに置く。.sbss は、セクション .sdata の直後に置かれる。オプション -msdata=eabi は、-mrelocatable オプションとは互換性がない。-msdata=eabi はまた、-memb オプションも設定する。
-msdata=sysv
System V.4 と組み込み PowerPC システムでは、小さなグローバルデータと静的データをセクション .sdata に置く。.sdata セクションはレジスタ r13 が指す。小さな非初期化グローバルデータと静的データをセクション .sbss に置く。.sbss は、セクション .sdata の直後に置かれる。オプション -msdata=sysv は、-mrelocatable オプションとは互換性がない。
-msdata=default
-msdata
System V.4 と組み込み PowerPC システムで、-meabi が指定されている場合は、-msdata=eabi が指定されている場合と同じようにコードをコンパイルする。-meabi が指定されていないと、-msdata=sysv と同じようにコードをコンパイルする。
-msdata-data
System V.4 と組み込み PowerPC システムでは、小さなグローバルデータと静的データをセクション .sdata に置き、小さな非初期化グローバルデータと静的データをセクション .sbss に置く。しかし、この小さなデータを参照するのにレジスタ r13 を使わない。これは、他の -msdata オプションが指定されない限り、デフォルトになる。
-msdata=none
-mno-sdata
組み込み PowerPC システムでは、全ての初期化済みグローバルデータと静的データをセクション .data に置き、全ての非初期化データをセクション .bss に置く。
-G num
組み込み PowerPC システムでは、num バイト以下のグローバルデータと静的データを、通常の data あるいは bss セクションではなく、小さなdata あるいは小さな bss セクションに置く。デフォルトでは、num は8 である。-G num は、リンカにも渡される。全てのモジュールを同じ値の -G num でコンパイルする必要がある。
-mregnames
-mno-regnames
System V.4 と組み込み PowerPC システムでは、アセンブリ言語出力で記号形式を使ったレジスタ名を出力する(出力しない)。


Node:RT Options, Next:, Previous:RS/6000 and PowerPC Options, Up:Submodel Options

IBM RT オプション

以下の -m オプションが IBM RT PC 用に定義されている。

-min-line-mul
整数乗算にたいして、インライン展開したコード列を使う。これがデフォルトである。
-mcall-lib-mul
整数の乗算にたいして lmul$$ を呼び出す。
-mfull-fp-blocks
IBM 推奨の最少量の詰めものスペースを取り込んだ、完全な大きさの浮動小数点データブロックを生成する。これがデフォルトである。
-mminimum-fp-blocks
浮動小数点データブロックに余分な詰めもののスペースを取り込まない。この結果、コードは小さくなるが実行は遅くなる。詰めもののスペースを動的に確保しなければならないからである。
-mfp-arg-in-fpregs
IBM の呼出し規約と互換性のない呼出し規約を使う。この規約では、浮動小数点引数は浮動小数点レジスタで渡される。varargs.hstdargs.h は、このオプションを指定した場合、浮動小数点演算と一緒に使うことはできない。
-mfp-arg-in-gregs
浮動小数点引数に対し、通常の呼出し規約を使う。これがデフォルトである。
-mhc-struct-return
一語より大きな構造体をレジスタではなく、メモリに入れて返す。これは MetaWare HighC(hc) コンパイラとの互換性のためにある。Portable C Compiler(pcc) との互換性を取るには-fpcc-struct-return オプションを使うこと。
-mnohc-struct-return
一語を越えるいくつかの構造体を、レジスタで渡したほうが良い場合はレジスタで渡す。これはデフォルトである。IBM 提供のコンパイラとの互換性を取るためには、-fpcc-struct-return オプションか-mhc-struct-return オプションを使う。


Node:MIPS Options, Next:, Previous:RT Options, Up:Submodel Options

MIPS オプション

以下の -m オプションが、MIPS 系コンピュータ用に定義されている。

-mcpu=cpu type
命令スケジューリングの際の機種のデフォルトを cpu type と想定する。cpu type は、r2000r3000r3900r4000r4100r4300r4400r4600r4650r5000r6000r8000orion のどれかである。さらに、r2000r3000r4000r5000r6000 は、r2k(あるいは r2K)、r3k 等のように省略できる。ある特定の cpu type を選ぶとその特定のチップに適したスケジューリングを行なう一方で、-mipsX-mabi を指定しない限り、MIPS ISA(Instruction Set Architecture、命令セットアーキテクチャ)のレベル 1 に合わないコードは何も生成しない。
-mips1
MIPS ISA のレベル 1 の命令を発行する。これがデフォルトである。r3000 が、この ISA レベルのデフォルトの CPU タイプである。
-mips2
MIPS ISA のレベル 2 の命令(branch likely, square root 命令)を発行する。r6000 が、この ISA レベルのデフォルトの CPU タイプである。
-mips3
MIPS ISA のレベル 3 の命令(64ビット命令)を発行する。r4000 が、この ISA レベルのデフォルトの CPU タイプである。
-mips4
MIPS ISA のレベル 4 の命令(条件付き move 命令、プリフェッチ命令、強化された FPU 命令)を発行する。r8000 は、この ISA レベルのデフォルトの cpu type である。
-mfp32
32個の32ビット浮動小数点レジスタが利用可能であることを仮定する。これはデフォルトである。
-mfp64
32個の64ビット浮動小数点レジスタが利用可能であることを仮定する。これは、-mips3 オプションが指定されたときのデフォルトである。
-mgp32
32個の32ビット汎用レジスタが利用可能であることを仮定する。これはデフォルトである。
-mgp64
32個の64ビット汎用レジスタが利用可能であることを仮定する。これは、-mips3 オプションが指定されたときのデフォルトである。
-mint64
long 型と int 型を強制的に 64 ビット幅にする。デフォルトについての説明とポインタの大きさについては-mlong32 を参照のこと。
-mlong64
long 型を強制的に 64 ビットにする。デフォルトについての説明とポインタの大きさについては-mlong32 を参照のこと。
-mlong32
long 型、int 型、ポインタ型を強制的に 32 ビット幅にする。

-mlong32-mlong64-mint64 のどれも指定されていないと、int、long、ポインタのサイズは、ABI と選択された ISA に依存する。-mabi=64 の場合、int は 32 ビット幅で long は 64 ビット幅である。-mabi=eabi の場合、-mips1-mips2 が指定されていると、int と long は 32 ビット幅になる。-mabi=eabi の場合、それより高い ISA が指定されていると、int は 32 ビット幅で、long が 64 ビット幅になる。ポインタ型の幅は、long の幅と汎用レジスタの幅の小さいほうになる(これは、ISA に依存する)。

-mabi=32
-mabi=o64
-mabi=n32
-mabi=64
-mabi=eabi
指定された ABI 用のコードを生成する。デフォルトの命令レベルは、32 に対しては -mips1 であり、n32 に対しては-mips3、その他に対しては -mips4 である。逆に、-mips1-mips2 を指定するとデフォルトの ABI は 32 になり、それ以外は 64 になる。
-mmips-as
MIPS アセンブラ用のコードを生成し、通常のデバッグ情報を追加するためにmips-tfile を起動する。これは、OSF/rose オブジェクト形式を使っている、OSF/1 参照プラットフォーム以外の全てのプラットフォームでのデフォルトである。-gstabs-gstabs+ のどちらかのオプションを使うと、mips-tfile プログラムが、MIPS ECOFF 内に stabs 形式のデバッグ情報を包み込む。
-mgas
GNU アセンブラ用のコードを生成する。これは、OSF/rose オブジェクト形式を使っている、OSF/1 の参照プラットフォームではデフォルトである。また、configure のオプション --with-gnu-as が指定されたときのデフォルトでもある。
-msplit-addresses
-mno-split-addresses
アドレス定数の上位部と下位部を別々にロードするコードを生成する。これにより、gcc が、アドレスの上位ビットを無駄にロードしないように最適化することが可能になる。この最適化には、GNU as と GNU ld が必要になる。この最適化は、GNU as と GNU ld が標準のツールである幾つかの組み込みターゲットではデフォルトで有効になる。
-mrnames
-mno-rnames
-mrnames を指定すると、レジスタ名として、ハードウェア名の代わりに、MIPS のソフトウェア名(例えば、$4 の代わりに a0)を使ったコードを出力する。このオプションをサポートしているアセンブラはAlgorithmics のアセンブラだけである。
-mgpopt
-mno-gpopt
-mgpopt オプションを指定すると、全てのデータ宣言を、テキストセクションの命令部分の前に書き出す。これにより MIPS のアセンブラが小さいグローバルおよび静的データ項目に対し、二語ではなく、一語によるメモリ参照を生成することが可能になる。最適化が指定されている場合には、これはデフォルトで有効になる。
-mstats
-mno-stats
-mstats オプションを指定すると、非インライン関数が処理される度に、標準エラー出力に一行出力し、プログラムの統計情報(セーブされたレジスタ数、スタックの大きさ等)を表示する。
-mmemcpy
-mno-memcpy
-mmemcpy オプションを指定すると、全てのブロック移動に対し、インラインコードを生成する代わりに、適切な文字列関数(memcpybcopy)を呼び出すようにする。
-mmips-tfile
-mno-mips-tfile
-mno-mips-tfile を指定すると、MIPS のアセンブラがデバッグ情報を追加した後のオブジェクトファイルに対し、mips-tfile プログラムによる後処理を行なわない。mips-tfile を実行しておかないと、デバッガからローカル変数の情報が扱えなくなる。さらに、stage2stage3 のオブジェクトには、アセンブラに渡された一時ファイル名が、オブジェクトファイル内に埋め込まれた形で入っている。このため、stage2 のオブジェクトと stage3 のオブジェクトが同じになることはない。-mno-mips-tfile オプションを指定するのは、mips-tfile プログラムにバグがあり、コンパイルが行えない場合にだけに術器である。
-msoft-float
浮動小数点用ライブラリ呼び出しを含む出力を生成する。警告: 必要となるライブラリは GCC の一部ではない。普通はその機種の通常の C コンパイラの機能が使われるが、クロスコンパイルの場合はこれをそのまま行なうことはできない。クロスコンパイルの場合は、適切なライブラリ関数を自分で用意しなければならない。
-mhard-float
浮動小数点命令を含む出力を生成する。これは、GCC のソースを変更しなければ、デフォルトである。
-mabicalls
-mno-abicalls
位置独立コード用に、System V.4 用の移植で使っている疑似命令.abicalls.cpload.cprestore を生成する(あるいは生成しない)。
-mlong-calls
-mno-long-calls
全ての呼出しを JALR 命令で行う。このためには、呼出しの前に、関数のアドレスをレジスタにロードしておく必要がある。このオプションを使う必要があるのは、現在の 512 メガバイトのセグメントの外側の関数を、ポインタ経由でなく呼び出す場合である。
-mhalf-pic
-mno-half-pic
外部参照へのポインタを、テキストセクションに置くのではなく、データセクションに置いてロードするようにする。
-membedded-pic
-mno-embedded-pic
いくつかの組み込みシステム向けに適した PIC コードを生成する。全ての呼出しは PC 相対アドレスを使って行われ、全てのデータのアドレスは$gp レジスタを使って扱われる。これには、そのための作業のほとんどを行う GNU as と GNU ld が必要である。これは、現在、ECOFF を使っているターゲットでしか動作していない。ELF では動いていない。
-membedded-data
-mno-embedded-data
可能であれば、変数を、まず最初に読み出し専用データセクションに割り当てる。次に可能であれば、小データセクションに割り当てる。さもなければ、データセクションに置く。こうすると、デフォルトよりも幾分遅いコードになるが、実行時に必要な RAM の量が小さくなるので、いくつかの組み込みシステムにとっては望ましいだろう。
-msingle-float
-mdouble-float
-msingle-float オプションを指定すると、r4650 チップのように、浮動小数点コプロセッサが単精度演算しかサポートしていないと想定する。-mdouble-float オプションを指定すると、倍精度演算を使うようになる。こちらがデフォルトである。
-mmad
-mno-mad
r4650 チップの場合のように、madmadumul 命令を使うことを許す。
-m4650
-msingle-float-mmad、それに少なくとも現在のところでは、-mcpu=r4650 を有効にする。
-mips16
-mno-mips16
16ビット命令を有効にする。
-mentry
疑似命令 entry と exit を使う。このオプションは -mips16 を一緒にしか使えない。
-EL
リトルエンディアン・モードのプロセッサ用にコードをコンパイルする。必要となるライブラリが存在すると仮定する。
-EB
ビッグエンディアン・モードのプロセッサ用にコードをコンパイルする。必要となるライブラリが存在すると仮定する。
-G num
num バイト以下の大きさのグローバルなデータ項目と静的なデータ項目を、普通のデータセクションや bss セクションではなく、小データセクションや小 bss セクションに置く。これにより、アセンブラが、通常の 2 命令のメモリ参照の代わりに、グローバルポインタ(gp あるいは $28)に基づいた一命令のメモリ参照を生成することが可能になる。num のデフォルト値は、MIPS のアセンブラを使う場合には 8 で、GNU アセンブラを使う場合には 0 である。-G num オプションはアセンブラとリンカにも渡される。全てのモジュールは、同じ値の -G num でコンパイルしなければならない。
-nocpp
MIPS アセンブラに対し、ユーザのアセンブラソースファイル(サフィックスが.s のもの)をアセンブルするときに、アセンブラのプリプロセッサを実行しないように指示する。

これらのオプションは、マシン記述の TARGET_SWITCHES マクロで定義されている。こられのオプションのデフォルトも、このマクロで定義されているので、デフォルトを変更するが可能である。


Node:i386 Options, Next:, Previous:MIPS Options, Up:Submodel Options

Intel 386 オプション

以下の -m オプションが、i386 シリーズ向けに定義されている。

-mcpu=cpu type
命令スケジューリングを行う際の機種型のデフォルトを cpu type と想定する。cpu type に指定可能な値は以下の通りである。

i386 i486 i586 i686
pentium pentiumpro k6

ある特定の cpu type を選ぶとその特定のチップ向けに適切にスケジューリングを行う一方で、GCC は、-march=cpu type オプションを指定しないと i386 上で動作しないコードは一切生成しない。i586pentium に、i686pentiumpro に同じである。k6 は、Intel のチップに対する AMD のチップである。

-march=cpu type
機種型 cpu type 用の命令を生成する。cpu type に指定できる値は、-mcpu に対するものに同じである。さらに言うなら、-march=cpu type を指定することには、-mcpu=cpu type が含まれる。
-m386
-m486
-mpentium
-mpentiumpro
それぞれ、-mcpu=i386、-mcpu=i486、-mcpu=pentium、-mcpu=pentiumpro の別名である。これらの別名は反対を唱えられている。
-mieee-fp
-mno-ieee-fp
IEEE 浮動小数点比較を使うかどうかを指定する。IEEE 浮動小数点比較を使うと、比較の結果が順序づけられない場合を正しく取り扱える。
-msoft-float
浮動小数点用ライブラリ呼び出しを含む出力を生成する。警告: 必要となるライブラリは GCC の一部ではない。であるわけではない。普通はその機種の通常の C コンパイラの機能が使われるが、クロスコンパイルの場合はこれをそのまま行なうことはできない。クロスコンパイルの場合は、適切なライブラリ関数を自分で用意しなければならない。

関数の浮動小数点の戻り値を 80387 のレジスタ・スタックに置く機種では、-msoft-float が指定された場合でも、いくらか浮動小数点オペコードが出力されることがある。

-mno-fp-ret-in-387
関数の戻り値に対し、FPU レジスタを使わない。

通常の呼出し規約では、FPU が無い場合でも、関数は float 型とdouble 型の値を FPU レジスタで返す。OS が FPU をエミュレートすべきであるという考え方である。

-mno-fp-ret-in-387 オプションを指定すると、代わりに、float 型とdouble 型の値を通常の CPU のレジスタに入れて返す。

-mno-fancy-math-387
387 のエミュレータの中には、387 の sincossqrt 命令をサポートしていないものがある。その場合は、このオプションを指定して、これらの命令を生成しないようにする。このオプションはFreeBSD ではデフォルトになっている。GCC のバージョン 2.6.1 以降は、-ffast-math オプションも指定しない限り、これらの命令は生成されない。
-malign-double
-mno-align-double
double 型、long double 型、long long 型の変数を二語境界に整列するか、一語境界に整列するかを指定する。double 型の変数を二語境界に整列させると、Pentium プロセッサではメモリを余分に食うものの、いくらか高速なコードを生成する。

注意-malign-double を使った場合は、上記の型を含む構造体は、整列の仕方が、386 用アプリケーション・バイナリ・インターフェース仕様書のものとは異なる。

-msvr3-shlib
-mno-svr3-shlib
GCC が非初期化ローカル変数を bss に置くか data に置くかを制御する。-msvr3-shlib を指定すると bss に置く。この二つのオプションは、System V Release 3 でのみ意味がある。
-mno-wide-multiply
-mwide-multiply
GCC が mulimul を使って、32ビットのオペランドからlong long の乗算と定数による 32ビット除算を行って、eax:edx に 64 ビットの結果を生成するかどうかを制御する。
-mrtd
異なる関数呼出し規約を使う。この規約では、決まった数の引数を取る関数はret num 命令で戻る。この命令は、戻るときに引数をポップする。これにより呼出し側で一命令節約できる。呼出し側で引数をポップする必要がないからである。

個々の関数がこの呼出し規約で呼ばれるようにするには関数属性 stdcall を指定すれば良い。また、関数属性 cdecl を使うとを-mrtd オプションを上書きできる。See Function Attributes

注意。この呼出し規約は通常 Unix で使われているものとは互換性がない。このため、Unix のコンパイラでコンパイルされたライブラリを呼び出す必要があるときには使用できない。

また、可変数引数(printf を含む)を取る関数全てに関数プロトタイプを提供しなければならない。そうしないと、それらの関数の呼出しに対し、正しくないコードが生成されてしまう。

さらに、引数がたくさんありすぎる関数を呼び出すと重大な誤りのあるコードが生成される。(普通、引数が余分にある場合は問題なく無視される。)

-mreg-alloc=regs
整数レジスタの割当順序のデフォルトを指定する。文字列 regs は、レジスタを指定する一連の文字である。使用できる文字は次の通り。a は EAX を割り当てる。b は EBX、c は ECX、d は EDX、S はESI、D は EDI、B は EBP を割り当てる。
-mregparm=num
整数引数を渡すのにレジスタを何個使うかを指定する。デフォルトでは、引数を渡すのにはレジスタは一個も使われず、最大でも 3 個のレジスタが使用可能である。ある特定の関数でこの振るまいを変えたいときは、関数属性 regparm を使うことができる。See Function Attributes.

警告:このオプションを指定し、かつ num がゼロでない場合は、どんなライブラリも含めて、全てのモジュールを同じ値で作らなければならない。システムのライブラリとスタートアップモジュールも例外ではない。

-malign-loops=num
ループを 2 の num 乗バイト境界に整列する。-malign-loops が指定されない場合、gas 2.8 以降を使わない限りデフォルトは 2 である。gas 2.8 以降の場合は、デフォルトは、8 バイトより離れていなければ、ループを 16 バイト境界に整列する。
-malign-jumps=num
命令のジャンプ先が 2 の num 乗境界になるように整列する。-malign-jumps を指定しないと、デフォルトは386 で最適化を行う場合は 2 であり、486 については gas 2.8 以降を使わない限り 4 である。gas 2.8 以降の場合は、デフォルトは、8 バイトより離れていなければ、ループを 16 バイト境界に整列する。
-malign-functions=num
関数の開始点を 2 の num 乗バイト境界に整列する。-malign-functions を指定しない場合、デフォルトは、386 用に最適化する場合は 2 で、486 用に最適化する場合は 4 である。
-mpreferred-stack-boundary=num
スタック境界を 2 の num 乗バイト境界に整列している状態を保つことを試みる。-mpreferred-stack-boundary を指定しない場合、デフォルトは 4(16バイトか 128 ビット)である。

スタックは 4 バイト境界に整列させる必要がある。Pentium と PentiumPro では、doublelong double の値は8 バイト境界に整列するべきである。そうしないと、実行時に実行速度のペナルティが非常に大きくなる。Pentium III では、ストリーミング SIMD 拡張(SSE) データ型 __m128 は、16 バイト境界に整列しておかないと同様のペナルティを受ける。

スタック上のこれらの値のアラインメントが適切になることを保証するために、スタック境界は、スタックに格納された任意の値で必要になるだけの大きさのアライメントに整列させる必要がある。さらに、各関数は、スタックのアライメントを保つように生成しなければならない。スタック境界を高くしてコンパイルした関数をスタック境界を低くしてコンパイルした関数から呼び出すのは、ほとんどの場合スタックの整列が正しくなくなる。コールバックを使うライブラリは常にデフォルトの設定を使うことをお奨めする。

アライメントを余分に取れば、スタックスペースも余分に使う。スタックスペースの使用量に注意しなければいけないコード、例えば、組み込みシステムや OS のカーネル等は、-mpreferred-stack-boundary=2 と指定して、好ましいアラインメントを小さくするのが良いだろう。


Node:HPPA Options, Next:, Previous:i386 Options, Up:Submodel Options

HPPA オプション

以下の -m オプションが HPPA シリーズ向けに定義されている。

-march=architecture type
指定されたアーキテクチャ用のコードを生成する。architecture type として使用可能な値は、PA 1.0 に対しては 1.0、PA 1.1 には 1.1、PA 2.0 には2.0 である。HP-UX の /usr/lib/sched.models を参照して、自分の機種用の適切なアーキテクチャのオプションを決めて欲しい。アーキテクチャ番号が小さいもの用にコンパイルされたコードは、大きいアーキテクチャでも動作するが、逆は動作しない。

PA 2.0 のサポートは現在 GAS のスナップショットの 19990413 以降が必要である。binutils の次のリリース(現在は 2.9.1)で、おそらくPA 2.0 のサポートが入るだろう。

-mpa-risc-1-0
-mpa-risc-1-1
-mpa-risc-2-0
それぞれ、-march=1.0-march=1.1-march=2.0 の別名である。
-mbig-switch
大きな switch 文用の表に適したコードを生成する。このオプションは、アセンブラやリンカが switch 文用の表の範囲内の分岐先を越えているという文句を言った場合にのみ使うこと。
-mjump-in-delay
関数呼びだしの遅延スロットを無条件ジャンプ命令で埋める。これは、その関数呼びだしの戻りアドレスポインタを条件ジャンプのターゲットになるように修正することで行なう。
-mdisable-fpregs
どんな形であれ、浮動小数点レジスタを使うのを避ける。これは、浮動小数点レジスタのコンテキスト切替えが遅いカーネルをコンパイルするときに必要になる。このオプションを指定して、かつ、浮動小数点演算を実行すると、コンパイラが異常終了する。
-mdisable-indexing
インデックス付きアドレッシングモードを使うのを避ける。これにより、MACH で MIG により生成されたコードをコンパイルするときの不明瞭な問題を回避できる。
-mno-space-regs
ターゲット機種にスペース・レジスタがないと想定したコードを生成する。これにより、GCC は、より高速な間接呼出しを生成し、スケーリングなしのインデックス付きアドレッシングモードを使えるようにする。

このようなコードは、レベル 0 の PA システムやカーネルに適している。

-mfast-indirect-calls
スペース境界を越えた呼出しはないと想定したコードを生成する。これにより、より高速な間接呼出しを行なうコードを生成するようになる。

このオプションは、共有ライブラリや関数内関数がある場合には正しく動作しない。

-mspace
実行時間よりもメモリ空間を最適化する。現時点では、これは関数プロローグとエピローグをインライン展開しないようにするだけである。このオプションは、PIC 用コード生成とプロファイリングとは互換性がない。
-mlong-load-store
HP-UX 10 のリンカにより必要とされることがある、3命令のロード/ストア命令列を生成する。これは、HP のコンパイラの +k オプションと等価である。
-mportable-runtime
HP の ELF システム向けに提案されているポータブルな呼出し規約を使う。
-mgas
GAS しか認識しないアセンブラ命令を使用することを可能にする。
-mschedule=cpu type
機種 cpu type に対する制限に従ってコードをスケジューリングする。cpu type の取りうる値は、70071007100LC72008000 である。HP-UX システムの /usr/lib/sched.models を参照して、読者の機種に適したスケジューリング・オプションを決めて欲しい。
-mlinker-opt
HP-UX リンカの最適化パスを有効にする。ただし、これによりシンボリックデバッグが出来なくなることに注意。また、HP-UX 8 と HP-UX 9 のリンカにあるバグを引き出してしまう。このバグは、何かのプログラムをリンクするときに正しくないエラーメッセージを出すというものである。
-msoft-float
浮動小数点用ライブラリ呼び出しを含む出力を生成する。警告: 必要となるライブラリは全ての HPPA ターゲットで利用可能であるわけではない。普通はその機種の通常の C コンパイラの機能が使われるが、クロスコンパイルの場合はこれをそのまま行なうことはできない。クロスコンパイルの場合は、適切なライブラリ関数を自分で用意しなければならない。組み込みターゲット hppa1.1-*-pro は、ソフトウェアによる浮動小数点サポートを提供している。

-msoft-float を指定すると、出力ファイル中の呼び出し規約が変わる。このため、プログラム全体をこのオプションでコンパイルしないといけない。特に、GCC 付属のライブラリである、libgcc.a をコンパイルするときに、-msoft-float を指定してコンパイルしないとこのライブラリが正しく動作しない。


Node:Intel 960 Options, Next:, Previous:HPPA Options, Up:Submodel Options

Intel 960 オプション

以下の -m オプションが Intel 960 の実装用に定義されている。

-mcpu type
命令スケジューリング、浮動小数点サポート、アドレッシングモードを含むその他のオプションについて、機種型 cpu type 用のデフォルトを仮定する。cpu type として指定可能なのは、次の通り。kakbmccacfsasb。デフォルトは kb である。
-mnumerics
-msoft-float
-mnumerics オプションは、プロセッサが浮動小数点命令をサポートしていることを指示する。-msoft-float オプションは、浮動小数点サポートを想定してはならないということを指示する。
-mleaf-procedures
-mno-leaf-procedures
call 同様 bal 命令でも呼出し可能になるように末端プロシージャを修正することを試みる(試みない)。これは、bal 命令がアセンブラやリンカで置き換え可能な場合は明示的な呼出しについてはコードの効率が良くなる。しかし、それ以外の場合、例えば関数ポインタ経由の呼出しや、このような最適化をサポートしていないリンカを使う場合にはコードの効率が悪くなる。
-mtail-call
-mno-tail-call
末尾再帰呼出しを分岐に最適化するのを追加で(GCC の機種独立部で行うもの以外に)試みる。読者はこれをやらない方が良いだろう。これが有効でない場合を検出するのがまだ完全ではないからである。デフォルトは -mno-tail-call である。
-mcomplex-addr
-mno-complex-addr
複雑なアドレッシングモードを使うのは、使用している i960 の実装では、良い結果が得られるということを想定する(想定しない)。複雑なアドレッシングモードは K シリーズでは価値がないが、C シリーズでは条件付きで有効である。現在のデフォルトは、CB と CC 以外の全てのプロセッサでは-mcomplex-addr になる。
-mcode-align
-mno-code-align
高速なフェッチのために 8 バイト境界にコードを整列させる(あるいは、気にしない)。現在のところ、デフォルトで有効になるのは、C シリーズの実装の場合だけである。
-mic-compat
-mic2.0-compat
-mic3.0-compat
iC960 の v2.0 や v3.0 と互換性を有効にする。
-masm-compat
-mintel-asm
iC960 アセンブラとの互換性を有効にする。
-mstrict-align
-mno-strict-align
整列していないアクセスを許さない(許す)。
-mold-align
構造体のアラインメントについて、Intel 版 GCC のバージョン 1.3(gcc 1.37ベース) との互換性を有効にする。このオプションには、-mstrict-align も含まれる
-mlong-double-64
long double 型を 64 ビット浮動小数点数として実装する。このオプションを指定しない場合、long double は 80 ビット浮動小数点数で実装される。このオプションが存在する唯一の理由は、fp-bit.c にはまだ 128 ビットの long double サポートがないからである。このため、ソフトウェアによる浮動小数点演算を行うターゲットを使用する人にしか役に立たない。それ以外の場合は、使わないようにお奨めしなければならない。


Node:DEC Alpha Options, Next:, Previous:Intel 960 Options, Up:Submodel Options

DEC Alpha オプション

以下の -m オプションが、DEC Alpha の実装向けに定義されている。

-mno-soft-float
-msoft-float
浮動小数点演算に対してハードウェア浮動小数点命令を使う(使わない)。-msoft-float を指定すると、libgcc1.c にある関数が浮動小数点演算を実行するのに使われる。浮動小数点演算をエミュレートするルーチンで置き換えるか、そのようなエミュレートを行うルーチンを呼び出すようにコンパイルされるかしない限り、これらのルーチンは浮動小数点演算を発行する。浮動小数点演算なしの Alpha ようにコンパイルを行うなら、ライブラリがそれらのルーチンを呼び出さないように構築されることを保証しなければならない。

浮動小数点演算なしの Alpha の実装でも浮動小数点レジスタが必要であることに注意。

-mfp-reg
-mno-fp-regs
浮動小数点レジスタセットを使う(使わない)コードを生成する。-mno-fp-regs を指定すると -msoft-float が暗黙に指定される。浮動小数点レジスタセットが使われない場合、浮動小数点オペランドはそれが整数であるかのように整数レジスタに入れて渡され、浮動小数点の結果は$f0 の代わりに $0 で返される。これは標準の呼出しシーケンスとは違うので、-mno-fp-regs 付きでコンパイルしたコードから呼び出される関数で、浮動小数点引数や戻り値を持つものもまた、このオプションを指定してコンパイルしなければならない。

このオプションが使われるのは、普通は、浮動小数点レジスタを使わず、それゆえに浮動小数点レジスタをセーブ/リストアする必要のないカーネルを構築するときである。

-mieee
Alpha アーキテクチャは、浮動小数点用ハードウェアを最大の性能を出すように最適化して実装している。この実装は、IEEE 浮動小数点規格にほぼ準拠している。だが、完全に準拠するには、ソフトウェアによる補助が必要である。このオプションにより、inexact flag が保持されない(下記参照)という点を除いて、IEEE に完全に準拠したコードを生成する。このオプションが有効になっていると CPP マクロ _IEEE_FP がコンパイル時に定義される。このオプションは、-D_IEEE_FP -mfp-trap-mode=su -mtrap-precision=i -mieee-conformant の省略形である。この結果生成されるコードは幾らか効率が落ちるが、非正規化数と、非数と正負の無限大のような IEEE の例外値を正しくサポートできる。他の Alpha 用コンパイラはこのオプションを -ieee_with_no_inexact と呼んでいる。
-mieee-with-inexact
これは -mieee と同様だが、生成されたコードは IEEE の inexact flag の維持も行う。このオプションを有効にすると、生成されたコードは完全に準拠した IEEE の数学演算を実装することになる。このオプションは、-D_IEEEFP -D_IEEE_FP_INEXACT に加えて、-mieee-conformant-mfp-trap-mode=sui-mtrap-precision=i の三つのオプションを指定したものの省略形である。Alpha の実装の中にはこうして得られたコードが、デフォルトで生成されるコードよりも非常に遅くなるものがある。inexact flag に依存するようなコードは滅多にないので、このオプションを普通は指定しなくて良いはずである。他の Alpha 用コンパイラはこのオプションを-ieee_with_inexact としている。
-mfp-trap-mode=trap mode
このオプションは、どの浮動小数点関係のトラップを有効にするかを扱う。他の Alpha 用コンパイラでは、-fptmtrap mode と言っているものである。trap mode には以下の四つの値のうち一つを設定可能である。
n
これはデフォルト(通常、normal)の設定である。有効になるトラップは、ソフトウェアでは無効にできないもの(例えば、ゼロによる除算)だけである。
u
n で有効になるトラップに加えて、アンダーフローによるトラップが有効になる。
su
u と同様だが、命令は、ソフトウェア補完(詳細については、Alpha のアーキテクチャマニュアルを参照のこと)に対して安全であるとの印がつけられる。
sui
su と同様だが、不正確なトラップも同じく有効になる。

-mfp-rounding-mode=rounding mode
IEEE の丸めモードを選択する。他の Alpha 用コンパイラでは、-fprmrounding mode と言っているものである。rounding mode は以下のどれか一つである。
n
通常の IEEE 丸めモード。浮動小数点数は最近のハードウェアで表現できる数に向かって丸められる。二つの数のちょうど中間の場合は偶数の方に向かって丸められる。
m
負の無限大に向かって丸める。
c
切り捨て丸めモード。浮動小数点数はゼロに向かって丸められる。
d
動的丸めモード。浮動小数点制御レジスタ(fpcr、Alpha アーキテクチャ参照マニュアルを参照のこと)中のあるフィールドが有効になる丸めモードを制御する。C ライブラリは、このレジスタを正の無限大に向かって丸めるモードに初期化する。このため、プログラムで fpcr を変更しない限り、d は正の無限大に向かっての丸めに対応する。

-mtrap-precision=trap precision
Alpha アーキテクチャでは、浮動小数点トラップは不正確である。これは、ソフトウェアの助けを借りなくては、浮動小数点トラップから回復するのが不可能であり、プログラムの実行は普通は終了させる必要があるといことを意味する。GCC は OS のトラップ・ハンドラを助けるコードを生成し、浮動小数点トラップが発生した正確な位置を特定することを可能にする。アプリケーションの要求に応じて、正確さのレベルを以下から選択することができる。
p
プログラム精度。このオプションはデフォルトであり、トラップハンドラはどのプログラムが浮動小数点例外を引き起こしたかしか特定できないことを意味する。
f
関数精度。トラップハンドラは浮動小数点例外を引き起こした関数を決定することができる。
i
命令精度。トラップハンドラは浮動小数点例外を引き起こした命令そのものを決定できる。

他の Alpha 用コンパイラは、これらに等価なオプション -scope_safe-resumption_safe を用意している。

-mieee-conformant
このオプションは、生成されたコードに IEEE に適合しているとのマークを付ける。このオプションを使うときは、-mtrap-precision=iと、-mfp-trap-mode=su-mfp-trap-mode=sui のどちらかを指定しなければならない。このオプションの効果は、生成されたアセンブリファイルの関数プロローグ部に .eflag 48 という行を一行加えるだけである。DEC Unix では、これには、 IEEE適合数学ライブラリルーチンがリンクされるという効果がある。
-mbuild-constants
通常 GCC は、32 ビットまたは 64 ビットの整数定数について、それがより小さな定数から二つまたは三つの命令で構築できるかどうかを調べる。それが出来ない場合は、その定数をそのまま出力し、実行時にデータ・セグメントからをロードするコードを生成する。

このオプションを使うと GCC は、たとえ、さらに命令数が増えることになっても(最大で6個)、全ての整数定数を命令コードで構築する。

このオプションを使う代表的な場合は、共有ライブラリの動的ローダを構築するときである。動的ローダはそれ自身共有ライブラリであり、変数や定数を自分自身のデータセグメントから見つけられるようになる前に、メモリ中で自分自身を再配置しなければならない。

-malpha-as
-mgas
ベンダ提供のアセンブラによりアセンブルされるコードを生成する(-malpha-as)か、GNU アセンブラ(-mgas)にアセンブルされるコードを生成するかを選択する。
-mbwx
-mno-bwx
-mcix
-mno-cix
-mmax
-mno-max
オプションの命令セット、BWX、CIX、MAX を使うコードを生成するようGCC に指示する。デフォルトは、-mcpu= オプションで指定したCPU 型でサポートされている命令セットか、何も指定されない場合はGCC の構築を行った CPU のものになる。
-mcpu=cpu_type
命令セット、レジスタセット、命令スケジューリング・パラメータを機種 cpu_type 用に設定する。EV 形式の名前を指定することもできるし、それに対応する CPU チップ番号を指定することもできる。GCC は、EV4 と EV5 シリーズのプロセッサ用のスケジューリング・パラメータをサポートしており、命令セットのデフォルト値はユーザが指定したプロセッサから選択する。プロセッサ型を指定しない場合は、GCC は、GCC の構築を行ったプロセッサをデフォルトにする。

cpu_type の値として使えるのは以下の通り。

ev4
21064
EV4 としてスケジューリングを行ない、命令セットの拡張はないものとする。
ev5
21164
EV5 としてスケジューリングを行ない、命令セットの拡張はないものとする。
ev56
21164a
EV5 としてスケジューリングを行ない、BWX 拡張をサポートする。
pca56
21164pc
21164PC
EV5 としてスケジューリングを行ない、BWX と MAX 拡張をサポートする。
ev6
21264
EV5 としてスケジューリングを行ない(DEC が EV6 用のスケジューリングパラメータを発表するまでは)、BWX、CIX、MAX 拡張をサポートする。

-mmemory-latency=time
アプリケーションから見える典型的なメモリ参照に対し、スケジューラが想定すべきレイテンシを設定する。この数は、アプリケーションが使うメモリアクセスパタンと外部キャッシュの大きさに非常に依存する。

time として有効な値は以下の通りである。

number
クロック数を表す 10進数。
L1
L2
L3
main
GCC は、「典型的な」 EV4 と EV5 のハードウェアについては、レベル1、2、3 のキャッシュを持つ場合についてのクロックサイクル数の見積値を、主記憶にたいするものと同様に保持している。L3 は EV5 に対してのみ有効であることに注意。


Node:Clipper Options, Next:, Previous:DEC Alpha Options, Up:Submodel Options

Clipper オプション

以下の -m オプションが、Clipper の実装用に定義されている。

-mc300
C300 Clipper プロセッサ用のコードを生成する。これがデフォルトである。
-mc400
C400 Clipper プロセッサ用のコードを生成する。すなわち、浮動小数点レジスタ f8..f15 を使用する。


Node:H8/300 Options, Next:, Previous:Clipper Options, Up:Submodel Options

H8/300 オプション

以下の -m オプションが、H8/300 の実装用に定義されている。

-mrelax
リンク時に幾つかのアドレス参照を可能であれば短くする。リンカの -relax オプションを使う。より詳しい説明については、See H8/300, を参照。
-mh
H8/300H 用のコードを生成する。
-ms
H8/S 用のコードを生成する。
-mint32
int 型のデータをデフォルトで 32 ビットにする。
-malign-300
h8/300h で、h8/300 と同じアラインメント規則を使う。h8/300h のデフォルトでは、long と float は 4 バイト境界に整合する。-malign-300 は、それらを 2 バイト境界に整合する。このオプションは、h8/300 では何の効果もない。


Node:SH Options, Next:, Previous:H8/300 Options, Up:Submodel Options

SH オプション

以下の -m オプションが、SH の実装用に定義されている。

-m1
SH1 用のコードを生成する。
-m2
SH2 用のコードを生成する。
-m3
SH3 用のコードを生成する。
-m3e
SH3e 用のコードを生成する。
-mb
ビッグエンディアン・モードのプロセッサ用にコードをコンパイルする。
-ml
リトルエンディアン・モードのプロセッサ用にコードをコンパイルする。
-mdalign
double 型を 64 ビット境界に整列する。これは呼出し規約を変えてしまうので、標準 C ライブラリの中のいくつかの関数は、まず -mdalign を指定して再コンパイルしておかないと動作しないだろう。
-mrelax
リンク時に幾つかのアドレス参照を可能であれば短くする。リンカの -relax オプションを使う。


Node:System V Options, Next:, Previous:SH Options, Up:Submodel Options

System V 向けオプション

以下のオプションが System V Release 4 では追加で使える。これらは、System V Relase 4 システムの他のコンパイラとの互換性のためにある。

-G
共有オブジェクトを作る。代わりに -symbolic-shared を使うことが推奨される。
-Qy
コンパイラが使用する各ツールのバージョンを、アセンブラ命令 .ident に入れて出力する。
-Qn
.ident 命令を出力ファイルに追加するのを止める(これがデフォルトである)。
-YP,dirs
-l で指定されたライブラリについてディレクトリ dirs だけを検索し、他の場所を検索しない。
-Ym,dir
プリプロセッサ M4 をディレクトリ dir から探す。アセンブラがこのオプションを使用する。


Node:TMS320C3x/C4x Options, Next:, Previous:System V Options, Up:Submodel Options

TMS320C3x/C4x オプション

以下の -m オプションが、TMS320C3x/C4x の実装用に定義されている。


-mcpu=cpu_type
機種型 cpu_type 用の命令セット、レジスタセット、命令スケジューリングのパラメータを設定する。cpu_type の値として使えるのは、c30c31c32c40c44 である。デフォルトは c40 であり、TMS320C40 用のコードを生成する。
-mbig-memory
-mbig
-msmall-memory
-msmall
ビッグ・メモリ・モデルあるいはスモール・メモリ・モデル向けのコードを生成する。スモール・メモリ・モデルでは、全てのデータが一個の 64K語ページに収まると想定する。実行時には、データページ(DP)レジスタが、.bss と .data セクションを含むその 64K ページを指すように設定されていなければならない。ビッグ・メモリ・モデルがデフォルトであり、直接的なメモリアクセス毎に DP レジスタの再ロードを必要とする。
-mbk
-mno-bk
一般的な整数オペランドをブロックカウントレジスタ BK に割り当てることを許す(許さない)。
-mdb
-mno-db
デクリメントして分岐、すなわち DBcond(D) 命令を使うコードの生成を有効にする(無効にする)。C4x ではデフォルトで有効になる。安全のために C3x では無効になっている。C3x での最大繰り返し回数は2^23+1だからである。(でも一体誰が C3x で 2^23 回以上ループを繰り返すだろうか?) GCC は、ループを逆順に回して、デクリメントして分岐命令をなるべく使えるようにするが、ループの中にメモリ参照が複数回ある場合はあきらめてしまう。つまり、RPTB 命令が利用できないループカウンタがデクリメントされるループの場合でも、幾らか効率の良いコードを生成することが可能になる。
-mdp-isr-reload
-mparanoid
DP レジスタを、割り込みサービスルーチン(ISR) の入り口点でセーブし、データセクションを指すように再ロードし、ISR の出口点でリストアすることを強制する。これは、だれかが、例えばあるオブジェクトライブラリ内で、DP レジスタを変更することで小メモリモデルに違反しない限り、必要とすべきではない。
-mmpyi
-mno-mpyi
C3x に対しては、整数の乗算にはライブラリ呼出しの代わりに24 ビット MPYI 命令を使い、32ビットの結果を保証する。オペランドの一つが定数なら、この乗算はシフトと加算を使って実行されることに注意。C3X の場合に -mmpyi オプションを指定しないと、ライブラリ呼出しの代わりに、平方演算がインラインで行われる。
-mfast-fix
-mno-fast-fix
浮動小数点値を整数値に変換する C3x/C4x の FIX 命令で、その浮動小数点値に最も近い整数ではなく、浮動小数点値以下の最も近い整数を選ぶ。このため、浮動小数点値が負なら、結果が不正に打ち切られるので、それを検出して補正するコードが追加で必要になる。このオプションを使うと、結果の補正に必要な追加コードの生成を無効にすることができる。
-mrptb
-mno-rptb
オーバヘッド無しのループ化のために、RPTB 命令を使った繰り返しブロック列を生成することを有効にする。RPTB 構文は、最内側のループで、関数呼出しやループ境界を越えるジャンプがない場合にだけ使われる。RPTB ループを入れ子にするのは、RC、RS、RE レジスタをセーブ/リストアするのに必要なオーバーヘッドがあるので、利点はない。これは、-O2 を指定した場合にデフォルトで有効になる。
-mrpts=count
-mno-rpts
一個の命令を繰り返す命令 RPTS を使うことを有効にする(無効にする)。繰り返しを行うブロックに命令が一個あり、ループ回数が count 未満であることが保証可能なら、GCC は RPTB の代わりに RPTS 命令を生成する。値を指定しない場合は、ループ回数がコンパイル時に決定できなくてもRPTS が生成される。RPTS に続く繰り返される命令は、各繰り返しでメモリから再ロードする必要はないので、オペランドに対して CPU バスを解放する。ただし、割り込みはこの命令によりブロックされるので、デフォルトでは無効になっている。
-mloop-unsigned
-mno-loop-unsigned
RPTS と RPTB(それに C40 の場合は DBも)を使うときの最大の繰り返し回数は2^23 + 1 である。これらの命令は、繰り返し回数が負であるかどうかをテストして、ループを終了させるからである。繰り返し回数が符号無しであれば、最大繰り返し回数が 2~23 + 1 を越える可能性がある。このオプションは符号無しの繰り返し回数を許す。
-mti
TI アセンブラ(asm30) 向けのアセンブラ構文を出力する。また、TI C3x C コンパイラで採用されている API との互換性も強要する。例えば、long double 型は浮動小数点レジスタに入れてではなく構造体として渡される。
-mregparm
-mmemparm
関数に引数を渡すのにレジスタ(スタック)を使うコードを生成する。デフォルトでは、引数は可能な所では、スタックに引数をプッシュするのではなく、レジスタで渡される。
-mparallel-insns
-mno-parallel-insns
並列命令の生成を許す。-O2 を指定した場合はデフォルトで有効になる。
-mparallel-mpy
-mno-parallel-mpy
-mparallel-insns も指定されている場合に、並列命令 MPY||ADD と MPY||SUB の生成を許す。これらの命令はレジスタの制約がきついので、大きな関数のコード生成をやりにくくする。


Node:V850 Options, Next:, Previous:TMS320C3x/C4x Options, Up:Submodel Options

V850 オプション

以下の -m オプションが V850 の実装用に定義されている。

-mlong-calls
-mno-long-calls
全ての呼出しを遠い(近い)呼出しとして扱う。呼出しが遠いと想定された場合、GCC は常に、関数のアドレスをレジスタにロードし、そのポインタを経由した間接呼出しを行なう。
-mno-ep
-mep
ポインタを ep レジスタにコピーするのに、同じインデックスポインタを、4回以上使っている基本ブロックの最適化を行なわない(最適化を行なう)。最適化を行なう場合は、デフォルトで -mep が有効になる。
-mno-prolog-function
-mprolog-function
関数のプロローグとエピローグでレジスタをセーブ/リストアするのに、外部関数を使わない(使う)。外部関数は遅いが、複数の関数が同じ数のレジスタをセーブするなら、コードサイズは小さくなる。-mprolog-function オプションは、最適化を行なう場合はデフォルトで有効になる。
-mspace
可能な限りコードを小さくすることを試みる。現時点では、これは-mep オプションと -mprolog-function オプションをオンにするだけである。
-mtda=n
static 変数またはグローバル変数のうち、大きさが n バイト以下のものを、ep レジスタが指し示す、微小データ領域に置く。この微小なデータ領域は、全部で 256 バイトまで保持できる(バイト参照毎に 128 バイトである)。
-msda=n
static 変数またはグローバル変数のうち、大きさが n バイト以下のものを gp レジスタが指し示す、小さなデータ領域に置く。この小さなデータ領域には、64Kバイトまで保持できる。
-mzda=n
static 変数またはグローバル変数のうち、大きさが n バイト以下のものをメモリの先頭の 32Kバイトの領域に置く。
-mv850
ターゲットプロセッサが V850 であることを指定する。
-mbig-switch
大きな switch 文用の表に適したコードを生成する。このオプションは、アセンブラやリンカが、switch 文用の表内の分岐範囲を越えているというメッセージを出したときにのみ使うこと。


Node:ARC Options, Next:, Previous:V850 Options, Up:Submodel Options

ARC オプション

以下のオプションが ARC 実装用に定義されている。

-EL
リトルエンディアンモード用にコードをコンパイルする。これがデフォルトである。
-EB
ビッグエンディアンモード用にコードをコンパイルする。
-mmangle-cpu
CPU 名を全ての公開シンボル名の先頭に付加する。マルチプロセッサシステムでは、異なる命令とレジスタセット特性を持つ多数の ARC の変種が存在する。このフラグは一つの CPU 用にコンパイルされたコードが他の CPU 用にコンパイルされたコードとリンクするのを防ぐ。「ほとんど同じ」である変種を扱う機能は存在しない。これは、全てか全くなしかのオプションである。
-mcpu=cpu
ARC の変種 cpu 用のコードをコンパイルする。どの変種がサポートされるかはコンフィギュレーションに依存する。全ての変種が -mcpu=base をサポートしており、これがデフォルトである。
-mtext=text section
-mdata=data section
-mrodata=readonly data section
関数、データ、読み出し専用データをデフォルトでそれぞれ、text sectiondata sectionreadonly data section に置く。これは、section 属性で上書き可能である。See Variable Attributes


Node:NS32K Options, Previous:ARC Options, Up:Submodel Options

NS32K オプション

以下の -m オプションが 32000 シリーズ向けに定義されている。これらのオプションのデフォルト値は、GCC のコンフィギュレーション時に32000 のどの型が選択されたかに依存する。最も共通する選択向けのデフォルト値は以下に示されている。

-m32032
-m32032
32032 用の出力を生成する。これは、GCC が 32032 や 32016 ベースのシステム用にコンフィギュレーションされたときのデフォルトである。
-m32332
-m32332
32332 用の出力を生成する。これは、GCC が 32332 ベースのシステム用にコンフィギュレーションされたときのデフォルトである。
-m32532
-m32532
32532 用の出力を生成する。これは、GCC が 32532 ベースのシステム用にコンフィギュレーションされたときのデフォルトである。
-m32081
浮動小数点用の 32081 命令を含む出力を生成する。これは、全てのシステムでデフォルトである。
-m32381
浮動小数点用の 32381 命令を含む出力を生成する。これは -m32081 も含む。32381 は、32332 と 32532 という CPU とのみ互換である。これは、 pc532-netbsd のコンフィギュレーションのデフォルトである。
-mmulti-add
乗算-加算浮動小数点命令 polyFdotF を生成する。このオプションは、-m32381 オプションが有効になっている場合にのみ使用できる。これらの命令を使うには、一般には性能に悪い影響を与えるような、レジスタ割当の変更を必要とする。このオプションは、特に乗算-加算命令を大量に使いそうなコードをコンパイルするときにだけ有効にすべきだろう。
-mnomulti-add
乗算-加算浮動小数点命令 polyFdotF を生成しない。これは全てのプラットフォームでのデフォルトである。
-msoft-float
浮動小数点ライブラリ呼出しを含む出力を生成する。注意。必要なライブラリが利用可能でない場合がある。
-mnobitfield
ビットフィールド命令を使わない。幾つかの機種では、シフト演算とマスク演算を使ったほうが高速である。これは pc532 のデフォルトである。
-mbitfield
ビットフィールド命令を使う。これは、pc532 以外の全てのプラットフォームでデフォルトである。
-mrtd
異なる関数呼出し規約を使う。この規約では、決まった数の引数を取る関数はret num 命令で戻る。この命令は戻る際に引数をポップする。

この呼出し規約は通常 Unix で使われているものとは互換性がない。このため、Unix のコンパイラでコンパイルされたライブラリを呼び出す必要があるときには使用できない。

また、可変数引数(printf を含む)を取る関数全てに関数プロトタイプを提供しなければならない。そうしないと、それらの関数の呼出しに対し、正しくないコードが生成されてしまう。

さらに、引数がたくさんありすぎる関数を呼び出すと重大な誤りのあるコードが生成される。(普通、引数が余分にある場合は問題なく無視される。)

このオプションの名前は、680x0 の rtd 命令から取ったものである。

-mregparam
異なる関数呼出し規約を使う。この規約では、先頭の二つの引数をレジスタで渡す。

この呼出し規約は通常 Unix で使われているものとは互換性がない。このため、Unix のコンパイラでコンパイルされたライブラリを呼び出す必要があるときには使用できない。

-mnoregparam
どの引数もレジスタでは渡さない。これは全てのターゲットでのデフォルトである。
-msb
常にゼロがロードされるインデックス・レジスタとして sb を使えるようになる。これは、pc532-netbsd ターゲットのデフォルトである。
-mnosb
sb レジスタは利用できないか、あるいは実行時システムでゼロに初期化されない。これは、pc532-netbsd 以外の全ての機種のデフォルトである。このオプションは、-mhimem-fpic が指定されているときは常に暗黙に含まれる。
-mhimem
ns32000 シリーズのアドレッシングモードの多くは、512MB までの変位を使っている。アドレスが、512MB を越えると、ゼロからの変位は使えない。このオプションは、512MB を越えてロード可能なコードを生成させる。これは、OS や ROM コードで役に立つだろう。
-mnohimem
コードが、仮想アドレス空間の先頭の 512 MB 内にロードされると想定する。これは、全てのプラットフォームでのデフォルトである。


Node:Code Gen Options, Next:, Previous:Submodel Options, Up:Invoking GCC

コード生成規約についてのオプション

以下は、機種独立のオプションで、コード生成において使われるインターフェース規約を制御する。

以下のほとんどのオプションには肯定形と否定形の両方の形式がある。-ffoo の否定形は -fno-foo である。以下の表では、どちらか一方の形しか列挙していない。デフォルトでないほうを列挙している。もう一方の形式は、no- を取り除くか、追加すれば良い。

-fexceptions
例外処理を有効にする。例外を伝えるのに必要な余分のコードを生成する。ターゲットによっては、この事は、すべての関数に対してフレームの巻き上げを生成することを意味する。これによりデータサイズが著しく大きくなるというオーバーヘッドが発生し得るが、実行には影響を与えない。このオプションを指定しない場合、C++ のような、例外処理を普通必要とする言語に対してはデフォルトで有効にし、C のような、普通必要としない言語については無効にする。ただし、C++ で書かれた例外ハンドラと正しく相互作用する必要のある C のコードをコンパイルするときは、このオプションを有効にする必要がある。また、例外処理を使っていない、古い C++ プログラムをコンパイルするときには、このオプションを無効にして良い。
-fpcc-struct-return
「小さい」 structunion の値を、レジスタではなく、大きなものの場合と同様にメモリに入れて返す。この規約は効率では劣るが、GCC でコンパイルしたファイルと他のコンパイラでコンパイルしたファイルの間で相互に呼び出しが可能になるという利点がある。

構造体をメモリに入れて返す規約の詳細は、ターゲットのコンフィギュレーションマクロに依存する。

小さい構造体、共用体とは、その大きさとアラインメントが整数型のどれかに一致するものである。

-freg-struct-return
structunion の値を可能な場合にはレジスタで返す規約を使う。この方法は、小さな構造体については -fpcc-struct-return よりも効率が良い。

-fpcc-struct-return もその逆の -freg-struct-return も指定しない場合は、ターゲットで標準の規約がデフォルトとなる。標準の規約がない場合は、GCC が標準のコンパイラであるターゲットを除いて、-fpcc-struct-return をデフォルトとする。GCC が標準のコンパイラである場合には、我々に標準の規約を選ぶ権利があるので、効率の良い、レジスタで返すほうを選ぶ。

-fshort-enums
enum 型に対して、その型で宣言されている可能な範囲の値を表すのに必要なバイト数しか割り当てない。もっと正確に言えば、その場合の enum 型は、それを収めるのに充分で、かつ、最小の整数型に同じである。
-fshort-double
double のサイズとして float と同じサイズを使う。
-fshared-data
データおよび非const 変数を、プライベートなデータとするのでなく、共有データとすることを要求する。このことによる違いは、共有データは同一のプログラムを実行する複数のプロセス間で共有されるが、プライベートなデータは、プロセス毎にコピーを持つような、特定のOS の元でしか意味を持たない。
-fno-common
非初期化グローバル変数について、コモンブロックとして生成するのではなく、オブジェクトファイルの bss セクションに割り当てる。これにより、同じ変数が二つの異なるコンパイル単位で(extern なしで) 宣言されていると、リンク時にエラーとなる。これが唯一役に立つのは、常にこのような動作をする他のシステムでのプログラムの動作を検証したいときだろう。
-fno-ident
#ident 制御子を無視する。
-fno-gnu-linker
グローバルの初期化子(C++ のコンストラクタやデストラクタ等)をGNU リンカで使われている形式で出力しない(GNU リンカが初期化子を取り扱う標準の方法となっているシステムの場合)。GNU リンカでないリンカを使いたいときはこのオプションを指定する。このとき、collect2 プログラムを使って、システムのリンカがコンストラクタとデストラクタを取り込むようにすることも必要となる。(collect2 は GCC の配布物に含まれている。) collect2 を使わなければならないシステムに対しては、コンパイラドライバである gcc は自動的にそうするようにコンフィギュレーションされる。
-finhibit-size-directive
アセンブラ命令 .size や、あるいは関数が途中で分割され、分割された二つの部分がメモリ中で離れた場所に置かれた場合に問題となるようなものを出力しない。このオプションは crtstuff.c をコンパイルするときに使われる。その他の場合には必要ないはずである。
-fverbose-asm
生成されたアセンブリコードに余分の注釈情報を加えて、読みやすくする。このオプションは、一般に、生成されたアセンブリコードを実際に読む必要がある人向けのものである(おそらく、本コンパイラ自体をデッバグするときに...)。

デフォルトの -fno-verbose-asm は、余分の情報を出さず、二つのアセンブラファイルを比較するときは便利である。

-fvolatile
ポインタを経由する全てのメモリ参照を揮発性と考える。
-fvolatile-global
外部データとグローバルデータに対する全てのメモリ参照を揮発性と考える。GCC は、このオプションを指定しても、静的データ項目が揮発性であるとは考えない。
-fvolatile-static
静的データに対する全てのメモリ参照を揮発性と考える。
-fpic
共有ライブラリで使うのに適した位置独立コード(PIC)を、ターゲットがサポートしていれば、生成する。これで生成したコードは、全ての定数アドレスをグローバルオフセット表(GOT)を通してアクセスする。動的ローダがプログラムの起動時に GOT のエントリを解決する(動的ローダは GCC の一部ではない。オペレーティングシステムの一部である)。リンクされた実行形式の GOT の大きさが、機種固有の最大値を越えた場合は、-fpic が動作しないということを示すエラーメッセージをリンカが出す。その場合、代わりに -fPIC を使って再コンパイルすること。(この最大値は、m88k では 16k、SPARC では 8k、m68k と RS/6000 では32k である。386 にはこの制限はない。)

位置独立コードは特別なサポートを必要とし、そのために一定の機種でしか動作しない。386 の場合は、GCC は System V については PIC をサポートしているが、Sun 386i についてはサポートしていない。IBM RS/6000 向けに生成されたコードは常に位置独立である。

-fPIC
ターゲット機種でサポートされていれば、位置独立コードを出力する。位置独立コードは動的リンクに適したもので、グローバルオフセット表の大きさについての制限がない。このオプションは、m68k、m88k、SPARC で違いが出る。

位置独立コードは特別なサポートを必要とし、そのために一定の機種でしか動作しない。

-ffixed-reg
reg で指定されたレジスタを固定レジスタとして扱う。生成されたコードは決してそのレジスタを参照してはならない(スタックポインタやフレームポインタやその他の決まった役割を持つものとして参照する場合を除く)。

reg はレジスタの名前でなければならない。受け付けるレジスタ名は機種依存であり、マシン記述マクロファイルの REGISTER_NAMES というマクロで定義される。

このオプションには否定形がない。三つの選択肢のうちの一つを指定するからである。

-fcall-used-reg
reg で指定されたレジスタを関数呼び出しにより破壊される、割当可能なレジスタとして扱う。このレジスタは、一時的な作業用や関数呼び出しを越えて生存しない変数に割り当てられる可能性がある。このオプションを付けてコンパイルされた関数は、レジスタ reg のセーブとリストアを行なわない。

このフラグをフレームポインタやスタックポインタに対して使うのは誤りである。このフラグを、その他の、マシンの実行モデルにおいて固定した広く知られている役割を持つレジスタに対して使うと、破壊的な結果をもたらす。

このオプションには否定形がない。三つの選択肢のうちの一つを指定するからである。

-fcall-saved-reg
reg という名前のレジスタを関数によりセーブされる割当可能なレジスタとして取り扱う。一時的なものや呼び出しを越えて生存する変数に対しても割り当てられる。こうしてコンパイルされた関数は、もし reg を使っていれば、それをセーブ/リストアする。

このフラグをフレームポインタやスタックポインタに対して使うのは誤りである。このフラグを、その他の、マシンの実行モデルにおいて固定した広く知られている役割を持つレジスタに対して使うと、破壊的な結果をもたらす。

このフラグを関数の戻り値を入れるレジスタに対して使うと、別の種類の破壊的な結果になる。

このオプションには否定形がない。三つの選択肢のうちの一つを指定するからである。

-fpack-struct
構造体のメンバを全て穴の無いように詰め込む。普通はこのオプションを使うことはないだろう。コードの効率が落ちるし、構造体メンバのオフセットがシステムライブラリのものと一致しなくなるからである。
-fcheck-memory-usage
各メモリ参照を検査するために余分なコードを生成する。GCC は、Checker のような、不正なメモリ参照を検知するプログラムに適したコードを生成する。

普通は、この全てのコードをこのオプションを付けてコンパイルするか、あるいは全く付けずにコンパイルする必要がある。

このオプションを付けてコンパイルしたコードと付けないでコンパイルしたコードを混ぜる場合は、副作用があり、かつ、このオプションを付けてコンパイルしたコードから呼び出される全てのコードは、それ自身、このオプションを付けてコンパイルされることを保証しなければならない。

ライブラリ関数のうち副作用のあるもの(例えば、read)を使うときは、このオプションを指定してそのライブラリ関数を再コンパイルする訳にはいかないこともあるだろう。その場合は、-fprefix-function-name オプションを指定して、読者のコードを包み込み、他の関数があたかも-fcheck-memory-usage オプションつきでコンパイルされたかのようにすることを GCC に要求する。これは、「スタブ」を呼び出すことによて行なわれる。スタブは検知器により提供される。読者の呼び出しているあらゆる関数に対してスタブを見つけたり、構築することが不可能な場合は、-fprefix-function-name オプションなしで -fcheck-memory-usage を指定する必要がある。

このオプションを指定するときは、メモリ検査を有効にした関数内でasm__asm__ というキーワードを使うことはできない。GCC は asm 文が行うことを理解できず、そのため適切なコードが生成できないので、拒絶される。ただし、関数属性no_check_memory_usage を付けると関数内のメモリ検査が無効になり、asm 文をそういう関数内に置くことが可能になる。検査された関数内で検査無しの関数をインライン展開するのは許されている。インライン関数でのメモリアクセスは検査されないが、その結果検査される。

読者の asm 文を検査無しのインライン関数に移動するが、それらがメモリをアクセスするなら、インライン関数内のサポートコードの呼出しを追加して、任意の読み出し、書き出し、コピーが行われることを指示することができる。これらの呼出しは、上で説明したスタブで行われるものに似たものになるだろう。

-fprefix-function-name
関数名に対して生成されたシンボルにプレフィックスを付けることを GCC に要求する。プレフィックスは関数の定義だけでなく関数呼び出し側にも付けられる。このオプション付きでコンパイルしたコードとこのオプションなしでコンパイルしたコードはスタブを使わない限り、一緒にリンクすることはできない。

以下のコードを -fprefix-function-name 付きでコンパイルすると

extern void bar (int);
void
foo (int a)
{
  return bar (a + 5);
}

GCC はコードが以下のように書かれているかのようにコンパイルする。

extern void prefix_bar (int);
void
prefix_foo (int a)
{
  return prefix_bar (a + 5);
}
このオプションは -fcheck-memory-usage と合わせて使うように設計されている。
-finstrument-functions
関数の入り口と出口に特別処理呼出しを生成する。関数入り口点の直後と関数出口点の直前で、以下のプロファリング関数が現在の関数とその呼出し側(call site)のアドレスを引数として呼び出される。(いくつかのプラットフォームでは、__builtin_return_address は現在の関数を越えては動作しないので、呼出し側情報はそれ以外のプロファイリング関数からは利用できない。)
void __cyg_profile_func_enter (void *this_fn, void *call_site);
void __cyg_profile_func_exit  (void *this_fn, void *call_site);

一番目の引数は、現在の関数の開始アドレスである。これは、シンボルテーブルから正確に検索できるものである。

この特別処理は、他の関数内にインライン展開された関数に対しても行われる。プロファイリング呼出しが、どこでインライン関数に入り、どこで出たかを概念的に示す。これは、インライン関数に対し、アドレスを取ることが可能な版が利用可能でなければならないことを意味する。ある関数を使用しているところが全てインライン展開されるのなら、これはコードサイズをさらに増やすことになる。読者の C コードでextern inline を指定するなら、インライン関数のアドレス取得可能版を提供しなければならない。(何はともあれ、これが普通の場合だが、最適化により常に関数がインライン展開されるなら、運が良ければ、static 版を提供しなくても済むかもしれない。)

関数に属性 no_instrument_function を指定すると、この特別処理は行われない。これは例えば、上に示したプロファイリング関数や、高優先度の割り込みルーチン、プロファイリング関数から安全に呼び出すことができない関数(プロファイリングルーチンが出力をおこなったり、メモリを確保するなら、おそらくシグナルハンドラが該当する)等に使われる。

-fstack-check
スタックの境界を越えないことを検証するコードを生成する。マルチスレッドの環境ではこのフラグを指定すべきだろう。シングルスレッドの環境では滅多に指定する必要がないだろう。スタックが一個しかなければ、ほぼ全てのシステムでスタックのオーバーフローを自動的に検出するからである。
-fargument-alias
-fargument-noalias
-fargument-noalias-global
仮引数間の依存関係および仮引数とグローバルデータの依存関係の可能性を指定する。

-fargument-alias は、引数(仮引数)がお互いに別名になっている可能性があること、それにグローバルデータの別名になっている可能性があることを指定する。-fargument-noalias は引数はお互いに別名になっていることはないが、グローバルデータの別名になっている可能性があることを指定する。-fargument-noaliase-global は、引数はお互いに別名になっていないし、グローバルデータの別名にもなっていないことを指定する。

それぞれの言語は、その言語の規格で必要とされるオプションはなんであれ、自動的に使うようになっている。そういうオプションを読者自身が使う必要はないはずである。

-fleading-underscore
このオプションとその反対のオプションである -fno-leading-underscore は、C のシンボルのオブジェクトファイル中での表現方法を強制的に変更する。使い道の一つは、古いアセンブリコードとリンクするのを助けることにある。

このオプションを指定するときは自分が何をしようとしているのかを理解している必要があるということ、それに全てのターゲットがこのオプションを完全にサポートしている訳ではないということに注意して欲しい。


Node:Environment Variables, Next:, Previous:Code Gen Options, Up:Invoking GCC

GCC に影響する環境変数

この節では、GCC の動作に関係する環境変数について説明する。これらの環境変数のうちのいくつかの仕事は、色々な種類のファイルを検索するときに使うディレクトリやプレフィックスを指定することである。またいくつかは、コンパイル環境の他の側面を指定するのに使われる。

また、検索場所を指定するのに -B-I-L (see Directory Options)等のオプションを使うことが出来ることに注意。これらのオプションは、環境変数で指定された場所よりも優先する。また、環境変数による指定は、GCC のコンフィギュレーションで指定された場所よりも優先する。See Driver

LANG
LC_CTYPE
LC_MESSAGES
LC_ALL
これらの環境変数は、GCC が、地域化(localization)情報を、異なる国の習慣とともに動作することが可能になるように使う方法を制御する。GCC は、コンフィギュレーションで指定されていれば、ロケール・カテゴリ LC_TYPELC_MESSAGES を調べる。これらのロケール・カテゴリには、読者のインストールでサポートされている任意の値を設定できる。代表的な値は、英国(United Kingdom)の英語を表す en_UK である。

環境変数 LC_CTYPE は、文字の分類を指定する。GCC はこれを使って、文字列中の文字の境界を決定する。これは、いくつかのマルチバイトのエンコーディングで必要になる。これらのエンコーディングでは、文字の境界がわからないと、文字列の終了やエスケープとして解釈されてしまうような引用文字やエスケープ文字が含まれている。

環境変数 LC_MESSAGES は、診断メッセージで使うべき言語を指定する。

環境変数 LC_ALL が設定されていると、LC_CTYPELC_MESSAGES の値を上書きする。設定されていないと、LC_CTYPELC_MESSAGES のデフォルトは、環境変数 LANG の値となる。これらのどの変数も設定されていない場合は、GCC は伝統的な C の英語の動作をデフォルトにする。

TMPDIR
TMPDIR が定義されていれば、その値で一時ファイルを置くディレクトリを指定する。GCC は一時ファイルを使ってコンパイルの一つのステージの出力を保持する。それが次のステージの入力として使われる。例えば、プリプロセッサの出力は、コンパイラ本体への入力になる。
GCC_EXEC_PREFIX
GCC_EXEC_PREFIX が設定されていると、コンパイラにより実行されるサブプログラムの名前のプレフィックスを指定する。このプレフィックスをサブプログラム名と組み合わせるときにスラッシュは補われないが、希望するならプレフィックスの最後にスラッシュを指定することができる。

GCC が指定されたプレフィックスを使ってサブプログラムを見つけられなかった時には、サブプログラムが通常置かれる場所を探す。

GCC_EXEC_PREFIX のデフォルト値は prefix/lib/gcc-lib/ であり、prefix は、configure スクリプトを実行したときのprefix の値である。

-B で指定したその他のプレフィックスは、このプレフィックスよりも優先する。

このプレフィックスは、リンク時に使われる crt0.o のようなファイルを探すのにも使われる。

さらに、このプレフィックスは、ヘッダファイルを検索すべきディレクトリを見つけるときに変わった使われ方をする。通常、/usr/local/lib/gcc-lib で(正確には、GCC_INCLUDE_DIR の値で)始まる名前の標準のディレクトリ毎に、その名前の始まりを指定されたプレフィックスに置き換えて、別のディレクトリ名を生成する。つまり、-Bfoo/ を指定すると、GCC は、普通なら /usr/local/lib/bar を探すところを、foo/bar を探すのである。この別のディレクトリは最初に検索される。標準のディレクトリが次に検索される。

COMPILER_PATH
COMPILER_PATH の値はコロンで区切ったディレクトリのリストであり、PATH に良く似ている。GCC は、GCC_EXEC_PREFIX を使ってサブプログラムを見つけられなかった場合に、これで指定されたディレクトリからサブプログラムを探す。
LIBRARY_PATH
LIBRARY_PATH の値はコロンで区切ったディレクトリのリストであり、PATH に良く似ている。ネイティブコンパイラとしてコンフィギュレーションを行なった場合は、GCC は、特別なリンカファイルを検索するときに、GCC_EXEC_PREFIX を使っても見つけられないときは、このように指定されたディレクトリを使う。GCC を使ってリンクを行なうときも、-l で指定された通常のライブラリを探すときに、これらのディレクトリを使う(ただし、-L で指定されたディレクトリがまず検索される)。
C_INCLUDE_PATH
CPLUS_INCLUDE_PATH
OBJC_INCLUDE_PATH
これらの環境変数は、特定の言語に関与する。各変数の値は、PATH のように、コロンで区切ったディレクトリのリストである。GCC がヘッダファイルを探すとき、使用している言語向けの変数に列挙されているディレクトリから探す。これは、-I で指定されたディレクトリの検索の後で、標準ヘッダファイルディレクトリの検索の前に行なわれる。
DEPENDENCIES_OUTPUT
この変数が設定されていると、その値が GCC により処理されるヘッダファイルに基づく、Make 用依存関係の出力方法を指定する。この出力は -M オプションによる出力に良く似ているが、独立したファイルに出力され、通常のコンパイル結果に追加される形で出力される。

DEPENDENCIES_OUTPUT の値は単なるファイル名でも良く、その場合は Make 用のルールはそのファイルに書かれる。Make のターゲット名はソースファイル名から推測する。あるいは、この変数の値はfile target という形でも良い。この場合、ファイル file に書き出されるルールは、ターゲット名としてtarget を使う。

LANG
この環境変数を使って、ロケール情報を GCC に渡す。この情報の一つの使い方としては、文字定数、文字列定数、コメントが C や C++ でパースされるときに使うべき文字セットを決定することがある。GCC をマルチバイト文字を許すようにコンフィギュレーションした場合は、LANG の値として以下のものが認識される。
C-JIS
JIS コード文字を認識する。
C-SJIS
SJIS コード文字を認識する。
C-EUCJP
EUCJP コード文字を認識する。

LANG が定義されていなかったり、上記以外の値になっている場合は、GCC はデフォルトのロケールで定義される mblenmbtowc を使って、マルチバイト文字を認識し変換する。


Node:Running Protoize, Previous:Environment Variables, Up:Invoking GCC

protoize の実行

protoize プログラムは、GNU C の選択的な部分である。これを使ってプロトタイプ宣言をプログラムに追加することができ、一つの面でプログラムを ANSI C に変換する。仲間のプログラム unprotoize は、その逆を行なう。見つかったプロトタイプ宣言から引数型を取り除く。

このプログラムを実行するときは、コマンド行引数として一組のソースファイルを指定しなければならない。この二つの変換プログラムは、これらのファイルをコンパイルしてどんな関数が定義されているかを調べることから始める。foo というファイルについて集められた情報葉、foo.X という名前のファイルにセーブされる。

この走査の後に実際の変換を行なう。指定したファイルは全て変換対象の資格を持つ。それからインクルードされているファイル(ソースであれ単なるヘッダであれ)も同様に資格を持つ。

しかし、資格を持つファイルが全て変換されるわけではない。デフォルトでは、protoizeunprotoize は、カレントディレクトリにあるソースとヘッダだけを変換する。変換すべきファイルが置かれているディレクトリを追加するには、-d directory オプションを使えば良い。また、特定のファイルを除外するには、-x file オプションを使う。ファイルは、資格を持ち、そのディレクトリ名が指定されたディレクトリ名の一つにマッチし、そのディレクトリ内の名前が除外されていない場合に、変換される。

protoize が行なう基本的な変換は、ほとんどの関数定義と関数の宣言を、引数の型を指定するように書き換えることである。書き換えが行なわれないのは、varargs 関数だけである。

protoize はオプションでソースファイルの先頭にプロトタイプ宣言をまとめて挿入し、関数の定義の前に現れる呼び出しで利用できるようにする。あるいは、未定義の関数が呼び出されているブロック内でブロックスコープのプロトタイプ宣言を挿入することもできる。

unprotoize が行なう基本的な変換は、ほとんどの関数の宣言から、引数の型を取り除くように書き換えることと関数定義を ANSI 以前の古い形式に書き換えることである。

どちらの変換プログラムも、変換不可能な関数の宣言や定義があると警告を出す。-q を指定すると、この警告を出さないようにできる。

protoizeunprotoize からの出力は、元のソースファイルを置き換える。元のソースファイルは、.save で終わるファイル名に置き換えられる。既に .save がついたファイルが存在していれば、変更前のファイルは単に捨てられる。

protoizeunprotoize はどちらも、GCC 自身に依存している。GCC を使ってプログラムを走査し、関数についての情報を集めているのである。このため、GCC がインストールされてないと、どちらのプログラムも動作しない。

以下に、protoizeunprotoize で使えるオプションの表を示す。どのオプションも、特に述べていない限り、どちらのプログラムでも使える。

-B directory
ファイル SYSCALLS.c.X を、通常のディレクトリ(普通は/usr/local/lib)の代わりに、directory から探す。このファイルには、標準のシステム関数についてのプロトタイプ情報が入っている。このオプションは protoize にだけ適用される。
-c compilation-options
compilation-options を、gcc を実行して .X ファイルを生成するときのオプションとして使う。さらに特別なオプション -aux-info が常に渡され、gcc.X ファイルを書き出すことを指示する。

コンパイル用のオプション群は、一個の引数として protoizeunprotoize に与えなければならないことに注意。gcc のオプションを複数指定したいときは、コンパイルオプション群全体を引用符で囲んで、シェルに一個の引数に見えるようにしなければならない。

使用できない gcc の特定のオプションがいくつかある。それを使うと出力の種類が正しくなくなる。そのオプションとは、-g-O-c-S-o である。これらのオプションを compilation-options に入れると、それは無視される。

-C
ファイル名が .c ではなく .C で終わるようにする。これは、C のプログラムを C++ に変換するときに使える。このオプションは protoize でのみ使用できる。
-g
明示的なグローバル宣言を追加する。これは、ソースファイルの中で呼び出されてはいるが宣言されていない関数について、ファイルの先頭にその関数の明示的な宣言を挿入するということを意味する。この宣言は、宣言されていない関数への呼び出しを含む最初の関数定義よりも前に置かれる。このオプションは protoize でのみ使用できる。
-i string
古い形式の仮引数宣言を文字列 string を使って字下げする。このオプションは protoize でのみ使用できる。

unprotoize は、関数のプロトタイプ形式の定義を古い形式の関数定義に変換する。古い形式では、引数は引数リストと最初の { の間で宣言される。デフォルトでは、unprotoize は空白5個でインデントする。代わりに空白一個でインデントしたい場合は、-i " " とする。

-k
.X ファイルを保存する。普通は、変換が終わった後に削除される。
-l
明示的なローカルの宣言を追加する。protoize-l を指定すると、宣言無しで関数を呼び出しているブロック毎にその関数のプロトタイプ宣言を挿入する。このオプションは、protoize でだけ使える。
-n
実際の変更は行なわない。このオプションを指定すると、-n を指定しなかった場合に行なわれたであろう変換についての情報を表示するだけである。
-N
.save ファイルを作らない。元のファイル単に削除される。このオプションは注意して使うこと。
-p program
program というプログラムをコンパイラとして使う。普通は gcc という名前が使われる。
-q
黙って仕事をする。ほとんどの警告が抑止される。
-v
gcc-v と同じように、バージョン番号を表示する。

ソースファイルのうちの一つだけ特別なコンパイラオプションを必要とする場合は、そのファイルに対する .X ファイルを特別に生成する必要がある。それには、そのソースファイルに対して、gcc に適切なオプションと -aux-infoオプションを付けて実行する。その後、protoize を全ファイルに対して実行する。protoize は既に存在する .X ファイルを使用する。それがソースファイルより新しいからである。例えば、以下のようにする。

gcc -Dfoo=bar file1.c -aux-info
protoize *.c

protoize コマンドのその他の使い方の場合は、特別なファイルをインクルードする必要がある。これは、.X ファイルが既に存在している場合でも必要である。そうしておかないと、変換されないからである。

protoize をうまく使いこなすためのさらなる情報については、See Protoize Caveats.

以下の情報のほとんどは、古いもので、EGCS のインストール手順で置き換えられている。歴史的な参照目的でのみここに提供する。


Node:Installation, Next:, Previous:Invoking GCC, Up:Top

GNU CC のインストール

ここでは、GNU CC を GNU システム、あるいは Unix システムにインストールするための手順を説明する。VMS の場合は、VMS Install を参照のこと。この節では、ソースの置かれているディレクトリでコンパイルを行なうことを仮定する。ソースディレクトリとは別のディレクトリでコンパイルする方法については、Other Dir を参照のこと。

MSDOS では、GNU C 自身をインストールすることはできない。GNU C 自身以外の MSDOS のコンパイラではコンパイルできないからである。このため、完全な DJGPP パッケージを入手する必要がある。DJGPP は、ソースだけでなくバイナリを含んでおり、さらに他に必要なツールやライブラリを全て含んでいる。

  1. 以前に、別のターゲットマシン向けに、同じディレクトリで GNU CC を構築したことがあるなら、make distclean を実行して正しくない可能性のあるファイルを全て消すようにする。この処理で消されるファイルの一つに Makefile がある。make distclean を実行して、Makefile が存在しないというエラーが出たら、恐らく、すでにファイルの消去が適切に行なわれていたことを意味する。
  2. System V リリース4 では、PATH で、必ず /usr/bin/usr/ucbの前に来るようにすること。/usr/ucb にある cc は、バグがあるライブラリを使ってしまうので。
  3. パーザ生成プログラムである Bison がインストールされていることを確認する。(Bison の出力ファイルである c-parse.ccexp.cc-parse.ycexp.y よりも新しく、.y ファイルを変更する予定がなければ、これは必要ない。)

    "Sept 8, 1998" より古いバージョンの Bison は、c-parse.c を正しく生成できない。

  4. GNU CC のコンフィギュレーションとして、システム標準のツールの代わりに他の GNU ツール(GAS や GNU リンカ等)を必要とするものを選んだ場合、その必要なツールを構築ディレクトリに asld 等の適切な名前でインストールする必要がある。これにより、GNU CC が enquire プログラムをコンパイルするのに適切なツールを見つけることができるようになる。

    システム標準のツールよりも先に来るように設定したうえで、引き続くコンパイルを行なうこともできる。

  5. ホスト、構築それにターゲットマシンのコンフィギュレーションを指定する。これは、configure というファイルを実行させるときに行なう。

    ビルドマシンとは、読者が使っているシステムであり、ホストマシンとは、できたコンパイラを実行させたいシステム(普通はビルドマシン)であり、ターゲットマシンとはそれ向けにコンパイラにコードを生成させたいシステムのことである。

    コンパイラ自身が動作するマシン向けのコードを生成するコンパイラ(ネイティブコンパイラ)を構築する場合は、普通は configure に何も引数を指定する必要はない。機種を推測し、それを構築マシンおよびホストマシン、ターゲットマシンとして使う。このため、configure が今フィギュレーションを推測できなかったり、推測が間違っていない限り、ネイティブコンパイラを構築するときにはコンフィギュレーションを指定する必要がない。

    推測がうまくいかない場合は、構築マシンの コンフィギュレーション名--host オプションで指定する。ホストとターゲットはデフォルトでホストマシンと同じになる。(クロスコンパイラを構築する場合は、Cross-Compiler。)

    以下に例を示す。

    ./configure --host=sparc-sun-sunos4.1
    

    コンフィギュレーション名は、正規名でも省略形でも良い。

    コンフィギュレーションの正規名は三つの部分をダッシュで区切ったものからなる。cpu-company-system という形式になる。(三つの部分はさらにその中にダッシュを含んでも良い。configure は、どのダッシュがどの役割を果たすかを区別できる。) 例えば、m68k-sun-sunos4.1 は Sun 3 を指定する。

    コンフィギュレーションの一部をニックネームまたは別名で置き換えることもできる。例えば、sun3m68k-sun を表すので、sun3-sunos4.1 としても Sun 3 を指定したことになる。これをさらに簡単にして sun3-sunos としても良い。なぜなら、SunOS のバージョンはデフォルトがバージョン 4 であると仮定されているからである。

    システムタイプのどれにでも、そして CPU タイプの幾つかにはその後にバージョン番号を指定することができる。大部分の場合は、バージョンは関係なく、無視される。このため、知っている場合にはバージョンを指定しても良い。

    サポートされているコンフィギュレーション名の一覧と多くのコンフィギュレーションについての注意書きについては、Configurations を参照のこと。

  6. configure を実行するとき、ハードウェアとソフトウェアを記述する特定のオプションを追加で指定する必要があるかもしれない。コンフィギュレーションの一部を独立に指定できるようになっている。それは、--with-gnu-as--with-gnu-ld--with-stabs--nfp である。
    --with-gnu-as
    GNU CC を GNU アセンブラ(GAS) と共に使うなら, configure の実行時に --with-gnu-as を指定することでその旨を宣言する必要がある。

    このオプションを指定しても、GAS のインストールは行なわない。GNU CC の出力を GAS で処理できるように修正するだけである。GAS の構築とインストールは読者の責任である。

    逆に、GAS を使うことを希望せず、構築時に --with-gnu-as を指定しないのであれば、GAS がインストールされていないことを確認するのは読者の責任である。GNU CC は、as という名前のプログラムを色々なディレクトリから探す。もし見つけたプログラムが GAS であれば、GAS が実行されることになる。GNU CC が使っているアセンブラがどこにあるのかわからない場合は、-v を指定して実行してみよう。

    GAS を使うかどうかによって違いが生じるシステムは以下の通りである。hppa1.0-any-anyhppa1.1-any-anyi386-any-sysvi386-any-isc
    i860-any-bsdm68k-bull-sysvm68k-hp-hpuxm68k-sony-bsd
    m68k-altos-sysvm68000-hp-hpuxm68000-att-sysvany-lynx-lynxosmips-any)。これら以外のシステムでは、--with-gnu-as は何の効果もない。

    上に列挙したシステムでは(HP-PA, i386 上の ISC、mips-sgi-irix5.* を除く)、GAS を使う場合には GNU リンカも使うべきである(--with-gnu-ld を指定する)。

    --with-gnu-ld
    GNU CC と一緒に GNU リンカを使う予定なら、--with-gnu-ld オプションを指定する。

    このオプションでは、GNU リンカをインストールしようとはしない。単に、GNU CC の振るまいを GNU リンカと協調して動作するように修正するだけである。

    --with-stabs
    MIPS ベースのシステムと Alpha では、GNU CC が通常の ECOFF 形式のデバッグ情報を作るか、BSD形式の stabs を ECOFF のシンボルテーブルを通して使うかのどちらかを指定しなければならない。通常の ECOFF デバッグ情報形式は、C 以外の言語を完全には取り扱うことができない。BSD stabs 形式は、他の言語も扱えるが、GNU デバッガ GDB でしか使えない。

    通常、GNU CC は、ECOFF 形式のデバッグ情報をデフォルトで使う。BSD stabs の方が良ければ、GNU CC をコンフィギュレーションする際に--with-stabs を指定する。

    GNU CC をコンフィギュレーションするさいに、どちらをデフォルトとして選んだかに関わらず、ユーザは -gcoff オプションと -gstabs+ オプションを使って、特定のコンパイル毎にデバッグ情報形式を明示的に指定することができる。

    --with-stabs は、i386 上の ISC システムでは、--with-gas も指定されたときに有効になる。このオプションにより、COFF 出力の中に埋め込む形の stabs デバッグ情報を使うことを選択する。この種類のデバッグ情報は C++ もサポートする。通常の COFF デバッグ情報はサポートしていない。

    --with-stabs は、i386 上の SVR4 でも有効である。このオプションにより、ELF 出力の中に埋め込む形の stabs デバッグ情報を使うことを選択する。C++ コンパイラは現在(2.6.0)、i386 上の SVR4 プラットフォームで通常使われている DWARF デバッグ情報をサポートしていない。このため、stabs を動作する選択肢となる。このオプションは、gas と gdb を必要とする。通常の SVR4 のツールでは、stabs を生成したり、解釈できないからである。

    --nfp
    ある種のシステムでは、マシンに浮動小数点ユニットがあるかどうかを指定しなければならない。そういうシステムには、m68k-sun-sunosnm68k-isi-bsd がある。他のシステムでは、今のところ --nfp は何の効果もないが、それを使って違いを出すと便利なシステムがおそらく他にもあるだろう。
    --enable-haifa
    --disable-haifa
    --enable-haifa を指定すると、ある実験的な命令スケジューラ(IBM Haifa 提供)を使うようにする。これにより生成されるコードが良くなることもあれば、良くならないこともある。良くなることが分かっているいくつかの機種ではデフォルトでこの機能が有効になっている。その場合、無効にするには --disable-haifa オプションを使えば良い。configure を実行すると、Haifa スケジューラが有効になっているかどうかを表示する。
    --enable-threads=type
    ある種のシステム、特に Linux ベース GNU システムは、Objective C の実行時にスレッド機能を提供するには信頼が置けないので、デフォルトでシングルスレッド実行時になる。だが、これらのシステムにスレッドの実装が利用可能なライブラリがあるかもしれない。その場合、スレッド機能は、このオプションに適切な type、おそらく posix を指定することで有効になる。type の可能な値は、singleposixwin32solarisirixmach である。
    --enable-checking
    このオプションを指定すると、GCC は、ツリー・ノード型の検査を、そのノードのフィールドを参照したときに、実行するように構築される。これは生成されるコードを変えることはしないが、GCC 内部のエラー検査を追加する。これにより、コンパイル速度は遅くなり、GCC を構築するのにGCC を使ったときにしか正しく動作しないだろう。

    configure スクリプトは、GNU CC に統合される他のコンパイラを、ソースディレクトリのサブディレクトリから探す。例えば、C++ 向けの GNU コンパイラは、G++ と呼ばれており、cp というサブディレクトリにある。configureMakefile にルールを挿入して、これらのコンパイラを全て構築するようにする。

    以下に、configure が設定するファイルについて残らず説明する。普通は、以下のファイルに注意を払う必要はない。

    • config.h という名前のファイルが作られる。このファイルは、読者がコンパイラを実行する機種の最上位のコンフィギュレーションファイルを #include で取り込む(see Config)。このファイルは、ホスト機種についての情報を定義する責任を持つ。tm.h をインクルードする。

      最上位レベルのコンフィギュレーションファイルはサブディレクトリconfig に置かれている。その名前は常に xm-something.h である。普通は xm-machine.h であるが、幾つか例外がある。

      シンボリックリンクのないシステムでは、config.h を適切なファイルを参照している #include 制御子を含むように設定する必要があるだろう。

    • tconfig.h というファイルが作られる。このファイルは、ターゲット機種の最上位レベルのコンフィギュレーションファイルをインクルードする。このファイルは、その機種で動作すべきある種のプログラムをコンパイルするのに使われる。
    • tm.h というファイルが作られる。このファイルは、ターゲットマシンのマシン記述マクロを定義するファイルをインクルードする。このファイルは、サブディレクトリ config に置く必要があり、そのファイル名は machine.h であることが多い。

    --enable-nls
    --disable-nls
    --enable-nls オプションを指定すると母国語サポート(Native Language Support, NLS)を有効にする。NLS を使うと、GCC は、合衆国で使われている英語以外の言語で診断メッセージを出力する。メッセージを翻訳したものはまだ利用可能ではないので、このオプションの主なユーザは、GCC の診断メッセージを翻訳している人々であり、翻訳作業結果の確認に使っている。一度翻訳が揃えば、母国語サポートをデフォルトで有効にする予定である。--disable-nls オプションで NLS を無効にできる。
    --with-included-gettext
    NLS が有効になっていると、GCC の構築手順では普通、ホストマシンにあるgettext ライブラリを使うことをまず試み、それが充分なものでない場合にだけ、GCC に含まれている GNU gettext ライブラリを使う。--with-included-gettext オプションを指定すると、付属の GNU gettext を優先させる。
    --with-catgets
    NLS が有効になっていると、ホストに gettext はないが、やや劣る catgets インターフェースならあるという場合、GCC の構築手順では普通、catgets は無視して、代わりに GCC に付属のGNU gettext ライブラリを使う。--with-catgets オプションを指定すると、その場合にホストの catgets を使う。
  7. ある特定の場合、configure を実行するときに他の特定のオプションを指定する必要がある。

  8. コンパイラを構築する。ソースディレクトリで make LANGUAGES=c を実行する。

    LANGUAGES=c は、C コンパイラのみコンパイルすることを指定する。特に指定しなければ通常は、サポートされている言語全てのコンパイラを構築する。現在サポートされているのは、C、C++、Objective C である。しかし、GNU C コンパイラ以外の他のコンパイラを使って構築する場合に、正しく動作することが保証されるのは C だけである。さらに付け加えるなら、C 以外のものをこのステージで構築するのは時間の無駄である。

    一般に、構築したい言語を指定するには、引数 LANGUAGES="list" を追加する。ここで list は、cc++objective-c のうちから一つ以上選んで並べたものである。GNU CC のソースディレクトリのサブディレクトリに何か追加言語の GNU コンパイラのソースを持っているなら、その名前をリストに指定しても良い。

    insn-emit.c で "statement not reached" という警告が出るかもしれないが、無視して良い。それで問題はない。それから、genopinit.c や、もしかするとそれ以外のファイルでも出るかも知れないが、"unknown escape sequence" という警告も問題がない。同様に、insn-emit.cinsn-recog. の"constant is so large that it is unsigned"、 enquire.o の比較が常に 0 になる旨の警告、それに cexp.y でのシフト回数が型の大きさを越えているというも無視して良い。それ以外のコンパイルエラーは問題の起きるマシンや OS への移植のバグの可能性があるので、調べて報告すべきである(see Bugs)。

    コンパイラの中には、バグや制限のために GNU CC をコンパイルできないものがある。例えば、Microsoft のコンパイラはマクロスペースを使い切ってしまうと言われている。いくつかの Ultrix のコンパイラは、式空間を使い切ってしまい、問題が起きたところで文をいくつかに分割しなければならない。

  9. クロスコンパイラを構築する場合は、ここで立ち止まること。See Cross-Compiler
  10. ステージ1のオブジェクトファイルと実行形式ファイルをサブディレクトリに移すのに、以下のコマンドを実行する。
    make stage1
    

    関連ファイルは stage1 という名前のサブディレクトリに移動される。インストールが完了したなら、ここに置かれたファイルをrm -r stage1 で消しても良い。

  11. GNU CC のコンフィギュレーションとして、システム標準のツールではなく、GNU のツール(GAS や GNU リンカなど)を必要とするものを選んだ場合、その必要とするツールを下位ディレクトリ stage1 にインストールすること。その場合、ファイル名は asld 等適切なものにする。こうすることで、ステージ1 のコンパイラが続くステージで適切なツールを見つけられるようになる。

    あるいは、後続のコンパイルを行なうのに、環境変数 PATH の値を、必要な GNU ツールがシステム標準のツールの前に来るように設定して行なっても良い。

  12. コンパイラ自身を以下のように再コンパイルする。
    make CC="stage1/xgcc -Bstage1/" CFLAGS="-g -O2"
    

    この過程は、ステージ2 コンパイラの作成と呼ばれる。

    上に示したコマンドは、サポートされている言語全てが使えるコンパイラを作成する。全部の言語は要らない場合は、作成したい言語を指定するには、引数に LANGUAGES="list" を追加する。list は、cc++objective-cproto のどれか一つ以上の名前を指定する。名前は空白で区切る。proto は、protoizeunprototize プログラムを表す。これらは独立した言語ではないが、インストールするかどうかをLANGUAGES で指定できる。

    ステージ3コンパイラを作成するなら、ステージ2 では C 言語のみ作成すれば充分である。

    ステージ2 コンパイラが一旦出来てしまえば、ディスクスペースが不足するような場合は、ディレクトリ stage1 を削除しても良い。

    68000 や 68020 のシステムで、浮動小数点ハードウェアがない場合は、デフォルトで浮動小数点ハードウェアが無いことを想定しているtm.h を選択しない限り、代わりに以下のようにコンパイルを行なうこと。

    make CC="stage1/xgcc -Bstage1/" CFLAGS="-g -O2 -msoft-float"
    

  13. GNU CC のテストのために、GNU CC 自身で複数回コンパイルする場合は、他に必要な GNU のツール(GAS や GNU リンカ等)を、stage1 でやったのと同じように、 stage2 ディレクトリにインストールしておき、以下を実行する。
    make stage2
    make CC="stage2/xgcc -Bstage2/" CFLAGS="-g -O2"
    

    この過程はステージ3コンパイラの作成と呼ばれる。-B オプション以外は、ステージ2コンパイラを作ったときと同じオプションを使うようにする。ただ、LANGUAGES オプションは同じである必要はない。上で示したコマンド行は、サポートしている全言語用のコンパイラを構築する。全言語は要らない場合は、構築したい言語を、前述したように、引数LANGUAGES="list" を加えることで指定できる。

    他に必要な GNU ツールをインストールしなくても良い場合は、stage1stage2を作って、コンパイラを二回構築する代わりに、以下のコマンド行を使うことができる。

    make bootstrap LANGUAGES=language-list BOOT_CFLAGS=option-list
    

  14. 最後のオブジェクトファイル群をステージ2のオブジェクトファイル群と比較する。両者は、タイムスタンプ(あれば)を覗いて、同等であるべきだ。

    機種によっては、オブジェクトファイルの意味のある比較が不可能な場合がある。常に「異なってしまう」ように見える。これは、今のところ、Solaris と ELF オブジェクトファイル形式を使用している幾つかのシステムが当てはまる。SGI の Irix の幾つかのバージョンと、Alpha システム上の DEC Unix(OSF/1) では、-save-temps を指定しないとオブジェクトファイルを比較できないだろう。比較に失敗したなら、これらの個々のシステムの説明を見て欲しい。他のシステムでも同じような問題が起きるかもしれない。

    ファイルの比較を行なうには次のコマンドを使う。

    make compare
    

    これは、ステージ2 とステージ3で異なるオブジェクトファイルについて知らせてくれる。何か違いがあれば、それが無害かどうかに関わらず、ステージ 2 のコンパイラが GNU CC を正しくコンパイルしなかったということを意味し、それゆえ潜在的に重大で、調査したうえで報告(see Bugs)を行なうべきバグが存在する可能性がある。

    オブジェクトファイルにタイムスタンプを挿入しないシステムでは、以下のコマンドが比較を行なう速い方法である(Bourne シェルを使っている)。

    for file in *.o; do
    cmp $file stage2/$file
    done
    

    MIPS のマシンで -mno-mips-tfile オプションを指定してコンパイラを構築した場合は、ファイルを比較することはできない。

  15. コンパイラドライバ、コンパイラの各パス、それに実行時のサポートファイルをインストールするには、make install を実行する。インストールされるファイルをコンパイルしたのと同じ値をCCCFLAGSLANGUAGES に対して使うようにする。同じ値にする理由の一つは、Make の中にはバグのために、この段階で不必要にファイルを再コンパイルするものがあるためである。これらの変数の値を同じにしておけば、適切に再コンパイルが行なわれる。

    例えば、ステージ2 コンパイラを構築してあれば、以下のようなコマンド行を使えば良い。

    make install CC="stage2/xgcc -Bstage2/" CFLAGS="-g -O" LANGUAGES="list"
    

    これは、ファイル cc1cpplibgcc.a をディレクトリ /usr/local/lib/gcc-lib/target/version にあるファイル cc1cpplibgcc.a にコピーする。このディレクトリは、コンパイラのドライバプログラムがこれらのファイルを探す場所である。ここで、target は、configure を実行したときに指定したターゲット機種のタイプの正規形であり、version は、GNU CC のバージョン番号である。この名前付の方法により、色々なバージョンやクロスコンパイラが共存可能になる。これはまた、他の言語のコンパイラの実行形式(例えば、C++ 用の cc1plus など)を同じディレクトリにコピーする。

    これは、ドライバプログラム xgcc/usr/local/bin/gcc にコピーするので、典型的なコマンド検索パス中に現れることになる。また、gcc.1/usr/local/man/man1 に、info ページを /usr/local/info にコピーする。

    システムによっては、このコマンドを実行すると幾つかのファイルを再コンパイルしてしまう。これは普通は make のバグによるものである。これは無視するか、あるいは GNU Make を使えば良い。

    注意: Sun のライブラリの alloca にはバグがある。このバグを回避するには、GNU CC でコンパイルされた GNU CC の実行形式をインストールするよう注意すること。(すなわち、stage1 ではなくて、stage2 か 3 で出来た実行形式をインストールする。) GNU CC は、組み込み関数の alloca を使い、ライブラリにあるものは決して使わない。

    (通常でも、stage2 また 3 の GNU CC の実行形式をインストールしたほうが良い。というのは、他のコンパイラでコンパイルしたものよりも高速に動作するからである。)

  16. C++ を使おうとしているなら、C++ 実行時ライブラリをインストールする必要がある。全ての入出力機能、特別なクラスライブラリなどを含む。

    GNU CC 用の標準C++実行時ライブラリは libstdc++ というものである。旧版の libg++ も利用可能であるが、変換が済んでいない古いソフトウェアにしか必要のないものである。読者が libg++ を必要とするかどうかわからない場合は、おそらく必要としないだろう。

    以下に GNU CC 用に libstdc++ を構築し、インストールする方法の一つを示す。

    まとめると、GNU CC を構築・インストールしたあと、以下のシェルコマンドをC++ ライブラリの配布物の最上位ディレクトリで実行することになる。configure-options には、GNU CC のコンフィギュレーションで使用したのと同じオプションを指定する。

    $ CXX=gcc ./configure configure-options
    $ make
    $ make install
    

  17. GNU CC には Objective-C の実行時ライブラリが含まれている。Objective-C 言語の不可欠な部分だからである。このライブラリに関連するファイルは objc というサブディレクトリに置かれている。GNU Objective-C Runtime Library をコンパイルするにはターゲットのC ライブラリのヘッダファイルが必要であり、スレッドサポートが必要ならターゲットのスレッドライブラリのヘッダファイルも必要である。クロスコンパイルの場合のヘッダファイルの問題については、See Cross-Compilers and Header Files

    configure を実行すると、ターゲットのプラットフォームに適したObjective-C のスレッド実装ファイルを選び出す。場合によっては、複数のスレッド実装をサポートしているプラットフォームがあったり、スレッドサポートを完全に無効にしたいなどの理由により、異なるバックエンドを選びたいこともあるだろう。それには、make の実行時に、コマンド行で Makefile 変数のOBJC_THREAD_FILE に値を指定すれば良い。例えば以下のようにする。

    make CC="stage2/xgcc -Bstage2/" CFLAGS="-g -O2" OBJC_THREAD_FILE=thr-single
    

    以下に現在利用可能なバックエンドの一覧を示す。


Node:Configuration Files, Next:, Up:Installation

configure が作り出すファイル達

configure により設定されるファイルを一つずつ挙げてみる。普通は、以下のファイルに注意を払う必要はない。


Node:Configurations, Next:, Previous:Configuration Files, Up:Installation

GNU CC でサポートしているコンフィギュレーション

以下はサポートしている CPU のタイプである。

1750a, a29k, alpha, arm, cn, clipper, dsp16xx, elxsi, h8300, hppa1.0, hppa1.1, i370, i386, i486, i586, i860, i960, m32r, m68000, m68k, m88k, mips, mipsel, mips64, mips64el, ns32k, powerpc, powerpcle, pyramid, romp, rs6000, sh, sparc, sparclite, sparc64, vax, we32k.

以下に、認識可能な企業名を示す。見て判るとおり、正式な名前ではなくて、良く使われる省略形を使っている。

acorn, alliant, altos, apollo, apple, att, bull, cbm, convergent, convex, crds, dec, dg, dolphin, elxsi, encore, harris, hitachi, hp, ibm, intergraph, isi, mips, motorola, ncr, next, ns, omron, plexus, sequent, sgi, sony, sun, tti, unicom, wrs.

企業名は、他に与えられた情報では充分でないときにだけ使われる。必要がなければ省略でき、cpu-system のように書いても良い。例えば、vax-ultrix4.2vax-dec-ultrix4.2 に同じである。

以下に、認識できるシステム名を示す。

386bsd, aix, acis, amigaos, aos, aout, aux, bosx, bsd, clix, coff, ctix, cxux, dgux, dynix, ebmon, ecoff, elf, esix, freebsd, hms, genix, gnu, linux-gnu, hiux, hpux, iris, irix, isc, luna, lynxos, mach, minix, msdos, mvs, netbsd, newsos, nindy, ns, osf, osfrose, ptx, riscix, riscos, rtu, sco, sim, solaris, sunos, sym, sysv, udi, ultrix, unicos, uniplus, unos, vms, vsta, vxworks, winnt, xenix.

システム名の指定は省略可能である。省略した場合は、configure がCPU と企業名からオペレーティングシステムを推測する。

システム名にバージョン番号を付け足すこともできる。これにより、違いが生じる場合もあるし、違いはない場合もある。例えば、bsd4.3bsd4.4 と書いて、BSD のバージョンを区別することができる。sysv3sysv4 の場合にはバージョン番号を必要とし、異なった扱いを受ける。

i860-dg-vms のようにありえない組合せを指定すると、configure はエラーメッセージを出すか、指定された情報の一部を無視して残りの部分だけで最善をつくして推測を行なう。configure は、使われる選択肢の正規名を常に出力する。GNU CC は、可能な選択肢の全てはサポートしていない。

ある機種の特定のモデルには名前がついていることがある。機種名の多くは、CPU と企業名の組合せの別名として認識される。例えば、上で述べた sun3 という機種名は、m68k-sun の別名である。企業名を機種名として受け付ける場合もある。この場合、その名前は特定の機種を指すのに広く使われている。以下に既知の機種名の表を示す。

3300, 3b1, 3bn, 7300, altos3068, altos, apollo68, att-7300, balance, convex-cn, crds, decstation-3100, decstation, delta, encore, fx2800, gmicro, hp7nn, hp8nn, hp9k2nn, hp9k3nn, hp9k7nn, hp9k8nn, iris4d, iris, isi68, m3230, magnum, merlin, miniframe, mmax, news-3600, news800, news, next, pbd, pc532, pmax, powerpc, powerpcle, ps2, risc-news, rtpc, sun2, sun386i, sun386, sun3, sun4, symmetry, tower-32, tower.

マシン名は、CPU タイプと会社名の両方を指定するということを覚えていて欲しい。読者が自作したコンフィギュレーションファイルをインストールしたい場合は、会社名として local を使ってそれにアクセスすることができる。コンフィギュレーション cpu-local を使うと、cpu プレフィックスのないコンフィギュレーション名が、コンフィギュレーションファイル名に使われる。

つまり、m68k-local と指定したとすると、このコンフィギュレーションはm68k.mdlocal.hm68k.cxm-local.ht-localx-local といったファイルを使う。これらは全てディレクトリ config/m68k に置かれる。

以下のリストは、知っていなければならない、特別な取扱いや特別な事項のあるコンフィギュレーションである。

1750a-*-*
MIL-STD-1750A プロセッサ。

MIL-STD-1750A のクロス・コンフィギュレーションはGNU Public License の元で利用可能な 1750A 向けアセンブラ/リンカであるas1750 用のコードを生成する。as1750 は、ftp://ftp.fta-berlin.de/pub/crossgcc/1750gals/ から入手可能である。同様のライセンスを持つ、1750A 向けシミュレータも同じ所から入手可能である。

libcc を構築中に出る致命的エラーは無視して良い(1750A 向けのlibgcc はまだ実装されていない。)

as1750 アセンブラは ms1750.inc というファイルを必要とする。このファイルはディレクトリ ms1750.inc にある。

GNU CC は、Fairchild F9450 C Compiler と同じセクションを生成する。すなわち、以下のものである。

Normal
プログラムのコード・セクション。
Static
読み書き(RAM)データ・セクション。
Konst
読み込み専用(ROM)定数セクション。
Init
初期化セクション(KREL を SREL にコピーするためのコード)。

アドレス可能な最小単位は 16 ビット(BITS_PER_UNIT が 16)である。これは、`char' 型が、一文字につき 16 ビットの語で表現されるということを意味する。1750A の "Load/Store Upper/Lower Byte" 命令はGNU CC では使われない。

alpha-*-osf1
DEC Alpha アーキテクチャを実装したプロセッサを使い、DEC Unix (OSF/1) が走るシステムである。例えば、DEC Alpha AXP システム等である。

クロスコンパイラとして構築されない限り、GNU CC は .verstamp 疑似命令をアセンブラ出力ファイルに書き出す。これには、システムヘッダファイル /usr/include/stamp.h から取ったバージョンが入っている。DEC Unix の新しいバージョンをインストールするときには、GCC を再構築して、新しいバージョンスタンプを取り出すようにしないといけない。

Alpha は 64 ビットアーキテクチャなので、32ビットの機種で動作するAlpha をターゲットとするクロスコンパイラは、64ビットの機種で動作するコンパイラが生成するコードと同程度に効率の良いコードを生成することはできない。これは、多くの最適化が、ターゲットのワードをホスト上での整数値として表せるということに依存しており、32ビットの機種上では実行できないからである。Alpha 上で動作する、ターゲットを 32 ビット機種とするクロスコンパイラを構築するのは、ほんの2,3の場合しかテストされておらず、多分正しく動かないだろう。

古いバージョンの DEC Unix では、CFLAGS-save-temps を追加しないと、make compare に失敗する。これらのシステムでは、アセンブラへの入力ファイル名がオブジェクトファイル内に収められているので、そのファイル名が stage1stage2 で異なると、比較に失敗してしまうのである。オプション -save-temps を指定すると、アセンブラへの入力ファイル名として、/tmp に置かれる、ランダムに選ばれた名前の代わりに、固定したファイル名を使う。-save-temps オプションは、これを指定しないと比較に失敗するのでない限り、追加しないこと。-save-temps を指定すると、各コンパイルの段階で、.i.s で終わるファイルを自分で消さないといけない。

GNU CC は現在、DBX と GDB が使うネイティブ(ECOFF)デバッグ情報形式とGDB だけが使う埋め込み STABS 形式の両方をサポートしている。これらのデバッグ情報形式と選択方法についての詳細は、既出のconfigure--with-stabs オプションの説明を参照のこと。

DEC のアセンブラにはバグがあり、.align 疑似命令を使ったときにECOFF 形式用の行番号情報が正しくないものを生成する。この問題を回避するために、GNU CC は、最適化を実行する場合でもECOFF 形式のデバッグ情報を書き出すときに、この疑似命令をださないようにしている。ただし、残念なことに、これには非常に困る副作用があり、-O を指定したときのコードのアドレスが、-g を合わせて指定するかどうかによって違ってきてしまう。

これを避けるには、-gstabs+ を指定して、DBX の代わりに GDB を使えば良い。DEC も今ではアセンブラのこの問題に気付いていて、早急に修正版を提供しようとしている。

arc-*-elf
Argonaut の ARC プロセッサである。このコンフィギュレーションは組み込みシステム向けである。
arm-*-aout
Advanced RISC Machines 社の ARM 一族のプロセッサである。埋め込みアプリケーションで良く使われている。標準の Unix 用コンフィギュレーションは存在しない。このコンフィギュレーションは基本的な命令列に対応し、a.out 形式のオブジェクトモジュールを生成する。

読者自身の特定のコンフィギュレーション向けには、arm.h の修正版を作る必要がある。

arm-*-linuxaout
a.out バイナリ形式を使う Linux ベース GNU システムの動作するARM プロセッサ(ELF はまだサポートされていない)。GNU/Linux binutils の2.8.1.0.7 以降を使わなければならない。これはsunsite.unc.edu:/pub/Linux/GCC や Linux ベース GNU システム向けの他のミラーサイトから入手することができる。
arm-*-riscix
ARM2 または ARM3 で動作する RISC iX。RISC iX は、Acorn による BSD Unix の移植である。バージョン 1.2 以前の RISC iX を使っている場合は、コンフィギュレーションの際にバージョン番号を明示的に指定しなければならない。RISC iX 付属のアセンブラは、stabs 形式のデバッグ情報をサポートしていないことに注意が必要である。現在、stabs 形式のサポートが入った新しいバージョンのアセンブラが Acorn から入手できる。ftp ではftp.acorn.com:/pub/riscix/as+xterm.tar.Z から入手できる。stabs デバッグ情報を有効にするには configure に--with-gnu-as を指定する。

configure を実行する前に GNU sed をインストールする必要がある。

a29k
AMD の Am29k シリーズのプロセッサである。通常、組み込みアプリケーションで使われる。標準のUNIX 向けのコンフィギュレーションは存在しない。このコンフィギュレーションは、AMD 標準の呼び出しシーケンスとバイナリインターフェースに対応しており、他の 29k 用のツールと互換性がある。

読者自身の特定のコンフィギュレーション向けには、a29k.h の修正版を作る必要がある。

a29k-*-bsd
BSD Unix のある版が動作するシステムで使われている場合のAMD Am29050 である。
decstation-*
MIPS ベースの DECstation は三つの異なるコンフィギュレーションをサポートしている。(Alpha ベースの DECstation 製品のコンフィギュレーション名は alpha-dec で始まる。) Ultrix、DEC OSF/1、OSF/rose である。これらのプラットフォーム向けには以下のようなコンフィギュレーションを使う。
decstation-ultrix
Ultrix のコンフィギュレーション
decstation-osf1
OSF/1 の DEC版。
decstation-osfrose
OSF/1 の Open Software Foundation の参照ポート。これは、オブジェクトファイル形式として、ECOFF の代わりにOSF/rose を使っている。普通、このコンフィギュレーションを選択することはないだろう。

MIPS の C コンパイラに対しては、cp/parse.c をコンパイルするために、オプション -Wf,-XNg1500 を指定して、スイッチ文のテーブルの大きさを大きくしておく必要がある。最適化オプションとして -O2 を使う場合は、-Olimit 3000 も使う必要がある。この二つのオプションはどちらも、configure が構築するMakefile には自動的に追加される。make の変数 CC を上書きして MIPS のコンパイラを使うには、-Wf,-XNg1500 -Olimit 3000 を追加する必要がある。

elxsi-elxsi-bsd
Elxsi の C コンパイラには、GNU C のコンパイルを妨げる制限があることが知られている。詳細については mrs@cygnus.com に連絡して欲しい。
dsp16xx
AT&T の DSP1610 シリーズのプロセッサへの移植である。
h8300-*-*
日立の H8/300 シリーズのプロセッサである。

呼びだし規約と構造体のレイアウトがリリース2.6 で変更された。全てのコードを再コンパイルする必要がある。新しい呼びだし規約では、関数の引数の最初の三つをレジスタで渡す。構造体は、大きさがもはや 2 の倍数のバイト数ではない。

hppa*-*-*
HP-PA プロセッサには色々な種類があり、色々な OS が動作する。GNU CC が正しいプロセッサ型とOSを使うようにコンフィギュレーションをしなければならない。正しくコンフィギュレーションあれていないと、GNU CC は正しく機能しない。この問題に対処する一番簡単な方法は GNU CC のコンフィギュレーションを行なう時にターゲットを指定しないことである。そうすると、configure スクリプトが自動的に正しいプロセッサ型とOSを決定してくれる。

HP-UX では -g は使えない。GNU CC の知らない、独特のデバッグ情報形式を使っているからである。だが、GCC に GAS と GDB を組み合わせて使うなら -g を使うことができる。全ての HP-PA のコンフィギュレーションで GAS を使うことを強くお勧めする。

その場合、GAS-2.6 以降と GDB_4.16 以降を使わなくてはならない。これらは、全ての伝統的 GNU ftp アーカイブサイトから取り寄せることができる。

HP-UX のいくつかのバージョンでは、GNU sed をインストールする必要がある。

コマンド検索パスに、/bin/usr/bin/usr/ccs/bin の現れる前に、GAS をインストールするディレクトリを置く必要がある。GNU CC を作る前に GAS をインストールしておく必要がある。

デバッグを可能にするには、構築を行なう前に --with-gnu-as オプションをつけて GNU CC のコンフィギュレーションを行なう。

i370-*-*
この移植はまだまだ予備的であり、たくさんバグがあることがわかっている。この機種向けの品質の良い移植を早急に求めている。
i386-*-linux-gnuoldld
gas/binutils のバージョン 2.5.2 以降をインストール済みでない場合に、Linux ベースの GNU システム上で a.out 形式のバイナリを生成するには、このコンフィギュレーションを使う。これは廃れたコンフィギュレーションである。
i386-*-linux-gnuaout
Linux ベースの GNU システム上でa.out 形式のバイナリを生成するには、このコンフィギュレーションを使う。このコンフィギュレーションは置き換えの途上にある。gas/binutils のバージョン 2.5.2 以降を使う必要がある。
i386-*-linux-gnu
Linux ベースの GNU システム上で ELF 形式のバイナリを生成するには、このコンフィギュレーションを使って。gas/binutils のバージョン 2.5.2 以降を使う必要がある。
i386-*-sco
RCC でコンパイルするのがお勧めである。また、システムに付いてくるmalloc ではなく GNU malloc をリンクするのが良いだろう。
i386-*-sco3.2v4
SCO のリリース 3.2 バージョン4 にはこのコンフィギュレーションを使う。
i386-*-sco3.2v5*
SCO OpenServe Release シリーズの 5.0.0、5.0.2、5.0.4、5.0.5、Internet FastStart 1.0、Internet FastStart 1.1 用である。

GNU CC は -mcoff を指定すると COFF バイナリを生成可能である。デフォルトは ELF バイナリである。ELF を構築する ELF コンパイラが生成されるように完全な make bootstrap を行うことをお勧めする。

TLS597 を ftp://ftp.sco.com/TLS から入手してインストールし、ELF C++ バイナリが 5.0.4 以前のリリースで正しく動作するようにしなければならない。

OS に無料で付いてくる SCO のネイティブ・アセンブラが普通は必要である。だが、GNU アセンブラも使えなくてはならないだろうから(読者が複雑な asm 文を使っているかもしれないから)、このパッケージを--with-gnu-as を指定してコンフィグレーションしなければならない。このためには、gcc/as として GNU アセンブラをインストール(cp か symlink) しておく。新しめの GNU binutils を使わなければならない。バージョン 2.9.1 はうまく動作するようだ。このオプションを選択した場合は、COFF イメージを構築するのは不可能になる。そうしようとすると、はっきりとした形で見えずに失敗に終わるだろう。一般に、"-with-gnu-as" オプションは、ネイティブのアセンブラ程良くはテストされていない。

注意: C++ を構築する場合は、make bootstrap を起動する手順を取る必要がある。ネイティブの OpenServer のコンパイラは、たくさんの正しい C プログラムを正しく構文解析できない cc1plus を作ってしまう可能性があるからである。ネイティブコンパイラで構築を行うときは、make bootstrap しなければならない。

i386-*-isc
システムに付いてくる malloc ではなく GNU malloc をリンクするのが良いだろう。

ISC バージョン 4.1 では、duduced.h を作るときに sed がコアダンプする。バージョン 4.0 の sed を使うこと。

i386-*-esix
システムに付いてくる malloc ではなく GNU malloc をリンクするのが良いだろう。
i386-ibm-aix
GAS のバージョン 2.1 かそれ以降、それに GNU LD の GNU binutils バージョン2.2 かそれ以降を使う必要がある。
i386-sequent-bsd
コンパイルする前に Berkeley 宇宙に行く。
i386-sequent-ptx1*
i386-sequent-ptx2*
configure を実行する前に GNU sed をインストールする必要がある。
i386-sun-sunos4
ブートストラップするには GNU CC の別のバージョンが必要である。これは、現在のバージョンをシステム標準のコンパイラで構築すると、libgcc2.c の一部をコンパイルするときに無限ループに陥るからである。GNU CC の任意のバージョンでコンパイルした GNU CC バージョン 2 にはこの問題はないようだ。

Sun のシステムに GNU CC をインストールする場合の情報については、Sun Install を参照のこと。

i[345]86-*-winnt3.5
このバージョンは、まだリリースされていない GAS を必要とする。それがリリースされるまでの間、前もって構築済みのバイナリ版を<ftp://cs.washington.edu/pub/gnat/> か cs.nyu.edu:pub/gnat から匿名 ftp で入手することができる。また、Windows NT 3.5 SDK の Microsoft のヘッダファイルを使わなければならない。9/4/94 付の CDROM の /mstools/h というディレクトリにこれらが置かれている。NT 3.5 用に特別に作られた、Microsoft リンカの修正版を使わなければならない。これもまた、NT 3.5 SDK CDROM に入っている。このリンカがないときは、Visual C/C++ 1.0 または 2.0 のリンカを使っても良い。

NT に GNU CC をインストールすると、ラッパーとしてのリンカが作られる。これは ld.exe という名前で、ライブラリの指定方法の点で(-L-l) Unix の ld の動作のまねをする。ld.exe はライブラリの Unix 名と Microsoft 名の両方を探す。例えば、-lfoo と指定すると、ld.exe は最初に libfoo.a を探し、次に foo.lib を探す。

GNU CC を Windows にインストールするには二つの方法がある。どちらを取るかは、Unix 的なシェルと色々な Unix 的なツールが手元にあるかどうかによる。

  1. Unix にあるようなシェルやユーティリティーがないときは、DOS のバッチスクリプト configure.bat を使う。これを、MSDOS のコンソールウィンドウかプログラムマネージャのダイアログボックスから configure winnt として起動する。configure.bat は、Unix にあるような sed プログラムがインストール済みであり、コマンド検索パスに入っていることを想定している。sed を使って、Makefile.in から Makefile を作るのである。

    こうしてできる Makefile では、Microsoft の Nmake 保守ユーティリティと Visual C/C++ V8.00 コンパイラを使って GNU CC を構築する。この方法を使う場合には、必要なユーティリティは sedtouch だけであり、コンパイラ自体の構築までしか自動的に行なわない。この後、fixinc.winnt が何をしているのかを眺めて、ヘッダフィアルを編集し、libgcc.a を主動で作らなければならない。

  2. 二番目のインストール方法では、Unix にあるようなシェルが使えて、Unix にあるようなユーティリティが充分揃っていてコマンド検索パスに入っていて、かつ GNU CC の以前のバージョンがインストール済みであることを想定している。GNU CC の古いバージョンは、上記の方法でインストールしたものでも構わないし、事前に構築されたバイナリを使っても構わない。この場合は、ふつうと同じく configure スクリプトを使えば良い。

i860-intel-osf1
これは Paragon 用である。

バージョン 1.0 のオペレーティングシステムを使っている場合は、システムの癖に対処するために特別な手順が必要なので、Installation Problems を参照のこと。

*-lynx-lynxos
LynxOS 2.2 およびそれ以前。これらは、GNU CC 1.x が /bin/gcc としてインストールされてくる。/bin/cc ではなく /bin/gcc を使ってコンパイルすべきである。GNU CC に GNU アセンブラと GNU リンカを使うように指示するには、コンフィギュレーション時に --with-gnu-as --with-gnu-ld を指定すれば良い。これらは、COFF 形式のオブジェクトファイルと実行形式ファイルを生成する。GNU アセンブラとリンカを使わない場合は、GNU CC はインストールされているツールを使い、a.out 形式の実行形式ファイルを生成する。
m32r-*-elf
三菱 M32R プロセッサ。このコンフィギュレーションは組み込みシステム用である。
m68000-hp-bsd
BSD Unix が動作する HP 9000 シリーズ 200 である。このシステム付属の C コンパイラでは GNU CC をコンパイルできないことに注意。ブートストラップ用の GNU CC のバイナリを入手するにはlaw@cygnus.com に連絡して欲しい。
m68k-altos
Altos 3068 である。GNU アセンブラ、GNU リンカ、GNU デバッガを使わなければならない。詳細は、README.ALTOS というファイルを参照すること。
m68k-apple-aux
A/UX が稼働する Apple の Macintosh である。GCC をコンフィギュレーションするのに、システムのアセンブラとリンカを使っても良いし、GNU のアセンブラとリンカを使っても良い。出来れば GNU のものを使うべきである。特に GNU C++ も使いたい場合は。GNU のアセンブラとリンカを使うコンフィギュレーションにするには、configure にオプション --with-gnu-as--with-gnu-ld を追加すれば良い。

システムに付属の C コンパイラでは GNU CC をコンパイルできないことに注意して欲しい。GNU CC をブートストラップするには jagubox.gsfc.nasa.gov にあるバイナリを使うことができる。また、同じところにあるパッチを当てたバージョンの /bin/ld を使うと、もともとのバージョンにある手前勝手な制限値をいくらか上げることができる。

m68k-att-sysv
AT&T 3b1、別名 7300 PC である。この機種で、標準の C コンパイラを使ってGNU CC をコンパイルするには特別な手順が必要である。これは標準のコンパイラのバグのせいである。GNU CC の以前のバージョンをインストールしてあるなら、もっと簡単にブートストラップできる。

GNU CC を 3b1 にインストールするのは、既に動作する GNU CC がないと困難である。これは、インストール済みの C コンパイラにバグがあるためである。しかし、以下のような手順でおそらくうまく行くだろう。我々には、この手順はテスト不可能である。

  1. cccp.c の先頭付近の #include "config.h" をコメントアウトして、make cpp を行なう。これで、GNU cpp の準備版を作る。
  2. 古い /lib/cpp を退避し、GNU cpp の準備版をこのファイル名でコピーする。
  3. cccp.c の変更を取り消すか、オリジナル版を再インストールし、もう一度 make cpp を行なう。
  4. こうしてできた GNU cpp の最終版を /lib/cpp にコピーする。
  5. ファイル tree.c に現れる obstack_free を全て_obstack_free に置き換える。
  6. make を実行して、GNU CC のファーストステージを作る。
  7. /lib/cpp をオリジナルのものに戻す。
  8. これで、普通の手順で、GNU CC をそれ自身でコンパイルしたり、インストールすることが可能になった。

m68k-bull-sysv
Bull DPX/2 のシリーズ 200 と 300 で、BOS-2.00.45 から BOS-2.01 を使っているもの。GNU CC は、システム付属のアセンブラとでもGNU アセンブラとでも使うことができる。configure スクリプトに対し --with-gnu-as を指定することで GNU アセンブラとシステムのCOFF 形式の組合せで使うこともできるし、--with-gnu-as --stabs を指定することで GNU アセンブラとDBX 形式を COFF 形式に包み込んだ形との組合せで使うこともできる。システムアセンブラの問題や DPX/2 用の GAS の入手方法については、F.Pierresteguy@frcl.bull.fr に問い合わせて欲しい。
m68k-crds-unox
Unos で構築するには configure unos とする。

Unos のアセンブラは、as ではなく casm という名前である。何らかの変な理由により、/bin/as/bin/casm にリンクすると、動作が代わってしまうのでうまく行かない。このため、GNU CC をインストールする際には、GCC の各パスがインストールされるサブディレクトリに以下のようなスクリプトを as という名前でインストールする必要がある。

#!/bin/sh
casm $*

デフォルトの Unos のライブラリは、libc.a ではなく、libunos.a という名前である。GNU CC を機能させるためには、gcc.c の中の -lc への全ての参照を -lunos に変えるか、/lib/libc.a/lib/libunos.a にリンクするかのどちらかを行なう。

GNU CC をシステム標準のコンパイラでコンパイルするには、alloca のバグを避けるため、ステージ 2 を作るときに-O を使わないようにすること。そうしておいて、ステージ 3 のコンパイラは、ステージ 2 コンパイラに -O を指定して作る。こうして出来るステージ 3 のコンパイラは、他のシステムでの通常のステージ 2 のコンパイラと同じ性格を持つものである。これを使って、ステージ 4 のコンパイラを作り、ステージ 3 のコンパイラと比較して、コンパイルが正しく行なわれたかどうかを検査すること。

(恐らく、x-crds にあるコメントにあるように、単に x-crdsALLOCA を定義すれば、上のパラグラフの話は不要になると思われる。うまく行った人がいたら、是非とも教えて欲しい。)

Unos は、要求時ページングではなくてメモリセグメンテーションを使っているので、メモリがたくさん必要になる。他のタスクが走っていなければ、5Mb でぎりぎり足りる。cc1 をリンクするのに失把したら、オブジェクトファイルをライブラリに入れたうえで、そのライブラリとリンクしてみて欲しい。

m68k-hp-hpux
HP-UX が動作する HP 9000 シリーズの 300 か 400 である。HP-UX バージョン 8.0 のアセンブラにはバグがあり、GNU CC をコンパイルできない。このバグを修正するには、HP からパッチ PHCO_4484 を入手して欲しい。

また、--with-gnu-as を指定して GAS を使いたい場合には、GAS のバージョン 2.1 以降と GNU リンカのバージョン 2.1 を使わなければならない。初期のバージョンの GAS は、GAS の出力を HP-UX のネイティブ形式に変換するプログラムに依存していた。だが、そのプログラムが更新されていないのである。GDB は HP-UX のネイティブ形式を理解しないので、GDB を使いたい場合も GAS を使う必要がある。

m68k-sun
Sun 3 である。デフォルトでは Sun FPA を使うコンフィギュレーションファイルは提供していない。浮動小数点トラップ向けのシグナルハンドラを設定するプログラムは、本質的に FPA と一緒には動作不可能だからである。

Sun のシステムでの GNU CC のインストールに関する情報については、Sun Install を参照のこと。

m88k-*-svr3
AT&T/Unisoft/Motorola V.3 のリファレンスポートが動作する、モトローラ m88k である。これらのシステムでは、標準の C コンパイラとしてGreen Hills C リビジョン 1.8.5 が使われることが多い。このコンパイラには明らかにバグがあり、そのため、ステージ 2 とステージ 3 のオブジェクトファイルが異なるものになってしまう。そうなった場合、ステージ 4 のコンパイラを作って、ステージ 3 と比較するようにして欲しい。その結果、ステージ 3 とステージ 4 のオブジェクトファイルが同じであったら、標準の C コンパイラのバグに遭遇した可能性が高い。こうして出来たステージ 3 とステージ 4 のコンパイラは使えると思う。

だがしかし、ブートストラップするのに一番良いのは、もしあるなら古いバージョンの GNU CC を使うことである。

m88k-*-dgux
DG/UX の動作するモトローラの m88k である。DG/UX 上 の 88open BCS のネイティブコンパイラまたはクロスコンパイラを構築するには、コンフィギュレーション名として m88k-*-dguxbcs を指定し、88open BCS のソフトウェア開発環境で構築を行なう。DG/UX 上の ELF のネイティブコンパイラまたはクロスコンパイラを構築するには、mm8k-*-dgux を指定し、DG/UX ELF 開発環境で構築を行なう。ソフトウェア開発環境を設定するには、sde-target コマンドを使い、引数として m88kbcsm88kdguxelf を指定する。

コンフィギュレーション名を指定しないと、configure が、現在のソフトウェア開発環境に基づいたコンフィギュレーションを推測する。

m88k-tektronix-sysv3
UTekV 3.2e の動作する Tektronix XD88 である。バグの多い Green Hills のコンパイラでブートストラップを行なうときは、ステージ 1 を作るとき最適化を行なわないこと。また、付属の LAI System V NFS もバグが多いので、NFS マウントされたディレクトリで構築する場合は、一回リブートしてから行なうこと。あるいは、NFS は全く使わないほうが良いだろう。さもないと、ステージ間の比較で問題が起きる可能性がある。
mips-mips-bsd
MIPS のオペレーティングシステムを BSD モードで実行しているMIPS のマシンである。このシステムの古いバージョンには、memcpymemcmpmemset といった関数がないものがある。読者のシステムにこれらの関数がない場合は、mips-bsd.h 中の TARGET_MEM_FUNCTIONS の定義を削除するか未定義にする必要がある。

MIPS の C コンパイラは、switch 文用の表の大きさを-Wf,-XNg1500 オプションで増加させておかないと、cp/parse.c をコンパイルできないと言われている。最適化オプション -O2 を使うには、-Olimit 3000 も必要である。この二つのオプションは両方とも、configure が作る Makefile には自動的に追加される。make の変数 CC を上書きして MIPS のコンパイラを使うには、-Wf,-XNg1500 -Olimit 3000 を追加する必要がある。

mips-mips-riscos*
MIPS の C コンパイラは、switch 文用の表の大きさを-Wf,-XNg1500 オプションで増加させておかないと、cp/parse.c をコンパイルできないと言われている。最適化オプション -O2 を使うには、-Olimit 3000 も必要である。この二つのオプションは両方とも、configure が作る Makefile には自動的に追加される。make の変数 CC を上書きして MIPS のコンパイラを使うには、-Wf,-XNg1500 -Olimit 3000 を追加する必要がある。

RISC-OS の動作する MIPS のマシンでは、4つの異なる個性をサポートする。デフォルトと BSD 4.3、System V.3、System V.4 である。(RISC-OS の古いバージョンでは V.4 はサポートしていない)。これらのプラットフォーム用に GCC をコンフィギュレーションするには、次のコンフィギュレーションを使う。

mips-mips-riscosrev
リビジョン rev の RISC-OS 用のデフォルトのコンフィギュレーション。
mips-mips-riscosrevbsd
リビジョン rev の RISC-OS 用の BSD 4.3 のコンフィギュレーション。
mips-mips-riscosrevsysv4
リビジョン rev の RISC-OS 用の System V.4 のコンフィギュレーション。
mips-mips-riscosrevsysv
リビジョン rev の RISC-OS 用の System V.3 のコンフィギュレーション。

ここでリビジョン rev は、RISC-OS のリビジョンである。RISC-OS のリビジョン 4 から リビジョン 5 に移るときはGCC を再コンフィギュレーションしなければならない。これは、リンカのバグ(詳細については Installation Problems) を回避する効果がある。

mips-sgi-*
SGI IRIX 4 で GCC をコンパイルするには、Silicon Graphics 提供のCD-ROM から "c.hdr.lib" というオプションをインストールする必要がある。これは、リリース 4.0.1 の二枚目の CD に入っている。

SGI IRIX 5 で GCC をコンパイルするには、Silicon Graphics 提供のIDO CD-ROM から "compiler_dev.hdr" というサブシステをインストールする必要がある。

IRIX 5 では、CFLAGS-save-temps を追加しないと、make compare に失敗する。このシステムでは、アセンブラに対する入力ファイル名がオブジェクトファイルに格納されるので、そのファイル名が stage1stage2 で違っているとオブジェクトファイルの比較に失敗する。オプション -save-temps を指定すると、アセンブラに対する入力ファイル名として、/tmp に置かれるランダムに選ばれた名前ではなくて、決まった名前を使う。-save-temps は、これなしでは比較に失敗するのでない限り、指定しないこと。これを指定してしまうと、各コンパイル段階の後で.i ファイルと .s ファイルを自分で削除しなければならなくなる。

MIPS の C コンパイラの場合は、switch 文用の表の大きさを-Wf,-XNg1500 というオプションを指定することで大きくしておかないとcp/parse.c がコンパイルできないと報告されている。最適化オプション -O2 を指定するときは、-Olimit 3000 も指定する必要がある。このどちらのオプションも、シェルスクリプト configure が作るMakefile では自動的に生成される。 make の変数 CC を上書きして、MIPS のコンパイラを使うときは、-Wf,-XNg1500 -Olimit 3000 というオプションを指定する必要がある。

Irix のバージョン 4.0.5F、それに多分その他のバージョンでも同じだが、アセンブラにバグがあり、命令の並べ替えが正しく行なわれない。これを回避するには、ターゲットのコニフィギュレーションをmips-sgi-irix4loser と指定する。このコンフィギュレーションは、アセンブラによる最適化を抑止する。

ターゲット mips-sgi-irix4 でコンフィギュレーションした場合は、アセンブラの最適化は -noasmopt オプションで抑止できる。このオプションはアセンブラには -O0 として渡り、命令の並べ替えを行なわない。

-noasmopt オプションを使うと、問題がアセンブラによる命令並べ替えに間違っているために起きるかどうかを調べることができる。-noasmopt を指定しても問題がなくならない場合でも、なおアセンブラによる命令並べ替えの問題のせいである可能性がある。この問題のために、GNU CC 自体が正しくコンパイルされていない恐れがある。

Irix 5 でデバッグを出来るようにするためには、GNU as の 2.5 以降を使わなければならず、gcc をコンフィギュレーションするときに configure のオプションに --with-gnu-as を指定しなければならない。GNU as は、binutils パッケージの一部として配布されている。

mips-sony-sysv
Sony MIPS NEWS である。これは NEWSOS 5.0.1 ではうまくいくが、5.0.2 ではうまくいかない(5.0.2 では COFF ではなく ELF が使われている)。5.0.2 は恐らくボランティアの手ですぐにサポートされるだろう。特に、共有ライブラリをリンクするときに GCC で生成されたコードをリンカが嫌う。
ns32k-encore
Encore ns32000 システムである。Encore システムは BSD の場合のみサポートされている。
ns32k-*-genix
National Semiconductor の ns32000 システムである。Genix の allocamalloc にはバグがあるので、GNU Emacs からコンパイル済みの版を取ってきて使う必要がある。
ns32k-sequent
コンパイルを行なう前に Berkley 宇宙に移行する。
ns32k-utek
UTEX の ns32000 システム("merlin") である。システム付属の C コンパイラでは GNU CC をコンパイルできない。tektronix!reed!mason に連絡を取って、ブートストラップに必要な GNU CC のバイナリを入手して欲しい。
romp-*-aos
romp-*-mach
IBM RT PC をサポートしている OS は、AOS と MACH だけである。GNU CC は RT 上の AIX をサポートしていない。GNU CC をコンパイルするには、GNU CC 自体の古いバージョンlを使うことをお勧めする。Metaware のコンパイラである hc でコンパイルするのは、一応動作するが、ステージ 2 とステージ 3 のオブジェクトの比較で、色々なファイルが一致しないだろう。これらの問題は、幾つかの浮動小数点定数のわずかな差異によるもので、安心して無視できるものである。ステージ 3 のコンパイラが正しいものである。
rs6000-*-aix
powerpc-*-aix
IBM XLC コンパイラの各リリースの色々な初期バージョンでは、GNU CC のブートストラップができない。症状としては、stage2 と stage3 のオブジェクトファイルの差異と、libgcc.a あるいは enquire をコンパイルするときのエラーがある。問題があることが判明しているリリースは以下の通り。xlc-1.2.1.8、xlc-1.3.0.0 (AIX3.2.5 と共に配布されている)、xlc-1.3.0.19 である。xlc-1.2.1.28 と xlc-1.3.0.24 (PTF 432238) はどちらも正しく動作するGNU CC を生成できることがわかっているが、より最近のリリースの方がGNU CC を正しくブートストラップできる。

リリース 4.3.0 の AIX と AIX 3.2.4 以前のリリースに含まれる IBM のアセンブラは、デバッグ情報疑似命令を受け付けない。このアセンブラに対する修正はPTF として入手可能である。さらに、AIX 3.2.5 以降および GNU アセンブラを使う場合は、GNU C コンパイラを構築するためには、1995年10月16日以降に修正されたバージョンの GNU アセンブラが必要である。以上の問題の詳細については README.RS6000 というファイルを参照のこと。

GNU CC は、まだ 64ビットの PowerPC 命令をサポートしていない。

このアーキテクチャでは Objective C は動作しない。呼び出し規約と互換性のない仮定をしているからである。

RS/6000 上の AIX では、合衆国以外の環境をサポートしている(NLS)。コンパイラとアセンブラは NLS を使って、浮動小数点数(浮動小数「点」として「.」と「,」のどちらを使うか)を含む様々なオブジェクトのロケール固有の表現をサポートしている。GNU CC でリンクしたライブラリが、アセンブラが受け付けるのと同じ浮動小数点形式を生成しないという問題が報告されている。この問題に出会ったら、環境変数 LANG を"C" か "En_US" に設定してみて欲しい。

AIX 4.1 用では、GNU CC がバインダ(リンカ)を起動する方法が変わったので、リンク時に、以前は出なかった、シンボルが二重定義されているという警告がでるかもしれない。AIX 用の GNU CC で生成されたアセンブリファイルは、元のプログラムに存在する、ある種のグローバル変数と関数の宣言について、シンボルの複数定義を含んでいる。警告が出ても、リンカは正しいライブラリや実行可能な実行形式を生成するはずである。

デフォルトでは、AIX 4.1 は Power でも PowerPC でも使えるコードを生成する。

-mcpu=cpu_type オプションに対するデフォルトをconfigure のオプション --with-cpu-cpu_type オプションで指定することができる。

powerpc-*-elf
powerpc-*-sysv4
System V.4 の動作する、ビッグエンディアンモードのPowerPC システム。

-mcpu=cpu_type オプションに対するデフォルトをconfigure のオプション --with-cpu-cpu_type オプションで指定することができる。

powerpc-*-linux-gnu
Linux ベースの GNU システムの動作する、ビッグエンディアンモードのPowerPC システム。

-mcpu=cpu_type オプションに対するデフォルトをconfigure のオプション --with-cpu-cpu_type オプションで指定することができる。

powerpc-*-eabiaix
-mcall-aix がデフォルトで選択された、ビッグエンディアンモードの組み込み PowerPC システム。

-mcpu=cpu_type オプションに対するデフォルトをconfigure のオプション --with-cpu-cpu_type オプションで指定することができる。

powerpc-*-eabisim
PSIM シミュレータの下で動作させるのに使われる、ビッグエンディアンモードの組み込み PowerPC システム。

-mcpu=cpu_type オプションに対するデフォルトをconfigure のオプション --with-cpu-cpu_type オプションで指定することができる。

powerpc-*-eabi
ビッグエンディアンモードの組み込み PowerPC システム。

-mcpu=cpu_type オプションに対するデフォルトをconfigure のオプション --with-cpu-cpu_type オプションで指定することができる。

powerpcle-*-elf
powerpcle-*-sysv4
System V.4 の動作する、リトルエンディアンモードのPowerPC システム。

-mcpu=cpu_type オプションに対するデフォルトをconfigure のオプション --with-cpu-cpu_type オプションで指定することができる。

powerpcle-*-solaris2*
Solaris 2.5.1 以降の動作する、リトルエンディアンモードの PowerPC システム。

-mcpu=cpu_type オプションに対するデフォルトをconfigure のオプション --with-cpu-cpu_type オプションで指定することができる。Sun 4.0 コンパイラのベータ版では GNU CC を正しく構築できないようだ。また、ホストアセンブラとリンカにも問題がある。この問題はGNU 版でこれらのツールを置き換えることで対処できる。

powerpcle-*-eabisim
PSIM シミュレータの下で動作させるのに使われる、リトルエンディアンモードの組み込み PowerPC システム。
powerpcle-*-eabi
リトルエンディアンモードの組み込み PowerPC システム。

-mcpu=cpu_type オプションに対するデフォルトをconfigure のオプション --with-cpu-cpu_type オプションで指定することができる。

powerpcle-*-winnt
powerpcle-*-pe
Windows NT の動作する、リトルエンディアンモードの PowerPC システム。

-mcpu=cpu_type オプションに対するデフォルトをconfigure のオプション --with-cpu-cpu_type オプションで指定することができる。

vax-dec-ultrix
Vax C(vcc) でコンパイルしてはいけない。(例えば、alloca が使われた場合に)正しくないコードを生成することがある。

一方、pcc で cp/parse.c をコンパイルするのは、pcc の内部テーブルの大きさの制限のため、うまくいかない。この問題を避けるには、GNU C コンパイラだけをまずコンパイルし、それを使って、必要な全ての言語フロントエンドを再コンパイルするのが良い。

sparc-sun-*
Sun のシステムでの GNU CC のインストールに関する情報については、Sun Install を参照のこと。
vax-dec-vms
VMS への GNU CC のインストール方法の詳細については、VMS Install を参照のこと。
we32k-*-*
この計算機は、3b2、3b5、3b20、その他類似の名前でも知られている。(ただし、3b1 は実際には 68000 である。Configurations 参照。)

システムのコンパイラでコンパイルするときは -g を使わないこと。システムのリンカが、デバッグ情報がついた、このような大きなプログラム扱えないようである。

システムのコンパイラは、GNU CC の stmt.c をコンパイルするときに、能力を越えてしまう。これを回避するには、GNU CC にある cpp をまず構築し、システムのプリプロセッサの代わりに、システムの C コンパイラと組み合わせて stmt.c をコンパイルすることである。以下にその方法を示す。

mv /lib/cpp /lib/cpp.att
cp cpp /lib/cpp.gnu
echo '/lib/cpp.gnu -traditional ${1+"$@"}' > /lib/cpp
chmod +x /lib/cpp

システムのコンパイラは、GNU CC の最適化ファイルの幾つかについて正しくないコードを生成する。このため、ステージ 2 コンパイラは最適化なしで構築しなければならない。その後、ステージ 3 コンパイラを最適化付きで構築する。それで出来上がった実行形式は動作するはずである。以下に実行すべきコマンドを示す。

make LANGUAGES=c CC=stage1/xgcc CFLAGS="-Bstage1/ -g"
make stage2
make CC=stage2/xgcc CFLAGS="-Bstage2/ -g -O"

C++ コンパイラを構築するには ULIMIT の設定を上げる必要があるかもしれない。出来上がった cc1puls は、1メガバイトを越えるので。


Node:Other Dir, Next:, Previous:Configurations, Up:Installation

別ディレクトリでのコンパイル方法

オブジェクトファイルと実行形式ファイル、ソースのあるディレクトリとは別のディレクトリに作りたい場合は、以下の部分で手順が異なる。

  1. VPATH の機能をサポートしている Make が必要である。(GNU Make はサポートしている。大抵の BSD システムの Make もサポートしている。)
  2. ソースディレクトリで configure を実行したことがあるなら、そのコンフィギュレーションを取り消さなければならない。そのためには以下のコマンドを実行する。
    make distclean
    
  3. configure を実行する前に、コンパイラを作成するディレクトリに移動する。
    mkdir gcc-sun3
    cd gcc-sun3
    

    シンボリックリンクのないシステムでは、このディレクトリはソースコードのあるディレクトリと同じファイルシステムになければならない。

  4. configure がどこにあるのかを実行時に指定してやる。
    ../gcc/configure ...
    

    これでも configure にコンパイラのソースがどこにあるのかを教えたことになる。configure は、自分が起動されたときのファイル名からディレクトリを取り出すからである。この指定を確実にしたければ、--srcdir オプションを使ってソースディレクトリを指定することもできる。例えば、以下のようにすれば良い。

    ../gcc/configure --srcdir=../gcc other options
    

    --srcdir で指定したディレクトリが、configure の存在するディレクトリと同じである必要はない。

これで、make を実行することができる。普通のソースファイルに変更があっても、上記のコンフィギュレーションの手順を繰り返す必要はない。しかし、コンフィギュレーションファイルを変更した場合は、シンボリックリンクがないシステムでは、configure を再実行する必要がある。


Node:Cross-Compiler, Next:, Previous:Other Dir, Up:Installation

クロスコンパイラの構築とインストールの方法

GNU CC は、多くの機種に対してクロスコンパイラとして機能するが、全部の機種に対してというわけではない。

GNU CC はアセンブラコードを生成するので、オブジェクトファイルを作るには、おそらく、GNU CC が実行させることのできるクロスアセンブラが必要になる。ターゲット機種以外のマシンでリンクを行ないたければ、同様にクロスリンカも必要になる。また、ホストマシンにインストール可能なターゲット機種用のヘッダファイルとライブラリも必要になる。


Node:Steps of Cross, Next:, Previous:Cross-Compiler, Up:Cross-Compiler

クロスコンパイルのステップ

クロスコンパイラを使って、プログラムをコンパイル、実行するには以下のような段階を経る必要がある。

大体の場合は、同じホストマシン上で全部やってしまうのが簡単である。というのは、GNU CC を一回起動するだけで済んでしまうからである。このためには、適当なクロスアセンブラやクロスリンカが必要である。幾つかのターゲットでは、GNU アセンブラと GNU リンカが用意されている。


Node:Configure Cross, Next:, Previous:Steps of Cross, Up:Cross-Compiler

クロスコンパイラのコンフィギュレーション

GNU CC をクロスコンパイラとして構築するには、configure を実行することから始める。--target=target を使ってターゲットを指定する。configure が使っているシステムを正しく認識しないときは、--build=build も合わせて指定する。以下の例では、HP の 68030 を使った BSD システム向けのコードを生成するクロスコンパイラのコンフィギュレーションを行なっている。これは、configure を実行しているシステムが正しく認識される場合である。

./configure --target=m68k-hp-bsd4.3


Node:Tools and Libraries, Next:, Previous:Configure Cross, Up:Cross-Compiler

クロスコンパイラ用のツールとライブラリ

クロスアセンブラとクロスリンカが利用できるのであれば、ここでインストールする。/usr/local/target/bin というディレクトリにこれらを置く。このディレクトリに置くべきツールの一覧を以下に示す。

as
クロスアセンブラ。
ld
クロスリンカ。
ar
クロスアーカイバ。ターゲットマシンの形式でアーカイブファイル(ライブラリ) を操作することができるプログラムである。
ranlib
アーカイブファイルのシンボルテーブルを作るプログラム。

GNU CC をインストールするとき、上記のプログラムをこのディレクトリから探し、クロスコンパイラが後で実行するときに探す適切な場所にコピーするかリンクを張る。

これらのファイルを用意する一番簡単な方法は、Binutils パッケージとGAS を構築することである。これらのツールを、GNU CC をコンフィギュレーションするのに使ったのと同じ --host オプションと --target オプションを使ってコンフィギュレーションするようにし、構築とインストールを行なう。このインストールで、Binutils や GAS の実行形式が自動的に適切なディレクトリに置かれる。ただ、残念なことに、Binutils や GAS は、GNU CC がサポートしているターゲットの全てでサポートされているわけではない。

標準 C ライブラリのような、クロスコンパイラと共に使うライブラリをインストールする場合は、それらを /usr/local/target/lib に置くこと。GNU CC をインストールすると、このディレクトリに置かれている全てのファイルが、GNU CC が検索してリンクを行なう正しい場所にコピーされる。以下に、ターゲット機種からライブラリを幾つかコピーする例を示す。

ftp target-machine
lcd /usr/local/target/lib
cd /lib
get libc.a
cd /usr/lib
get libg.a
get libm.a
quit

必要になるライブラリの正確な組と、ターゲットマシン上での位置は、オペレーティング・システムに非常に依存する。

多くの機種では、crt0.ocrtn.o のような、各実行形式ファイルにリンクされる「開始ファイル」を必要とする。この二つのファイルは、/usr/local/target/lib に存在しなければならない。crt0.o には複数の変種が存在する可能せいがある。これは、プロファイリングや他のコンパイルオプションに応じて使われる。ターゲットの STARTFILE_SPEC の定義を見て、どういう開始ファイルを使っているかを見て欲しい。以下に、これらのファイルをターゲットマシンからコピーする方法の例を示す。

ftp target-machine
lcd /usr/local/target/lib
prompt
cd /lib
mget *crt*.o
cd /usr/lib
mget *crt*.o
quit


Node:Cross Runtime, Next:, Previous:Tools and Libraries, Up:Cross-Compiler

libgcc.a とクロスコンパイラ

GNU CC でコンパイルしたコードは、決まった実行時サポート関数を暗黙に使う。このうちの幾つかの関数は、GNU CC 自身で問題なくコンパイルできるのだが、幾つかできないものがある。問題となる関数はソースファイル libgcc1.c にあるものである。このファイルから作られるライブラリは libgcc1.a と呼ばれる。

ネイティブコンパイラを構築するときは、これらの関数は何か他のコンパイラでコンパイルされる。そのコンパイラとはGNU CC をブートストラップするのに使っているものである。おそらく、そのコンパイラは、これらの演算を開かれたコードで書く方法を知っているだろうし、あるいは、その機種に付いてくるはずの実行時のエミュレーション機能を呼び出す方法を知っているだろう。だが、この方法はクロスコンパイラを構築する場合には使えない。構築に使うコンパイラはホストシステムについては知っているが、ターゲットシステムのことは知らないからである。

このため、クロスコンパイラを構築する際には、期待される仕事を行なう適切なライブラリ libgcc1.a を用意する必要がある。

libgcc1.c をクロスコンパイラ自体でコンパイルするのはうまくいかない。このファイルにある関数群は、GNU CC が読者のターゲット機種用にはどうやって開かれた形でコードを書けば良いか知らないような算術演算を実装するものであると想定されている。これらの関数を GNU CC 自体でコンパイルしたなら、無限に再帰的なコンパイルになってしまう。

任意の与えられたターゲットで、これらの関数のほとんどは必要ではない。GNU CC が、算術演算を開いたコードに書けるなら、これらの関数を呼び出さない。読者のターゲット機種で、これらの関数を一切必要としないというのも可能である。その場合は、libgcc1.a として空のライブラリを与えれば良い。

多くのターゲットでは、サポートが必要なライブラリは、乗算と除算用のもののみである。乗算と除算を行う関数を含むライブラリとリンクするのなら、MULSI3_LIBCALL 等のマクロを定義することで、GNU CC に直接呼出しを行わせることが可能である。これらのマクロは、ターゲット記述マクロファイルで定義する必要がある。幾つかのターゲットについては、既に定義済みである。これで libgcc1.a を不要とするのには充分である可能性がある。もしそうなら、空のライブラリを指定することが可能である。

ターゲットによっては、浮動小数点命令がないものがある。これらの機種では libgcc1.a 内の別の関数が必要になる。それは、浮動小数点算術演算を行うものだえる。GNU CC の最近のバージョンには、浮動小数点演算をエミュレートするファイルが含まれている。ある程度作業を行えば、libgcc1.a として使える浮動小数点エミュレータを作り上げることが出来るはずである。おそらく、将来のバージョンでは、この作業を自動的に簡単に行うコードが入るだろう。入るかどうかは、実装したいという人が誰かいるかどうかに依る。

組み込みターゲットの中には、 libgcc1.a の必要な全てのルーチンを C またはアセンブラで書いたものが付いてくるものがある。これらのターゲットでは、libgcc1.a を自動的に構築するので、読者は何も特別なことをする必要がない。その他の組み込みターゲットは、なんら libgcc1.a を必要としない。なぜなら、必要な演算は全てハードウェアによりサポートされているからである。

読者のターゲットシステムに何か別の C コンパイラがあるなら、GNU CC をその機種でのネイティブ・コンパイラとしてコンフィギュレーションし、make libgcc1.alibgcc1.a を構築することが可能であり、その結果得られるファイルをクロスコンパイラと共に使うことができる。このためには、ターゲット機種で以下の手順を実行する。

cd target-build-dir
./configure --host=sparc --target=sun3
make libgcc1.a

次に以下をホスト機種で実行する。

ftp target-machine
binary
cd target-build-dir
get libgcc1.a
quit

libgcc1.a で必要とされる関数を提供するもう一つの方法として、それらの関数に対して perform_... マクロを適切に定義する方法がある。これらのマクロ定義で、これから実装しようとしているまさにその C の算術演算子を使っていなければ、読者が構築中のクロスコンパイラでコンパイルできるはずである。(これらの定義が読者のターゲットファイルに既に存在するなら、必要なものは揃ったことになる。)

perform_... マクロを使って libgcc1.a を構築するには、GNU CC を構築するときに LIBGCC1=libgcc1.a OLDCC=./xgcc とする。そうしない場合は、make を実行する前に、クロスコンパイラを構築するディレクトリに、代わりのライブラリをlibgcc1.a という名前で置く必要がある。


Node:Cross Headers, Next:, Previous:Cross Runtime, Up:Cross-Compiler

クロスコンパイラとヘッダファイル

単体のプログラムや組み込みシステム向けのプログラムをクロスコンパイルする場合は、GNU CC の一部(それに読者のプログラムの一部)であるものを除いて、ヘッダファイルは何も必要ないだろう。しかし、読者のプログラムを libc.a のような標準 C ライブラリとリンクしたいのであれば、そのライブラリに付属するはずのヘッダファイルを使ってコンパイルする必要があるだろう。

GNU C コンパイラにはこういうヘッダファイルは付いていない。何故なら、(1) システムに依存するものであり、(2) C ライブラリに所属するものであって、コンパイラに所属するものではないからである。

GNU C ライブラリが読者の対象機種をサポートしているなら、そこからヘッダファイルを入手できる(読者のプログラムをリンクするときに実際に GNU ライブラリを使うことを想定した場合)。

読者の対象機種に C コンパイラが付いているなら、おそらく適切なヘッダファイルも付いてくるはずである。このヘッダファイルをホストマシンからアクセスできるようにすれば、クロスコンパイラからも使える。

そうなっていない場合は、クロスコンパイルを行なうには読者自身がヘッダファイルを用意しなければならない。

適当なヘッダファイルが見つかったなら、それをクロスコンパイラを構築する前に、ディレクトリ /usr/local/target/include に置く。そうしておくと、インストールの際に fixincludes が正しく実行され、ヘッダファイルの修正版を GNU CC が使用する場所にインストールされる。

ヘッダファイルはクロスコンパイラを構築する前に用意しなければならない。構築の段階で、実際にクロスコンパイラを実行して libgcc.a の一部を生成するからである。(これらは、GNU CC でコンパイル可能な一部である。) この一部は適切なヘッダファイルを必要とする。

以下にヘッダファイルをターゲット機種からコピーする方法の例を示す。ターゲット機種上でまず以下を実行する。

(cd /usr/include; tar cf - .) > tarfile

次にホストマシンで以下を実行する。

ftp target-machine
lcd /usr/local/target/include
get tarfile
quit
tar xf tarfile


Node:Build Cross, Previous:Cross Headers, Up:Cross-Compiler

クロスコンパイラ構築の実際

ようやく、一個の機種向けのコンパイラをコンパイルするのに、ステージ 1 を構築する段階に進むことができる。読者が何らかの libgcc1.a を用意していなければ、そのファイルを必要とする時点でコンパイルが止まり、適切なエラーメッセージを出すだろう。libgcc1.a を用意していれば、コンパイラを構築すると、libgcc1-test というテストプログラムをコンパイル、リンクするはずである。このリンクの際に、エラーが出たなら、libgcc1.a の中に必要なルーチンが全部は揃っていないということである。

読者はヘッダファイル float.h を提供しなければならない。そのための一つの方法は、ターゲット機種で enquire をコンパイルし、実行することである。enquire がやることは、ターゲット機種上で実行して、実験により、ターゲット機種の浮動小数点表現の性質を明らかにすることである。enquire は発見した結果をヘッダファイルfloat.h に記録する。ターゲット機種で enquire を実行してこのファイルを生成できない場合は、何か別の手段で適切な float.h を用意する必要が出てくるだろう。さもないと、プログラムの中でfloat.h を使わないようにしなければならなくなる。

クロスコンパイラの場合は、ステージ2 を作らないように。クロスコンパイラを使って、GNU CC をクロスコンパイラとして構築することはできない。何故なら、そうすると、ホストではなくて、ターゲット機種上で動作するプログラムができるからである。例えば、386から68030へのクロスコンパイラをそれ自身でコンパイルした場合、その結果は 386 にとっても(68030のコードにコンパイルされるので)、68030 にとっても(386 をホストとしてコンフィギュレーションされているので) 正しくない。GNU CC 自身を 68030 のコードにコンパイルしたいのであれば、68030 上でコンパイルしようとも、386 上でクロスコンパイラとしてコンパイルしようとも、コンフィギュレーションジに 68030 をホストとして指定しなければならない。

クロスコンパイラをインストールするには、普通と同じに、make install とする。


Node:Sun Install, Next:, Previous:Cross-Compiler, Up:Installation

GNU CC を Sun にインストール

Solaris では、GNU CC を作るときに、/usr/ucb にある、リンカやその他のツールを使わないこと。代わりに、/usr/ccs/bin にあるものを使うようにする。

アセンブラが、ブートストラップの際に Error: misaligned data と報告してきたら、おそらく GNU アセンブラの古いバージョンを使っているせいである。GNU binutils の最新版に更新するか、Solaris のアセンブラを使うこと。

libgcc.a をコンパイルするときに、環境変数 FLOAT_OPTION が設定されていないことを確認すること。libgcc.a をコンパイルするときにこの環境変数が f68881 に設定されていると、コンパイルした結果のコードが特別な開始ファイルとリンクすることを要求し、特別な苦労をしないと正しくリンクできないだろう。

Sun のライブラリの特定のバージョンの alloca にはバグがある。このバグを避けるには、GNU CC でコンパイルした GNU CC のバイナリをインストールする。こうしてインストールしたバイナリは、allocaを組み込み関数として使い、ライブラリ中のものを使うことはない。

Sun のコンパイラの幾つかのバージョンは、GNU CC をコンパイルしているときに落ちてしまう。問題は、cpp がセグメンテーション違反を起こすことにある。この問題は、環境変数に大量のデータが設定されていることに起因するように思える。この問題を回避するには、以下のコマンド行を使い、Sun CC でGNU CC をコンパイルする。

make CC="TERMCAP=x OBJS=x LIBFUNCS=x STAGESTUFF=x cc"

SunOS 4.1.3 と 4.1.3_U1 には、GNU CC をコンパイルしている時に不定期にコアダンプするというバグがある。共通する症状は再現性のない内部コンパイラエラーである。この問題を直すには、Sun の推奨パッチ 100726(SunOS 4.1.3 用) か 101508(SunOS 4.1.3_U1) をインストールするか、あるいはもっと新しい SunOS のリリースに更新することである。


Node:VMS Install, Next:, Previous:Sun Install, Up:Installation

GNU CC を VMS にインストール

VMS 版の GNU CC は、ソースコードとコンパイル済みバイナリの双方を含むバックアップ・セーブセットで配布されている。

gcc コマンドを、VMS C コンパイラと同じ方法で、簡単に使えるようにインストールするには、GNU CC 用の VMS CLD ファイルを以下のようにインストールしなければならない。

  1. VMS の論理名 GNU_CCGNU_CC_INCLUDE を定義し、GNU CC の実行形式(gcc-cpp.exegcc-cc1.exe、等)とC のインクルードファイルが置かれているディレクトリをそれぞれ指すようにする。これには、
    $ assign /system /translation=concealed -
      disk:[gcc.] gnu_cc
    $ assign /system /translation=concealed -
      disk:[gcc.include.] gnu_cc_include
    

    というコマンドに適切なディスク名とディレクトリ名を指定する。これらのコマンドを読者のシステム起動ファイルに入れておけば、リブート時に常に実行されるようにすることができる。読者が望むなら、[GCC] ディレクトリに置いたGCC_INSTALL.COM スクリプトを経由して行なうことも出来る。

  2. GCC コマンドを以下のコマンド行でインストールする。
    $ set command /table=sys$common:[syslib]dcltables -
      /output=sys$common:[syslib]dcltables gnu_cc:[000000]gcc
    $ install replace sys$common:[syslib]dcltables
    
  3. 以下のようにして、ヘルプファイルをインストールする。
    $ library/help sys$library:helplib.hlb gcc.hlp
    

    これで、GNU CC を gcc /verbose file.c のようなコマンド行で起動できるようになったはずである。これは Unix の場合のgcc -v -c file.c というコマンドに同じである。

GNU C++ を使う場合には、まず GNU CC をインストールしておいてから、以下の段階を踏まなければならない。

  1. This can be done with the command: VMS 論理名 GNU_GXX_INCLUDE を定義し、プリプロセッサが C++ のヘッダファイルを検索するディレクトリを指すようにする。このためには以下のコマンドを実行する。
    $ assign /system /translation=concealed -
      disk:[gcc.gxx_include.] gnu_gxx_include
    

    ここで適切なディスク名とディレクトリ名を指定する。C++ 実行時ライブラリを使うなら、ここがそのライブラリのインストール手続によりヘッダファイルがインストールされる場所である。

  2. gcc-cc1plus.exe というファイルを入手し、gcc-cc1.exe が置かれているディレクトリにこれを置く。

    これで GNU C++ コンパイラは gcc /plus /verbose file.cc のようなコマンドで起動できるようになる。これは Unix の場合のg++ -v -c file.cc と同じである。

我々は、バージョンが対応しているバイナリとソースを VMS 用の配布テープに入れるようにしている。だが、時々バイナリがソースよりも古いバージョンになってしまうことがある。常に更新するようにする時間がないためである。(/version オプションを使ってバイナリのバージョンを知ったうえで、ソースファイルの中の version.c と比較すると、バイナリとソースの同期が取れているかどうかが判る。) バイナリの方が古い場合は、そのバイナリを使って、ソースコードから再コンパイルした方が良い。再コンパイルしなければならないようなら、以下の手順に従うこと。

  1. コマンド・プロシージャ vmsconfig.com を実行して、tm.hconfig.haux-output.cmd. というファイルを設定し、tconfig.hhconfig.h を作る。また、このプロシージャは、make-cc1.com が使用するたくさんのリンカ・オプション・ファイルと、make-l2.com が使用する一個のデータファイルを作成する。
    $ @vmsconfig.com
    
  2. 上で定義された論理名とコマンドテーブルを設定する。さらに、VMS 論理名 GNU_BISON を定義し、Bison の実行形式が置かれているディレクトリを指すようにする。このためには以下のコマンドを実行する。
    $ assign /system /translation=concealed -
      disk:[bison.] gnu_bison
    

    読者が選ぶなら、BISON ディレクトリにある INSTALL_BISON.COM スクリプトを使っても良い。

  3. BISON コマンドを以下のコマンド行でインストールする。
    $ set command /table=sys$common:[syslib]dcltables -
      /output=sys$common:[syslib]dcltables -
      gnu_bison:[000000]bison
    $ install replace sys$common:[syslib]dcltables
    
  4. 全てを再コンパイルするために @make-gcc と打つ(あるいは、ファイル make-gcc.com をバッチ・キューに投入する)。GNU CC コンパイラだけでなく GNU C++ コンパイラも構築したければ、最初に make-gcc.com を編集して、コメントに書かれている操作に従う必要がある。
  5. GCC を使うためには、GCC でコンパイルされたコードから呼び出され、ある特定の作業を行う関数ライブラリが必要である。これをコンパイルするには、コマンド・プロシージャ make-l2.com を使う必要がある。これを使うとライブラリ libgcc2.olb を生成する。libgcc2.olb は、libgcc2.c の出所と同じディストリビューションから構築された GCC を使って構築する必要がある。make-gcc.com は、このために必要なことを全て自動的に行う。

    このライブラリをインストールするには、以下のコマンドを使う。

    $ library gnu_cc:[000000]gcclib/delete=(new,eprintf)
    $ library gnu_cc:[000000]gcclib/delete=L_*
    $ library libgcc2/extract=*/output=libgcc2.obj
    $ library gnu_cc:[000000]gcclib libgcc2.obj
    

    最初のコマンドは、別のモジュール名で置かれる libgcc2 から来るモジュールで置き換えられる古いモジュールを単に消去する。モジュール neweprintf は、読者の gcclib.olb には実際には存在しないかもしれない。VMS のライブラリアンがこれらのモジュールが存在しないと文句を言った場合は、単にそのメッセージを無視して、次のコマンドを続けること。第二のコマンドは、libgcc2.c ライブラリの以前のバージョンから来るモジュールを消去する。

    読者のシステムの GNU CC を更新したときはいつでも、このライブラリも上記のプロシージャで更新しなければならない。

  6. GCC を構築するのに、ソースファイルのあるディレクトリには何もファイルを作りたくないこともあるだろう。例えば、ソースファイルが読みだし専用ディスク上にある場合が該当するだろう。そう言う場合は、以下の DCL コマンドを実行する(読者のところの実際のパス名に置き換えること)。
    $ assign dua0:[gcc.build_dir.]/translation=concealed, -
             dua1:[gcc.source_dir.]/translation=concealed  gcc_build
    $ set default gcc_build:[000000]
    

    ここで、ディレクトリ dua1:[gcc.source_dir] にはソースコードが置かれており、ディレクトリ dua0:[gcc.build_dir] は生成されるオブジェクトファイルと実行形式を全て置くディレクトリである。一度こうしておけば、上に記述したように GCC の構築を進めることができる。(gcc_build はルート起点の論理名であり、そのため検索リストの各要素に入っているデバイス名は、何か別のルート起点論理名ではなく実際の物理デバイス名でなくてはならないことに注意。)

  7. GNU CC を以前のバージョン GNU CC で作ろうとしているなら、GNU アセンブラの最新版を使っているかどうかも確かめなければならない。特に、GNU CC バージョン 2 はグローバル定数変数の取扱いが、GNU CC バージョン 1 と微妙に異なり、GAS バージョン 1.38.1 には、GCC バージョン 2 と共に動作させるのに必要なパッチが存在しない。GAS 1.38.1 を使うと、extern const 宣言された変数には、読みだし専用ビットが設定されず、リンカが、そういう変数に対し、psect 属性が一致しないという警告メッセージを出す。この警告メッセージは単に邪魔なだけであり、無視して良い。

    GNU CC の 1.33 以前のバージョンでコンパイルする場合は、全てのコンパイルでオプションとして /DEFINE=("inline=") を指定すること。このためには、make-cc1.com に現れる全ての gcc コマンドを編集する必要がある。(古いバージョンには inline のサポートに問題があったのである。)一度 1.33 以降の GNU CC が動くようになれば、このファイルを元に戻すことが出来る。

  8. GNU CC を VAX C コンパイラで構築したい場合は、make-cccp.commake-cc1.com にちょっと変更を加えて、CCCFLAGSLIBS の別の定義を選ぶ必要がある。これらのファイル中のコメントを参照のこと。ただし、GNU アセンブラ(GNU as, 別名 GAS)の正しく動作するバージョンが、GNU CC のバックエンドとして、バイナリのオブジェクトモジュールを生成するのに必要である。GAS は GNU CC のソースには含まれていない。GAS は、libgcc2 をコンパイルして gcclib を作るのにも必要である(上記参照)。make-l2.com では、GAS が gnu_cc:[000000]gnu-as.exe として使える事を想定している。

    GNU CC を VMS で使うには、VMS 用ドライバプログラム gcc.exegcc.comgcc.cld が必要である。これらは、GNU CC のソースではなくて VMS 用バイナリ(gcc-vms) に入って配布されている。GAS、Bison も gcc-vms に含まれている。

    VAX C で GNU CC を構築するのに一度成功すれば、できたコンパイラを使って自分自身を再構築した方が良い。その前に、make-cccp.commake-cc1.com の中の CCCFLAGSLIBS の定義を元に戻すのを忘れないこと。二代目のコンパイラは、他のコンパイラで構築しているときには抑止しなくてはならなかった多数の最適化の利点を享受することができる。

以前のバージョンの GNU CC では、生成されたコードを共有可能なVAXCRTL ライブラリとリンクするとおかしな結果になることがときどきあった。現在のバージョンでは正しく動作するはずである。

ただし、現在のバージョンでも、GNU CC 自体は共有可能な VAXCRTL とリンクすべきではない。VAXCRTL にあるバージョンの qsort にはバグがあり(VMS バージョン V4.6 から V5.5 にかけて存在するのが知られている)、GNU CC が正しく動作しない。

実行形式は、make-cc1.commake-cccp.com により、VAXCRTL のバージョンのオブジェクトライブラリを使って生成されることで、gcclib.olb にある qsort ルーチンを使うようになる。GCC の実行形式を共有可能な VAXCRTL とリンクしたければ、ファイル tm.h(vmsconfig.com により作られる)を編集して、マクロ QSORT_WORKAROUND を定義する必要がある。

QSORT_WORKAROUND は GNU CC を VAX C でコンパイルする場合は常に定義されて、gcclib.olb がまだ利用可能でない場合の問題を回避するようになっている。


Node:Collect2, Next:, Previous:VMS Install, Up:Installation

collect2

GNU CC は、ほぼ全てのシステムで collect2 というユーティリティを使って、プログラムの開始時に様々な初期化関数を呼び出すような設定を行なう。

collect2 の仕組みは、まず一度プログラムのリンクを行ない、リンカの出力ファイルを調べてコンストラクタ関数であることを示す名前を持つシンボルを探す。そのようなシンボルが一つでもあれば、シンボルのテーブルを含む一時 .c ファイルを作り、コンパイルし、そのオブジェクトファイルを追加して二回目のリンクを行なう。

コンストラクタ群の実際の呼び出しは、__main というサブルーチンにより実行される。__main は、main 関数本体の先頭で自動的に呼び出される(main 関数は GNU CC でコンパイルしておく必要がある)。__main の呼び出しは、C プログラムをコンパイルするときにも必要である。というのは、C と C++ のオブジェクトを両方リンクするのに必要になるからである。(-nostdlib オプションを使うと、__main の参照が解決されない。__main が標準 GCC ライブラリで定義されているからである。その場合は、コンパイルのコマンド行の最後に -lgcc を付け加えれば、解決できる。)

collect2 は、コンパイラの各パスがインストールされるディレクトリに、ld という名前でインストールされる。collect2 が本当の ld を探す必要があるときは、次のようなファイルを探す。

「GNU CC の検索ディレクトリ」とは、GNU CC がコンパイラの各パスのコマンドを検索する全てのディレクトリを意味する。-B で指定したディレクトリも含む。

クロスコンパイラの場合の検索は若干異なる。

collect2 は、collect2 自身が起動されたときのファイル名を使って ld を実行することを明示的に回避している。実際に、そういうファイル名のリストを記憶している。例えば、collect2 の一つのコピーが、検索パスの二番目の場所に ld としてインストールされた collect2 の別のコピー(またはバージョン)を見つけたと言うような場合である。

collect2 は、nmstripld に対する上記のと同じアルゴリズムを使って検索する。


Node:Header Dirs, Previous:Collect2, Up:Installation

標準ヘッダファイルのディレクトリ

GCC_INCLUDE_DIR は、ネイティブとクロスで同じものを意味する。GNU CC が私的なインクルードファイルを格納する場所であり、また GNU CC が修正版インクルードファイルを格納する場所でもある。クロスコンパイルされた GNU CC は、$(tooldir)/include にあるヘッダファイルに対して fixincludes を実行する。(クロスコンパイル用ヘッダファイルを修正する必要があるなら、それを GNU CC を構築する前にインストールしておかなくてはならない。クロスコンパイル用ヘッダファイルが既に ANSI C と GNU CC に適切なものになっているのであれば、何も特別な処理は必要ない。)

GPLUSPLUS_INCLUDE_DIR は、ネイティブとクロスで同じものを意味する。g++ が最初にヘッダファイルを探す場所である。C++ ライブラリは、このディレクトリにはターゲット独立のヘッダファイルしかインストールしない。

LOCAL_INCLUDE_DIR は、ネイティブコンパイラだけが使う。通常は、/usr/local/include になる。GNU CC はこのディレクトリを検索するので、ユーザはヘッダファイルを/usr/local/include にインストールして置くことができる。

CROSS_INCLUDE_DIR は、クロスコンパイラだけが使う。GNU CC はここには何もインストールしない。

TOOL_INCLUDE_DIR は、ネイティブとクロスコンパイラの両方で使われる。GNU CC が使うであろう他のパッケージのヘッダファイルをインストールする場所である。クロスコンパイラの場合は、これは /usr/include に等価である。クロスコンパイラを構築するときに、fixincludes は、このディレクトリに置かれているヘッダファイルを全て処理する。


Node:C Extensions, Next:, Previous:Installation, Up:Top

C 言語に対する拡張

GNU C は、ANSI C 言語標準規格には無い機能を多数提供している。(-pedantic オプションを使うと、これらの機能をどれか使っている場合に、警告メッセージを出してくれる。) 条件付きコンパイルを行う場合に、これらの拡張機能が使えるかどうかテストするには、予約済マクロ __GNUC__ が定義されているかどうかを調べれば良い。このマクロは、GNU CC では常に定義される。

これらの拡張機能は、C と Objective C で利用できる。その大部分は、C++ でも利用可能である。C++ にのみ適用可能な拡張については、See Extensions to the C++ Language.


Node:Statement Exprs, Next:, Previous:C Extensions, Up:C Extensions

式中の文と宣言

複文を小括弧で囲むと、GNU C では式として使用できる。これにより、式の中でループや switch 文や局所変数を使用できる。

さて、複文とは中括弧で囲まれた文の列であった。この拡張構文では、中括弧のまわりを小括弧が囲むことになる。例えば、

({ int y = foo (); int z;
   if (y > 0) z = y;
   else z = - y;
   z; })

は、foo () の絶対値を取る正しい式である。(必要以上に複雑だが。)

複文の最後には、セミコロン付きの式を置く必要がある。この最後の式の値が複文全体の値の役割を果たす。(中括弧の最後に他の種類の文を使うと、複文全体の型は void になり、有効な値を持たないことになる。

この機能は、マクロを安全に定義する場合に特に有効である。安全にというのは、マクロの引数の評価を一度だけ行うように出来るという意味である。例えば、最大値を取る関数は、標準規格 C のマクロとして以下のように定義するのが普通である。

#define max(a,b) ((a) > (b) ? (a) : (b))

しかし、この定義は ab のどちらかを二回評価してしまい、引数が副作用を持つ場合は予期しない結果を生じる。GNU C では、引数の型を知っていれば、マクロを安全に定義できる。int 型の場合は以下のようになる。

#define maxint(a,b) \
  ({int _a = (a), _b = (b); _a > _b ? _a : _b; })

複文式は、定数式が要求される場面では使えない。例えば、列挙定数の値や、ビットフィールドの幅、静的変数の初期値等には使えない。

引数の型が判らない場合でも、typeof (see Typeof) または型名付を使うことによって、上記の手法が使用可能である。


Node:Local Labels, Next:, Previous:Statement Exprs, Up:C Extensions

局所的に宣言されたラベル

局所ラベルは、複文式のスコープで宣言することができる。局所ラベルは単なる識別子である。普通の goto 文を使ってそこにジャンプすることが出来るが、ジャンプ元は局所ラベルの属する複文式の中に限られる。

局所ラベルの宣言は以下のように行う。

__label__ label;

または、

__label__ label1, label2, ...;

局所ラベルの宣言は、複文式の先頭、つまり、({ の直後で、他の通常の宣言の前になければならない。

局所ラベルの宣言はラベルを定義するが、ラベル自体を定義するわけではない。局所ラベル自体の定義は、通常のラベルと同じく label: を使って、複文式中で行う必要がある。

局所ラベルの機能は、複文式が使われるのがマクロ定義中であることが多いので、重宝する。マクロが入れ子になったループを含んでいる場合、goto を使ってループから脱出することが可能になる。しかし、通常の、関数内のスコープのラベルはこの目的には使えない。一個の関数の中でマクロは何度も使われる可能性があり、その場合、何度もマクロが展開され、同じラベルが一つの関数内で複数回定義されることになってしまうからである。局所ラベルを使えば、この問題は回避できる。以下に例を上げる。

#define SEARCH(array, target)                     \
({                                               \
  __label__ found;                                \
  typeof (target) _SEARCH_target = (target);      \
  typeof (*(array)) *_SEARCH_array = (array);     \
  int i, j;                                       \
  int value;                                      \
  for (i = 0; i < max; i++)                       \
    for (j = 0; j < max; j++)                     \
      if (_SEARCH_array[i][j] == _SEARCH_target)  \
        { value = i; goto found; }              \
  value = -1;                                     \
 found:                                           \
  value;                                          \
})


Node:Labels as Values, Next:, Previous:Local Labels, Up:C Extensions

ラベルの値

関数内で定義されたラベルのアドレスは、同じ関数内であれば、単項演算子 && を使って取得することが出来る。ラベルのアドレス値の型は void * になる。ラベルのアドレス値は、定数であり、この型の定数が有効なところならどこでも使うことが出来る。例を挙げよう。

void *ptr;
...
ptr = &&foo;

ラベルのアドレス値を使うためには、そのラベルをジャンプすることが出来なければならない。このためには、計算形 goto 文1goto *exp; を使う。例えば以下のようにする。

goto *ptr;

void * 型であれば、任意の式を使うことが出来る。

これらの定数の使い道の一つは、ジャンプテーブルの静的配列を初期化することである。

static void *array[] = { &&foo, &&bar, &&hack };

こうすれば、以下のように、添え字でラベルを選ぶことが出来る。

goto *array[i];

添字の範囲についての検査は行なわないことに注意すること。C 言語では、配列の参照においては添字の範囲の検査は行ない。

この様なラベル値の配列は、switch 文と同様の機能を提供する。もちろん、switch 文を使ったほうがきれいなので、対象とする問題が switch 文にうまく当てはまらない場合以外は、switch 文を使うべきである。

もうひとつの、ラベル値の使い道は、スレッドを使ったコードのインタプリタにある。インタプリタ関数内のラベルは、超高速ディスパッチ用の素レッドコードに格納することができる。

この機構を使って、異なる関数中のコードにジャンプすることができる。それをやると、全く予測できない事が発生するだろう。これを避けるのに一番良い方法は、ラベルのアドレスを自動変数にだけ格納し、引数としては渡さないことである。


Node:Nested Functions, Next:, Previous:Labels as Values, Up:C Extensions

入れ子関数

ネストした関数 とは、なにか別の関数のなかで定義された関数である。(GNU C++ ではネストした関数はサポートしていない。) ネストした関数の名前は、定義されたブロック内で有効である。以下の例では、square という名前のネストした関数を定義し、二回呼び出している。

foo (double a, double b)
{
  double square (double z) { return z * z; }

  return square (a) + square (b);
}

ネストした関数からは、それを含む関数の変数のうち、ネストした関数が定義されている点で見えるものは全部参照可能である。これは、レキシカル・スコーピング と呼ばれている。例えば、以下の例では、ネストした関数が offset という名前の変数を親関数から継承している。

bar (int *array, int offset, int size)
{
  int access (int *array, int index)
    { return array[index + offset]; }
  int i;
  ...
  for (i = 0; i < size; i++)
    ... access (array, i) ...
}

ネストした関数は、関数内の、変数の定義が出来る場所で定義出来る。つまり、任意のブロック中の最初の文の前になる。

ネストした関数をその名前のスコープの外側から呼び出すのは、そのアドレスを格納したり、別の関数にアドレスを渡したりすることで可能である。

hack (int *array, int size)
{
  void store (int index, int value)
    { array[index] = value; }

  intermediate (store, size);
}

ここで、関数 intermediate は、引数として store のアドレスを受け取る。intermediatestore を呼び出すなら、その時に store に与えられる引数が、array に格納するのに使われる。だが、この方法は、そのネストした関数を包含する関数(この例では、hack) が終了しない間だけ、機能する。

ネストした関数を、そのアドレスを使って、その包含関数が終了した後で呼び出そうとすると、大変なことになる。包含しているスコープレベルを抜けた後に呼び出しを行なうとした場合、もはやスコープにない変数を何か参照していると、運が良ければうまくいくかもしれないが、危険を犯すことになる。だが、ネストした関数がスコープから出てしまったものを何も参照していない場合は、安全である。

GNU CC はネスト関数のアドレスを取るのに、トランポリン と呼ばれる方法を使って実装している。これについて説明している論文が http://master.debian.org/~karlheg/Usenix88-lexic.pdf から利用できる。

ネスト関数は、包含関数内でラベルが明示的に宣言されていれば、包含関数から継承したそのラベルにジャンプすることができる(see Local Labels)。そういうジャンプは直ちに包含関数に戻り、goto を実行したネスト関数と中間の関数を終了する。以下に例を示す。

bar (int *array, int offset, int size)
{
  __label__ failure;
  int access (int *array, int index)
    {
      if (index > size)
        goto failure;
      return array[index + offset];
    }
  int i;
  ...
  for (i = 0; i < size; i++)
    ... access (array, i) ...
  ...
  return 0;

 /* Control comes here from access
    if it detects an error.  */
 failure:
  return -1;
}

ネスト関数は常に内部リンケージとなる。extern 付きで宣言するのは誤りである。ネスト関数を、その定義の前に宣言する必要があるときは、auto を使うこと(これは、この場合以外の関数宣言では意味がない。)

bar (int *array, int offset, int size)
{
  __label__ failure;
  auto int access (int *, int);
  ...
  int access (int *array, int index)
    {
      if (index > size)
        goto failure;
      return array[index + offset];
    }
  ...
}


Node:Constructing Calls, Next:, Previous:Nested Functions, Up:C Extensions

関数呼び出しの構築

以下に示す組み込み関数を使うと、関数が受け取った引数を記録することができたり、また、引数の数や型を知らなくても、同じ引数を別の関数に渡すことができる。

また、関数呼び出しの戻り値を記録し、後でその値を返すこともできる。これは、その関数が返そうとしているデータ型を知らなくても可能である。(ただし、呼び出し側の関数がそのデータ型が返ってくることを想定している場合に限られるが。)

__builtin_apply_args ()
この組み込み関数は、現在の関数に渡されたのと同じ引数を付けての呼び出しをどのように行なうかを記述するデータへの void * 型のポインタを返す。

この関数は引数ポインタレジスタ、構造体値アドレス、関数へ引数を渡すのに使われる可能性のある全てのレジスタを、スタック上に割り当てられたメモリブロックにセーブする。次に、そのブロックのアドレスを返す。

__builtin_apply (function, arguments, size)
この組み込み関数は、function(void (*)() 型)を、arguments (void * 型) と size (int 型) で記述される仮引数のコピーを引数として呼び出す。

arguments の値は、__builtin_apply_args が返す値とすべきである。引数 size は、スタックの引数データの大きさをバイト単位で指定する。

この関数は、function が返す値をどのように返すかを記述するデータへの、void * 型のポインタを返す。このデータは、スタック上に割り当てられたメモリブロック中にセーブされる。

size の適切な値を計算するのはいつでも簡単というわけではない。この値は __buitin_apply によって、スタック上にプッシュされ、入力引数領域からコピーされるデータ量を計算するのに使われる。

__builtin_return (result)
この組み込み関数は、それを含む関数から result で記述される値を返す。result には、__builtin_apply が返す値を指定すべきである。


Node:Naming Types, Next:, Previous:Constructing Calls, Up:C Extensions

式の型に名前を与える

初期化式の形式の typedef 宣言を使うことで、ある式の型に名前を付けることができる。以下に、exp の型に name という型名を定義する例を示す。

typedef name = exp;

これは、式文と共に使うと有効である。以下に、式文と共に使っている、どの算術型にでも適用できる、安全な最大値マクロの定義例を示す。

#define max(a,b) \
  ({typedef _ta = (a), _tb = (b);  \
    _ta _a = (a); _tb _b = (b);     \
    _a > _b ? _a : _b; })

ローカル変数名をアンダースコアで始まる名前にするのは、ab が置き換えられた式内で発生する変数名の衝突を避けるためである。将来的には、新しい宣言構文の形式を考えて、変数を宣言するのに、そのスコープが、その変数に対する初期化子以降にのみ開始するようにしたいと考えている。これは、衝突を避けるのにより信頼性の高い方法となるだろう。


Node:Typeof, Next:, Previous:Naming Types, Up:C Extensions

typeof による型の参照

式の型を参照するには、typeof を使う方法もある。このキーワードの構文は、sizeof に良く似ているが、意味的にはtypedef で定義される型名に似ている。

typeof の引数には、二通りの書き方がある。式を与える方法と型を与える方法である。以下に式を指定する例を示す。

typeof (x[0](1))

ここでは、x が関数の配列であることを仮定している。この構文で記述される型は、関数の戻り値の型になる。

次に、引数に型名を指定した例を示す。

typeof (int *)

これで記述される型は、int へのポインタという型になる。

ANSI C プログラムからインクルードされたときに正しく動作しなければならないヘッダファイルを書く場合は、typeof の代わりに __typeof__ を使うこと。See Alternate Keywords.

typeof構文は、typedef 名が書けるところならどこにでも置ける。例えば、宣言や、キャストや、sizeoftypeof の中で使うことができる。


Node:Lvalues, Next:, Previous:Typeof, Up:C Extensions

拡張左辺値

複文式、3項演算式、それにキャストは、そのオペランドが左辺値であれば、左辺値として許される。つまり、これらのアドレスを取ったり、値を格納出来る。

C++ の標準は、複文式と3項演算子式を左辺値として使うこと、それから参照型へのキャストを許しているので、C++ のコードではこの拡張を使う意味はあまりない。

例えば、複文式は題入可能である。列の最後の式が左辺値となる。以下の二つの式は等価である。

(a, b) += 5
a, (b += 5)

同様に、複文式のアドレスを取ることができる。以下の二つの式は等価である。

&(a, b)
a, &b

条件式は、その型が void でなくて、真の分岐と偽の分岐がどちらも有効な左辺値なら、やはり有効な左辺となる。例えば、以下の二つの式は等価である。

(a ? b : c) = 5
(a ? b = 5 : (c = 5))

キャストも、そのオペランドが左辺値であれば、有効な左辺値である。左辺がキャストである単純な代入の場合、まず右辺がキャストで指定されるタイプに変換され、次にキャストなしの左辺式の型に変換される。それが格納された後、その値はキャストで指定された型に戻されて、代入自体の値となる。つまり、a の型が char * という場合、以下の二つの式は等価である。

(int)a = 5
(int)(a = (char *)(int)5)

+= のように算術演算と組み合わされた代入演算をキャストに適用すると、キャストの結果の型を使って算術演算を行ない、次に前述の場合と同じように続行される。つまり、以下の二つの式は等価になる。

(int)a += 5
(int)(a = (char *)(int) ((int)a + 5))

左辺値のキャストのアドレスを取ることはできない。そのアドレスを使うと一貫性がなくなるからである。&(int)f という書き方が許されるとしよう。f の型は float 型とする。そうすると、以下の文は、整数のビットパターンを浮動小数点数が属する場所に格納しようとすることになる。

*&(int)f = 1;

これは、(int)f = 1 が行なうことと全く違う。(int)f = 1 は、1 を浮動小数点に変換し、それを格納する。この一貫性のなさを発生させるよりも、キャストに & を使うのを禁止したほうが良いだろうと我々は考えている。

f のアドレスを int * 型のポインタとして本当に必要なら、単に (int *)&f と書けば良い。


Node:Conditionals, Next:, Previous:Lvalues, Up:C Extensions

三項演算子のオペランドの省略

三項演算子の式で、二番目のオペランドを省略することができる。省略した場合は、最初のオペランドの値が 0 でなければその値が式の値となる。

つまり、以下のような場合、

x ? : y

式の値は、x の値が 0 でなければその値となり、x が 0 ならy の値となる。

これは以下の式と全く等価である。

x ? x : y

上記のような簡単なケースでは、二番目のオペランドを省略できる有り難みが良くわからないかもしれない。これが役に立つのは、最初のオペランドが副作用が持っているか、副作用を持つ可能性がある(マクロの引数の場合)時である。その場合、中間項でそのオペランドを繰り返し使うと、副作用が二回実行される。中間項のオペランドを省略すると、既に計算済みの値を使い、再計算による望ましくない作用を伴わない。


Node:Long Long, Next:, Previous:Conditionals, Up:C Extensions

倍語整数

GNU C は、int の二倍の大きさの整数型をサポートしている。この型は、符号付きの場合は long long int、符号無しの場合はunsigned long long int と書く。long long int 型の定数を作るには、整数にサフィックス LL を付ける。unsigned long long int 型の整数の場合には、ULL である。

他の整数型同様、これらの型を算術演算で使用することができる。これらの型についての、加算、減算、ビット毎のブール演算は、全ての機種で開かれた形で書かれている。乗算は、機種が全語から倍語への拡幅乗算命令をサポートしているなら、開かれた形で書かれている。除算とシフトは、特別なサポートを提供している機種でのみ開かれた形で書かれている。開かれた形で書かれていない演算は、GNU CC 付属の特別なライブラリルーチンを使う。

long long 型を関数の引数に使うときは、関数のプロトタイプ宣言なしの場合は、落とし穴に注意すること。ある関数が引数として int 型を想定している場合、long long int 型の値を渡すと、呼び出し側と呼び出される側で想定している引数のバイト数が違うので、混乱が生じる。関数が long long int を想定し、それに対し、int 型を渡す場合も同じである。このような問題を避ける最も良い方法は、プロトタイプ宣言を使うことである。


Node:Complex, Next:, Previous:Long Long, Up:C Extensions

複素数

GNU C は複素数型をサポートしている。整数の複素数型も浮動小数点数の複素数型もどちらも使うことができる。これには、__complex__ という予約語を使う。

例えば、__complex__ double x; と宣言すると、x は、実数部も虚数部も double 型の変数になる。__complex__ short int y; と宣言すると y は、実数部も虚数部も short int 型になる。後者の方はあまり役にたちそうもないが、複素数型は一通り全部揃っていることを表している。

複素数型の定数は、サフィックス ij をつけて書く(どちらか一つで、どちらでも同じである)。例えば、2.5fi という定数は __complex__ float 型で、3i__complex__ int 型になる。このように書いた整数は、常に純虚数値になるが、これを実定数に足せば、望みの複素数値を作ることができる。

複素数値を持つ式 exp から実数部を取り出すには、__real__ exp と書く。同様に、虚数部を取り出すには、__imag__ を使う。

演算子 ~ を複素数型の値に使うと、複素共役を取る。

GNU CC は複素数型の自動変数は連続的には確保しない。実数部はレジスタに取り、虚数部の方はスタック上に取る(あるいはその逆) ことさえ可能である。GNU CC が現在サポートしているデバッグ情報形式で、このような非連続的な確保を表現する手段を持っているものはない。このため、GNU CC は非連続的に確保された複素変数を、あたかも複素数型でない二つの独立した変数であるかのように記述する。実際の変数名が foo であれば、疑似的な二つの変数名は、foo$realfoo$imag になる。このような疑似的な変数は、デバッガから値を調べたり設定したりすることが可能である。

GDB は将来、このような変数の組を認識し、一個の複素数型変数として扱えるようになるだろう。


Node:Hex Floats, Next:, Previous:Complex, Up:C Extensions

16進浮動小数

GNU CC は 1.55e1 のような普通の10進表記で書かれた浮動小数点数だけでなく、0x1.fp3 のように16進表記で書かれた数も認識する。この表記では、16進接頭辞 0x と指数フィールド p またはP は必須である。指数は、仮数部に掛けられる 2 の冪乗数を表す10進数である。すなわち、0x1.fp3 は 1 15/16 を、p3 により、8 を掛けたものになり、結局 0x1.fp3 の値は 1.55e1 と同じになる。

10進表記の浮動小数点数と違い、16進表記では指数は常に必要である。指数を書かないと、例えば 0x1.f にあるような曖昧さを解決できない。この数は 1.0f とも取れるし、あるいは ffloat 型の浮動小数点定数の拡張形式でもあるので 1.9375 とも取れるのである。


Node:Zero Length, Next:, Previous:Hex Floats, Up:C Extensions

大きさゼロの配列

GNU C では長さが 0 の配列を使うことができる。これを構造体の最後の要素として置き、実際には可変長となるオブジェクトのヘッダとして使うことができる。

struct line {
  int length;
  char contents[0];
};

{
  struct line *thisline = (struct line *)
    malloc (sizeof (struct line) + this_length);
  thisline->length = this_length;
}

C の標準では、長さ 0 の配列は許されないため、上記の contents の長さを 1 にしなければならない。このため、スペースが無駄になったり、malloc の引数が複雑になったりする。


Node:Variable Length, Next:, Previous:Zero Length, Up:C Extensions

可変長配列

GNU C では可変長の自動変数配列を使うことができる。この配列は、普通の自動配列と同じように宣言するが、長さ指定が定数式でないところが違う。メモリは宣言のある場所で確保され、それが属するブロックを抜けるときに解放される。以下に例を示す。

FILE *
concat_fopen (char *s1, char *s2, char *mode)
{
  char str[strlen (s1) + strlen (s2) + 1];
  strcpy (str, s1);
  strcat (str, s2);
  return fopen (str, mode);
}

配列名の有効範囲から、ジャンプや break で抜けると、配列名に割り当てられているメモリは解放される。配列名の有効範囲にジャンプしてくるのは許されず、エラーになる。

関数 alloca を使えば、可変長配列と同じような効果を得ることができる。alloca は、多くの C の処理系で利用可能である(が、全ての処理系で利用可能なわけではない)。一方、可変長配列の方がエレガントである。

この二つの方法には他にも違いがある。allocal で確保した領域はその関数がリターンするまで存在し続ける。可変長配列の領域の方は、配列名のスコープを抜けた瞬間に解放される。(ある一つの関数で、可変長配列とalloca の両方を使った場合、ある可変長配列を解放すると、その可変長配列の確保以後に alloca で確保された領域も全て解放される。)

可変長配列を関数の引数として使うこともできる。

struct entry
tester (int len, char data[len][len])
{
  ...
}

配列の長さは、メモリが確保されるときに一回だけ計算され、その配列の有効範囲内では記憶されており、sizeof で参照することができる。

最初に配列を渡し、長さは後から渡したい場合は、仮引数のリストで前方宣言を行なえば良い。これももう一つ別の GNU の拡張機能である。

struct entry
tester (int len; char data[len][len], int len)
{
  ...
}

セミコロンの前の int len仮引数の前方宣言である。これは、data の宣言をパースするときに len という名前を既知のものとする役割を果たす。

仮引数リストには、こういう前方宣言を幾つ書いても良い。前方宣言は、カンマまたはセミコロンを使って区切る。ただし、最後の前方宣言はセミコロンで終わっていなければならず、その後に「本物の」仮引数リストが続く。どの前方宣言も、「本物の」仮引数宣言の名前とデータ型に一致しなければならない。


Node:Macro Varargs, Next:, Previous:Variable Length, Up:C Extensions

改変数引数を持つマクロ

GNU C では、関数と同じように、マクロも可変数の引数を取ることができる。その場合のマクロの定義構文は関数の場合に使われるものに良く似ている。次に例を示す。

#define eprintf(format, args...)  \
 fprintf (stderr, format , ## args)

args残りの引数である。呼び出し側と同じだけの、ゼロ個以上の引数を取る。これら全ての引数とその間にカンマを加えたものが、args の値となり、args が使われるマクロ本体に代入される。結局、この例は以下のように展開される。

eprintf ("%s:%d: ", input_file_name, line_number)
==>
fprintf (stderr, "%s:%d: " , input_file_name, line_number)

文字列定数の直後のカンマは eprintf の定義から来たものであるのに対し、最後のカンマは args の値から来たものであることに注意。

## を使う理由は、args に全く引数がない場合を扱うためである。その場合、args の値は空となる。そうすると、マクロ定義中の二番目のカンマが邪魔になる。マクロをそのまま展開すると、以下のようになる。

fprintf (stderr, "success!\n" , )

これは、C の文法として誤ったものになる。## を使うとこの場合のカンマを取り除くので、代わりに以下のようになる。

fprintf (stderr, "success!\n")

これは、GNU C プリプロセッサの特別な機能である。## の後の残りの引数が空の場合の 、先行する、マクロ定義から来る非空白文字の列を捨てさる。(もう一つ別のマクロ引数が先行する場合は、何も捨てない。)

最後の先行する非空白文字の列の代わりに、最後のプリプロセッサ・トークンを捨て去ったほうが良いのかもしれない。実際、いつかはこの機能をそのように変えたいと思う。我々としては、マクロ定義を書くときは、先行する非空白文字の列をちょうど一個のトークンとなるように書いて、我々がこの機能の定義を変えたときにも意味が変わらないようにすることをお勧めする。


Node:Subscripting, Next:, Previous:Macro Varargs, Up:C Extensions

左辺値でない配列の添え字を取ることが可能

左辺値でない配列の添え字を取ることが、単項の & 演算子が許されない場合でも、可能である。例えば、以下は GNU C では有効だが他の C の方言では有効でない。

struct foo {int a[4];};

struct foo f();

bar (int index)
{
  return f().a[index];
}


Node:Pointer Arith, Next:, Previous:Subscripting, Up:C Extensions

voidポインタと関数へのポインタに対する演算

GNU C では、加算と減算の演算が、void へのポインタと関数へのポインタに対しても使うことができる。これは、void と関数の大きさを1 として扱うことにより行なわれる。

この結果、sizeofvoid 型と関数型に使うこともでき、どちらも 1 を返す。

オプション -Wpointer-arith を指定すると、この拡張が使われている場合に警告するように要求する。


Node:Initializers, Next:, Previous:Pointer Arith, Up:C Extensions

非定数による初期化

C++ の標準と同様に、GNU C では、自動変数である集合体の初期化子の要素は定数式でなくても良い。以下に、実行時に変化する要素を持つ初期化子の例を挙げる。

foo (float f, float g)
{
  float beat_freqs[2] = { f-g, f+g };
  ...
}


Node:Constructors, Next:, Previous:Initializers, Up:C Extensions

コンストラクタ式

GNU C はコンストラクタ式をサポートしている。コンストラクタは、キャストと初期化子を組み合わせたように見える。その値は、キャストにより指定された型のオブジェクトであり、初期化子で指定された要素を持つ。

普通、型として指定するのは構造体である。struct foostructure が以下のように宣言されているとしよう。

struct foo {int a; char b[2];} structure;

次の例では、struct foo をコンストラクタで構築している。

structure = ((struct foo) {x + y, 'a', 0});

これは、以下のように書いたのと同じである。

{
  struct foo temp = {x + y, 'a', 0};
  structure = temp;
}

また、配列をも構築することができる。コンストラクタの全要素が、単純な定数式からなっており、初期化子として使うのに適していれば、そのコンストラクタは左辺値であり、強制的にその先頭の要素へのポインタとすることができる。以下に例を示す。

char **foo = (char *[]) { "x", "y", "z" };

要素が単純な定数でない配列コンストラクタはあまり役に立たない。その場合、コンストラクタは左辺値ではないからである。有効な使い方は二つだけである。それを添え字で参照すること、あるいは、それで配列変数を初期化することである。前者はおそらく switch 文を使うより遅くなる。一方、後者は通常の C の初期化子と同じことをする。以下に、配列コンストラクタの添え字参照の例を示す。

output = ((int[]) { 2, x, 28 }) [input];

スカラ型と共用体型に対するコンストラクタ式も許されるが、その場合コンストラクタ式はキャストと等価になる。


Node:Labeled Elements, Next:, Previous:Constructors, Up:C Extensions

初期化子のラベル付要素

標準の C では、初期化子の要素は決まった順番で現れることを要求する。この順番は、配列や構造体の要素が初期化される順番と同じである。

GNU C では、要素を任意の順番で指定することができる。これには要素毎に、それが適用される配列の添え字や構造体のフィールド名を指定する。この拡張は、GNU C++ では実装されていない。

配列の添え字を指定するには、要素の値の前に、[index][index] = と書く。例えば、

int a[6] = { [4] 29, [2] = 15 };

は、

int a[6] = { 0, 0, 15, 0, 29, 0 };

と等価である。添え字の値は、初期化される配列が自動変数であっても、定数式でなければならない。

ある範囲の要素を同じ値で初期化するには、[first ... last] = value と書く。例えば、以下のように書く。

int widths[] = { [0 ... 9] = 1, [10 ... 99] = 2, [100] = 3 };

この場合、配列の大きさは、最も大きな添え字の値に 1 を加えたものであることに注意。

構造体初期化子においては、要素の値の前に、初期化するフィールドの名前をfieldname: で指定する。例えば、以下の構造体があるとする。

struct point { int x, y; };

以下の初期化は

struct point p = { y: yvalue, x: xvalue };

次のと等価である。

struct point p = { xvalue, yvalue };

同じ意味を持つ別の書き方は .fieldname = である。以下に例を示す。

struct point p = { .y = yvalue, .x = xvalue };

また、要素ラベル(コロン形式かピリオド = 形式で)を使って共用体を初期化し、共用体のどの要素が使われるべきかを指定することができる。例えば、

union foo { int i; double d; };

union foo f = { d: 4 };

は、4 を double に変換し、二番目の要素として共用体に格納する。対照的に、4 を union foo 型に変換すると、整数 i として共用体に格納する。何故なら、4 が整数だからである。(See Cast to Union.)

この要素に名前をつける方法と、通常の C の連続する要素を初期化する方法を組み合わせることができる。初期化子の要素でラベルのないものはそれぞれ、配列あるいは構造体の次の連続する要素に適用される。例えば、

int a[6] = { [1] = v1, v2, [4] = v4 };

は、以下のものと等価である。

int a[6] = { 0, v1, v2, 0, v4, 0 };

配列初期化子の要素にラベルを付けるのは、添え字が文字だったり、enum 型に属する場合に特に便利である。例えば、以下のように書くことができる。

int whitespace[256]
  = { [' '] = 1, ['\t'] = 1, ['\h'] = 1,
      ['\f'] = 1, ['\n'] = 1, ['\r'] = 1 };


Node:Case Ranges, Next:, Previous:Labeled Elements, Up:C Extensions

case の範囲指定

一個の case ラベルにある範囲の連続する値を以下のように指定することができる。

case low ... high:

これは、適切な数の case ラベルを用意し、その一つ一つがlow から high の範囲の各整数値を持つようにするのと同じ効果が得られる。ここで、lowhigh も含まれる。

この機能は、ASCII 文字コードの範囲に使うととりわけ便利である。

case 'A' ... 'Z':

注意... の両側には空白を置くこと。そうしないと、それを整数値として使うときに間違って解釈される。例えば、

case 1 ... 5:

と書くようにして、以下のようにはしないこと。

case 1...5:


Node:Cast to Union, Next:, Previous:Case Ranges, Up:C Extensions

共用体型へのキャスト

共用体型へのキャストは、指定された型が共用体型であることを除けば他のキャストと同じである。型を指定するには、union tag かtypedef 名で可能である。だが、共用体へのキャストは実際にはコンストラクタであり、キャストではない。このため、通常のキャストのような左辺値は生じない。(See Constructors.)

共用体型にキャスト可能な型は、共用体のメンバの型である。すなわち、以下のような共用体と変数が与えられていると、

union foo { int i; double d; };
int x;
double y;

xy はどちらも union foo 型にキャスト可能である。

キャストを共用体型変数への代入の右辺として使うのは、共用体のメンバに格納するのと同じことである。

union foo u;
...
u = (union foo) x  ==  u.i = x
u = (union foo) y  ==  u.d = y

また、共用体のキャストを関数の引数として使うこともできる。

void hack (union foo);
...
hack ((union foo) x);


Node:Function Attributes, Next:, Previous:Cast to Union, Up:C Extensions

関数属性の宣言

GNU C では、読者のプログラムで呼び出している関数について一定の宣言を行うと、GNU CC が関数呼出しを最適化したり、読者のコードをさらに注意深く検査することの手助けとなる。

キーワード __attribute__ を使うことにより、宣言を書くときに特別な属性を指定することができる。このキーワードの後に、二重の括弧で囲んだ属性の指定を置く。関数に対しては現在 9 個の属性、noreturnconstformatno_instrument_functionsectionconstructordestructorunusedweak が定義されている。section を含むその他の属性は、変数宣言(see Variable Attributes)や型(see Type Attributes) に対してサポートされている。

また、各キーワードの前後に __ を付けた属性を指定しても良い。これにより、同じ名前のマクロがある可能性を心配することなく、ヘッダファイルの中でこれらの属性を使うことができる。例えば、noreturn の代わりに __noreturn__ を使うことができる。

noreturn
標準ライブラリ関数のうち幾つかは、abortexit のように戻ることが不可能な関数がある。GNU CC はこのことを既に知っている。プログラムの中には、決して戻らない関数を自分で定義することもあるだろう。読者は、そういう関数を noreturn と宣言することで、その事実を GNU CC に知らせることができる。例えば、以下のように書いたとする。
void fatal () __attribute__ ((noreturn));

void
fatal (...)
{
  ... /* Print error message. */ ...
  exit (1);
}

キーワード noreturn を付けると、GNU CC は関数 fatal が戻りえないことを想定する。そうすると、fatal が戻った場合に何が起きるかを考えることなしに最適化を行うことができる。これによりちょっとだけ良いコードになる。もっと重要なのは、変数が初期化されていないという見せ掛けの警告を押さえることができる点にある。

呼出し側関数によりセーブされるレジスタが、noreturn 関数を呼び出す前にリストアされると想定してはいけない。

nonreturn と指定された関数に void 型以外の戻り値型を持たせるのは意味がない。

noreturn 属性は、GNU C のバージョン 2.5 以前では実装されていない。戻ることのない関数を宣言するもう一つの方法は、次のようになる。この方法は、現在のバージョンでも使えるし、古いバージョンの幾つかでも使える。

typedef void voidfn ();

volatile voidfn fatal;

const
多くの関数は引数以外の値を見ないし、戻り値以外の値に影響を与えない。このような関数は、単なる算術演算子と同じように、共通部分式削除とループ最適化の適用を受ける。こういう関数は属性 const を付けて宣言すべきだろう。例えば、
int square (int) __attribute__ ((const));

とすると、架空の関数 square は、プログラムが示すよりも呼び出す回数が少なくても安全であることを表す。

const 属性は、GNU のバージョン 2.5 以前では実装されていない。関数に副作用が無いことを宣言する別の方法としては、以下の方法がある。これは現在のバージョンと幾つかの古いバージョンで動作する。

typedef int intfn ();

extern const intfn square;

この方法は GNU C++ 2.6.0 以降では使えない。言語仕様で const は、戻り値に付けなければならないからである。

ポインタの引数があり、それにより指し示されるデータを参照している関数は、const と宣言してはならないことに注意。同様に、非 const 関数を呼び出している関数は普通は const であってはならない。void 型の関数に const を付けるのは意味がない。

format (archetype, string-index, first-to-check)
属性 format は、関数が printfscanfstrftime 形式の引数を取り、その引数をフォーマット指定文字列に対して型検査を行うことを指定する。例えば、
extern int
my_printf (void *my_object, const char *my_format, ...)
      __attribute__ ((format (printf, 2, 3)));

と宣言すると、GNU CC は、my_printf への呼出しの引数を、 printf 形式のフォーマット指定文字列である引数 my_format との一貫性について検査を行わせる。

パラメータ archetype は、フォーマット文字列がどのように解釈されるかを決め、printfscanfstrftime のどれかにしないといけない。パラメータ string-index はどの引数がフォーマット指定文字列の引数かを指定する(1 から始める)。一方、first-to-check はフォーマット指定文字列に対して検査を行うべき最初の引数の番号である。検査に使える引数がない関数(例えば vprintf)に対しては、3番目のパラメータをゼロと指定すること。この場合、フォーマット文字列についてだけ一貫性があるかどうかの検査が行われる。

上の例で言うと、フォーマット文字列 (my_format) は関数 my_print の二番目の引数であり、検査すべき引数は3番目の引数から始まるので、format 属性の正しいパラメータは2 と 3 になる。

format 属性を使うと、フォーマット文字列を引数として取る読者自身の関数を認識して、GNU CC がこれらの関数への呼出しに誤りがないかどうか検査させることができる。GCC は ANSI ライブラリ関数 printffprintfsprintfscanffscanfsscanfstrftimevprintfvfprintfvsprintf については、警告を要求したとき(-Wformat を指定したとき)は、常にフォーマットを検査するので、ヘッダファイル stdio.h を修正する必要はない。

format_arg (string-index)
format_arg 属性は、関数が、 printf あるいは scanf 形式の引数を取り、それを変更し(例えば別の言語へ翻訳する)、さらにprintf あるいは scanf 形式の関数に渡すということを指定する。例えば、
extern char *
my_dgettext (char *my_domain, const char *my_format)
      __attribute__ ((format_arg (2)));

と宣言すると、GCC は、結果が printfscanfstrftime 形式の関数に渡される my_dgettext への呼出しに現れる引数を、printf 形式のフォーマット文字列引数 my_format と比べて、一貫性があるかどうかを検査する。

パラメータ string-index は、どの引数がフォーマット文字列引数であるかを指定する(1から始まる)。

format-arg 属性を使うと、フォーマット文字列を修正するような読者自身の関数を認識して、引数が、読者自身の関数の一つへの呼出しであるような printfscanfstrftime関数の呼出しを検査できるようにする。GCC は、gettextdgettextdcgettext を常にこのように取り扱う。

no_instrument_function
-finstrument-functions を指定すると、プロファイリングを行う関数への呼出しが、ほとんどのユーザがコンパイルした関数の入り口と出口に生成される。この属性を指定した関数については、それが行われない。
section ("section-name")
GCC は、普通、生成したコードを text セクションに置く。だが、時によっては、追加のセクションが必要になったり、ある特定の関数を特別なセクションに置く必要が出てくる。section 属性は、関数を特定のセクションに置くことを指定する。例えば、
extern void foobar (void) __attribute__ ((section ("bar")));

と宣言すると、関数 foobarbar セクションに置かれる。

ファイル形式によっては、勝手にセクションを作ることをサポートしていないので、section 属性は全てのプラットフォームで使えるわけではない。あるモジュールの内容全部をある特定のセクションに移したい場合は、リンカの機能を使うことを考えてみて欲しい。

constructor
destructor
constructor 属性は、指定した関数が、プログラムの実行がmain () に入る前に自動的に呼び出されるようにする。同じように、destructor 属性を指定すると、その関数が、main () が終了した後か exit () が呼ばれた後に、自動的に呼び出されるようにする。これらの属性を指定した関数は、プログラムの実行の間に暗黙に使われるデータを初期化するのに使える。

これらの属性は Objective C については現在実装されていない。

unused
この属性は、関数につけると、その関数は使われない可能性があるということを表す。GNU CC はこの関数に対して警告を出さないようになる。GNU C++ は現在、パラメータが C++ で有効でない定義としては、この属性をサポートしていない。
weak
weak 属性を使うと、それを指定した宣言は、グローバルシンボルではなくウィークシンボルとして生成される。これは主にユーザコードで上書き可能なライブラリ関数を定義するのに使われるが、関数でない宣言でも使うことができる。ウィークシンボルは ELF ターゲットでサポートされている。GNU アセンブラとリンカを使う場合は a.out ターゲットでもサポートされる。
alias ("target")
alias 属性を指定すると、その宣言は何か別のシンボルの別名として生成される。別のシンボルはかならず指定しなければならない。例えば、
void __f () { /* do something */; }
void f () __attribute__ ((weak, alias ("__f")));

とすると、f__f のウィークな別名として宣言する。C++ では、元の名前にはエンコードされた名前を使わなければならない。

全てのターゲット機種でこの属性がサポートされているわけではない。

no_check_memory_usage
-fcheck-memory-usage を指定すると、サポート・ルーチンの呼出しがほとんどのメモリアクセスの前に生成され、サポートコードが使用状況を記録できるようにし、かつ非初期化また未割当のメモリ領域を使ったのを検知できるようにする。GCC が正しく扱えないので、asm 文は許されない。関数にこの属性を付けて宣言すると、その関数に対するメモリ検査コードを出さないようにし、異なるオプションを使って別個にコンパイルせずともasm 文が使えるようになり、さらに、このオプションを使ってコンパイルしても無限再帰になることなく、望むなら読者自身のサポートルーチンを書けるようになる。
regparm (number)
Intel 386 では、regparm 属性を指定すると、number 個の整数引数を、スタックの代わりにレジスタ EAXEDXECX で渡すようになる。可変数引数を取る関数は、依然として全部の引数がスタックで渡される。
stdcall
Intel 386 では、stdcall 属性を指定すると、可変数引数を取るのでない限り、呼ばれた関数が、引数を渡すのに使われたスタックをポップすると想定する。

Windows NT 向け PowerPC コンパイラは、現在、stdcall 属性を無視する。

cdecl
Intel 386 では、cdecl 属性を指定すると、可変数引数を取るのでない限り、呼びだし側関数が、引数を渡すのに使われたスタックをポップすると想定する。これは、-mrtd オプションの効果を打ち消すのに使える。

Windows NT 向け PowerPC コンパイラは、現在、cdecl 属性を無視する。

longcall
RS/6000 と PowerPC では、longcall 属性を指定するとGCC はその関数を常にポインタ経由で呼び出すようにする。これにより、現在位置から 64 メガバイト(67,108,864バイト)以上離れた位置にある関数も呼び出せるようになる。
dllimport
PowrPC で Windows NT を稼働している場合、dllimport 属性を指定すると、GCC は、その関数を、Windows NT dll ライブラリにより設定される関数ポインタへのグローバルポインタ経由で呼び出す。このポインタ名は、__imp_ とその関数名を組み合わせて作られる。
dllexport
PowrPC で Windows NT を稼働している場合、dllexport 属性を指定すると、GCC は、関数ポインタへのグローバルポインタを提供する。これにより、その関数は dllimport 属性を指定することで呼び出せるようになる。このポインタ名は、__imp_ とその関数名を組み合わせて作られる。
exception (except-func [, except-arg])
PowrPC で Windows NT を稼働している場合、exception 属性を指定すると GCC は、宣言された関数に対し生成される構造化例外テーブルのエントリを修正する。文字列または識別子 except-func が、構造化例外テーブルの 3番目のエントリに置かれる。これは、ある関数を表す。この関数は、例外が発生したときに例外処理機構から呼び出される。指定されていれば、文字列あるいは識別子 except-arg が、構造化例外テーブルの4番目のエントリに置かれる。
function_vector
このオプションは、H8/300 と H8/300H において、指定した関数が関数ベクタを経由して呼び出される必要があることを示すのに使う。関数ベクタ経由して関数を呼び出すと、コードサイズが小さくなる。ただし、関数ベクタ大きさに制限があり(H8/300 では最大 128 エントリ、H8/300H では最大 64 エントリである)、割り込みベクタとスペースを共有する。

このオプションを正しく動作させるには、GNU binutils バージョン 2.7 以降の GAS と GLD を使わなければならない。

interrupt_handler
このオプションは、H8/300 と H8/300H において、指定した関数が割り込みハンドラであることを示すのに使う。GCCは、この属性が指定されていると、割り込みハンドラの中で使うのに適した、関数入り口点と出口点の命令列を生成する。
eightbit_data
このオプションは、H8/300 と H8/300H において、指定した変数が8ビットデータセクションに置かれるべきであることを示すのに使う。GCC は、8ビットデータ領域にあるデータについては、特定の操作に対しより効率の良いコードを生成する。8ビットデータ領域は、合計 256 バイトのデータに制限されていることに注意。

このオプションを正しく動作させるには、GNU binutils バージョン 2.7 以降の GAS と GLD を使わなければならない。

tiny_data
このオプションは、H8/300 と H8/300H において、指定した変数が小(tiny)データセクションに置かれるべきであることを示すのに使う。GCC は、小データ領域にあるデータについてのロードとストアに対しより効率の良いコードを生成する。小データ領域は、合計32キロバイトよりちょっと下回る大きさに制限されていることに注意。
interrupt
このオプションは、M32R/D において、指定した関数が割り込みハンドラであることを示すのに使う。GCCは、この属性が指定されていると、割り込みハンドラの中で使うのに適した、関数入り口点と出口点の命令列を生成する。
model (model-name)
このオプションは、M32R/D において、オブジェクトのアドレス可能性と関数に対して生成されるコードを設定するのに使う。識別子 model-name は、smallmediumlarge のうちのどれか一つである。これらはそれぞれコード・モデルを表す。

small モデルオブジェクトは、メモリの下位 16MB に置かれ(これにより、それらのアドレスは ld24 命令によりロード可能になる)、bl 命令で呼びだし可能である。

medium モデルオブジェクトは、32ビットアドレス空間のどこに置いても良く(GCC は、これらのアドレスをロードするのに seth/add3 命令列を生成する)、bl 命令で呼びだし可能である。

large モデルオブジェクトは、32ビットアドレス空間のどこに置いても良く(GCC は、これらのアドレスをロードするのに seth/add3 命令列を生成する)、bl 命令では到達可能でない可能性がある(GCC は、さらに遅い seth/add3/jl 命令列を生成する)。

複数の属性を一個の宣言の中で指定するには、二重括弧の中にカンマで区切って並べるか、一つの属性宣言の直後に属性宣言を続けて書けば良い。

__attribute__ 機能に反対する人達もいて、代わりにANSI C の #pragma を使うべきだと主張している。#pragma を使わないのには理由が二つある。

  1. #pragma コマンドをマクロから生成するのは不可能である。
  2. 他のコンパイラで同じ #pragma がどんな意味を持つかわからない。

この二つの理由は、#pragma を使えば良いのではないかと提案されているほとんど全てのアプリケーションに対して適用される。#pragma は何に対して使っても基本的に誤りなのである。


Node:Function Prototypes, Next:, Previous:Function Attributes, Up:C Extensions

プロトタイプ宣言と古い形式の定義

GNU C は ANSI C を拡張して、関数のプロトタイプがその後に現れる古い形式の、非プロトタイプ的定義を上書きすることを許している。以下の例を考えてみよう。

/* Use prototypes unless the compiler is old-fashioned.  */
#ifdef __STDC__
#define P(x) x
#else
#define P(x) ()
#endif

/* Prototype function declaration.  */
int isroot P((uid_t));

/* Old-style function definition.  */
int
isroot (x)   /* ??? lossage here ??? */
     uid_t x;
{
  return x == 0;
}

uid_t 型がたまたま short になる場合を考えてみよう。ANSI C ではこの例は許されない。なぜなら、古い形式の非プロトタイプ的な定義においては、ワードより小さいサイズの引数は格上げされるからである。このため、この例では、関数の定義での引数は実際には int になるので、引数の型が short であるプロトタイプと一致しないのである。

ANSI C のこの制限により、旧来の C コンパイラでも動作するコードを書くのが難しくなっている。プログラマは、uid_t 型が、short なのか、int なのか、あるいは long なのか知らないからである。このため、GNU C ではこういう場合、プロトタイプで後続の古い形式の定義を上書きするようになっている。もっと正確に言うと、GNU C では、関数のプロトタイプの引数型が、後に現れる古い形式の定義で指定される型を、前者の型が格上げ前の後者の型と同じである場合には、上書きするのである。このため、GNU C では上の例は、以下のように書いたのと同じである。

int isroot (uid_t);

int
isroot (uid_t x)
{
  return x == 0;
}

GNU C++ では古い形式の関数定義をサポートしていないので、この拡張は関係ない。


Node:C++ Comments, Next:, Previous:Function Prototypes, Up:C Extensions

C++ 形式のコメント

GNU C では、C++ 形式のコメント、すなわち、// で始まり、行末までとなるコメントを使うことができる。他の多くの C の実装でもこのコメント形式を許しており、将来 C の規格に取り入れられそうである。しかし、-ansi-traditional を指定した場合はC++ 形式のコメントを認識しない。それらは、dividend//*comment*/divisor のような古い形の構文と互換でないからである。


Node:Dollar Signs, Next:, Previous:C++ Comments, Up:C Extensions

識別子名中のドル記号

GNU C では、普通、ドル記号を識別子名の中で使うことができる。これは、多くの古い C の実装でそういう識別子を許しているからである。しかし、2,3のターゲット機種では識別子名の中にドル記号が使えない。これは、そのターゲットのアセンブラが識別子名中のドル記号を許していないためであることが多い。


Node:Character Escapes, Next:, Previous:Dollar Signs, Up:C Extensions

定数中の <ESC> 文字

文字列や文字定数中で、文字シーケンス \e を使って ASCII 文字<ESC> を表すことが可能である。


Node:Alignment, Next:, Previous:Character Escapes, Up:C Extensions

型や変数のアラインメントの問い合わせ

キーワード __alignof__ をオブジェクトに対して使うと、そのオブジェクトのアラインメントを返し、型に対して使うとその型で通常必要とされる最小のアラインメントを返す。構文は sizeof と同じである。

例えば、ターゲット機種が double の値が 8 バイト境界に揃うことを要求している場合には、__alignof__ (double) は 8 になる。これは、多くの RISC 機種で実際に正しい。それよりは古目の設計の機種では、__alignof__ (double) は 4 だったり、2 ということさえある。

機種によってはアラインメントを全く必要としないものもある。そういう機種では、どんな型に対する参照も、たとえ奇数アドレスにあっても許される。こういう機種に対しては、__alignof__ は、型の 推奨 アライメントを報告する。

__alignof__ のオペランドが型ではなくて左辺値の時は、その左辺値が取ることが知られているうちの最大のアラインメントが、__alignof__ の値となる。このアラインメントはそのデータ型自体による場合もあるし、それが構造体の一部であり、その構造体のアラインメントを継承していることによる場合もある。例えば、以下のように宣言したとする。

struct foo { int x; char y; } foo1;

__alignof__ (foo1.y) の値はおそらく 2 か 4 になり、それは__alignof__ (int) と同じになる。これは、foo1.y のデータ型はそれ自体はなんらアラインメントを要求しないとしてもである。

オブジェクトのアラインメントを指定する関連する機能としては、__attribute__ ((aligned (alignment))) がある。次のセクションを参照のこと。


Node:Variable Attributes, Next:, Previous:Alignment, Up:C Extensions

変数の属性の指定

キーワード __attribute__ を使うと、変数や構造体のフィールドの特別な属性を指定することができる。このキーワードの後ろに属性の指定を二重括弧の中に入れて書く。現在、変数用には 8 個の属性が定義されている。alignedmodenocommonpackedsectiontransparent_unionunusedweak である。その他に、関数(see Function Attributes) と型(see Type Attributes) で使える属性がある。

また、各キーワードの前後に __ を付けた属性を指定しても良い。これにより、同じ名前のマクロがある可能性を心配することなく、ヘッダファイルの中でこれらの属性を使うことができる。例えば、aligned の代わりに __aligned__ を使うことができる。

aligned (alignment)
この属性は変数や構造体のフィールドの最小のアラインメントをバイト単位で指定する。例えば、
int x __attribute__ ((aligned (16))) = 0;

と宣言すると、GCC はグローバル変数 x を 16 バイト境界に割り当てる。68040 では、これをasm 式と組み合わせることで、オペランドが16バイト境界に整列している必要がある move16 命令を使えるようになる。

また、構造体のフィールドのアラインメントを指定することもできる。例えば、倍語境界に整列した int の対を作るには以下のように書けば良い。

struct foo { int x[2] __attribute__ ((aligned (8))); };

これは、double 型のメンバを入れた共用体を作って、その共用体を倍語境界に整列させるという通常の手段の代替方法である。

関数に対してはアラインメントを指定することはできない。関数のアラインメントは機種によって決まっており、変更不可能である。typedef 名に対してもアラインメントを指定することはできない。typedef 名は新たな型ではなくて、単なる別名に過ぎないからである。

上の例のように、与えられた変数や構造体フィールドに対して GCC に使って欲しいと思うアラインメントを明示的に指定することが可能である。もう一つの方法として、アラインメント因子を書かずに、コンパイルのターゲット機種の意味のある最大のアラインメントを変数やフィールドに与えるようコンパイラに任せることもできる。例えば、以下のように書くことができる。

short array[3] __attribute__ ((aligned));

aligned 属性の指定で、アラインメント因子を書かないと、GCC は、宣言された変数やフィールドに、読者のコンパイルのターゲットである機種で任意のデータ型に対して使われる最大のアラインメントを自動的に設定する。こうすると、コピー操作の効率が良くなることが多い。GCC は、このようにアラインメントを設定した変数やフィールドとの間のコピーを行うときに、最大のメモリの塊をコピーする命令を使うことができるからである。

aligned 属性ができるのはアラインメントを大きくすることだけである。だが、小さくするには packed 属性を指定すれば良い。

aligned 属性の効果は、リンカの持つ制限により制限を受ける可能性があることに注意して欲しい。多くのシステムでは、リンカは、変数のアラインメントを、ある決まった最大のアラインメントまでしか調整できない。(リンカの中には、可能なアラインメントの最大値が非常に小さいものがある。) 読者のところのリンカが、変数を最大で 8 バイト境界にまでしか整列できないのであれば、__attribute__aligned(16) と指定しても、8 バイトのアラインメントしか提供されない。詳細な情報についてはリンカのドキュメントを見て欲しい。

mode (mode)
この属性は、宣言に対するデータ型を指定する。この型はモード mode に対応するどんな型でも良い。これは実質的には、その幅に対応した整数型か浮動小数点型を要求したことになる。

また、モード byte または __byte__ を指定して、一バイト整数に対応するモードであることを指示することもできる。同様に、word または __word__ で一語長の整数モードを、pointer または __pointer__ でポインタを表現するのに使われるモードを指示する。

nocommon
この属性は、GNU CC に対し、変数をコモン領域に置かずに、直接メモリ割当を行なうよう要求する。オプション -fno-common オプションを指定すると、全ての変数に対しこれを行なう。

変数に対し nocommon 属性を指定すると、ゼロによる初期化が行なわれることになる。ある変数は、一個のソースファイルでしか初期化してはならない。

packed
packed 属性は、変数や構造体フィールドが持つアラインメントを最小限にすべきであることを指定する。最小限のアラインメントとは、aligned 属性でもっと大きな値を指定しない限り、変数の場合は1バイトであり、構造体フィールドの場合は 1 ビットである。

以下の構造体では、フィールド x がパックされており、このため a の直後に配置される。

struct foo
{
  char a;
  int x[2] __attribute__ ((packed));
};

section ("section-name")
通常、GNU CC は生成したオブジェクトを databss といったセクションに置く。だが、追加で別のセクションが必要になったり、あるいはある種の特別な変数を特別なセクションに置く必要があったりすることがある。これは、例えば特別なハードウェアにマップするため等の理由で必要になる。section 属性は、変数(または関数)をある特定のセクションに置くことを指定する。例えば、以下のプログラムでは色々な固有のセクション名を使っている。
struct duart a __attribute__ ((section ("DUART_A"))) = { 0 };
struct duart b __attribute__ ((section ("DUART_B"))) = { 0 };
char stack[10000] __attribute__ ((section ("STACK"))) = { 0 };
int init_data __attribute__ ((section ("INITDATA"))) = 0;

main()
{
  /* Initialize stack pointer */
  init_sp (stack + sizeof (stack));

  /* Initialize initialized data */
  memcpy (&init_data, &data, &edata - &data);

  /* Turn on the serial ports */
  init_duart (&a);
  init_duart (&b);
}

section 属性は、上記の例のように、グローバル変数の初期値付き定義に使うこと。GNU CC は、初期値なしの変数宣言にsection 属性を使うと、警告を発するか、さもなければ無視する。

section 属性は、リンカの動作する仕組みにより、完全に初期化されたグローバルな定義にしか使うことができない。リンカは各オブジェクトは一回だけ定義されることを要求する。例外は、非初期化変数であり、一時的に common (あるいはbss) セクションに置かれ、このため複数回「定義」可能である。変数を強制的に初期化するには、-fno-common オプションかnocommon 属性を使うことが出来る。

オブジェクトファイル形式の中には、任意のセクションをサポートしないものがあり、そのため section 属性は全てのプラットフォームで利用できるわけではない。あるモジュールの全内容をある特定のセクションに対応させる必要がある場合は、代わりにリンカの機能を使うことを考えたほうが良い。

transparent_union
この属性は、共用体である関数の仮引数に付け、対応する実引数の型はその共用体のどのメンバの型であっても良いが、実引数は共用体の先頭のメンバの型として渡されるということを意味する。詳細は See Type Attributes を参照。また、この属性を共用体データ型のtypedef に使うこともできる。その場合、この型を持つ全ての関数仮引数に適用される。
unused
この属性は、変数に付け、この変数が使用されない可能性があることを意味する。GNU CC は、この変数については警告を出さない。
weak
weak 属性は、See Function Attributes で説明する。
model (model-name)
M32R/D ではこの属性を使って、あるオブジェクトのアドレス可能性を設定する。識別子 model-name は、smallmediumlarge の一つで、それぞれコードモデルを表す。

small モデルのオブジェクトはメモリの下位 16MB に置かれる(これにより、これらのオブジェクトのアドレスは ld24 命令でロード可能である。)

medium モデルと large モデルのオブジェクトは 32 ビットのアドレス空間のどこにでも置かれる(GNU CC はこれらのアドレスをロードするために、seth/add3 命令を生成する)。

複数の属性を指定するには、それらを二重括弧で囲み、その中でカンマで各属性を区切る。例えば、__attribute__ ((aligned (16), packed)) とする。


Node:Type Attributes, Next:, Previous:Variable Attributes, Up:C Extensions

型の属性の指定

キーワード __attribute__ を使うと、struct 型やunion 型を定義するときに、特別な属性を指定することができる。このキーワードの後ろに、属性の指定を二重括弧に入れて続けておく。型を定義する際の属性としては、現在三つ定義されている。alignedpackedtransparent_union である。これ以外の属性が、関数(see Function Attributes)や変数(see Variable Attributes)用に定義されている。

これらのうちの属性は、キーワードの前後に __ を付加して指定しても良い。こちらを使うと、同じ名前のマクロがあるかどうかを気にせずにヘッダフィアルの中で使うことができる。例えば、aligned の代わりに __aligned__ を使っても良い。

属性 alignedtransparent_union は、typedef 宣言の中か、完全な enum、struct、union 型の定義 の閉じ中括弧の直後に置くことができる。属性 packed は、定義の閉じ中括弧の直後にだけ置くことができる。

また、属性を、閉じ括弧の後ろではなくて、enum、struct、union タグとその型名の間に置くこともできる。

aligned (alignment)
この属性は、指定された型の変数に対し、最小のアラインメントをバイト数で指定する。例えば、
struct S { short f[3]; } __attribute__ ((aligned (8)));
typedef int more_aligned_int __attribute__ ((aligned (8)));

と宣言すると、struct S 型や more_aligned_int 型の変数がそれぞれ、少なくとも 8 バイト境界に割り当てられ、整列されることを保証する。SPARC では、struct S 型の変数を全て8 バイト境界に整列すると、GNU CC が ldd 命令と std 命令(倍語ロードと倍語ストア)を struct S 型の一つの変数を同じ型の変数にコピーするのに使うことができ、そのため実行時の効率が改善される。

任意の与えられた struct 型や union 型のアラインメントはANSI C 規格により、少なくとも、問題の structunion の全てのメンバのアラインメントの最小公倍数の倍数になることが要求されていることに注意して欲しい。このため、structunion 型のアラインメントを調整するのに、そのメンバのどれか一つに alignment を属性を付加することで、実質的に行なえることになる。だが、上の例で説明した書き方の方が、struct 型や union 型全体のアラインメントを調整するための指定としては、より明白で、判りやすく、読みやすい方法と言える。

前出の例のように、与えられた struct 型や union 型に対して使って欲しいアラインメントをバイト単位で明示的に指定することができる。別の方法としては、アラインメント因子を書かずに、コンパイルのターゲット機種で意味のある最大のアラインメントをその型に指定させるのを、GNU CC に任せることもできる。例えば、以下のように書いても良い。

struct S { short f[3]; } __attribute__ ((aligned));

aligned 属性の指定で、アラインメント因子を書かないと、GCC は、その型に、読者のコンパイルのターゲットである機種で任意のデータ型に対して使われる最大のアラインメントを自動的に設定する。こうすると、コピー操作の効率が良くなることが多い。GCC は、このようにアラインメントを設定した変数やフィールドとの間のコピーを行うときに、最大のメモリの塊をコピーする命令を使うことができるからである。

上の例で、short の大きさがどれも 2 バイトであれば、struct S 型全体の大きさは 6 バイトになる。この大きさ以上で、最小の 2 の冪乗は 8 なので、GCC は struct S 型全体のアラインメントを 8 バイトに設定する。

与えられた型に対し時間効率の良いアラインメントを選択するようにGCC に要求し、その型の単独のオブジェクトだけを個々に宣言することもできるが、GCC の時間優先アラインメントを選択する能力は、主に適切な(効率良く整列する)型を持つ変数の配列を作ろうとしている時にしか役に立たない。効率良く整列される型の変数の配列を宣言したり、使う時は、読者のプログラムは関連する型へのポインタに対するポインタ算術演算(あるいは同じことだが添え字による参照) も行われるだろう。これらのポインタ算術演算に対して GCC が生成するコードは、効率良く整列される型に対するもののほうが、他の型に対するものより効率が良くなる。

属性 aligned はアラインメントを増加させるだけだが、packed を指定すれば減少させることもできる。以下を参照。

aligned 属性の効果は、リンカの持つ制限により限定される可能性があることに注意してほしい。多くのシステムでは、リンカはある決まった最大のアラインメントに変数のアラインメントを切り上げるよう調整することしかできない。(リンカによっては、このサポートされている最大のアラインメントが非常に小さいこともある。) 読者のところのリンカが、最大 8 バイトまでしか変数のアラインメントを取れない場合は、__attribute__aligned(16) を指定しても、8 バイトのアラインメントしか取れない。詳細については読者のところのリンカのドキュメントを見て欲しい。

packed
この属性は、enum 型、struct 型、union 型の定義に付けて、その型を表現するのに最低限必要なメモリを指定する。

この属性を struct 型と union 型に指定するのは、その構造体や共用体のメンバのそれぞれに packed 属性を指定するのと同じである。コマンド行で -fshort-enums オプションを指定するのは、全ての enum 型の定義に packed 属性を指定すると同じである。

この属性は enum の定義の閉じ中括弧の後にしか指定できない。typedef の中では、その中に enum の定義も含んでいない限り、指定できない。

transparent_union
この属性を union 型の定義に付けると、その共用体型を持つ関数のパラメータがある場合、その関数への呼出しが特別な方法で取り扱われる。

第一に、ある透過共用体型に対応する引数は、その共用体のメンバのうちのどの型にでもなりうる。この場合、キャストは不要である。また、共用体がポインタ型を含んでいれば、対応する引数はヌルポインタ定数か void ポインタ式になりうる。共用体が、void ポインタ型を含んでいれば、対応する引数は任意のポインタ式になりうる。共用体のメンバの型がポインタであれば、それが参照している型についての const のような修飾子は、保存されなければならない。これは普通のポインタの変換と同じである。

第二に、その引数は、透過共用体自身の呼出し規約ではなくて、共用体の先頭のメンバの呼出し規約を使って関数に渡される。その共用体のメンバは全て同じマシン表現にならなければならない。これは、この引数を正しく渡すために必要である。

透過共用体は、互換性の理由により複数のインターフェースを持つライブラリ関数のために設計されている。例えば、関数 wait は、Posix に準拠するためには int * 型の値を受け付けるか、4.1BSD のインターフェースに準拠するためには union wait * 型の値を受け付けるかのどちらかでなければならない。wait の仮引数がvoid * であれば、wait はどちらの種類の引数でも受付可能になるが、他のどんなポインタ型でも受け付けることになってしまい、引数型の検査が役に立たなくなってしまう。代わりに、<sys/wait.h> では以下のようにインターフェースを定義しても良い。

typedef union
  {
    int *__ip;
    union wait *__up;
  } wait_status_ptr_t __attribute__ ((__transparent_union__));

pid_t wait (wait_status_ptr_t);

このインターフェースでは、int * 型か union wait * 型の引数を渡すことができる。呼出し規約は int * を使う。プログラムでは、どちかの型の引数で wait を呼び出すことができる。

int w1 () { int w; return wait (&w); }
int w2 () { union wait w; return wait (&w); }

このインターフェースを使った場合、 wait の実装は以下のようになるだろう。

pid_t wait (wait_status_ptr_t p)
{
  return waitpid (-1, p.__ip, 0);
}

unused
この属性を型(unionstruct を含む)に指定すると、この型の変数が使われない可能性があることを意味する。GNU CC は、この型の変数が何もしないように見えた場合でも、これらの変数に対しては警告を出さない。これは、ロックやスレッドのクラスでは良くあることである。これらの場合、定義はされるが参照はされない。だが、コンストラクタやデストラクタが含まれていて、その中には色々な管理を行なう機能を持つ。

属性を複数指定するには、カンマで区切って全体を二重括弧で囲む。例えば、__attribute__ ((aligned (16), packed)) とする。


Node:Inline, Next:, Previous:Type Attributes, Up:C Extensions

マクロと同程度の速さのインライン展開関数

関数を inline と宣言することで、その関数のコードを呼出し箇所に統合することを GNU CC に指示する。これにより、関数呼出しの負荷を削除するので実行が速くなる。さらに、実引数値のどれかが定数であれば、それらの値が既知であることにより、インライン指定のついた関数のコードを全て含める必要が無いように、コンパイル時のコードの単純化が可能になる。インライン展開によりコードサイズがどうなるかは予測が難しい。インライン展開により、オブジェクトコードは大きくなることもあるし、小さくなることもある。個々の場合による。関数のインライン展開は最適化の一つであり、最適化付きコンパイルの場合にしか実際には機能しない。-O を指定しなければ、実際にはどの関数もインライン展開されない。

関数のインライン展開を宣言するには、その宣言で inline というキーワードを以下のように使う。

inline int
inc (int *a)
{
  (*a)++;
}

(ANSI C に準拠するプログラムで取り込まれるヘッダファイルを各場合は、inline の代わりに __inline__ と書くようにする。See Alternate Keywords。) 「充分単純」な関数は、-finline-functions オプションを指定することで、全てインライン展開関数とすることができる。

関数定義中である特定の使い方をしていると、インライン展開に適さなくなることに注意。そういう使い方には次のものがある。varargs を使っている、alloca を使っている、可変長データ型を使っている(see Variable Length)、計算形 goto を使っている(see Labels as Values)、非局所 goto を使っている、入れ子関数を使っている(see Nested Functions)。-Winline を指定すると、inline 付きの関数が置き換え可能でない場合は警告を出し、可能でない理由を表示する。

C と Objective C では、C++ とは違って、キーワード inline は、関数のリンケージには影響しないことに注意。

GNU CC は、C++ プログラムのクラス本体内で定義されているメンバ関数は、明示的に inline と宣言されていなくても、自動的にインライン展開する。(この効果をなくすには、-fno-default-inline オプションを指定する。see Options Controlling C++ Dialect.)

ある関数がインライン展開関数であり static でもあるとき、その関数への呼出しが全て呼出し側に統合されて、かつその関数のアドレスが使われることがない場合は、関数自身のアセンブラコードは決して参照されることがない。この場合、GNU CC は、-fkeep-inline-functions を指定しない限り、その関数のアセンブラコードを実際には出力しない。呼出しの中には様々な理由(特に、関数定義の前にある呼出しや、関数定義内の再帰呼出しは統合が不可能である)に統合できない。統合されない呼出しがあると、その関数は通常のようにアセンブラコードにコンパイルされる。関数は、プログラムがそのアドレスを参照している場合もコンパイルされなければならない。インライン展開が不可能だからである。

インライン関数が static でない場合は、コンパイラは他のソースファイルからの呼出しがあることを想定しなければならない。グローバルシンボルはどんなプログラムでも一箇所でしか定義できないので、その関数は他のソースファイルで定義してはならない。このため、他のソースファイルにある呼出しは統合できないのである。このため、非 static インライン関数は常に普通の形でコンパイルされる。

関数定義に inlineextern の両方を指定すると、その定義はインライン展開でのみ使われる。関数定義自体がコンパイルされることは決してない。その関数のアドレスを明示的に参照してもコンパイルされないのである。そのようなアドレスは、関数を宣言しただけで定義していない場合のように、外部参照になる。

inlineextern をこのように組み合わせると、ほとんどマクロと同じ効果になる。これの使い方は、この二つのキーワードを付けた関数定義をヘッダファイルに置いておき、この定義のコピー(inlineextern を付けないもの)をライブラリファイルに置いておくのである。ヘッダファイルの方の関数定義は、この関数のほとんどの呼出しをインライン展開されるようにする。この関数のそれ以外の使い方をすれば、ライブラリ中の一個のコピーの方を参照する。

GNU C は、最適化を行わない場合はどんな関数もインライン展開しない。こういう場合にインライン展開した方が良いのかどうかはっきりしていない。だが、最適化を行わない場合の正しい実装が難しいということが判ったので、我々は簡単な方にした。すなわち、インライン展開をしないことにした。


Node:Extended Asm, Next:, Previous:Inline, Up:C Extensions

C の式をオペランドとするアセンブラ命令

asm を使った場合のアセンブラ命令で、その命令のオペランドをC の式を使って指定することができる。これは、読者が使いたいデータがどのレジスタにあるのか、メモリのどこにあるのかを考える必要がないということを意味する。

マシン記述に現れるようなアセンブラ命令のテンプレート、それに各オペランドに対するオペランド制約文字列を指定しなければならない。

例えば、以下に 68881 の fsinx 命令の使い方を示す。

asm ("fsinx %1,%0" : "=f" (result) : "f" (angle));

ここで、angle 入力オペランドを表す C の式であり、result は出力オペランドを表す C の式である。それぞれ、"f" をオペランド制約として持ち、浮動小数点レジスタが必要である事を示している。=f= は、オペランドが出力であることを表している。出力オペランドの制約は全て = を使わなければならない。制約の書き方はマシン記述で使われているものと同じである(see Constraints)。

各オペランドは一個のオペランド制約文字列とそれに続く括弧に入った C の式で記述される。コロンでアセンブラテンプレートと出力オペランドの先頭を区切り、もう一つのコロンで最後の出力オペランドと入力オペランドの先頭を区切る。カンマで、それぞれのグループのオペランドを区切る。オペランドの総数は、10 か、マシン記述中の命令パターンで使われているものの中で最大のオペランド数か、どちらか大きいほうに制限される。

出力オペランドはないが、入力オペランドはあるという場合は、出力オペランドが本来置かれる場所を囲むようにコロンを二つ続けて置かなければならない。

出力オペランドの式は左辺値でなければならない。GNU CC はこれを検査することが可能である。入力オペランドは左辺値である必要はない。GNU CC は、オペランドのデータ型が実行される命令に適切なものかどうかの検査は行えない。アセンブラ命令テンプレートの構文解析は行わないので、それが何を意味するものか、あるいはそれがアセンブラへの入力として有効なものかどうかさえも判らないのである。拡張された asm の機能がもっとも良く使われるのは、GNU CC がその存在を知らないような機械語命令に対してである。出力式が直接アドレスを指定できないものである場合は(例えば、ビットーフィールド)、制約でレジスタを許すようにしなければならない。その場合、GNU CC は asm の出力としてレジスタを使い、その後そのレジスタを出力先に格納する。

通常の出力オペランドは書き込み専用でなければならない。GNU CC は、現在の命令の前にこれらのオペランドに入っていた値は死んでおり、生成する必要がないと想定する。拡張 asm は、入力/出力両用、あるいは読み書き両用のオペランドをサポートしている。そういうオペランドであることを示すには制約文字 + を使い、出力オペランドとして列挙する。

読み書き両用のオペランド(あるいは一部のビットしか変化しないオペランド) に対する制約がレジスタを許しているなら、別の選択肢として、論理的にはその機能を二つの別々のオペランドに分割し、一つを入力オペランド、もう一つを書き込み専用出力オペランドとすることもできる。この二つのオペランドの間の関係は、制約により、命令を実行するときには二つのオペランドが同じ位置にある必要があると指定することで、表される。両方のオペランドに同じ C の式を使うことも出来るし、違う式を使っても良い。例えば、以下では、(架空の) combine 命令を bar を読みだし専用読みだし元オペランドとして、foo を読み書き両用目的先オペランドとして書いている。

asm ("combine %2,%0" : "=r" (foo) : "0" (foo), "g" (bar));

オペランド 1 の制約 "0" は、オペランド 0 と同じ位置を占めなければならないということを表す。制約の中に数字を置くのは入力オペランドの場合だけ許され、それは出力オペランドを参照していなければならない。

制約の中の数字だけが、一つのオペランドがもう一つ別のオペランドと同じ位置になることを保証できる。単に foo が両方のオペランドの値になっているというだけでは、生成されるアセンブラコードで同じ位置になるということを保証するには充分ではない。以下のように書いたのでは正しく動作しない。

asm ("combine %2,%0" : "=r" (foo) : "r" (foo), "g" (bar));

色々な最適化や再ロードにより、オペランド 0 と 1 が異なるレジスタに置かれる可能性はある。GNU CC は、そうしない理由はないということを知っている。例えば、GCC は foo の値のコピーが一つのレジスタにあることを見つけ、オペランド 1 用にそれを使うが、オペランド 0 を別のレジスタに出力するかもしれない(後で foo 自身のアドレスにコピーする)。当然、オペランド 1 用のレジスタはアセンブラコードでは言及さえされていないので、その結果は動作しないのだが、GNU CC にはそれが判らないのである。

命令によっては特定のハードレジスタを上書きするものがある。このことを記述するには、入力オペランドの後ろに3番目のコロンを置き、その後に上書きされるハードレジスタ名を、レジスタ一つを一つの文字列として置く。以下に VAX 用の実際の例を示す。

asm volatile ("movc3 %0,%1,%2"
              : /* no outputs */
              : "g" (from), "g" (to), "g" (count)
              : "r0", "r1", "r2", "r3", "r4", "r5");

入力オペランドと出力オペランドが重なるような破壊指定はエラーである(例えば、一つのメンバからなるレジスタクラスを記述するオペランドを破壊されるリストで言及すること)。一番はっきりしている例は、入力オペランドが変更を受けるのに、出力として使われていないという記述を行うのは正しくない。いずれにしても入力オペランドと出力オペランドとして指定する必要がある。使われない出力オペランドしかない場合は、以下で説明するように、asm 分に volatile を指定する必要もある。

このアセンブラコードから特定のハードウェアレジスタを参照する場合は、おそらく、三番目のコロンの後にそのレジスタを列挙して、GCC に対してそのレジスタの値が変更を受けることを知らせる必要があるだろう。

読者の書いたアセンブラ命令が条件コードレジスタを変更し得るなら、cc を破壊されるレジスタのリストに入れておく。いくつかの機種では GNU CC は、条件コードをある特定のハードウェアレジスタで表現する。それ以外の機種では、条件コードは違う取扱いを受けるので、cc を指定しても意味がない。だが、どんな機種でもコードとしては有効である。

読者の書いたアセンブラ命令が予期できない形でメモリを変更するなら、memory を破壊されるレジスタのリストに追加しておく。こうすると、GCC は、そのアセンブラ命令を越えては、メモリ値をレジスタにキャッシュしておくことはしない。

複数のアセンブラ命令をまとめて一個の asm テンプレートに入れることができる。その場合、それぞれを改行(\n と書く)かアセンブラが許すなら、セミコロンで区切る。GNU アセンブラはセミコロンが使えるし、ほとんどの Unix アセンブラでも使えるようだ。入力オペランドはどの破壊レジスタも使わないこと、そして、出力オペランドのアドレスも使われないことが保証されている。このため、破壊レジスタは好きなだけ何度でも読み書きすることができる。一個のテンプレートに複数の命令を入れる例を以下に示す。サブルーチン _foo はレジスタ 9 と 10 で引数を受け取ることを想定している。

asm ("movl %0,r9;movl %1,r10;call _foo"
     : /* no outputs */
     : "g" (from), "g" (to)
     : "r9", "r10");

出力オペランドに & 制約修飾子がない限り、GNU CC は、関係のない入力オペランドと同じレジスタにそれを割り当てる。この時、入力は出力が生成される前に消費されるという想定を行う。この想定は、アセンブラコードが実際に複数の命令から成っている場合は偽になる可能性がある。そういう場合、入力と重なってはならない出力オペランドにはそれぞれ& を付けること。 See Modifiers

アセンブラ命令により生成される条件コードをテストしたい場合は、以下のように、asm 構文に分岐と命令を含めなければならない。

asm ("clr %0;frob %1;beq 0f;mov #1,%0;0:"
     : "g" (result)
     : "g" (input));

これはアセンブラが、GNU アセンブラやほとんどの Unix のアセンブラのように、ローカルラベルをサポートしていることを想定している。

ラベルについて言えば、一つの asm から別の asm へのジャンプはサポートされていない。GCC の最適化器はそういうジャンプについては知らないので、どのように最適化するかを決めるときに考慮にいれることができないのである。

普通、これらの asm 命令を最も手軽に使うには、関数のように見えるマクロに押し込めることである。例えば、以下のようにする。

#define sin(x)       \
({ double __value, __arg = (x);   \
   asm ("fsinx %1,%0": "=f" (__value): "f" (__arg));  \
   __value; })

ここでは、変数 __arg を使って、命令が適切な double 型の値に作用すること、それに引数 x として自動的に double 型に変換可能なものだけを受け付けることを保証している。

命令が正しいデータ型に作用することを保証するもう一つの方法は、asm の中でキャストを使うことである。これは、変数 __arg を使う方法とは、さらに差異の大きな型に変換するという点において異なる。例えば、望ましい型が int だとすると、引数を int にキャストした場合、その引数としてポインタを何の不満もなく受け付ける。一方、その引数を、__arg で指定される int 型の変数に代入すると、呼出し側で明示的にキャストしていない限り、ポインタ型を使うと警告がでる。

asm 文に出力オペランドがあると、GNU CC は最適化目的のためにその命令に、出力オペランドを変更する以外の副作用がないことを想定する。これは副作用がある命令を使うことができないということではないが、注意しなくてはならない。GCC は、出力オペランドが使われていないとその命令を消去したり、ループの外側に移動したり、共通部分式を構成している場合には二つの命令を一つに置き換えたりするからである。また、読者の命令に変数について副作用があり、その変数がそれ以外には変更を受けないものに見えたなら、その変数の元の値は、レジスタに残っていれば、後で再使用される可能性がある。

asm の後にキーワード volatile を指定することで、その asm 命令が削除されたり、著しく移動されたり、組み合わせられたりするのを避けることができる。

#define get_and_set_priority(new)  \
({ int __old; \
   asm volatile ("get_and_set_priority %0, %1": "=g" (__old) : "g" (new)); \
   __old; })

出力のない asm 命令を書くと、GNU CC はその命令に副作用があることを知り、その命令を消したりループの外側に移動したりしない。読者の書いた命令の副作用が純粋に外部的なものでないが、入力を読み込み、指定されたレジスタやメモリを破壊する以外の方法で読者のプログラム中の変数に影響を与えるなら、キーワード volatile を指定して、GNU CC の将来のバージョンが中心領域内で命令を移動するのを防いでおくべきである。

オペランドや破壊が一つもない asm 命令(それに「古い形式の」asm)は、到達不能でない限り、おかまいなしに削除されたり大きく移動されたりすることはない。キーワード volatile を書いたのと同じである。

volatile 指定付きの asm 命令であっても、GCC にとって違いがないと見れば、例えばジャンプ命令をまたぐといったような移動も行われる可能性があるので注意して欲しい。揮発性 asm 命令の列がそのまま連続に保たれると期待することはできない。出力が連続になって欲しければ、一個の asm 文を使うことである。

アセンブラ命令で残された条件コードをアクセスする方法を探そうと誰しも思うだろう。だが、それを実装しようとすると、信頼できる方法がないことがわかった。問題は、出力オペランドは再ロードを必要とすることがあり、それにはストア命令を続ける必要が出てくる。ほとんどの機種ではこれらの命令により、値を検査する前に条件コードを変えてしまうということにある。この問題は、通常の「テスト」命令と「比較」命令では起きない。これらの命令には出力オペランドがないからである。

ANSI C のプログラムからインクルードされるヘッダファイルでは、asm の代わりに __asm__ と書くようにする。See Alternate Keywords

i386 浮動小数点 asm オペランド

スタック状のレジスタを asm のオペランドで使うには幾つか規則がある。これらの規則は、スタック状レジスタであるオペランドにのみ適用される。

  1. asm_operands 中で死ぬ入力レジスタの組が与えられた場合、どれが asm 文により暗黙にポップされて、どれが GCC で明示的にポップしなければならないかを知る必要がある。

    asm 文により暗黙にポップされる入力kレジスタは、出力オペランドにマッチするように制約が課されていない限り、明示的に破壊しなければならない。

  2. asm 文により暗黙にポップされる任意の入力レジスタについて、ポップした分を補償するためにスタックをどうやって調整するかを知る必要がある。ポップされない入力レジスタのどれかが、暗黙にポップされるレジスタよりもレジスタスタックの最上位に近い場合、スタックがどのように見えるかを知るのは可能ではないだろう。スタックの残りの部分がどのように「上下」するのか明らかでないのである。

    暗黙にポップされる入力レジスタは全て、暗黙にポップされないどの入力レジスタよりもレジスタスタックの最上に近くなければならないのである。

    ある入力が insn の中で死ぬのであれば、再ロードでその入力レジスタを出力再ロード用に使っても良い。次の例を考えてみよう。

    asm ("foo" : "=t" (a) : "f" (b));
    

    この asm 文は、入力 B が asm によりポップされないこと、asm が結果をレジスタ・スタックにプッシュする、すなわち、スタックが前より一段深くなるということを言っている。しかし、入力 B がこの insn で死ぬのであれば、再ロードは、入力と出力に同じレジスタを使うことが出来ると考えるだろう。

    入力オペランドのどれかが制約 f を使っていれば、全ての出力レジスタの制約は早期破壊 & を使用しなければならない。

    上の asm は以下のように書ける。

    asm ("foo" : "=&t" (a) : "f" (b));
    

  3. オペランドの幾つかは、スタック上の特定の位置にある必要がある。出力オペランドは全てこのカテゴリに入る。ユーザが制約で指示しない限り、どのレジスタに出力が現れるか知る方法がないのである。

    出力オペランドは、asm の後で出力がどのレジスタに現れるかをはっきりと指示しなければならない。=f は許されない。このオペランド制約は一個のレジスタからなるクラスを選択しなければならない。

  4. 出力オペランドは、存在するスタックレジスタの間に「挿入」してはいけない。387 のオペコードで読み書きオペランドを使っているものはないので、全ての出力オペランドは asm_operands の前で死んでおり、asm_operands によりプッシュされる。レジスタスタックの一番上以外の場所にプッシュするのは意味がない。

    出力オペランドはレジスタスタックの一番上から始まっていなければならない。出力オペランドはレジスタを「スキップ」してはいけない。

  5. asm 文の中には、内部的な計算のためにスタックスペースを余分に必要とするものがある。これは、入力と出力に関係のないスタックレジスタを破壊することにより保証することができる。

以下に、書くのが妥当と思われる asm 文を2,3示す。次の asm 文は入力を一つ取り、この入力は内部的にポップされる。そして、出力を二つ生成する。

asm ("fsincos" : "=t" (cos), "=u" (sin) : "0" (inp));

次の asm 文は、二つの入力を取る。これらは、オペコード fyl2xp1 によりポップされ、一つの出力に置き換えられる。ユーザは、reg-stack.c が fyl2xpl が両方の入力をポップするということが判るように破壊指定 st(1) を書かなければならない。

asm ("fyl2xp1" : "=t" (result) : "0" (x), "u" (y) : "st(1)");


Node:Asm Labels, Next:, Previous:Extended Asm, Up:C Extensions

アセンブラコードで使用される名前の制御

C の関数や変数の、アセンブラコード中で使われる名前を指定することができる。それには、キーワード asm(または__asm__)を以下のように宣言の後に書く。

int foo asm ("myfoo") = 2;

これにより、アセンブラコードの中で、変数 foo に対して使われる名前は、通常の _foo ではなく、myfoo とすることを指定する。

C の関数や変数の名前には通常アンダースコアが頭につくシステムでは、この機能により、アンダースコアが頭につかない、リンカ用の名前を定義することが可能になる。

関数の定義では、asm を上のように使うことはできないが、以下のように、関数の宣言をその定義の前に書き、宣言の後ろに asm を書くことで同じ効果が得られる。

extern func () asm ("FUNC");

func (x, y)
     int x, y;
...

指定したアセンブラでの名前が、何か他のアセンブラシンボルとぶつからないことを保証するのはユーザの責任である。また、レジスタ名を使ってはならない。もし使うと、全く不正なアセンブラコードが生成される。GNU CC には、静的変数をレジスタにストアする能力はない。おそらく、将来その機能が追加されるだろう。


Node:Explicit Reg Vars, Next:, Previous:Asm Labels, Up:C Extensions

指定したレジスタに置かれる変数

GNU C では、2,3 のグローバル変数を指定したハードウェアレジスタに置くことができる。また、通常のレジスタ変数が割り当てられるべきレジスタを指定することもできる。


Node:Global Reg Vars, Next:, Previous:Explicit Reg Vars, Up:Explicit Reg Vars

グローバルレジスタ変数の定義

GNU C ではグローバルレジスタ変数を以下のように定義することができる。

register int *foo asm ("a5");

ここで a5 は、使用したいレジスタ名である。レジスタはその機種で関数呼び出しで退避/復帰されるものを選ぶようにしておくと、ライブラリルーチンで値が破壊されることがない。

当然レジスタ名は CPU に依存するので、CPU タイプに応じてプログラムを条件で分ける必要がある。a5 というレジスタは、68000 の場合はポインタ型の変数向けとしては、良い選択である。レジスタウィンドウを持つ機種の場合は、「グローバル」なレジスタを選ぶようにし、関数呼び出し機構により影響を受けないようにする必要がある。

さらに、同じ CPU タイプでもその上で動作する OS によっては、レジスタの呼び方が違う場合がある。その場合はさらに場合わけが必要になる。例えば、68000 で動作する OS の中には上記の例のレジスタを%a5 と呼ぶものもある。

将来的にはコンパイラに自動的にレジスタを選ぶように指示する手段があって良いだろうが、まず、どのようにして選択すべきか、そしてその選択を読者が知るにはどのようにしたら良いかを明らかにしなければならない。明らかな解決手段はないのである。

グローバルレジスタ変数をあるレジスタに割り当てると、少なくともコンパイル単位内では、そのレジスタはその目的にだけ使われる。現在のコンパイル単位内の関数では、他の用途にそのレジスタが割り当てられることはない。また、このコンパイル単位内の関数で退避/復帰されることもない。このレジスタへの格納は、死んでいるように見えても決して削除されないが、参照は削除されたり、移動されたり、簡素化される可能性がある。

グローバルレジスタ変数をシグナルハンドラや、一つ以上の制御スレッドからアクセスするのは安全ではない。というのは、システムのライブラリルーチンがそのレジスタを別の目的で一時的に使う可能性があるからである。(システムのライブラリルーチンをその目的のために特別にコンパイルし直せばその限りではないが。)

グローバルレジスタ変数を使っている関数が、別のやはりグローバルレジスタ変数を使っている関数 foo を、この変数についての情報無しに(例えば、この変数が宣言されていない別のソースファイルにある等) コンパイルされた三番目の関数 lose を経由して呼び出すのは危険である。これは、lose がそのレジスタをセーブした上で何か他の値を置く可能性があるからである。例えば、qsort に渡す比較関数の中でグローバルレジスタ変数を使えると思ってはいけない。qsort が、何か他のものをそのレジスタに置く可能性があるからである。(qsort を同じグローバルレジスタ変数を使うように再コンパイルすれば、この問題は解消する。)

qsort や他のソースファイルで、実際にはグローバルレジスタ変数を使っていないものを再コンパイルして、そのレジスタを他の目的には使わないようにしたければ、-ffixed-reg オプションを指定すれば充分である。実際にソースコードにグローバルレジスタの宣言を追加する必要はない。

グローバルレジスタ変数の値を変え得る関数は、この変数なしでコンパイルした関数からは安全に呼び出すことができない。呼出し側が戻り値を見つける場所にある値を書き換える可能性があるからである。このため、グローバルレジスタ変数を使っているプログラムの途中への入り口点となる関数は、呼出し側に所属する値を明示的にセーブ/リストアしなければならない。

ほとんどの機種では、longjmp は、各グローバルレジスタ変数に、それらの変数の setjmp の時点での値をリストアする。しかし、中には longjmp がグローバルレジスタ変数の値を変えない機種もある。移植性を良くするためには、setjmp を呼び出す関数は、グローバルレジスタ変数をセーブし、longjmp の中でそれらをリストアするように調整を行なわなければならない。こうしておけば、longjmp が何をするかに関わらず同じ動作が期待できる。

全てのグローバルレジスタ変数の宣言は、全ての関数定義の前になければならない。もしグローバルレジスタ変数の宣言が関数定義の後に現れても、その宣言では先行する関数でそのレジスタが別の目的で使われるのを防ぐことができない。

グローバルレジスタ変数は初期値を持つことができない。実行形式ファイルには、レジスタの初期内容を提供する方法がないからである。

SPARC では、g3 〜 g7 がグローバルレジスタに適しているとの報告がある。ただし、幾つかのライブラリ関数、例えば、getwd や、除算と剰余算のサブルーチンは g3 と g4 を修正する。g1 と g2 はローカルの一時レジスタである。

68000 では、a2 〜 a5 と d2 〜 d7 が適している。当然ながら、これらのうちの 2,3個ではなく、もっとたくさん使うのは適していない。


Node:Local Reg Vars, Previous:Global Reg Vars, Up:Explicit Reg Vars

ローカル変数にレジスタを指定するには

ローカルのレジスタ変数を、以下のようにレジスタを指定して定義することができる。

register int *foo asm ("a5");

ここで a5 は使われるべきレジスタ名である。この書き方は、グローバルレジスタ変数を定義する場合と同じだが、ローカル変数の場合は関数内に現れることに注意。

普通、レジスタ名は CPU に依存するが、これは問題ではない。特定のレジスタは明示的なアセンブラ命令で役に立つことが多いからである(see Extended Asm)。これらのどちらも一般に CPU 型に応じてプログラムを条件節で場合分けする必要がある。

さらに、一つの CPU タイプで動作するオペレーティングシステムが複数ある場合は、レジスタの指定法が違う可能性がある。例えば、幾つかの 68000 上のオペレーティングシステムでは、上記のレジスタを %a5 と読んでいる。

レジスタ変数をこのように定義しても、指定されたレジスタを予約することはない。フロー制御によりこのレジスタ変数の値が生きていないと分かった場所で、他の目的に使うことは依然として可能である。だが、これらのレジスタはリロードパスで利用できなくなる。この機能を使い過ぎると、コンパイラが関数をコンパイルするのに使えるレジスタが足りなくなってしまう。

このオプションは、このレジスタ変数が、ユーザが指定したレジスタにいつでも入るようなコードを GNU CC が生成することを保証するものではない。asm 文でこのレジスタを明示的に参照するコードを書いて、それが常にこの変数を指すと仮定してはいけない。

局所レジスタ変数への格納は、データ流解析に従うと死んでいるようであれば、削除される可能性がある。局所レジスタ変数への参照は、削除されたり、移動されたり、単純化される可能性がある。


Node:Alternate Keywords, Next:, Previous:Explicit Reg Vars, Up:C Extensions

もう一組のキーワード

-traditional オプションを指定すると、特定のキーワードをいくつか無効にする。-ansi を指定すると、その他のキーワードをいくつか無効にする。これは、GNU C の拡張や ANSI C の機能を、ANSI C のプログラムと旧来の C のプログラムを含む全てのプログラムで使えなければならない、汎用のヘッダファイルで使いたい場合に問題になる。その場合、キーワードasmtypeofinline-ansi でコンパイルしたプログラムでは動作しないので使えない。一方、キーワード constvolatilesignedtypeofinline は、-traditional を指定してコンパイルしたプログラムで動作しない。

この問題を解決するには、問題となる各キーワードの頭に __ を付ければ良い。例えば、asm の代わりに __asm__ を、const の代わりに __const__ を、inline の代わりに __inline__ を使う。

他の C コンパイラはこれらの代替キーワードを受け付けないので、別のコンパイラでコンパイルした場合には、代替キーワードをマクロとして定義し、通常のキーワードに置き代わるようにすることができる。それには以下のようにする。

#ifndef __GNUC__
#define __asm__ asm
#endif

-pedantic は、GNU C の拡張の多くに警告を出す。そういう警告のうち、一つの式の中に収まっているものについては、その式の前に __extension__ を書くことで、出さないようにすることができる。__extension__ には、これ以外の効果はない。


Node:Incomplete Enums, Next:, Previous:Alternate Keywords, Up:C Extensions

不完全な enum

enum のタグを、可能な値を指定することなしに定義することが可能である。これは不完全型を生じるが、struct foo を要素を記述すること無しに書いた場合とほとんど同じような結果になる。後の宣言で、可能な値を指定すれば完全な型となる。

型が不完全である間は、その型を使って変数や記憶領域を割り当てることはできない。だが、その型へのポインタを使うことは可能である。

この拡張はそれほど役に立つわけではないが、enum の取扱いが、structunion の取扱いとより一貫性を保てるようになる。

この拡張は GNU C++ ではサポートされない。


Node:Function Names, Next:, Previous:Incomplete Enums, Up:C Extensions

文字列としての関数名

GNU CC は、現在の関数名を表す文字列変数を二つ前もって定義している。変数 __FUNCTION__ は、ソースコードに現れた通りの関数名を表す。変数 __PRETTY_FUNCTION__ は、言語に固有の形式で整形した関数名を表す。

この二つは、C 言語の関数ではいつでも同じになるが、C++ の関数では違ったものになる可能性がある。例えば、

extern "C" {
extern int printf (char *, ...);
}

class a {
 public:
  sub (int i)
    {
      printf ("__FUNCTION__ = %s\n", __FUNCTION__);
      printf ("__PRETTY_FUNCTION__ = %s\n", __PRETTY_FUNCTION__);
    }
};

int
main (void)
{
  a ax;
  ax.sub (0);
  return 0;
}

というプログラムの出力は以下のようになる。

__FUNCTION__ = sub
__PRETTY_FUNCTION__ = int  a::sub (int)

この二つの名前はマクロではなくて、定義済の文字列変数である。例えば、関数の中で #ifdef __FUNCTION__ としても何も特別な意味は持たない。プリプロセッサは __FUNCTION__ という識別子について何も特別な処理を行なわないからである。


Node:Return Address, Next:, Previous:Function Names, Up:C Extensions

関数の戻りアドレスやフレームアドレスを得るには

以下の関数を使って、関数の呼び出し元についての情報を得ることができる。

__builtin_return_address (level)
この関数は、現在の関数か、あるいはその呼び出し元関数のどれか一つの戻りアドレスを返す。引数 level は、呼び出しスタックを走査すべきフレーム数である。この値が 0 であれば、現在の関数の戻りアドレスを返す。この値が 1 であれば、現在の関数の呼び出し元の戻りを返す。以下同様。

引数 level は整数定数でなければならない。

機種によっては、現在の関数以外の関数の戻りアドレスを決定することが不可能な場合がある。そういう場合や、スタックの頂点に達したときは、この関数は 0 を返す。

この関数は、ゼロ以外の引数をつけてデバッグ用にのみ使うべきである。

__builtin_frame_address (level)
この関数は __builtin_return_address に似ているが、関数の戻りアドレスではなく、関数フレームのアドレスを返す。__builtin_frame_address を引数値を 0 として呼び出すと、現在の関数のフレームアドレスを返す。1 を引数値とすると、現在の関数の呼び出し元関数のフレームアドレスを返す。以下同様。

フレームは、ローカル変数やセーブされたレジスタを保持するスタック上の領域である。フレームアドレスは、普通は、その関数によりスタックにプッシュされた先頭のワードのアドレスになる。しかし、厳密な定義は、プロセッサと呼び出し規約に依存する。プロセッサにフレームポインタ専用レジスタがあれば、関数はフレームを一個持ち、__builtin_frame_address は、そのフレームポインタレジスタの値を返す。

__builtin_return_address についての注意が、この関数についても同様に当てはまる。


Node:Other Builtins, Next:, Previous:Return Address, Up:C Extensions

GNU CC が提供するその他の組み込み関数

GNU CC はこれまでに述べた以外にもたくさんの組み込み関数を提供している。その中の幾つかは内部で使う目的のものがあり、例外や可変長引数リストの処理に使われる。これらについては、ここでは説明しない。頻繁に変更が行われるからである。これらの関数を一般的な目的で使用するのはお勧めしない。

その他の関数は、最適化目的で提供されている。

GNU CC には、標準 C ライブラリにある多くの関数の組み込み版が含まれている。これらは常に、例え -fno-builtin オプション(see C Dialect Options)を指定した場合でも、C ライブラリの関数と同じ意味を持つものとして取り扱われる。これらの関数は、C ライブラリ関数の allocaffsabsfabsffabsfabsllabsmemcpymemcmpstrcmpstrcpystrlensqrtfsqrtsqrtlsinfsinsinlcosfcoscosl に対応する。

組み込み関数 __builtin_constant_p を使うと、ある値がコンパイル時に定数であったかどうかを知ることができ、そのため、GNU CC がその値を含む式について定数畳み込みが実行できるかを知ることができる。この関数の引数がテストすべき値になる。この関数は、引数がコンパイル時定数であることがわかっていた場合には整数 1 を返し、コンパイル時定数であったことがわからない場合には整数 0 を返す。0 が返ってきても、その値が定数でなかったということを意味するものではない。単に GNU CC が、-O オプションで指定された値では、定数であることが証明できなかっただけである。

この関数が使われる代表的な場合は、メモリが重要なリソースになる組み込みアプリケーションであろう。何か複雑な形算式があって、それが定数を含んでいれば定数畳み込みを行って欲しいだろうが、定数を含まない場合は関数を呼び出す必要がある。例えば、以下のような場合である。

#define Scale_Value(X)  \
  (__builtin_constant_p (X) ? ((X) * SCALE + OFFSET) : Scale (X))

この組み込み関数は、マクロやインライン展開関数で使っても良い。ただし、インライン展開関数の中で使って、その関数に対する引数を組み込み関数への引数として渡した場合、そのインライン関数の引数に文字列定数やコンストラクタ式(see Constructors)を指定して呼び出した場合は決して 1 を返さない。また、-O オプションを指定しない限り、インライン関数に数値定数を渡したときは 1 を返さない。


Node:Deprecated Features, Previous:Other Builtins, Up:C Extensions

消えた機能

過去において、GNU C++ コンパイラは新しい機能を実験するために拡張がなされた。当時は C++ 言語が進化途上だったのである。現在では、C++ 規格が完成したので、これらの幾つかの機能は依り良い別の機能で置き換えられている。古い機能を使うと、その機能が将来削除されるいくつかの場合に警告が発せられる。その他の場合には、機能は既に削除されている。

以下のリストは全てを網羅していないが、現在では廃止要求が出ている幾つかのオプションについて説明する。

-fthis-is-variable
C++ の初期のバージョンでは、this への代入を、アプリケーション定義のメモリ割当を実装するのに使うことができた。現在では、割当関数(operator new)が、同じ効果を得るための規格に適った方法になっている。
-fexternal-templates
-falt-external-templates
これらは、g++ でテンプレートの実体化を実装するためのたくさんの方法のうちの二つである。See Template Instantiation。C++ 規格は、実装単位を越えてテンプレート定義がどのように組織されなければならないかをはっきりと定義している。g++ には、規格に適ったコードとうまく動作する暗黙の実体化機構がある。


Node:C++ Extensions, Next:, Previous:C Extensions, Up:Top

C++ 言語に対する拡張

GNU コンパイラは、C++ 言語に対して以下の拡張を提供している(また、C 言語の拡張機能も大部分が C++ プログラムで使用可能である)。以下の機能が利用可能かどうかを検査するコードを書くには、GNU コンパイラを使っているかどうかを、 C プログラムの場合と同じ方法でテストさせることができる。それには、定義済みマクロ __GNUC__ を検査する。また、__GNUG__ を使うと特に GNU C++ であることを調べることができる。(see Standard Predefined)。


Node:Naming Results, Next:, Previous:C++ Extensions, Up:C++ Extensions

C++ の名前付戻り値

GNU C++ は、C++ のプログラムでは、関数定義構文を拡張して、関数の結果を入れる名前を関数定義本体の外側で指定できるようにしている。(訳注: これに相当する機能が最近制定された C++ 規格に入っているようである。)

type
functionname (args) return resultname;
{
  ...
  body
  ...
}

この機能を使うことで、関数の戻り値がクラス型の場合の余分なコンストラクタ呼び出しを避けることができる。例えば、関数 m が、X v = m (); と宣言されていており、その結果がクラス X とする。

X
m ()
{
  X b;
  b.a = 23;
  return b;
}

m には引数が無いように見えるが、実際には暗黙の引数が一つある。戻り値のアドレスである。呼び出し時に、v を保持するのに充分なスペースを指すアドレスが暗黙の引数として渡される。次に、b がコンストラクタにより構築され、その a フィールドに値 23 が設定される。最後に、コピーコンストラクタ(X(X&) という形式のコンストラクタ)がb に適用され、コピー先は暗黙の戻り値位置になり、v がようやく戻り値に結合される。

だが、これは無駄である。ローカルの b は、すぐコピーされていってしまう何かを保持するために宣言されているにすぎない。「省略」(elision) アルゴリズムと手続間データフロー解析を組み合わせたコンパイラなら、おそらくこういうものを全部消去することができるだろうが、戻り値を明示的に操作することで、効率の良いコードを生成するようユーザがコンパイラを支援するほうがずっと実用的だろう。これにより、ローカル変数とコピーコンストラクタを完全に避けることができる。

GNU C++ の拡張関数定義構文を使うと、最初に戻り値に r という名前を付け、その a フィールドに直接代入することで、一時的な割当とコピーを避けることができる。

X
m () return r;
{
  r.a = 23;
}

r の宣言は標準的で適切な宣言である。この効果は、m の本体のどの部分よりも 前に実行される。

この型の関数は他には何も制限を付け加えない。特に、return 文を実行可能だし、関数本体の終端に達する(「端から落ちる」)ことで暗黙に戻ることも可能である。

X
m () return r (23);
{
  return;
}

この場合、あるいは X m () return r (23); {} としても、曖昧さはない。戻り値 r はどちらの場合も初期化済みだからである。以下の書き方は読みにくいかも知れないが、これもまた予測できる動作をする。

X
m () return r;
{
  X b;
  return b;
}

r で示される戻り値スロットが最初に初期化されるが、return b; という文でこの値は上書きされる。コンパイラは r を破壊する(デストラクタがあればそれを呼び出し、なければ何もしない)ことでこれに対処し、次に rb で再初期化する。

この拡張は主に多重定義された演算子を使う人を助けるために提供している。多重定義演算子の場合は、単に引数だけでなく、関数の戻り値を制御するという需要が多いのである。コピーコンストラクタの性能ペナルティが大きい(特に良くあるのが、デフォルトのコンストラクタは高速である場合)クラスの場合は、大きな助けになる。この拡張の不利な点は、戻り値に対するデフォルトのコンストラクタがいつ呼ばれるかを制御しないことにある。常に先頭で呼び出される。


Node:Min and Max, Next:, Previous:Naming Results, Up:C++ Extensions

C++ の最小と最大演算子

二つの引数の「最小値」や「最大値」を返す演算子があると大変便利である。GNU C++ では(GNU C は除く)、

a <? b
これは、最小値、すなわち、数値 ab の小さいほうを返す。
a >? b
これは、最大値、すなわち、数値 ab の大きいほうを返す。

この二つの演算子は通常の C++ ではプリミティブではない。以下の例で示すように、C++ では二つの値の最小値を返すのにマクロを使うことができるからである。

#define MIN(X,Y) ((X) < (Y) ? : (X) : (Y))

そうすると、int min = MIN (i, j); とすることで、min に変数 ij の最小値を設定することができる。

しかし、XY に副作用が含まれていると予期しない動作を起こすことがある。例えば、MIN (i++, j++) は期待とは違って、小さいほうのカウンタを二回インクリメントしてしまう。GNU C の拡張を使うと、この手の問題を回避する安全なマクロを書くことが可能になる(see Naming an Expression's Type)。だが、MINMAX をマクロとして書いてしまうと、基本的な算術演算に関数呼び出し形式の記法を使うことを強制することにもなる。GNU C++ の拡張を使えば、代わりに int min = i <? j; と書ける。

<?>? はコンパイラに組み込みなので、副作用のある式も正しく扱う。int min = i++ <? j++; は正しく動作する。


Node:Destructors and Goto, Next:, Previous:Min and Max, Up:C++ Extensions

GNU C++ の goto とデストラクタ

C++ プログラムでは、goto 文を安全に扱うことができる。デストラクタを必要とする集合型データを含むブロックを抜け出るのに使うことができる。この場合、デストラクタは goto が制御を移す前に実行される。

goto を使って、コンストラクタを必要とするスコープに入る のは、以前として禁止されている。


Node:C++ Interface, Next:, Previous:Destructors and Goto, Up:C++ Extensions

一個のヘッダファイルに宣言と定義を入れる

C++ のオブジェクトの定義は極めて複雑になることがある。原則として、ソースコードには、複数のソースファイルにまたがって使用するオブジェクト毎に二種類のものが必要となる。第一に、インターフェースの指定が必要になる。これは、オブジェクトの構造を型宣言と関数プロトタイプで記述する。第二に、実装自体が必要になる。ヘッダファイルにインターフェース定義を分けて、実際の実装と並行して保守するのはうんざりする話である。また、危険でもある。インターフェースの定義と実装の定義を分けておくと、一貫性が保たれない可能性があるからである。

GNU C++ では、一個のヘッダファイルで両方の目的に使うことができる。

注意。この機能を指定する方法は移行中である。当面は、二つの #pragma 文のうちの一つを使わなければならない。将来的には、別の方法を使ようになり、#pragma 文は必要なくなるだろう。

ヘッダファイルには完全な定義を入れておくが、ソースコードからインクルードするときは #pragma interface という目印を付ける。これにより、通常のソースファイルがそのヘッダファイルを #include で取り込んだときに、そのヘッダファイルをインターフェース仕様としてだけ使うことをコンパイラに許す。完全な実装を含む一個のソースファイルでは名前付の規約か#pragma implementation を使って、ヘッダファイルのこの別の使い方を指示することができる。

#pragma interface
#pragma interface "subdir/objects.h"
オブジェクトクラスを定義している ヘッダファイルでこの文を使って、そのクラスを使っているオブジェクトファイルの大部分でスペースを節約する。通常、一定の情報のローカルのコピー(インラインメンバ関数、デバッグ情報、仮想関数を実装する内部テーブルのバックアップコピー) は、クラス定義を含む各オブジェクトファイルで保持しなければならない。この pragma を使うと、そのような重複を避けることができる。#pragma inreface を含むヘッダファイルが、あるコンパイル単にインクルードされていると、この補助的な情報は生成されない(主となる入力ソースファイル自体が #pragma implementation を使っていない限り)。代わりに、オブジェクトファイルに、リンク時に解決される参照が入る。

この制御子の二番目の形式は、同じ名前のヘッダファイルが色々なディレクトリに複数あるときに役に立つ。この形式を使う場合は、#pragma implementation に同じ文字列を指定しなければならない。

#pragma implementation
#pragma implementation "objects.h"
インクルードされたヘッダファイルから完全な出力を得たい(そしてグローバルに可視にしたい)時は、このプラグマを 主となる入力ファイル で使う。インクルードされるヘッダファイルは、#prama interface を使うべきである。インライン展開されるメンバ関数、デバッグ情報、仮想関数を実装するのに使われる内部的な表のバックアップコピーが全て実装ファイルに生成される。

#pragma implementation を引数なしで使うと、ソースファイルとしてベース名2が同じインクルードファイルに適用される。例えば、他に#pragma implementation と書くのはこれだけで、#pragma implementation "allclass.h" に等価である。

GNU C++ のバージョン 2.6.0 以前では、allclass.h は、allclass.cc からインクルードしていると、#pragma implementation を指定していなくても、常に実装ファイルとして扱われた。これは利点より問題点の方が多いように思われる。

#pragma implementation を明示的に使う場合には、ソースファイルでは、それにより影響を受けるヘッダファイルをインクルードする前に、現れなければならない。

一個の実装ファイルに複数のヘッダファイルからコードをインクルードさせたい場合は文字列引数を使う。(また、ヘッダファイルをインクルードする#include も使わなければならない。#pragma implementation は指定したファイルの使い方を指定するだけであって、実際のインクルードは行なわないからである。)

一個のヘッダファイルの内容を複数の実装ファイルに分ける方法はない。

#pragma implementation#pragma interface は、関数のインライン展開にも影響する。

#pragma interface を記述したヘッダファイル内でクラスを定義すると、そのクラス内で定義される関数の効果は、明示的な extern 宣言に似ている。コンパイラは、この関数の一個の独立したバージョンを定義するコードを全く吐かない。その定義は、その関数の呼び出し側でインライン展開するのに使われるだけである。

逆に、同じヘッダファイルを #pragma implementation を宣言している主となるソースファイルでインクルードすると、コンパイラは関数自身のコードを吐く。これは、ポインタ経由で(あるいはインライン展開なしでコンパイルされた呼び出し側から)見つけることのできるバージョンの関数を定義する。その関数への呼び出しが全部インライン展開可能なら、-fno-implement-inlines 付きでコンパイルすることで、関数のコードを吐くのを避けることができる。呼び出しがどれか一つでも印ライン展開されてないと、リンク時のエラーとなる。


Node:Template Instantiation, Next:, Previous:C++ Interface, Up:C++ Extensions

テンプレートはどこ

C++ のテンプレートは、普通 UNIX システムに見られるようなものよりも、環境からより多くの情報を必要とするような言語機能の最初のものである。コンパイラとリンカは、各テンプレートの実体は、それが必要なら実行形式の中でただ一つしか存在すること、そしてそれ以外にはないことをなんとかして保証しなければならない。この問題に対するアプローチには二つの基本的な方法がある。以下では、それらを Boralnd モデルと Cfront モデルと呼ぶ。

Borland model
Borland C++ はテンプレートの実体化問題を解決するのに、共通ブロックに等価なコードをリンカに追加した。コンパイラは、テンプレートの実体を、それを使っているコンパイル単位毎に出力し、リンカがそれらを一緒にまとめる。このモデルの良いところは、リンカはオブジェクトファイルの面倒を見るだけで良いということである。オブジェクトファイル以外には何も考えなくて良い。このモデルの欠点は、テンプレートコードが繰り返しコンパイルされるので、コンパイル時間が長くなることである。このモデル向けに書いたコードはヘッダファイル中の全てのテンプレート定義をインクルードしがちである。実体化するには見えていなくてはならないからである。
Cfront model
AT&T の C++ トランスレータである Cfront はテンプレートの実体化問題を解決するのに、テンプレートのリポジトリという概念を作り出した。テンプレートリポジトリトは、テンプレートの実体が格納され、自動的に維持される場所である。より最近のバージョンのリポジトリの仕組みは以下の通りである。個々のオブジェクトファイルが構築されると、コンパイラは見つけたテンプレートの定義と実体をどんなものでもリポジトリに置く。リンク時に、リンクラッパがリポジトリ中のオブジェクトファイルに追加され、まだ出力されていない実体で必要なものがコンパイルされる。このモデルの良いところは、コンパイル速度が速いということとシステムのリンカをそのまま使えるということである。Borland モデルを実装するには、コンパイラベンダはリンカも置き換える必要がある。Cfront モデルの欠点は、とてつもなく複雑さが増し、そのため問題が起きる可能性も大きくなる。コードによってはこの方法は透過的だが、実際には一つのディレクトリで複数のプログラムを構築したり、一つのプログラムが複数のディレクトリにわかれているプログラムを構築するのが大変難しくなる。このモデル向けに書いたコードはインライン展開されないメンバテンプレートを別のファイルで分離して定義し、別ファイルを別々にコンパイルする傾向がある。

GNU ld バージョン 2.8 以降を、Linux/GNU、Solaris 2、Microsoft Windows のような ELF システムで使うときは、g++ は Borland モデルを使用する。他のシステムでは、g++ はどちらの自動的に処理の行なわれるモデルも実装していない。

将来の g++ は、ハイブリッドモデルをサポートする予定である。ハイブリッドモデルでは、GCC は コンパイルに含まれるテンプレート定義に対するどんな実体化でも生成し、テンプレート定義と実体化のコンテキスト情報をオブジェクトファイルに格納する。リンクラッパは、必要に応じて情報を抽出し、GCC を起動して残りの実体化を生成する。その後で、リンカが重複した実体化を組み合わせる。

現時点では、テンプレートの実体化の取扱いには以下のオプションがある。

  1. テンプレートを使用しているコードを -frepo 付きでコンパイルする。GCC は、拡張子が .rpo のファイルを生成する。このファイルは、そこで実体化されうる、対応するオブジェクトファイルで使われるテンプレートの実体化を全て列挙する。リンクのラッパである次に、collect2.rpo ファイルを更新して、GCC にそれらの実体化がどこで起きるかを知らせ、影響を受けるオブジェクトファイルを再構築する。リンク時のオーバーヘッドは第一パスの後では無視できる。GCC が同じファイルに実体化を置き続けるからである。

    これは、Borland モデルで書かれたアプリケーションコードには最善の選択である。Cfront モデルで書かれたコードは、修正を行ってテンプレート定義が、実体化の一つ以上の点利用可能になるようにする必要があるだろう。普通この修正は、各テンプレートヘッダの最後に#include <tmethods.cc> を追加するだけである。

    ライブラリコードの場合、そのライブラリで必要になるテンプレートの実体化を全て提供したいのなら、単にそのオブジェクトファイルを全て一緒にリンクすれば良い。リンクは失敗するが、副作用として実体化が引き起こされる。ただし、注意しなければならないのは、複数のライブラリが同じ実体化を提供しようとすると衝突が発生する事である。もっとうまく扱うには、次のオプションで説明される明示的な実体化を使うこと。

  2. -fno-implicit-templates オプションを指定してコンパイルし、テンプレート実体の暗黙の生成を行なわないようにし、ユーザが使用するものを全部明示的に実体化するようにする。この方法を取ると、他の方法を取る場合よりも、正確にどの実体が必要なのかについての知識が余計に要求される。だが、こちらの方が謎めいた点が少ないし、ずっと扱いやすい。明示的な実体化をプログラム全体に散らばらせることができる。それには、おそらく、実体が使われる翻訳単位に置くか、テンプレート自体を定義している翻訳単位に置くかする。必要な明示的な実体化を全て一つの大きなファイルに入れることができる。あるいは、
    #include "Foo.h"
    #include "Foo.cc"
    
    template class Foo<int>;
    template ostream& operator <<
                    (ostream&, const Foo<int>&);
    

    上のような小さなファイルを必要な実体毎にを作ったり、これらkらテンプレート実体化ライブラリを作ることができる。

    Cfront モデルのコードを使っている場合、メンバテンプレート定義を#include していないファイルをコンパイルするときに-fno-implicit-templates オプションを使うと、おそらく回避できるだろう。

    実体化を行うのに一つの大きなファイルを使うなら、-fno-implicit-templates なしでコンパイルして、明示的な実体化で必要な(しかし、他のどのファイルでも必要としない)実体を全て、それらを指定せずに、得たいこともあるだろう。

    g++ は、Working Paper で概説されているテンプレート実体化構文を拡張して、明示的な実体化の前方宣言と、テンプレートクラスに対しGCC がサポートするデータ(すなわち vtable)を、そのメンバどれ一つ実体化することなしに実体化することを可能にしている。

    extern template int max (int, int);
    inline template class Foo<int>;
    

  3. 何もしない。g++ が自動的な実体管理を実装しているかのように振る舞う。Borland モデル用に書いたコードは正しく動作する。だが、各コンパイル単位にはそれが使っているテンプレートのそれぞれの実体を含む。大きなプログラムでは、コードの重複が受け入れられないほどの量になるだろう。
  4. テンプレート定義を含む全てのファイルに #pragma interface を追加する。これらのファイルそれぞれについて、#include している側の幾つかの .C ファイルの先頭に、#pragma implementation "filename" を追加する。次に、全てを -fexternal-templates 付きでコンパイルする。そうすると、テンプレートはそれを実装している(すなわち、実装が存在するファイルに #pragma implementation 行がある) 翻訳単位でのみ展開される。他のファイルは全て外部参照を使う。運が良ければ、なにもかもうまく行くはずである。未定義のシンボルがあるというエラーになったら、プログラムで使われている各テンプレートの実体が、そのテンプレートを実装しているファイルで使われていることを確認する必要がある。そのファイルで特定の実体を一つも使っていないなら、単に明示的に実体化することができる。それには、最新の C++ working paper にある、以下のような構文を使う。
    template class A<int>;
    template ostream& operator << (ostream&, const A<int>&);
    

    この戦略は、どちらのモデル向けに書かれたコードでも動作する。Cfront モデル向けに書かれたコードを使う場合は、クラステンプレートを含むファイルとそのメンバテンプレートを含むファイルは、同じコンパイル単位で実装されるべきである。

    ちょっとだけ違う方法として、代わりにオプション-falt-external-templates を使う方法がある。このオプションを指定すると、テンプレートの実体が、テンプレートが定義されているファイルを実装する翻訳単位ではなく、最初に実体化されるヘッダを実装している翻訳単位に生成される。このヘッダは全ての翻訳単位で同じでなければならない。そうなってないとおそらく破綻するだろう。

    これらのプラグマについてのより詳細な議論は、See Declarations and Definitions in One Header


Node:Bound member functions, Next:, Previous:Template Instantiation, Up:C++ Extensions

メンバ関数への束縛ポインタから関数ポインタを取り出す

C++ では、メンバ関数へのポインタ(pointer to member function, PMF) はワイドポインタとでも呼ぶべきものを使って、可能な呼出し機構を全て扱うように実装されている。PMF は、this ポインタの調整方法や、指し示されている関数が仮想であれば vtable のある場所、さらにはそのメンバ関数が vtable のどこにあるかといった情報を格納する必要がある。内側のループで PMF を使っている場合、その決定を本当に考え直したほうが良い。選択の余地がないのであれば、指定されたオブジェクト/PMF のペアに対して呼ばれる関数へのポインタを取り出して、ループの内側で直接それを呼び出せば、幾らか実行時間の節約になる。

関数ポインタ経由の呼出しには以前としてペナルティが課されるということに注意して欲しい。現代のほとんどのアーキテクチャでは、このような呼出しは CPU の分岐予測機能を無効にしてしまう。これは通常の仮想関数呼出しにも当てはまる。

この拡張の構文は以下の通り。

extern A a;
extern int (A::*fp)();
typedef int (*fptr)(A *);

fptr p = (fptr)(a.*fp);

この拡張を使うには -Wno-pmf-conversions を指定しなければならない。


Node:C++ Signatures, Previous:Bound member functions, Up:C++ Extensions

シグネチャを使った型抽象

GNU C++ ではキーワード signature を使って、完全抽象クラスインターフェースをデータ型として定義することができる。シグネチャポインタを使って、この抽象化を実際のクラスと関係付けることができる。シグネチャを使いたい場合は、GNU コンパイラに-fhandle-signatures オプションを指定して実行する。(このオプションを指定すると、もう一つのキーワード sigof も、将来の拡張に備えて、予約する。)

大雑把に言って、シグネチャは型の抽象化あるいはクラスのインターフェースである。他の言語にも同様の機能を持つものがある。C++ のシグネチャはML のシグネチャ、Haskell の型クラス、Modula-2 の定義モジュール、Modula-3 のインターフェースモジュール、Emerald の抽象型、Trellis/Owl の型モジュール、Scratpad II のカテゴリ、POOL-I の親戚である。シグネチャについてのもっと詳細な議論については、Signatures: A Language Extension for Improving Type Abstraction and Subtype Polymorphism in C++。これは、Gerald Baumgartner and Vincent F. Russo によるもので、Tech reportCSD-TR-95-051, Dept. of Computer Sciences, Purdue University, August 1995 に掲載されている。少々改訂したバージョンが、Software--Practice & Experience, 25(8), pp. 863-889, August 1995) にある。この技術報告書は、匿名 FTP により、ftp.cs.purdue.edupub/gb/Signature-design.ps.gz から入手できる。

文法的には、シグネチャの宣言はメンバ関数宣言とネストした型宣言の集まりである。例えば、以下のシグネチャ宣言は、メンバ関数 int foo ()int bar (int) を持つ、新しい抽象型 S を定義する。

signature S
{
  int foo ();
  int bar (int);
};

シグネチャ型には実装の定義はないので、シグネチャの実体を直接書くことはできない。代わりに、必要とするインターフェースを含む任意のクラスへのポインタを シグネチャポインタ として定義することができる。このようなクラスはシグネチャ型を実装する。

あるクラスを S の実装として使うには、そのクラスが、パブリックなメンバ関数 int foo ()int bar (int) を持っていることを保証しなければならない。このクラスは、パブリックでもパブリックでなくも、他のメンバ関数も持つことができる。シグネチャで宣言されているものを提供している限り、シグネチャ型の実装として適切なのである。

例えば、C がシグネチャ S の要件を満たすクラスであるとする(CS適合する)。すると、

C obj;
S * p = &obj;

これはシグネチャポインタ p を定義し、それをC 型のオブジェクトを指すように初期化する。メンバ関数を int i = p->foo (); のように呼び出すと、obj.foo () が実行される。

標準の C++ では、抽象仮想クラスが幾らか似た機能を提供している。代わりにシグネチャを使うことの主な利点は二つある。

  1. 下位型を取ることにより継承に依存しなくなる。クラスや T 型のシグネチャは、S で宣言されているメンバ関数が全て、T にもある限り、どんな継承階層構造であっても、シグネチャ型 S の下位型である。このため、クラスの継承階層構造を反映した型を使うことを強制される代わりに、任意の継承(実装)階層構造から完全に独立している下位型の階層構造を定義できる。
  2. シグネチャを使うと、既存のクラス階層をシグネチャ型の実装として使うことができる。もしこのクラス階層がコンパイルされた形でしか利用できないとすると、抽象仮想クラスを使うときに困ることになる。抽象仮想クラスは既存のクラス階層の一番上に後から取り付けることはできないからである。このため、インターフェースクラスをその抽象仮想クラスの下位型として書く必要がある。

シグネチャについての詳細を一つ述べる。シグネチャ宣言には、メンバ関数宣言と同様、メンバ関数定義も含めることができる。シグネチャの、完全に定義されているメンバ関数はデフォルト実装と呼ばれる。クラスは、適合するために特定のインターフェースを含む必要はない。例えば、クラス C は以下のシグネチャに適合し得る。

signature T
{
  int f (int);
  int f0 () { return f (0); };
};

これは、C がメンバ関数 int f0 () を実装していてもしていなくても良い。C::f0 を定義すれば、その定義が優先する。定義しなければ、S::f0 のデフォルト実装が適用される。


Node:Gcov, Next:, Previous:C++ Extensions, Up:Top

gcov: テストカバレージプログラム

gcov は、GNU CC と合わせて使うことにより、プログラムのカバレージをテストするツールである。

本章では、gcov バージョン 1.5 について説明する。


Node:Gcov Intro, Next:, Previous:Gcov, Up:Gcov

gcov 入門

gcov はテストカバレージプログラムである。GNU CC と一緒に使って解析することで、プログラムをより効率良く、高速に実行できるようにするのを助ける。gcov をプロファイリングツールとして使うことで、どの最適化策がもっとも影響があるかを発見する手助けとなる。別のプロファイリングツール gprof と合わせて使うと、プログラムのどの部分が最も計算時間を消費しているかを評価することができる。

プロファイリングツールは、プログラムの性能を解析する助けとなる。gcovgprof のようなプロファイリングツールを使うと、以下のような基本的な性能統計情報を得ることができる。

読者のコードがコンパイルされたときにどのように動作するかについての上記の情報が一度分かってしまえば、各モジュールを見て、どのモジュールを最適化すべきかを知ることができる。gcov は、どこを最適化すれば良いかを決めるのを助ける。

ソフトウェアの開発者は、テストスイートと組み合わせてカバレージテストも使って、ソフトウェアが実際にリリースできるほど充分良いものであるかどうかを確認する。テストスイートは、プログラムが期待どおりに動作するかどうかを検証できる。カバレージプログラムは、そのプログラムのどれぐらいの部分がテストスイートにより検査されたかを調べる。そうすることで、開発者はどんな種類のテストケースをテストスイートに追加する必要があるかを決めることができ、さらに良いテストとさらに良い最終的な製品を作り出すことが可能になる。

gcov を使う予定なら、読者のコードは最適化なしでコンパイルすべきである。何故なら、最適化を行なうと、コードの幾つかの行を組み合わせて一つの機能にすることがあり、コードが大量にコンピュータの計算時間を使っている場所である「ホットスポット」を探すのに必要なだけの情報が得られないからである。同様に、gcov は行毎に(最も細かい単位では)統計を累積するので、一行には一個の文しか置かないプログラミングスタイルが最もうまくいく。ループや他の制御構造に展開される、複雑なマクロを使っていると、統計があまり役に立たなくなる。マクロの呼び出しが現れた行についてだけ報告を行なうからである。関数と同じように振る舞う複雑なマクロを使っているなら、そのマクロをインライン関数に置き換えればこの問題は解決される。

gcov は、sourcefile.gcov という名前のログファイルを作り、そのファイルは、ソースファイル sourcefile.c の各行が何回実行されたかを示す。これらのログファイルを gprof と組み合わせると、プログラムの性能の細かなチューニングを助けることができる。gprof は、gcov から得られる情報と組み合わせて使うことのできる、時間に関する情報を与える。

gcov は、GNU CC でコンパイルしたコードにしか使えない。他のプロファイリングやテストカバレージ機構とは互換性はない。


Node:Invoking Gcov, Next:, Previous:Gcov Intro, Up:Gcov

gcov の起動方法

gcov [-b] [-v] [-n] [-l] [-f] [-o directory] sourcefile
-b
分岐頻度を出力ファイルに書きだし、分岐に関する要約情報を標準出力に書き出す。このオプションを指定することで、プログラム中のそれぞれの分岐がどれぐらい成立しているかを知ることができる。
-v
gcov のバージョン番号を標準エラー出力に表示する
-n
gcov の出力ファイルを作らない。
-l
インクルードされたソースファイルに対して長いファイル名を使う。例えば、ヘッダファイル x.h がコードを含んでいて、a.c からインクルードされている場合、gcova.c に対して実行すると、出力ファイルとして、x.h.gcov ではなくてa.c.x.h.gcov という名前のファイルを作る。これは、x.h が複数のソースファイルからインクルードされている場合に役に立つ。
-f
ファイル単位の要約に加えて、関数単位の要約を出力する。
-o
オブジェクトファイルが置かれているディレクトリを指定する。gcov は、これで指定されたディレクトリから、.bb.da という拡張子が付いたファイルを探す。

gcov を使うには、まずプログラムをコンパイルするときにGNU CC の特別なオプションを二つ指定しなければならない。-fprofile-arcs -ftest-coverage である。これを指定するとコンパイラは、gcov で必要とされる付加的な情報(基本的にはプログラムのフローグラフ)を生成し、また、gcov で必要とする余分のプロファイリング情報を生成するためにオブジェクトファイルに付加的なコードを追加する。これらの付加的なファイルは、ソースコードが置かれているディレクトリに置かれる。

プログラムを実行させると、プロファイル出力が生成される。-fprofile-arcs を指定してコンパイルしたソースファイル毎に、.da という拡張子が付いたファイルがソースディレクトリに置かれる。

gcov の引数にプログラムのソースファイル名を指定して実行させると、今度は各行毎の実行頻度が付いたコードのリスティングが出力される。例えば、読者のプログラムが tmp.c であるとすると、gcov の基本的な機能を使ったときに表示されるものは以下のようになる。

$ gcc -fprofile-arcs -ftest-coverage tmp.c
$ a.out
$ gcov tmp.c
 87.50% of 8 source lines executed in file tmp.c
Creating tmp.c.gcov.

ファイル tmp.c.gcovgcov の出力が含まれている。以下に例を示す。

                main()
                {
           1      int i, total;

           1      total = 0;

          11      for (i = 0; i < 10; i++)
          10        total += i;

           1      if (total != 45)
      ######        printf ("Failure\n");
                  else
           1        printf ("Success\n");
           1    }

-b オプションを使うと、出力は以下のようになる。

$ gcov -b tmp.c
 87.50% of 8 source lines executed in file tmp.c
 80.00% of 5 branches executed in file tmp.c
 80.00% of 5 branches taken at least once in file tmp.c
 50.00% of 2 calls executed in file tmp.c
Creating tmp.c.gcov.

この場合できる tmp.c.gcov の例は以下の通り。

                main()
                {
           1      int i, total;

           1      total = 0;

          11      for (i = 0; i < 10; i++)
branch 0 taken = 91%
branch 1 taken = 100%
branch 2 taken = 100%
          10        total += i;

           1      if (total != 45)
branch 0 taken = 100%
      ######        printf ("Failure\n");
call 0 never executed
branch 1 never executed
                  else
           1        printf ("Success\n");
call 0 returns = 100%
           1    }

基本ブロック毎に、その基本ブロックの最後の行の後に一行表示が追加され、基本ブロックの終りとなる分岐や呼び出しを記述する。あるソースの一行で終わる基本ブロックが複数ある場合は、その行にリストされる分岐や呼び出しは複数個存在する可能性がある。その場合、分岐と呼び出しはそれぞれ与えられた数となる。これらの分岐と呼び出しをソースコードの構文に対応させる簡単な方法はない。だが、一般には一番小さい番号の分岐や呼び出しが、そのソース行の一番左側の構文に対応する。

分岐の場合、それが少なくとも一回でも実行されたなら、分岐が成立した回数を分岐を実行した回数で割ったものをパーセンテージで表したものが表示される。一回も実行されなければ、"never executed" というメッセージが表示される。

呼び出しの場合、それが少なくとも一回でも実行されたなら、その呼び出しから戻ってきた回数を呼び出しが実行された回数で割ったものをパーセンテージで表したものが表示される。これは普通は 100% になるが、exitlongjmp を呼び出している関数の場合はこれより小さくなることもある。そういう関数は、呼び出されたときに戻ってこない可能性がある。

実行回数は累積される。.da ファイルを消さずにサンプルプログラムをもう一回実行すると、ソースの各行が実行された回数が前回の実行結果に追加される。これは色々な面で役に立つ可能性がある。例えば、ある検証テストスイートの一部として実行する多数のプログラムについてデータを蓄積したり、非常に多くのプログラムの実行についてより正確な長期的な情報を提供するのに使うことができる。

.da ファイル中のデータは、プログラムが終了する直前にセーブされる。-fprofile-arcs 付きでコンパイルされたソースファイル毎に、プロファイリング用コードがまず、存在する .da ファイルを読み込もうとする。そのファイルが実行形式にマッチしない(基本ブロックの回数値の数が異なる)場合は、そのファイルの内容を無視する。次に、新しい実行回数値を追加し、最後にデータをファイルに書き出す。


Node:Gcov and Optimization, Next:, Previous:Invoking Gcov, Up:Gcov

GCC の最適化と合わせた使い方

gcov を使って自分のコードの最適化を行なう予定なら、まず最初に自分のプログラムをコンパイルするときに GNU CC の特別なオプションを二つ指定しなければならない。それを除けば、他の GNU CC のどのオプションでも使うことができる。しかし、プログラムのあらゆる行が実行されることを確認するには、最適化オプションは同時には指定しないほうが良い。機種によっては、最適化により、幾つかの簡単なコード行が、他の行と組み合わされることにより、削除されてしまう可能性があるからである。例えば、

if (a != b)
  c = 1;
else
  c = 0;

というコードは、機種によっては一個の命令にコンパイルされることがある。この場合、gcov が各行毎の実行回数を別々に計算する術がない。何故なら、各行に対応する独立したコードがないからである。このため、このプログラムを最適化つきでコンパイルすると gcov の出力は以下のようになる。

      100  if (a != b)
      100    c = 1;
      100  else
      100    c = 0;

これは、このコードブロックが、最適化により組み合わされ、100回実行されたことを示す。ある意味ではこの結果は正しい。この4行全体を表す命令が一個しかないからである。だが、この出力では、結果が 0 になった回数と結果が 1 になった回数が分からない。


Node:Gcov Data Files, Previous:Gcov and Optimization, Up:Gcov

gcov のデータファイル

gcov は、プロファイリングを行なうのにファイルを三つ使う。これらのファイル名は、元のソースファイルのサフィックスを .bb.bbg.da のどれか一つに置き換えたものになる。これらのファイルは全てソースファイルと同じディレクトリに置かれ、プラットフォーム独立な方法で格納されているデータを含む。

.bb.bbg の付いたファイルは、ソースファイルをGNU CC の -ftest-coverage オプションを付けてコンパイルしたときに生成される。.bb ファイルには、ソースファイルのリスト(ヘッダファイルを含む)、ソースファイル内の関数、ソースファイル内の各基本ブロックに対応する行番号が含まれる。

.bb ファイルの形式は、色々な 4バイトの整数のリストからなる。この整数は、そのファイル内の各基本ブロックの行番号に対応する。各リストは、行番号 0 で終端される。行番号が -1 だと、ソースファイル名(4バイト境界に詰め物され、その後にもう一つ -1 が続く)が続くことを示す。さらに、行番号が -2 だと、関数名(これも4バイト境界に詰め物され、もう一つ -2 が続く)が続くことを示す。

.bbg ファイルは、ソースファイルのプログラムフローグラフを再構成するのに使われる。それには、各関数毎のプログラムフロー弧(一つの基本ブロックから別の基本ブロックへの分岐で、分岐が成立する可能性があるもの)のリストが含まれており、.bbファイルと組み合わせることで、gcov にプログラムフローを再構成させることが可能になる。

.bbg ファイルの形式は以下のようになる。

        関数 #0 の基本ブロック数(4バイトの数)
        関数 #0 の弧の総数(4バイトの数)
        基本ブロック #0 の弧の数(4バイトの数)
        弧 #0 の目的基本ブロック(4バイトの数)
        フラグビット(4バイトの数)
        弧 #1 の目的基本ブロック(4バイトの数)
        フラグビット(4バイトの数)
        ...
        弧 #N の目的基本ブロック(4バイトの数)
        フラグビット(4バイトの数)
        基本ブロック #1 の弧の数(4バイトの数)
        弧 #0 の目的基本ブロック(4バイトの数)
        フラグビット(4バイトの数)
        ...

-1(4バイトの数として格納される)を使って、基本ブロックの各関数リストを区切り、ファイルが正しく読み込まれたことを確認する。

.da ファイルは、GNU CC の -fprofile-arcs オプションを使って構築されたオブジェクトファイルを含むプログラムが実行されたときに生成される。別々の .da ファイルがこのオプションを指定してコンパイルしたソースファイル毎に作られる。その .da ファイルの名前は、生成されるオブジェクトファイルに絶対パスで格納される。このパス名は、ソースファイル名の拡張子を .da で置き換えたものになる。

.da ファイルの形式は非常に簡単である。先頭の 8 バイトの数が、このファイルに入っている回数値の数であり、その後に回数値が続く。回数値は 8バイトの数として格納されている。各回数値は、プログラムの各弧が実行された回数に対応する。回数値は累積される。プログラムが実行される度に、既にある .da ファイルと今回の起動による新しい回数値を組み合わせる。弧の数が現在のプログラムに対応しない .da ファイルの内容は無視され、代わりに単に上書きされる。

この三つファイルは全て、gcov-io.h 内の関数群を使って整数を格納する。このヘッダにある関数群はストリームへデータを格納したり、ストリームからデータを取り出す、機種独立な方法を提供している。


Node:Trouble, Next:, Previous:Gcov, Up:Top

GCC の既知の問題の原因

この節では、GCC の使用者に影響のある既知の問題点について述べる。ほとんどは GCC のバグではない。もしバグなら、修正してるはずだからである。しかし、使用者から見ればバグに見えることもある。

以下の問題点には、他のソフトウェアのバグによるものもあるし、追加するには大変な作業が必要なので入れていない機能があることによるものもあるし、仕様がどうあるべきか人々の間で意見の一致を見ていないことによるものもある。


Node:Actual Bugs, Next:, Previous:Trouble, Up:Trouble

修正予定のバグ


Node:Installation Problems, Next:, Previous:Actual Bugs, Up:Trouble

GCC のインストール時の問題

以下に、GCC のインストール過程で発生する問題(それに実際には何も間違いではない見かけ上の問題)の一覧を示す。


Node:Cross-Compiler Problems, Next:, Previous:Installation Problems, Up:Trouble

クロスコンパイラの問題

様々な理由により、特定の機種でクロスコンパイルを行なうと問題に出くわす可能性がある。


Node:Interoperation, Next:, Previous:Cross-Compiler Problems, Up:Trouble

相互運用性

この節では、GNU C や GNU C++ を、特定のシステム上の他のコンパイラや、アセンブラ、リンカ、ライブラリ、デバッグと共に使う場合に出会う様々な問題を説明する。


Node:External Bugs, Next:, Previous:Interoperation, Up:Trouble

特定のプログラムをコンパイルするときの問題

特定のプログラムの中にはコンパイルするのに問題があるものがある。


Node:Incompatibilities, Next:, Previous:External Bugs, Up:Trouble

GCC の非互換性

GNU C と既存の(非 ANSIの)版の C には注意しなければならない非互換性がたくさんある。-traditional オプションを指定すると、GNU C が他の C コンパイラと同じように動作するので、これらの非互換性の多くは消えるが、全部がなくなるわけではない


Node:Fixed Headers, Next:, Previous:Incompatibilities, Up:Trouble

修正されたヘッダファイル

GCC は、システムのヘッダファイルの幾つかを修正したバージョンをインストールする必要がある。これは、多くのターゲットシステムで、ヘッダファイルの中に、変更なしには GCC ではうまく扱えないものが存在するからである。その中の幾つかにはバグがあり、幾つかにはANSI C との非互換性があり、中には他のコンパイラの特別な機能に依存しているものがある。

GCC をインストールすると、修正したヘッダファイルを自動的に作成してインストールする。これは、fixincludes と呼ばれるプログラムを実行することで行なわれる。(ターゲットによっては、fixinc.svr4 のような別の名前のものが使われる。) 普通は、これに関して注意を払う必要はない。だが、自動的にはうまくいかない場合もある。


Node:Standard Libraries, Next:, Previous:Fixed Headers, Up:Trouble

標準ライブラリ

GCC 自体は、ISO/ANSI C 規格がconforming freestanding implementation と呼んでいるものに準拠しようとしている。これは、ANSI C 言語の全ての機能が利用可能であり、さらに float.hlimits.hstdarg.hstddef.h の中身も利用可能であるということを意味する。C ライブラリのその他の部分は、OS ベンダにより提供される。その C ライブラリが C の規格に準拠していなければ、読者のプログラムをコンパイルするとき(とりわけ、-Wall を指定したときに、警告が出る可能性がある。

例えば、SunOS 4.1.3 の sprintf 関数は char * を返すが、C の規格では sprintfint を返すようになっている。fixincludes プログラムでこの関数のプロトタイプを規格に一致するようにすることもできるが、それは間違いである。なぜなら、この関数自体は依然として char * を返すからである。

規格に従ったライブラリが必要な場合は自分でそれを見つける必要がある。GCC では提供していない。GNU C ライブラリ(glibc と呼ばれる)は、多数のオペレーティングシステムに移植されており、ANSI/ISO、POSIX、BSD、SystemV との互換性を提供している。また、オペレーティングシステムのベンダーにより新しいライブラリが利用可能かどうか問い合わせることもできるだろう。


Node:Disappointments, Next:, Previous:Standard Libraries, Up:Trouble

失望と誤解

この節で述べる問題は、残念なことだが、実際的な回避方法が見つかっていない。


Node:C++ Misunderstandings, Next:, Previous:Disappointments, Up:Trouble

GNU C++ についてのよくある誤解

C++ は複雑な言語であり進化途上にあり、その規格の定義(ISO C++ 標準)は最近定まったばかりである。その結果、読者の使っているコンパイラは時々読者を脅かせることがあるだろう。たとえその動作が正しいものであるとしてもである。この節では、この手の問題が良く起きる領域の幾つかについて議論する。


Node:Static Definitions, Next:, Previous:C++ Misunderstandings, Up:C++ Misunderstandings

static メンバの宣言と定義

クラスに static のデータメンバがある場合、その static なメンバを宣言するだけでは充分でない。それを定義もしなければならない。以下に例を示す。

class Foo
{
  ...
  void method();
  static int bar;
};

この宣言でなされることは、クラス FooFoo::bar という名前の int があること、Foo::method という名前のメンバ関数があることだけである。だが、依然として、methodbar両方をどこかで定義する必要がある。ANSI 規格のドラフトに従うなら、初期化子を一個、ある一つの(そして一つだけの)ソースファイルで、以下のように提供しなければならない。

int Foo::bar = 0;

他の C++ コンパイラは、この規格の動作を正しく実装していない可能性がある。その結果、そのようなコンパイラの一つから g++ に移行したときに、実際に正しく動くように見えたプログラムが規格に適合しないということが見つかるかもしれない。g++ は、定義のない static のデータメンバは、未定義のシンボルとして報告する。


Node:Temporaries, Next:, Previous:Static Definitions, Up:C++ Misunderstandings

一時オブジェクトは意外に早く消滅する

一時オブジェクトの一部に対してポインタや参照を使うのは危険である。コンパイラは読者が予想している前にオブジェクトを消してしまうことが良くあり、その場合、ゴミを指すポインタが残る。この問題が最も良く現れるのは、文字列クラスのようなクラス、とりわけ char * あるいは const char * 型への変換関数を定義しているクラスにおいてである。これは、C++ 規格の string クラスがメンバ関数 c_str を呼び出すよう要求している理由の一つである。だが、何か内部構造へのポインタを返すクラスは何であれ、潜在的にこの問題が発生する可能性がある。

例えば、あるプログラムで、 string オブジェクトを返す関数 strfunc を使っていて、もう一つ別の関数 charfuncchar へのポインタに対して操作を行なうとする。

string strfunc ();
void charfunc (const char *);

void
f ()
{
  const char *p = strfunc().c_str();
  ...
  charfunc (p);
  ...
  charfunc (p);
}

この場合、c_str メンバ関数が返す C の文字列へのポインタをセーブしておいて、c_str を毎回呼び出すよりも、そのセーブしておいたポインタを使うほうが妥当と思える。だが、strfunc の呼出しにより作られる一時的な文字列は、p が初期化された後で破壊され、その時点で p はフリーされたメモリ領域を指したままになっている。

こういうコードは、何か他のコンパイラの場合には問題なく動作する可能性がある。特に、一時変数を普通のローカル変数と一緒に破壊する、古びた cfrontベースのコンパイラでその可能性がある。だが、GNU C++ の動作は規格に適合しているので、プログラムが一時オブジェクトの遅延破壊に依存しているなら、それは移植性がない。

このようなコードを安全に書くには、一時変数に名前を与えて、その名前のスコープの最後まで存在し続けるよう強制することである。例えば、以下のように書くと良い。

string& tmp = strfunc ();
charfunc (tmp.c_str ());


Node:Copy Assignment, Previous:Temporaries, Up:C++ Misunderstandings

仮想基底に対する暗黙kのコピー代入

基底クラスが仮想クラスである場合、基底クラスのサブオブジェクト一つだけがそれぞれの完全なオブジェクトに属する。また、コンストラクタとデストラクタは一度だけ起動され、最下位の派生クラスから呼び出される。だが、このようなオブジェクトが代入されたときの動作は規定されていない。例えば、

struct Base{
  char *name;
  Base(char *n) : name(strdup(n)){}
  Base& operator= (const Base& other){
   free (name);
   name = strdup (other.name);
  }
};

struct A:virtual Base{
  int val;
  A():Base("A"){}
};

struct B:virtual Base{
  int bval;
  B():Base("B"){}
};

struct Derived:public A, public B{
  Derived():Base("Derived"){}
};

void func(Derived &d1, Derived &d2)
{
  d1 = d2;
}

C++ の規格は、Derived のオブジェクトを構築するときやコピー構築するときは、Base::Base は一度しか呼び出されないことを規定している。Derived のオブジェクトに対する暗黙のコピー代入が起動されたときに(上の例の func の中のように)、Base::operator= が二回以上呼ばれるかどうかは規定されていない。

g++ は、コピー代入について「直観的」なアルゴリズムを実装している。これは全ての直接の基底を代入し、次に全てのメンバを代入するというものだる。このアルゴリズムでは、仮想基底のサブオブジェクトに何度も出くわす。上の例では、コピーは次の順序で進む。valname(strdup 経由で)、bval、再び name となる。

アプリケーションコードをコピー代入を元にしたいのなら、ユーザ定義のコピー代入演算子を定義すれば不確実さがなくなる。そういう演算子を使えば、アプリケーションは、仮想基底サブオブジェクトが代入されるかどうか、それに、その方法を定義することができる。


Node:Protoize Caveats, Next:, Previous:C++ Misunderstandings, Up:Trouble

protoize を使うときの注意点

変換プログラム protoizeunprotoize は、読者が手で調整しないと正しく動作しないように、ソースファイルを変更してしまうことがたまにある。


Node:Non-bugs, Next:, Previous:Protoize Caveats, Up:Trouble

行なう予定のない変更

この節では、要望が多いものの、GCC としてはやらない方が良いと我々が考えているために、実装していないものを挙げる。


Node:Warnings and Errors, Previous:Non-bugs, Up:Trouble

警告メッセージとエラーメッセージ

GNU コンパイラは二種類の診断メッセージを出力する。エラーと警告である。それぞれ別の目的がある。

警告は、プログラムが読者の意図どおりのことを本当にやってくれるのかを確認した方が良いと思われる危険な点や、あるいは廃れた機能を使っていたり、GNU C あるいは GNU C++ の非標準の機能を使っている点を指摘する。警告の多くは、-W で始まるオプションのうちの一つを指定することで読者が要求したときしか発行されない(例えば、-Wall を指定すると、色々な役に立つ警告を出すよう要求する)。

GCC は読者のプログラムを常に可能な限りコンパイルしようとする。単に(例えば)規格に準拠していないというだけで、意味が明らかなプログラムを根拠もなく拒絶することはない。だが、場合によっては C や C++ の規格がある種の拡張を禁ずることを指定しており、規格に準拠したコンパイラであるためには診断メッセージを発行しなければならない場合もある。-pedantic オプションを指定するとそういう場合の警告を発する。-pedantic-errors を指定すると警告ではなくエラーとなる。この事は、ANSI でない構文は全て警告やエラーを受け取るということではない。

以上のオプションや関係するコマンド行オプションについての詳細は、See Options to Request or Suppress Warnings.


Node:Bugs, Next:, Previous:Trouble, Up:Top

バグレポート

読者のバグレポートは、GCC の信頼性を上げるのに本質的な役割を果たす。

問題に出会ったら、最初にすべきことはそれが既知のものかどうかを調べることである。See Trouble. 知られていないものだったら、その問題を報告すべきである。

バグレポートを出すことによって、読者の問題が解決するかもしれないし、しないかもしれない。(解決しない場合は、サービス提供者の名簿を見て欲しい。Service を参照のこと。) ある一個のバグレポートの一番重要なのは、それが GCC の時期バージョンの動作を改善することで、コミュニティ全体を助ける点にある。バグレポートは、読者による GCC の保守への貢献になるのである。

保守担当者には非常に負荷がかかっており、あらゆるバグレポートに返事をだすことは不可能である。だが、そのバグが修正済みでなければ、我々から読者にパッチを送って、それが動作するかどうかを教えてもらうこともある。

バグレポートがその目的を果たせるようにするためには、バグ修正に役立つ情報を含めなければならない。


Node:Bug Criteria, Next:, Up:Bugs

読者の見つけたのはバグか?

読者が、果たしてバグを見つけたのかどうか判らない場合のために、以下に指針を示す。


Node:Bug Lists, Next:, Previous:Bug Criteria, Up:Bugs

バグレポートの送り先

GNU コンパイラ集に関するバグレポートは、bug-gcc@gcc.gnu.org に送って欲しい。GNU 全体の規約に従うと、ツール "foo" についてのバグレポートの送り先は bug-foo@gnu.org になるので、bug-gcc@gnu.org というアドレスに送っても良い。これは上記のアドレスに転送される。

バグレポートを送る前に、<URL:http://www.gnu.org/software/gcc/bugs.html> を読んで、バグレポートの出し方を見て欲しい。

バグレポートをメールする代わりに、ニュースグループにポストしようとする人が良くいる。これはうまく行きそうに思えるかも知れないが、一つ重大な問題がある。ニュースグループにポストした場合、ポストした人にメールを返すときの経路が判らないのである。このため、受け取った保守担当者がもっと情報が必要だと思っても、報告者に連絡する術がないのである。このため、バグレポートを送るときは必ず正しいメーリングリストに送らなければならない。

最後の手段としては、書面でバグレポートを以下の宛先に送っても良い。

GNU Compiler Bugs
Free Software Foundation
59 Temple Place - Suite 330
Boston, MA 02111-1307, USA


Node:Bug Reporting, Next:, Previous:Bug Lists, Up:Bugs

バグレポートの出し方

バグレポートの出し方についての追加や、最新の手順については<URL:http://www.gnu.org/software/gcc/bugs.html>. を見て欲しい。

役に立つバグ報告の第一原則は次のとおり。全ての事実を報告すること。ある事実について、それに言及すべきか、しないでおくべきか確信が持てないときは、言及すべきである。

人は良く事実を省略しがちである。問題を引き起こしたのが何かということを知っているつもりになり、そのために詳細は関係ないと思ってしまうからである。このため、報告する人のサンプルプログラムで変数名がどうなっているかは関係ないだろうと思ってしまう。多分関係ないことが多いだろうが、確認できないこともある。問題のバグは、その変数名が格納されているメモリ位置からデータを取り出すときに、そのメモリ参照の指す先が正しくないためかもしれない。変数名が違っていたら、バグがあっても、その位置の内容がコンパイラに正しい動作を行なわせるかもしれない。そういうこともあるので、確実を期すために、詳細で完全な例を送って欲しいのである。これは読者ができる最も簡単なことで、最も役に立つことでもある。

バグレポートの目的は、そのバグがまだ知られていないものなら、誰かが修正出来るようにすることにあることを忘れないで欲しい。バグが既に知られているものであるなら、何が起きたかはあまり重要ではない。つまり、バグレポートを書くときは必ず、そのバグは既知のものではないと想定したうえで書いて欲しいのである。

概略的な事実しか書かずに、「これ当たりかな|?」等と書いてくる人が時々いるが、これではバグを直す助けにはならないので、基本的には役に立たないと言える。我々は、調査可能になる程度に充分な詳細を教えてくれるよう返事することになる。最初から詳細に書いてくれると物事が早く進むのである。

バグレポートはそれ自体に全てが含まれるようにして欲しい。我々がさらなる情報提供をお願いしたときには、最初書いてなかった情報に加えて、最初に報告済みの情報も全部含めてくれるのが最善である。

報告するバグは一個のメッセージにつき一個にして欲しい。そうしてもらうと、どのバグが修正済みかを追跡するのと、読者のバグレポートを適切な保守担当者に転送するのが容易になる。

バグを調査できるようにするためには、以下の項目を全て報告して欲しい。

以下は必要ないものである。


Node:Sending Patches, Previous:Bug Reporting, Up:Bugs

GCC に対するパッチの送り方

GCC について、バグ修正や改善を書いてくれるなら、それは大変役に立つことである。修正案はパッチ用メーリングリストgcc-patches@gcc.gnu.org に送って欲しい。

以下の指針に従って、読者のパッチを我々が効率良く調べることができるようにして欲しい。これらの指針に従ってもらえないと、読者の情報が有益なものであっても、それを使うのに余分な仕事が必要になってしまうのである。GNU C を保守することは、最善の環境にあってもたくさんの作業を必要とするので、読者にも最善を尽くしてもらわないと維持するのが困難である。


Node:Service, Next:, Previous:Bugs, Up:Top

GCC についての助けを得るには

GCC のインストールや使用や改変についての手助けが必要な場合、手助けしてくれるところの探し方が二つある。


Node:Contributing, Next:, Previous:Service, Up:Top

GCC の開発に貢献するには

GCC のリリースがうまく動作することを保証する事前テストのお手伝いをしても良いという方、あるいは GCC の改良作業をしてみたいという方は、是非とも保守担当者 gcc@gcc.gnu.org に連絡していただきたい。事前テスターの方にはバグを報告するだけでなく、調査することもやっていただきたい。

改良作業をしてみたい方は、提案されているプロジェクトについて尋ねてみて欲しい。あるいは、自分自身のアイデアを提案して欲しい。まだ作業を始めていないなら、始める前に bug-gcc@prep.ai.mit.edu に連絡するのが良いだろう。保守担当者は、読者の拡張を、GCC の他の部分や他の開発計画によりうまく適合させる方法を示唆することができるかもしれない。


Node:VMS, Next:, Previous:Contributing, Up:Top

VMS 上での GCC の使い方

以下に VMS 上での GCC の使い方を説明する。


Node:Include Files and VMS, Next:, Up:VMS

インクルードファイルと VMS

Unix と VMS のファイルシステムの差異により、GCC は #include で指定されたファイル名を VMS が理解できる名前に変換する。基本的な戦略は、インクルードファイルであることを指定するプレフィックスを前に付け、ファイル名全体を VMS のファイル名に変換し、その後でファイルのオープンを試みる。GCC はどれか成功するまで、色々なプレフィックスを一つずつ試す。

  1. 最初に試されるプレフィックスは論理名 GNU_CC_INCLUDE: である。これは、GNU C のヘッダファイルが伝統的に置かれるところである。ヘッダファイルを標準以外の場所に置くときは、論理名 GNU_CC_INCLUDE に検索リストを指定する。このリストの各要素は論理名のルートとして使うのに適したものである。
  2. 次に試すプレフィックスは SYS$SYSROOT:[SYSLIB.] である。これは、VAX-C のヘッダが伝統的に置かれる場所である。
  3. インクルードファイルの指定そのものが有効な VMS ファイル名なら、プリプロセッサはこの名前をプレフィックスなしで使って、そのインクルードファイルをオープンすることを試みる。
  4. フィル指定が有効な VMS ファイル名でない場合(例えば、デバイス指定子やディレクトリ指定子が入っていなかったり、文字 / を含んでいたりする場合)は、プリプロセッサはそれを Unix の構文から VMS の構文に変換することを試みる。

    この変換の仕組みは次の通りである。最初のディレクトリ名がデバイスになり、残りのディレクトリが VMS 形式のディレクトリ名に変換される。例えば、X11/foobar.h という名前は X11:[000000]foobar.hX11:foobar.h に変換され、このように変換されしまえばオープン可能になる。この戦略により、論理名をヘッダファイルの実際の位置を指すように割り当てることができるようになる。

  5. 以上の戦略のどれもうまく行かない場合は、#include は失敗する。

次の形の include 制御子は、

#include foobar

良くある VAX-C と GCC の非互換性の元である。VAX-C はこれを標準の#include <foobar.h> 制御子のように取り扱う。これは、GCC が実装している ANSI C の動作と互換性がない。ANSI C dへあ、名前 foobar をマクロとして展開する。マクロ展開の結果は最終手k位に #include の二つの標準形の一つを生じる必要がある。

#include "file"
#include <file>

この問題に出会ったら、一番良い解決方法はソースコードを修正して、#include 制御子を二つの標準形のうちの一つに変換することである。そうすれば、どちらのコンパイラでも動作する。急ぎで汚い修正でよければ、ファイル名を、以下のように、適切に展開されるマクロとして定義する方法もある。

#define stdio <stdio.h>

これは、その名前がプログラム中の他のものとぶつからない限りにおいて、正しく動作するだろう。

もう一つの非互換性の元は、VAX-C は、

#include "foobar"

と書いた場合、実際には foobar.h を要求していると仮定していることである。GCC はこんな仮定はしておらず、指定されたものそのままを受け取り、foobar というファイルを読み込もうとする。この問題を回避する最善の方法は、include 命令で適切なファイル拡張子を常に指定することである。

VMS 用 GCC は、ほとんどの汎用のプログラムをコンパイルするのに充分なインクルードファイルのセットとともに配布されている。GCC の配布には、いくつかのVMS システム固有の関数用の定数や構造体を定義するヘッダファイルが含まれていないが、かといって、これらの関数について GCC が使えないということはない。まず、パブリックドメインのユーティリティ UNSDL(DECUS のテープに入っている)を使うか、あるいは、システムのマクロライブラリの一つから適切なモジュールを抜き出す課して、ヘッダファイルを生成あるいは作って置き、次にエディタを使って C のヘッダファイルを構築しなければならないだろう。

#include に指定するファイル名には、DECNET のノード名を含めることはできない。ノード名を明示的に、あるいは論理名を通じて間接的に使おうとすると、プリプロセッサは入出力エラーを出す。


Node:Global Declarations, Next:, Previous:Include Files and VMS, Up:VMS

グローバル宣言と VMS

GCC は、VAX-C のキーワード globalrefglobaldefglobalvalue を提供していない。GAS、GNU アセンブラの隠し機能を使うと同じ効果を得られる。以下のマクロにより、この機能を正当で自然な方法で使うことができる。

#ifdef __GNUC__
#define GLOBALREF(TYPE,NAME)                      \
  TYPE NAME                                       \
  asm ("_$$PsectAttributes_GLOBALSYMBOL$$" #NAME)
#define GLOBALDEF(TYPE,NAME,VALUE)                \
  TYPE NAME                                       \
  asm ("_$$PsectAttributes_GLOBALSYMBOL$$" #NAME) \
    = VALUE
#define GLOBALVALUEREF(TYPE,NAME)                 \
  const TYPE NAME[1]                              \
  asm ("_$$PsectAttributes_GLOBALVALUE$$" #NAME)
#define GLOBALVALUEDEF(TYPE,NAME,VALUE)           \
  const TYPE NAME[1]                              \
  asm ("_$$PsectAttributes_GLOBALVALUE$$" #NAME)  \
    = {VALUE}
#else
#define GLOBALREF(TYPE,NAME) \
  globalref TYPE NAME
#define GLOBALDEF(TYPE,NAME,VALUE) \
  globaldef TYPE NAME = VALUE
#define GLOBALVALUEDEF(TYPE,NAME,VALUE) \
  globalvalue TYPE NAME = VALUE
#define GLOBALVALUEREF(TYPE,NAME) \
  globalvalue TYPE NAME
#endif

(名前の前のプレフィックス _$$PsectAttributes_GLOBALSYMBOL は、シンボルの属性が修正された後で、GAS により消去される。) これらのマクロは、VMS 用バイナリ配布中のヘッダファイル GNU_HACKS.H で提供されている。使い方の例を以下に示す。

GLOBALREF (int, ijk);
GLOBALDEF (int, jkl, 0);

マクロ GLOBALREFGLOBALDEF は配列に対しては単純には使えない。配列の次元を宣言の中の正しい位置に置く方法がないからである。ただし、まず配列型に対して typedef を定義しておけばこれらのマクロを使って配列を宣言することができる。以下のようにする。

typedef int intvector[10];
GLOBALREF (intvector, foo);

配列や構造体の初期化子もこのマクロでは使えない。初期化子をそれ自身マクロとして定義するか、GLOBALDEF マクロを手で展開することは可能である。GLOBALREF マクロを大きな配列に対して使いたいが、その配列の各要素を明示的に初期化する必要はないという場合もあるだろう。その場合、{0,} という形の初期化子を使うこともできる。これは配列全体を 0 に初期化する。

この実装の問題は、GLOBALVALUEREFGLOBALVALUEDEF で宣言した変数が常に配列になってしまうことである。例えば、

GLOBALVALUEREF(int, ijk);

と宣言すると、変数 ijkint [1] 型の配列として宣言する。globalvalue が実際には定数なのでこうなる。その「値」はリンカが普通はアドレスと考えるものである。これは、C の整数値の動作ではなく、配列の動作である。このため、このシンボルを配列名として取り扱うと一貫した結果が得られる。その値が間違った型を持つように見えるという点を除けば。この配列の要素を参照しようとしてはいけない。 これは要素はなにも持っていないのである。配列の「アドレス」は実際の記憶域のアドレスではないかもしれないのである。

シンボルが配列であるという事実は、その変数が使われたときに警告が出るという可能性につながる。警告を避けるには型キャストを挿入すること。以下に例を示す。マクロ展開の中にマクロ名自身と同じ名前を使っても良いという ANSI C の機能を活かしている。

GLOBALVALUEREF (int, ss$_normal);
GLOBALVALUEDEF (int, xyzzy,123);
#ifdef __GNUC__
#define ss$_normal ((int) ss$_normal)
#define xyzzy ((int) xyzzy)
#endif

列挙型である変数に対して globaldefglobalref を使ってはいけない。実装されていないからである。代わりに、その変数を整数とし、列挙値のそれぞれに globalvaluedef を使うこと。例は以下のようになる。

#ifdef __GNUC__
GLOBALDEF (int, color, 0);
GLOBALVALUEDEF (int, RED, 0);
GLOBALVALUEDEF (int, BLUE, 1);
GLOBALVALUEDEF (int, GREEN, 3);
#else
enum globaldef color {RED, BLUE, GREEN = 3};
#endif


Node:VMS Misc, Previous:Global Declarations, Up:VMS

その他の VMS にまつわる問題

GCC は、main に対し、明示的に戻り値を指定しない場合は、デフォルトで 1 を返すように自動的に設定を行う。1 を返すと、通常の成功終了を示す状況コードとして VMS が解釈する。GCC のバージョン 1 はこのデフォルトを提供していなかった。

VMS 上の GCC は GNU アセンブラ、GAS と共にしか動作しない。VMS のデバッガに意味のあるデバッグ情報を生成するには バージョン 1.37 以降の GAS を使う必要がある。GAS で生成したオブジェクトファイルは普通の VMS リンカを使う。

GCC の以前のバージョンでは、生成されたコードを共有可能なVAXCRTL ライブラリとリンクするとおかしな結果が出ることがときどきあった。現在では、正しく動作するはずである。

const グローバル変数の使用についての注意。const 修飾子は、その変数を使っている全てのソースファイルの、その変数のあらゆる外部宣言で指定しなければならない。そうしないと、リンカがその変数に対する属性に不一致がある旨の警告を発する。この警告が出てもプログラムは動作するが、その変数は書き込み可能な記憶域に置かれてしまう。

VMS のリンカは、グローバルシンボルの大文字と小文字を区別するが、ほとんどの VMS コンパイラはすべてのグローバルシンボルを大文字に変換し、ほとんどの実行時ライブラリルーチンも名前が大文字である。これらのルーチンの呼出しを信頼できるものとするために、GCC(GASによって) はグローバルシンボルを、他の VMS コンパイラのように、大文字に変換する。しかし、C では普通大文字小文字を区別するので、GCC(GAS経由で)は、通常の C の振るまいを、全てが小文字ではない名前をそれぞれ特別な処理(オーグメント)をすることで保存しようとする。オーグメントは、名前を最大 23 文字で打ち切り、その後に23文字の大文字小文字のパターンをエンコードした文字群を付ける。ドル記号が一つでも含まれている名前は例外であり、オーグメントはせず、直接大文字に変換する。

名前のオーグメントは、他のコンパイラにより生成されたコンパイル済みライブラリ(例えば Xlib 等)を使うプログラムにとっては悪い結果をもたらす。GCC のオプション /NOCASE_HACK を指定するとオーグメントを禁止できる。C の外部関数と外部変数を通常の VMS での場合のように大文字小文字の区別をしない。これは VMS では動作するものの、他のシステムへの移植性はない。GCC のオプション /NAMES もまたグローバル名の取扱いの制御方法を提供している。

関数名と変数名は GNU C++ ではいくらか異なった取扱いになる。GNU C++ コンパイラは、関数名について 名前のマングリングを行う。これは、関数名に、その関数の取る引数のデータ型を記述する情報を追加するものである。この結果起きることの一つは、関数名が非常に長くなりうる事である。VMS のリンカは名前の先頭 31 文字しか認識しないので、各関数と変数が 31 文字で表現可能な一意的な名前を持つことを保証するために特別な処理が行われる。

その名前(必要とされるなら、名前のオーグメントを加えたもの)の長さが、32 文字未満であるなら、特別な処理は行われない。名前が 31 文字より長ければ、アセンブラ(GAS)がその関数名に基づいたハッシュ文字列生成し、関数名を 23 文字に切り詰め、その後にハッシュ文字列を追加する。GCC にオプション /VERBOSE を指定すると、アセンブラは、打ち切りされるシンボル毎に完全な名前と打ち切り後の名前を表示する。

/NOCASE_HACK オプションは、libg++ を使用するプログラムをコンパイルするときは使うべきでない。libg++ には、大文字小文字を区別しない環境では、区別できなくなってしまうオブジェクトの実体(例えば、Filebuffilebuf) がたくさんある。これは、オーグメントを選択的に禁止する必要がある場合につながる(例えば、libg++ と Xlib を同じプログラムで使っている場合)。それを行うような特別な機能は存在しないが、オーグメントを禁止したい、大文字小文字の混じったシンボル毎に、マクロを定義することでそういう結果を得ることは可能である。そのマクロは、それ自身の小文字版に展開される必要がある。例えば、以下のようにする。

#define StuDlyCapS studlycaps

これらのマクロ定義は、ヘッダファイルに置くことで、読者のソースコードの変更回数を最小限に押さえることができるだろう。


Node:Portability, Next:, Previous:VMS, Up:Top

GCC と互換性

GCC の第一の目標は、品質の良い、高速なコンパイラを、 GNU システムが動作することをねらいとするクラスのマシン向けに作ることであった。そのクラスのマシンとは、32 ビットマシンで、8ビットを一バイトとするアドレッシングを持ち、汎用レジスタがたくさん持つものである。洗練されているとか、理論的な能力とか簡潔さなどは二の次である。

GCC はターゲット機種についての情報のほとんどを、機種記述から得る。機種記述はその機種の命令毎に代数式を与える。これはターゲットを記述する方法としては非常に明解な方法である。ただし、コンパイラが、この形式で表現するのが困難な情報が必要な時は、筆者は機種記述にその場しのぎのパラメータの定義をためらわずに入れる。移植性の目的はコンパイラについて必要な全作業を少なくすることにあり、それ自身には興味がない。

GCC は機種依存コードは含んでいないが、エンディアン(最上位バイトがワードの中のバイトの最上位アドレスを占めるのか、最下位アドレスを占めるのか) や自動インクリメント・アドレッシングが利用可能かなどの機種パラメータに依存するコードは含んでいる。RTL 生成パスでは、ある特定の種類の構文木に対してコード生成の戦略を複数持つ必要があることが多い。これらの戦略はパラメータの異なる組合せに対して使用可能である。著者は可能な場合全てを取り扱うことせず、共通に現れるものや、著者が出会ったものに絞っている。取り扱っていない組合せに出会ったら、GCC が abort を呼び出すので読者も気が付くだろう。幸いにも、新たな戦略を機種独立な形で追加することができ、その新たな戦略を必要とするターゲット機種にしか影響を及ぼさない。


Node:Interface, Next:, Previous:Portability, Up:Top

GCC の出力に対するインターフェース

GCC は、ターゲットシステム上で通常使われるのと同じ関数呼び出し規約を使うように、通常は構成される。これは、マシン記述マクロの記述によりなされる。

しかし、構造体と共用体の返し方は機種によって異なることがある。その結果、PCC でコンパイルしたそのような型を返す関数をGCC でコンパイルした関数から呼び出せないことがあるし、その逆もある。これはあまり問題にはならない。Unix のライブラリルーチンで構造体や共用体を返すものは滅多にないからである。

GCC は、1、2、4、8 バイト長の構造体と共用体は、intdouble の戻り値に使うのと同じレジスタに入れて返す。(GCC は普通はそのような型の変数もレジスタに割り当てる。) それ以外の大きさの構造体と共用体は、呼び出し側によって渡されるアドレス(通常、レジスタで渡される)に格納することで返される。マシン記述マクロの STRUCT_VALUESTRUCT_INCOMING_VALUE により、GCC に、このアドレスをどこに渡すかを指定する。

対照的に、多くのターゲット機種上の PCC は、どの大きさの構造体と共用体でも静的な領域にデータをコピーし、その領域のアドレスをポインタ値であるかのように返すことで、返す。呼び出し側は、そのメモリ領域からその値が必要とされる場所にデータをコピーしなければならない。この方法は、GCC の方法よりも遅く、また再入可能でない。

ターゲット機種によっては、RISC マシンや 80386 のように、システム標準の規約が、サブルーチンに、戻り値を置くアドレスを渡すようになっている。こういう機種では、この方法が使われている場合は、GCC は標準のコンパイラと互換になるようにコンフィギュレーションされる。1,2,4,8バイトの構造体については互換でない可能性がある。

GCC は、引数渡しについてはシステム標準の規約を使う。機種によっては、最初の幾つかの引数はレジスタで渡し、その他は全てスタックで渡される。どの機種でも引数を渡すのにレジスタを使うようにすることができる。それにより、おそらく、非常に速度が速くなるだろう。だが、その結果、標準の規約に従っているコードとの互換性が全く無くなってしまう。このため、この変更は GCC をシステムに取っての唯一の C コンパイラとして切り替えた場合にのみ意味がある。完全な GNU システムができた暁には、ある種の機種ではレジスタによる引数渡しを実装し、ライブラリを GCC でコンパイルできるようにする予定である。

機種によっては(特に SPARC)、特定の型の引数は「不可視の参照」により渡される。これは、渡すべき値がメモリに置かれ、そのメモリ位置のアドレスがサブルーチンに渡されることを意味する。

longjmp を使う場合には、自動変数に注意しなければならない。ANSI C によれば、volatile 宣言されていない自動変数の値は、longjmp 呼び出しの後、未定義になる。そしてこれは GCC が行なうと約束する全てでもある。なぜなら、レジスタ変数を正しくリストアするのは非常に困難であり、GCC の目玉の一つが、特に指定しなくても、変数をレジスタに置くことができる点にあるからである。

変数の値を longjmp によって変えられたくないが、古い C コンパイラが受け付けないので volatile も使いたくないという場合は、単にその変数のアドレスを取れば良い。変数のアドレスが一度でも取られると、それがアドレスの値を単に計算するだけでその値を使わなくても、その変数はレジスタに置かれなくなる。

{
  int careful;
  &careful;
  ...
}

GCC でコンパイルしたコードは、特定のライブラリルーチンを呼び出す可能性がある。その大部分は、算術演算を行なう命令がない場合に、代わりに算術演算を取り扱う。これは、ある機種では乗算と除算が含まれ、また、任意の機種で浮動小数点サポートが -msoft-float により無効になっている場合の浮動小数点演算が含まれる。C 標準ライブラリの一部、例えば bcopymemcpy 等もまた、自動的に呼び出される。通常の関数呼びだし方法が、これらのライブラリルーチン呼び出しに使われる。

これらのライブラリルーチンはライブラリ libgcc.a で定義されるべきであり、GCC はプログラムをリンクするときに自動的にこれを探す。乗算命令と除算命令のある機種では、ハードウェア浮動小数点が使われていれば、普通は libgcc.a は必要ないが、その場合でも検索される。

各算術演算関数は libgcc1.c で定義されており、対応するC の算術演算子を使っている。このファイルが何か別の C コンパイラでコンパイルする限り、そのコンパイラは全ての C の算術演算子をサポートしているので、このファイルは正しく動作するはずである。だが、GCC でコンパイルすると libgcc1.c は動作しない。なぜなら、各算術関数がそれ自身への呼び出しにコンパイルされてしまうからである。


Node:Passes, Next:, Previous:Interface, Up:Top

コンパイラの各パスとソースファイル

コンパイラ全体の制御構造は、toplev.c に記述されている。このファイルは、初期化、引数の解析、ファイルのオープン/クローズ、各パスの順次実行を受け持つ。

構文解析パスは一度だけ起動され、入力全体を構文解析する。関数が文単位で構文解析されるにつれ、その関数に対する RTL 中間コードが、生成される。各文は、構文木として読み込まれ、その後 RTL に変換される。その後、その文の構文木用のメモリ領域が再利用される。型(とその大きさを表す式)、宣言、結合の概略と何重に入れ子になっているかの表現は、関数のコンパイルが完了するまで残っている。これは、全てデバッグ情報を出力するのに必要である。

構文解析パスが、完全な関数定義か最上位の宣言を読み込む度に、関数 rest_of_compilationrest_of_decl_compilation を呼び出す。これらの関数は toplev.c にあり、アセンブラ言語の出力で終わる、以後必要な全ての処理に責任がある。コンパイラの他の全てのパスは、順番に、rest_of_compilation の中で実行される。この関数がある関数定義をコンパイルする処理から戻ると、その関数定義のコンパイルに使われた記憶領域はインライン関数でない限り完全に解放される(see An Inline Function is As Fast As a Macro)。

以下にコンパイラの全パスとそのソースファイルの一覧を示す。また、-d で始まるオプションで要求されるデバッグダンプについての解説も含めた。

さらに幾つかのファイルが、全ての、あるいは多くのパスで使われる。


Node:RTL, Next:, Previous:Passes, Up:Top

RTL 表現

GCC の仕事の大半は、レジスタ転送言語(RTL)と呼ばれる中間表現に対してなされる。このレジスタ転送言語では、出力すべき命令を一つづつ、その命令が行う操作を代数的な形式で記述する。

RTL は、Lisp 言語のリストにヒントを得たものである。RTL は、他の構造体を指す構造体からなる内部形式と、マシン記述とデバッグ用ダンプ出力で用いられるテキスト形式の二種類の形式を持つ。テキスト形式では、内部形式でのポインタを示すのに多重の括弧を使う。


Node:RTL Objects, Next:, Previous:RTL, Up:RTL

RTL オブジェクト型

RTL は5種類のオブジェクトを使う。式、整数、幅広整数、文字列、ベクトルである。式が最も重要である。ある RTL 式(省略形は"RTX") は、C 言語の構造体だが、普通はポインタで参照される。RTL 式の型は typedef 名rtx で与えられる。

整数は、単に int である。10進数を使って表記する。幅広整数は、整数型のオブジェクトのうちで、その型が HOST_WIDE_INT のものである(see Config)。やはり、10進数を使って表記する。

文字列は文字の連なりである。メモリ中では、通常の C 言語の形式である、char * で表現され、C 言語と同じ文法にしたがって表記する。ただし、RTL での文字列は決してヌルにはならない。マシン記述中で空文字列を書いた場合、メモリ中ではヌルポインタではなく、ヌル文字へのポインタとして表現される。文脈によっては、文字列の代わりにヌルポインタを使っても有効である。RTL のコード内では、文字列は symbol_ref 式の中で最も良く使われる。しかし、マシン記述を構成する RTL 式の他の文脈にも現れる。

ベクトルは、式を指す任意個数のポインタから成る。ベクトルの要素数はベクトルの中で明示的に表現される。ベクトルは、空白で区切られた要素を順番に並べたものを、鍵括弧([...])で囲んで表記する。長さ 0 のベクトルは作成されない。代わりにヌルポインタが使われる。

式は式コード(または RTX コードと呼ばれる) で分類される。式コードは rtl.def で定義される名前であり、大文字で記述したC の列挙型定数でもある。許される式コードとその意味は機種には依存しない。ある RTX のコードはマクロ GET_CODE (x) によって取り出すことができ、また、マクロ PUT_CODE (x, newcode) で変更することができる。

式コードは、式の中にオペランドが幾つあるか、およびオペランドがどんな種類のオブジェクトかを決定する。Lisp と違って RTL では、オペランドを見てもどんな種類のオブジェクトか知ることはできない。代わりに、文脈から知る必要がある。つまり、オペランドを含む式の式コードから知る必要がある。例えば、式コードが subreg である式の中では、最初のオペランドが式と見なされ、二番目のオペランドが整数とみなされる。式コード plus の式では、二つのオペランドがあり、どちらも式としてみなされる。式コード symbol_ref の式では、オペランドは一つであり、文字列としてみなされる。

式は、式のタイプ名と、そのフラグとあればマシンモード、式のオペランドを空白で区切り、括弧で囲んで表記する。

式コード名は、md ファイル中では小文字で書くが、C のコードとしては大文字となって現れる。このマニュアルでは、const_int のように書くことにする。

通常、式が要求される場合でも、ヌルポインタが有効なコンテキストが二、三存在する。その場合には、(nil) と表記する。


Node:RTL Classes, Next:, Previous:RTL Objects, Up:RTL

RTL クラスとフォーマット

様々な式コードは幾つかのクラスに分類される。そのクラスは一文字で表現される。ある RTX コードのクラスは、マクロGET_RTX_CLASS (code) を使って知ることができる。現在、rtx.def では以下のクラスを定義している。

o
実際のオブジェクト、例えば、レジスタ(REG)やメモリ位置(MEMSYMBOL_REF)等の実際のオブジェクトを表すRTX コードである。定数やオブジェクトに基本的な変換を施したもの(ADDRESSOFHIGHLO_SUM)も含まれる。SUBREGSTRICT_LOW_PART はこのクラスには含まれず、クラス x に含まれることに注意。
<
NELT 等の比較用の RTX コードである。
1
NEGNOTABS 等の単項算術演算用のRTX コードである。このカテゴリには、値の拡張(符号付きも符号無しも)や整数と浮動小数点の間の変換も含まれる。
c
PLUSAND 等の交換可能な二項演算の RTX コードである。NEEQ は比較なので、< クラスになる。
2
MINUSDIVASHIFTRT 等の交換可能でない二項演算の RTX コードである。
b
ビットフィールド演算の RTX コードである。現時点では、ZERO_EXTRACTSIGN_EXTRACT だけである。これらは入力が三つあり、左辺値である(そのため、挿入にも同じように使える)。See Bit Fields
3
その他の3入力演算の RTX コードである。現時点では、IF_THEN_ELSE のみでる。
i
命令全体を表す RTX コードである。INSNJUMP_INSNCALL_INSN がある。See Insns
m
MATCH_DUP 等の、insn にマッチする何かを表す RTX コードである。マシン記述にのみ現れる。
x
その他の全ての RTX コードである。このカテゴリには、マシン記述でしか使われない(DEFINE_* 等)残りのコードが含まれる。副作用を記述する全てのコードと insn の連鎖に現れる、NOTEBARRIERCODE_LABEL 等の非 insn が含まれる。

rtl.def には、式のタイプ毎に、その式が含むオブジェクトの数とその種類が記述されている。オブジェクトの種類の書き方としては次の四つ(五つのtypo?)がある。式(実際には式へのポインタ)の場合は e、整数は i、幅広整数は w、文字列は s、式のベクトルはE と書く。式コードを表す文字の連なりを フォーマットと呼ぶ。例えば、subreg のフォーマットは ei となる。

その他に以下のフォーマット指定文字が使われる。

u
u は、デバッグ用ダンプで異なった表示がなされる以外はe に同じである。insn へのポインタで使われる。
n
n は、デバッグ用ダンプで異なった表示がなされる以外は i に同じである。note insn で行番号やコード番号のために使われる。
S
S は省略可能な文字列を示す。メモリ中での RTL オブジェクトでは、Ss に同じであるが、md ファイルからオブジェクトを読み込む場合には、このオペランドの文字列値は省かれる。省かれた文字列はヌル文字列であるとして扱われる。
V
V は省略可能なベクトルを示す。メモリ中での RTL オブジェクトでは、VE に同じであるが、md ファイルからオブジェクトを読み込む場合には、このオペランドのベクトル値は省かれる。省かれたベクトルは、実質的には要素が一つもないベクトルと同じである。
0
0 は、通常のカテゴリには収まらないものを入れるためのスロットであることを意味する。0 のスロットは、どのダンプにも表示されず、gcc の極く一部で特別な使われ方をする。

以下は、オペランド数、式コードのフォーマットを得るためのマクロである。

GET_RTX_LENGTH (code)
コードが code である RTX のオペランド数。
GET_RTX_FORMAT (code)
コードが code である RTX のフォーマットを C の文字列で表したもの。

RTX コードの幾つかのクラスは常に同じフォーマットである。例えば、全ての比較演算のフォーマットは ee であると想定しても安全である。

1
このクラスのコードのフォーマットは全て e である。
<
c
2
このクラスのコードのフォーマットは全て ee である。
b
3
このクラスのコードのフォーマットは全て eee である。
i
このクラスのコードのフォーマットは全て iuueiee で始まる。ある insn の連鎖にリンクされた RTL オブジェクトのクラスが全てi ではないことに注意。
o
m
x
これらのコードのフォーマットについては何ら想定を置くことはできない。


Node:Accessors, Next:, Previous:RTL Classes, Up:RTL

オペランドへのアクセス

式中のオペランドは、XEXPXINTXWINT、それにXSTR というマクロを使って参照することができる。これらのマクロはそれぞれ引数を二つ取る。RTL式のポインタ(RTX) とオペランドの番号である。オペランドの番号は 0 からはじまる。例えば、

XEXP (x, 2)

とあれば、式 x の二番目のオペランドを式として参照する。

XINT (x, 2)

こちらは、同じオペランドを整数として参照する。同様に、XSTR を使うと文字列として参照する。

どんなオペランドも整数として、あるいは式として、また文字列として参照できる。ユーザは、オペランドに実際貯えられている値の種類に応じて、正しい参照方法を選ばなければならない。これは、オペランドを含んでいる式の式コードを見て判断するのが良い。また、オペランド数を調べるのも式コードで調べることができる。

例えば、xsubreg 式なら、オペランドは二つあり、それぞれ XEXP (x, 0)XINT (x, 0) として正しく参照できる。XINT (x, 0) とすると、オペランド 0 の式のアドレスを整数にキャストしたものが得られる。こういう参照の仕方が有効な場合は滅多にないと思うが、もし書くなら(int) XEXP (x, 0) としたほうがきれいである。また XEXP (x, 1) という書き方もエラー無しでコンパイルできて、二番目の整数オペランドを式のポインタにキャストした結果を返す。しかし、それを参照したときに恐らくプログラムが落ちてしまう。さらには、XEXP (x, 28) のように書くこともできるが、式の終りを越えたメモリをアクセスし、予期できない結果に終わるだろう。

オペランドがベクトルの場合の参照方法はもっと複雑である。マクロ XVEC を使うとベクトルへのポインタそのものが得られ、XVECEXPXVECLEN を使うとそれぞれ、ベクトルの要素と長さを得ることができる。

XVEC (exp, idx)
expidx 番目のオペランドをベクトルへのポインタとして参照する。
XVECLEN (exp, idx)
expidx 番目のオペランドであるベクトルの長さを返す。この値は int 型である。
XVECEXP (exp, idx, eltnum)
expidx 番目のオペランドであるベクトルの eltnum 番目の要素を参照する。この値は RTX である。

eltnum が負でないことおよび XVECLEN (exp, idx) より小さいことを保証するのはユーザの責任である。

このセクションで定義したマクロは全て左辺値として展開されるので、単に参照するだけでなく、オペランドや長さやベクトルの要素を代入することができる。


Node:Flags, Next:, Previous:Accessors, Up:RTL

RTL 式中のフラグ

RTL 式は、ある種の型の式で使われる色々なフラグ(一ビットのビットフィールド)とその他の値を含んでいる。ほとんどの場合、フラグは以下のマクロで参照される。

MEM_VOLATILE_P (x)
mem 式において、揮発性のメモリ参照の場合に非 0 となる。volatil フィールドに格納され、/v と出力される。
MEM_IN_STRUCT_P (x)
mem 式において、構造体や共用体、配列全体かそれらの成分を参照するときに非0となる。スカラ変数への、あるいはポインタを通してのスカラ変数への参照の場合は 0 となる。in_struct フィールドに格納され、/s と出力される。このフラグと MEM_SCALAR_P がどちらもクリアされていると、この MEM が構造体の中にあるのかどうかがわからない。両方のフラグが同時に設定されることがあってはならない。
MEM_SCALAR_P (x)
mem 式において、構造体や共用体、配列のメンバでないことが知られているスカラに対する参照の場合はゼロでない値となる。構造体や共用体、配列のメンバに対する参照や、ポインタを経由しての間接参照に対しては、たとえそのポインタがスカラ型を指していてもゼロとなる。このフラグと MEM_STRUCT_P が両方ともクリアされていると、この MEM が構造体の中にあるのかどうか分からない。両方のフラグを同時にセットしてはならない。
MEM_ALIAS_SET (x)
mem 式において、x が属する別名のセットを表す。これがゼロであれば、x どの別名のセットにも入っておらず、任意のものの別名になりうる。ゼロでない場合は、x は、同じ別名セットに入っているオブジェとの別名にしかならない。この値は、言語フロントエンドにより(言語固有の方法で)設定される。このフィールドはビットフィールドではない。整数であり、mem の第二引数に現れるものである。
REG_LOOP_TEST_P
reg 式において、レジスタの生存期間がループの脱出条件のテストに含まれるなら、非0となる。in_struct フィールドに格納され、/s と出力される。
REG_USERVAR_P (x)
reg 式において、ユーザのソースコード中に存在する変数に対応するなら非0となる。コンパイラ内部で一時的に生成されたものなら0となる。volatil フィールドに格納され、/v と出力される。
REG_FUNCTION_VALUE_P (x)
reg 式において、このレジスタに現在の関数の戻り値が置かれるなら非 0 である。(これは物理レジスタの場合にのみ発生する。) integrated フィールドに格納され、/i と出力される。

同じ物理レジスタが現在の関数が呼び出した関数の戻り値を置くのに使われても良いが、そういう使い方の場合には REG_FUNCTION_VALUE_P は 0 である。

SUBREG_PROMOTED_VAR_P
subreg 式において、それが、マシン記述マクロ PROMOTED_MODE (see Storage Layout)に従って、より幅の広いモードに拡張されたオブジェクトを参照した際に作られたものなら、非ゼロである。この場合、subreg のモードはそのオブジェクトの宣言されたモードであり、SUBREG_REG のモードはそのオブジェクトを保持するレジスタのモードである。拡張された変数は、それぞれの代入の際に、常に、より幅の広いモードへ符号拡張またゼロ拡張される。in_struct フィールドに格納され、/s として出力される。
SUBREG_PROMOTED_UNSIGNED_P
SUBREG_PROMOTED_VAR_P が、参照されているオブジェクトがゼロ拡張され続ける場合はゼロでなく、符号拡張され続ける場合はゼロとなるような、subreg の中では、非ゼロである。unchanging フィールドに格納され、/u と出力される。
RTX_UNCHANGING_P (x)
reg または mem では、その値が変化しないのであれば、非 0 である。(このフラグは、ポインタを経由しての定数へのメモリ参照では設定されない。そういうポインタは、現在の関数ではオブジェクトは明示的には変化しないということを保証するだけである。オブジェクトは、他の関数やエイリアシングにより変化し得るのである。) unchanging フィールドに格納され、/u と出力される。
RTX_INTEGRATED_P (insn)
インライン関数呼び出しの結果生じる insn 中では非 0 である。integrated フィールドに格納され、/i と出力される。
RTX_FRAME_RELATED_P (x)
一個の insn また式で、関数プロローグの一部であり、かつ、スタックポインタを設定しているか、フレームポインタを設定しているか、レジスタをセーブしているものの中であれば、ゼロでない値となる。このフラグは、RTL プロローグを持つターゲットで例外処理をサポートするのに必要となる。
SYMBOL_REF_USED (x)
symbol_ref 中で、x が使われていることを指示する。通常は、x が external として一度だけ宣言されていることを保証するのに使われるだけである。used フィールドに格納される。
SYMBOL_REF_FLAG (x)
symbol_ref 中で、機種に固有な目的のためのフラグとして使われる。volatil フィールドに格納され、/v として出力される。
LABEL_OUTSIDE_LOOP_P
label_ref 式の中で、ラベルへの参照がある場合、そのラベルが、ラベルへの参照を含む最も内側のループの外側にあるなら、非ゼロとなる。in_struct フィールドに格納され、/s として出力される。
INSN_DELETED_P (insn)
insn の中で、その insn が削除済であれば非 0 である。volatil フィールドに格納され、/v と出力される。
INSN_ANNULLED_BRANCH_P (insn)
分岐 insn の遅延スロットにある insn の中で、無効化分岐を使うべきかどうかを指示する。以下の sequence の議論を参照のこと。unchanging フィールドに格納され、/u と出力される。
INSN_FROM_TARGET_P (insn)
分岐命令の遅延スロット中の insn の中で、その insn が分岐命令のターゲットから来たものであることを示す。分岐 insn の INSN_ANNULLED_BRANCH_P ビットが立っていれば、この insn は、分岐が成立したときにのみ実行される。INSN_FROM_TARGET_Pビットが立っていない無効化された分岐命令の場合は、insn は、分岐が成立しなかったときにのみ実行される。INSN_ANNULLED_BRANCH_P が設定されていない場合は、この insn は常に実行される。in_struct フィールドに格納され、/s と出力される。
CONSTANT_POOL_ADDRESS_P (x)
symbol_ref の中で、現在の関数の「定数プール」の一部を参照しているなら、非ゼロとなる。これらは、関数の先頭に近いアドレスであり、GNU CC は、直接的にアクセスが可能であると仮定する(恐らく、ベースレジスタの助けを借りて)。unchanging フィールドに格納され、/u と出力される。
CONST_CALL_P (x)
call_insn の中で、insn が定数関数への呼び出しを表しているかどうかを示す。unchanging フィールドに格納され、/u と出力される。
LABEL_PRESERVE_P (x)
code_label の中で、そのラベルが削除不可であることを示す。非局所的 goto によるラベルの参照でこのビットがセットされる。in_struct フィールドに格納され、/s と出力される。
SCHED_GROUP_P (insn)
命令スケジューリング中、ある insn において、直前の insn はこの insn と同時にスケジューリングされなければならないことを示す。これを使って、ある命令のグループが命令スケジューリングのパスによって、分割されないことを保証する。例えば、call_insn の直前のuse insn は、call_insn から分離されることはない。in_struct フィールドに格納され、/s として出力される。

以下に、上述のマクロが参照するフィールドを挙げる。

used
通常は、このフラグは、関数の RTL 生成の最後で、ある式が insn の中に何回現れたかを数えるために、一時的に使われるだけである。二回以上現れた式は、共有構造の規則に従ってコピーされる(see Sharing)。

symbol_ref では、そのシンボルに対する外部宣言が既に書き込み済であることを意味する。

reg では、リーフレジスタの番号付け替えのコード部分で、各レジスタの番号付け替えが一回だけ行われることを保証するのに使われる。

volatil
このフラグは、mem式、symbol_ref式、reg式およびinsn の中で使われる。RTL ダンプファイルでは、/v と表記される。

mem 式の中では、メモリ参照が揮発性(volatile)であれば 1 である。揮発性メモリ参照は、削除や並べかえや結合は出来ない。

symbol_ref 式の中では、機種固有の目的で使われる。

reg 式の中では、その値がユーザレベルの変数であれば、1 である。0 であれば、コンパイラが内部的に使う一時的なものであること示す。

insn の中では、1 であればその insn が既に削除された事を意味する。

in_struct
mem式の中では、その式が参照するメモリデータが、構造体または配列の全体あるいは一部であれば、1 となる。スカラ変数であれば、0 になる。C 言語のポインタを通しての参照は 0 となる。ポインタはスカラ変数を指すからである。この情報により、GCC が、エイリアシングが起こる場合について何らかの決定を下すことができるようになる。

分岐命令の遅延スロットの insn の中では、1 であれば、この insn が分岐先から来たものであることを意味する。

命令のスケジューリングの間では、insn の中では、1 であれば、この insn は、直前の insn と共に構成するグループの一部としてスケジュールされなければならないことを意味する。

reg 式の中では、その式が示すレジスタの生存範囲が、あるループの条件式の中に完全に収まるのであれば、1 である。

subreg 式の中では、1 であれば、その subreg が、より広いモードから格上げされたモードを持っていたオブジェクトを参照していることを示す。

label_ref 式の中では、1 であれば、参照しているラベルが、その label_ref 式のある insn を含む最も内側のループの外にあることを示す。

code_label 式の中では、そのラベルが削除されることが決してありえないのなら、1 である。これは、非局所的な goto の目的先であるラベルで使われる。

RTL ダンプの中では、このフラグは /s と表記される。

unchanging
reg 式と mem 式の中では、1 であれば、その式の値が決して変化しないことを意味する。

subreg 式の中では、その subreg 式が、より広いモードへ格上げされたモードを持つ符号無しのオブジェクトを参照しているのであれば、1 である。

insn の中では、1 であれば、無効化付きの分岐であることを意味する。

symbol_ref 式の中では、1 であれば、このシンボルが、関数毎の定数プール中の何かを参照していることを示す。

call_insn の中では、1 であれば、この命令が定数関数への呼び出しであることを意味する。

RTL ダンプ中では、このフラグは /u と表示される。

integrated
insnを含む、ある種の式の中では、このフラグは、この RTL が手続き統合(procedure integration)により生成されたことを意味する。

reg 式の中では、このフラグは、このレジスタが、現在の関数により返されるはずの値を含んでいることを示す。引数をレジスタで渡す機種では、同じ番号のレジスタが引数としても使われるが、その様に使用される場合にはこのフラグはセットされない。


Node:Machine Modes, Next:, Previous:Flags, Up:RTL

マシンモード

マシンモードは、データオブジェクトの大きさ、その表現方法を記述する。C のコード中では、マシンモードは列挙型 enum machine_mode で表現される。この列挙型は、machmode.def で定義されている。各 RTL 式にはマシンモードを格納する場所があり、そのため、ある種のツリー式(正確には、宣言と型である)を格納する場所も持っている。

デバッグダンプとマシン記述のなかでは、RTL 式のマシンモードは、式コードの後ろにコロンで区切って書く。各マシンモード名に付くmodeは、省略される。例えば、(reg:SI 38) は、reg 式で、マシンモードはSImode である。モードが VOIDmode の場合は、モードとしては何も出力されない。

以下にマシンモードの表を示す。以下では、「バイト」とは、BITS_PER_UNIT ビットのオブジェクトを指す(see Storage Layout)。

QImode
「1/4 精度整数」(Quarter-Integer)モードは、整数として扱われる1バイトを表現する。
HImode
「1/2 精度整数」(Half-Integer)モードは、2バイト整数を表す。
PSImode
「部分単精度整数」(Partial Single Integer)モードは、4バイトを占有するが、実際に4バイト全てを使うことはないような整数を表す。マシンによっては、これがポインタ用の正しいモードになる。
SImode
「単精度整数」(Single Integer)モードは、四バイト整数を表す。
PDImode
「部分倍精度整数」(Partial Double Integer)モードは、8バイトを占有するが、実際に8バイト全てを使うことはないような整数を表す。マシンによっては、これがある種のポインタ用の正しいモードになる。
DImode
「倍精度整数」モードは八バイト整数を表す。
TImode
「4倍精度整数」(Tetra Integer)モードは、16バイト整数を表す。
SFmode
「単精度浮動小数点数」(Single Floating)モードは、単精度(四バイト)浮動小数点数を表す。
DFmode
「倍精度浮動小数点数」(Double Floating)モードは、倍精度(八バイト)浮動小数点数を表す。
XFmode
「拡張精度浮動小数点数」(Extended Floating)モードは、3倍精度(12バイト) 浮動小数点数を表す。このモードは、IEEE 拡張浮動小数点数に使う。システムによっては、12バイトの中には実際に使われないビットがある。
TFmode
「4倍精度浮動小数点数」(Tetra Floating)モードは、4倍精度(16バイト) 浮動小数点数を表す。
CCmode
「条件コード」(Condition Code)モードは、条件コードの値を表す。条件コードは、機種に固有のビットの一群で、比較演算の結果を表す。これ以外の機種固有のモードが条件コードに対して使われることもある。これらのモードは、cc0 を使う機種では使われない。(see Condition Code。)
BLKmode
「ブロック」(Block)モードは、他のどのモードも適用できないような集合体の値を表す。RTL では、メモリへの参照のみがこのモードを取りうる。しかも、それが文字列移動またはベクトル命令中に現れたときだけに限られる。このような命令を持たない機種では、BLKmode が RTL に現れることはない。
VOIDmode
「ボイド」(Void)モードは、モードがないこと、あるいはモードを指定しないことを意味する。例えば、コードが const_int である RTL 式はVOIDmode になる。何故なら、文脈が要求するどんなモードとしても取ることが出来るからである。RTL のデバッグダンプ中では、VOIDmode は、モードが一切無いことにより表現される。
SCmode, DCmode, XCmode, TCmode
これらのモードは、浮動小数点数値の対として表現された複素数を表す。浮動小数点数値は、それぞれ、SFmode, DFmode, XFmode, TFmode になる。
CQImode, CHImode, CSImode, CDImode, CTImode, COImode
これらのモードは、整数値の対として表現された複素数を表す。整数値は、それぞれ、QImode, HImode, SImode, DImode, TImode, OImode である。

マシン記述では、Pmode を C のマクロとして定義し、このマクロはアドレス向けのマシンモードに展開される。普通は、これは BITS_PER_WORD の大きさのモードであり、32ビットのマシンでは SImode になる。

マシン記述に必ず記述が必要なのは、QImode と、それぞれBITS_PER_WORDFLOAT_TYPE_SIZEDOUBLE_TYPE_SIZE に対応するモードである。GCC は、8バイトの構造体と共用体に対して DImode を使うことを試みるが、MAX_FIXED_MODE_SIZE の定義を書き換えることにより、抑止することができる。また、16バイトの構造体と共用体向けに TImode を使わせることも可能である。同様に、C の short int 型に、HImode を使うのを避けるように設定することも可能である。

現在では、GCC の中でマシンモードを明示的に参照しているコードはほとんどなく、あっても早々に削除してしまう予定である。その代わり、マシンモードをモードのクラスに分割している。マシンモードのクラスは、列挙型enum mode_class で表される。この列挙型は machmode.h で定義されている。取りうるモードクラスは以下の通りである。

MODE_INT
整数モード。デフォルトでは、QImode, HImode, SImode, DImode, TImode が該当する。
MODE_PARTIAL_INT
「部分整数モード」を表す。PSImodePDImode が該当する。
MODE_FLOAT
浮動小数点モード。デフォルトでは、SFmode, DFmode, XFmode, TFmode である。
MODE_COMPLEX_INT
整数複素数モード。(現時点では実装されていない。)
MODE_COMPLEX_FLOAT
浮動小数点複素数モード。デフォルトでは、SCmodeDCmode, XCmode, and TCmode である。
MODE_FUNCTION
静的チェーンを含む、Algol や Pascal の関数変数である。(現時点では実装されていない。)
MODE_CC
条件コード値を表すモード。これには、CCmode と、EXTRA_CC_MODES マクロに示された全てのモードが含まれる。See Jump PatternsCondition Code を参照のこと。
MODE_RANDOM
これは、上記のどのクラスにも当てはまらないモードのための受皿モードである。現時点では、VOIDmodeBLKmodeMODE_RANDOM に該当する。

以下にマシンモード関連の C マクロを示す。

GET_MODE (x)
RTX x のマシンモードを返す。
PUT_MODE (x, newmode)
RTX x のマシンモードを newmode にする。
NUM_MACHINE_MODES
ターゲット機種で利用可能なマシンモードの数を表す。これは、マシンモード値のうち最大のものに 1 を足したものになる。
GET_MODE_NAME (m)
モード m の名前を文字列で返す。
GET_MODE_CLASS (m)
モード m のモードクラスを返す。
GET_MODE_WIDER_MODE (m)
指定したモードの次に広い自然なモードを返す。例えば、GET_MODE_WIDER_MODE (QImode) という式は、HImode を返す。
GET_MODE_SIZE (m)
モード m のデータの大きさをバイト数で返す。
GET_MODE_BITSIZE (m)
モード m のデータの大きさをビット数で返す。
GET_MODE_MASK (m)
一語中のビットのうち、モード m の範囲内に収まる全てのビットを表すビットマスクを返す。このマクロは、ビット数が HOST_BITS_PER_INT 以下であるモードに対してのみ使うことができる。
GET_MODE_ALIGNMENT (m)
モード m のオブジェクトに必要なアラインメントをビット数で返す。
GET_MODE_UNIT_SIZE (m)
モード m のデータの部分単位の大きさをバイト数で返す。これは、複素数のモードの場合以外は、GET_MODE_SIZE と同じである。複素数のモードの場合は、部分単位の大きさは、実数部また虚数部の大きさである。
GET_MODE_NUNITS (m)
あるモードに含まれる単位の数を返す。すなわち、GET_MODE_SIZEGET_MODE_UNIT_SIZE で割ったものを返す。
GET_CLASS_NARROWEST_MODE (c)
モードクラス c の中で最も幅の狭いモードを返す。

グローバル変数 byte_modeword_mode は、モードクラスが MODE_INT であり、ビット数がそれぞれ BITS_PER_UNITBITS_PER_WORD のモードを保持している。32ビットマシンでは、それぞれ QImodeSImode になる。


Node:Constants, Next:, Previous:Machine Modes, Up:RTL

定数式型

最も簡単な RTL 式は、定数値を表すものである。

(const_int i)
この型の式は、整数値 i を表す。i は、マクロ INTVAL を使って INTVAL (exp) のように参照するのが良く行われる。これは、XWINT (exp, 0) と書くのと同じである。

整数値 0 を表す式オブジェクトは唯一つしかなく、変数 const0_rtx の値だけである。同じく、整数値 1 に対する式は、const1_rtx だけであり、整数値 2 に対する式は、const2_rtx だけである。さらに、整数値 -1 に対する式は constm1_rtx だけである。コードが const_int で、値が 0, 1, 2, -1 のどれかの式を作ろうとすると、それぞれ、const0_rtxconst1_rtxconst2_rtxconstm1_rtx が返される。

同様に、値が STORE_FLAG_VALUE である整数に対するオブジェクトは唯一つだけで、const_true_rtx になる。STORE_FLAG_VALUE が1 であれば、const_true_rtxconst1_rtx は同じオブジェクトを指す。STORE_FLAG_VALUE が -1 なら、const_true_rtxconstm1_rtx は同じオブジェクトを指すことになる。

(const_double:m addr i0 i1 ...)
モード m の浮動小数点定数か、HOST_BITS_PER_WIDE_INT ビットには収まらないが HOST_BITS_PER_WIDE_INT の二倍のビット数になら収まるような整数定数を表す(GNU CC は、それ以上に大きい定数を表現する機能は提供していない)。後者の場合は、mVOIDmode になる。

addr は、定数が置かれているメモリ上の位置に対応する mem 式を保持する。メモリ上の位置は確保されていないが、現在のコンパイル(表示されないフィールドを使い維持されている)の全ての const_double 式の連鎖上には存在するなら、addrconst0_rtx を含む。その連鎖に存在しなければ、addrcc0_rtx を含む。addr は、マクロ CONST_DOUBLE_MEMCONST_DOUBLE_CHAIN を経由した連鎖フィールドを使ってアクセスするようになっている。

mVOIDmode なら、値を表すビット群は i0i1 に格納される。i0 はマクロ CONST_DOUBLE_LOW で、i1CONST_DOUBLE_HIGH で参照するのが通例となっている。

定数が浮動小数点数なら(精度に関わらず)、その値を格納するのに必要な整数の個数は、REAL_VALUE_TYPE に依存する(see Cross-compilation)。その整数群は浮動小数点数を表現するが、厳密にはターゲットマシンまたホストマシンの浮動小数点数形式ではない。ターゲットマシンで使われる正確なビットパターンに変換するには、マクロ REAL_VALUE_TO_TARGET_DOUBLE と関連マクロを使用すること(see Data Output)。

マクロ CONST0_RTX (mode) は、値が 0 でモードが mode の式を参照する。モード mode が、MODE_INT のクラスのモードであれば、const0_rtx を返す。そうでなければ、モード modeCONST_DOUBLE 式を返す。同様に、マクロ CONST1_RTX (mode) は、値が 1 でモード mode の式を参照する。CONST2_RTX についても同様である。

(const_string str)
値が str である文字列定数を表す。現時点では、この式は insn の属性(see Insn Attributes)についてのみ使われている。というのは、C 言語の文字列定数はメモリ中に置かれるからである。
(symbol_ref:mode symbol)
アセンブラのデータに対するラベルの値を表現する。symbol は、アセンブララベル名を記述する文字列である。この文字列が * で始まるなら、ラベル名は、symbol から* を除いたものになる。それ以外の場合は、symbol そのものがラベル名となり、通常は _ というプレフィックスが付く。

symbol_ref にはモードがあり、普通は Pmode になる。普通は、このモードがシンボルに対して直接有効になる唯一のモードである。

(label_ref label)
コードに対するアセンブラ・ラベルの値を表現する。オペランドは一つであり、それは式となる。この式は、ラベルの置かれるべき位置を特定するための命令列に現れる code_label でなければならない。

コードラベルの参照に異なる式のタイプを使用するのは、ジャンプ最適化で区別できるようにするためである。

(const:m exp)
アセンブル時の代数計算の結果として生じる定数を表現する。オペランド exp は、定数(const_intsymbol_reflabel_ref 式)に plusminus を組み合わせたもののみからなる式である。ただし、全ての組合せが有効とは限らない。アセンブラは、再配置可能なシンボルについては勝手な計算は出来ないからである。

mPmode でなければならない。

(high:m exp)
exp、普通は symbol_ref の上位ビット群を表現する。ビット数は機種依存であり、通常はレジスタの上位ビットを初期化する命令で指定されるビット数になる。lo_sum と共に使って、RISC で良く使われる、グローバルなメモリ位置を参照する典型的な二命令の列を表現する。

mPmode でなければならない。


Node:Regs and Memory, Next:, Previous:Constants, Up:RTL

レジスタとメモリ

以下に、レジスタとメモリへのアクセスを記述する、RTL 式のタイプを示す。

(reg:m n)
小さな整数 n (FIRST_PSEUDO_REGISTER より小さい)に対して、マシンのレジスタ番号 n、すなわちハードレジスタの参照であることを意味する。n が大きな値の場合は、一時的な値か 仮想レジスタを表す。GCC の戦略としては、まず、このような仮想レジスタが無限個あると仮定してコード生成を行ない、後で、ハードレジスタかメモリ参照への置き換えを行なう。

m は、この参照のマシンモードである。モードの指定が必要なのは、一般に複数のモードで各レジスタを参照することが可能だからである。例えば、レジスタを一つ取ってみると、そこには全語を入れることができるが、それを半語やバイトとして参照する命令や、色々な精度の浮動小数点数として参照する命令もありうるのである。

レジスタをアクセスするモードが一つしかないマシンの場合でも、モードは常に指定しなければならない。

FIRST_PSEUDO_REGISTER というシンボルはマシン記述により定義される。というのは、あるマシンのハードレジスタの数はそのマシンの不変の特徴だからである。ただ、マシンのレジスタが全て汎用レジスタである必要はない。データの格納に使える全てのマシンレジスタは、ハードレジスタ番号が与えられる。たとえ、それらのレジスタが特定の命令でしか使えなかったり、特定の型のデータしか保持できなくても。

ハードレジスタは一つの関数の中でも色々なモードでアクセスされる。しかし、疑似レジスタにはそれぞれ自然なモードが与えられており、そのモードでしかアクセスされない。疑似レジスタを自然なモード以外のモードでアクセスするのを記述する必要があるときは、subreg 式が使われる。

1ワードより多くのデータを指定するマシンモードを持つ reg 式は、実際には幾つかの連続するレジスタを表す事がある。そのレジスタ番号が、ある一個のハードウェアレジスタを指定するだけでなく、実際には、その指定されたレジスタから始まる、幾つかの連続したハードウェアレジスタ群を表している。

関数 RTL コードで使われている疑似レジスタ番号はそれぞれ、一意的な reg 式で表現される。

FIRST_VIRTUAL_REGISTER から LAST_VIRTUAL_REGISTER までの範囲の疑似レジスタ番号のうちいくつかは、RTL 生成過程にしか現れず、最適化過程の前に削除される。こういう疑似レジスタ番号は、それを含む関数についての RTL 生成が完了するまでは決定できないスタックフレーム中の位置を表す。以下の仮想レジスタ番号が定義されている。

VIRTUAL_INCOMING_ARGS_REGNUM
スタック渡しされた入力引数の先頭のワードを指し示す。通常、これらの引数は呼びだし側によって置かれるが、呼び出された側が、以前にレジスタで渡された引数の幾つかをプッシュすることもありうる。

RTL が完了した時点で、この仮想レジスタは、 ARG_POINTER_REGNUM で指定されるレジスタと FIRST_PARM_OFFSET の値の和に置き換えられる。

VIRTUAL_STACK_VARS_REGNUM
FRAME_GROWS_DOWNWARD が定義されていれば、このマクロはスタック上の先頭の変数のすぐ上を指す。FRAME_GROWS_DOWNWARD が定義されていない場合は、スタック上の先頭の変数そのものを指す。

VIRTUAL_STACK_VARS_REGNUM は、FRAME_POINTER_REGNUM で指定されるレジスタと STARTING_FRAME_OFFSET の値の和で置き換えられる。

VIRTUAL_STACK_DYNAMIC_REGNUM
これは、必要とするメモリ量の分だけスタックポインタの調整が行なわれた直後の、スタック上に動的に確保されたメモリの位置を指す。

この仮想レジスタは、STACK_POINTER_REGNUM で指定されるレジスタとSTACK_DYNAMIC_OFFSET の値の和に置き換えられる。

VIRTUAL_OUTGOING_ARGS_REGNUM
スタックが前もってプッシュされたときに、出力引数が書き込まれるべきスタック上の位置を指す。(push insn を使ってプッシュされる引数は常に STACK_POINTER_REGNUM を使うべきである。)

この仮想レジスタは、STACK_POINTER_REGNUM で指定されるレジスタとSTACK_POINTER_OFFSET の値の和に置き換えられる。


(subreg:m reg wordnum)
subreg 式は、マシンに取って自然なモード以外のモードにあるレジスタ、あるいは実際には複数のレジスタを参照する複数ワードの reg のうちの一つのレジスタを参照するのに使われる。

疑似レジスタにはそれぞれ自然なモードがある。その自然なモードとは異なるモードでの操作が必要な場合、例えば、一個のバイトを保持している疑似レジスタに対してフルワードの移動命令を行なう場合は、その疑似レジスタは subreg の中に収まっていなければならない。この例の場合は、wordnum は 0 である。

m は普通は少なくとも reg のモードの幅しかなく、その場合、reg のビットのうち m に入っているものだけを考えれば良い。

場合によっては、mreg のモードよりも広い。そういう subreg 式は、病的と呼ばれることがある。このような式は、より広いモードのオブジェクトを参照したいが、付加的なビットがどういう値を持っているかは気にしないという場合に使われる。再ロードパスは、病的な参照はハードレジスタに対してのみ作られることを保証する。

subreg の別の使い方は、複数のレジスタからなる値から個々のレジスタを取り出すことである。DImodeTImode の様なマシンモードは、一語より長い値、つまり通常二つ以上のレジスタを必要とする値である可能性がある。こういうレジスタの一つを参照するには、subreg をモードSImode で使い、wordnum でどのレジスタかを指定する。

病的でない subreg に格納すると、subreg と同じワードに属するビットに予期できない結果を生ずる。この手抜きにより、そういう命令に対して効率の良いコードを生成するのが用意になる。subreg の外側の全ビットを保存する命令を表現するには、subregstrict_low_part で囲めば良い。

コンパイル時のパラメータである WORDS_BIG_ENDIAN が 1 に設定されていれば、ワード番号 0 が最上位部であることを指示する。1 でなければ、ワード番号 0 は最下位部を指示する。

ターゲットによっては、FLOAT_WORDS_BIG_ENDIANWORDS_BIG_ENDIAN が一致しないものが 2、3ある。だが、GCC のほとんどの部分は、浮動小数点値を、整数値と同じエンディアンであるとして取り扱っている。これがうまく働くのは、単に、それらを整数値の集まりとして扱っているからである。real.c と実行時ライブラリだけが、FLOAT_WORDS_BIG_ENDIAN に注意している。

結合パスと再ロードパスの間で、第一引数が reg ではなくmem になっている、病的な subreg が発生する可能性がある。また、再ロードパスの後では、mem を含む病的な subreg が発生する可能性があり、通常、mem が疑似レジスタを置き換えたスタックスロットである場合に起きる。

DFmode の値を subreg を使って SFmode で参照するのは正しくないことに注意。マシンによっては、DFmode の値の上位部分が単精度浮動小数点数値と同じフォーマットでない場合がある。

また、一個のハードレジスタにある複数ワードの値のうちの一ワードをアクセスすることは、その値が大きさから期待されるよりも少ないレジスタで保持できるときは、正しくない。例えば、32ビットマシンでは、浮動小数点レジスタは一個の DFmode の値全体を保持できる。レジスタ 10 がそのようなレジスタなら、(subreg:SI (reg:DF 10) 1) は正しくない。なぜなら、そのような参照を一個のマシンレジスタに変換する方法がないからである。再ロードパスは、subreg 式がこのような形式になるのを抑止する。

subreg 式の先頭のオペランドは SUBREG_REG マクロで、第二オペランドは SUBREG_WORD マクロで参照する。

(scratch:m)
一個の命令の実行に必要とされ、それ以降は使われないスクラッチレジスタを表す。局所レジスタ確保か再ロードパスのどちらかにより、reg に変換される。

scratch は、普通は clobber 演算中に存在する(see Side Effects)。

(cc0)
条件コードレジスタを参照する。オペランドは無く、マシンモードも持たない。使い方は以下の二通りがある。

コード cc0 の式オブジェクトはただ一つだけ存在する。変数 cc0_rtx の値である。コード cc0 の式を作りだそうとすると必ず cc0_rtx が返ってくる。

命令が暗黙のうちに条件コードを設定する可能性がある。多くのマシンでは、ほぼ全ての命令が計算したり、格納した値に基づいて条件コードを設定する。こういう動作を RTL に明示的に記録する必要はない。というのは、マシン記述に、その命令が条件コードを設定することを認識するための指示が含まれているからである(マクロ NOTICE_UPDATE_CC を使う)。See Condition Code。条件コードを設定することだけを目的とする命令、そして条件コードを使用する命令だけが、(cc0) を書く必要がある。

マシンによっては、条件コードレジスタにレジスタ番号が与えられ、reg(cc0) の代わりに使われる。条件コードを書き換える命令がほんの一部の命令に限られるなら、このアプローチが望ましい。また別のマシンでは、条件コードを汎用レジスタに格納する。その場合は疑似レジスタを使うべきである。

Sparc や RS/6000 のようなマシンでは、二種類の算術演算命令のセットがある。一つのセットは条件コードを設定し、もう一つは設定しない。このような場合を扱う最も良い方法は、通常は、条件コードを設定しない命令を生成し、算術演算の実行と条件コードレジスタ(この場合は(cc0) ではない)の設定の両方を行なうパターンを作ることである。例としては、sparc.mdaddccandcc を探してみて欲しい。

(pc)
プログラムカウンタを表す。オペランドは取らず、マシンモードも持たなくて良い。(pc) が使えるのは、分岐命令の特定の文脈においてだけである。

コードが pc である式オブジェクトはただ一つである。変数 pc_rtx の値である。コードが pc の式を作ろうとすると返ってくるのはpc_rtx になる。

分岐を行なわない命令は全て、プログラムカウンタをインクリメントすることにより暗黙のうちに変更する。しかし、このことを RTL に記述する必要はない。

(mem:m addr)
この RTX は、式 addr で表されるアドレスの主記憶への参照を表す。m はメモリの、アクセスされる単位の大きさを表す。
(addressof:m reg)
この RTX はレジスタ reg のアドレスを要求することを表す。モードは常に Pmode である。CSE のフェーズの後で関数内に addressof 式がどんなものであれ残っていれば、reg は強制的にスタックに置かれ、addressof 式は、そのスタックスロットのアドレスを表す plus 式で置き換えられる。


Node:Arithmetic, Next:, Previous:Regs and Memory, Up:RTL

算術演算用 RTL 式

指定されない限り、代数演算式の全てのオペランドはモード m に対して有効でなければならない。あるオペランドがモード m に対して有効なのは、オペランド自身のモードが m の場合か、オペランドが const_int または const_doublemMODE_INT クラスのモードの時である。

交換可能な二項演算の場合には、定数は二番目のオペランドに置くべきである。

(plus:m x y)
マシンモード m で実行される、xy で表される値の加算を表す。
(lo_sum:m x y)
plus にほぼ同じだが、x と、y の下位ビットの和を表す点が異なる。下位ビット数は機種により異なるが、一般には、Pmode のビット数から、コード high によってセットされるビット数を引いたものになる(see Constants)。

m は、Pmode でなければならない。

(minus:m x y)
減算を表す以外は plus と同じである。
(compare:m x y)
比較目的の y から x を引く減算の結果を表す。無限の精度があるかのように、計算は桁溢れなしで行われる。

当然のことだが、実際に無限の精度で引き算を行える機械は存在しない。だが、引き算の結果の符号だけが使われる場合は、無限の精度で引き算ができるような振りをすることができる。その場合、引き算の結果は条件コードに格納される。そして、この種類の式が正しく使えるのはこういう場合、すなわち、条件コードに格納される値としてだけである。

モード m は、xy のモードには関係なく、条件コードの値のモードになる。(cc0) が使われるのなら、VOIDmode になる。それ以外の場合は、MODE_CC クラスの中のあるモードになる。良く使われるのは CCmode である。See Condition Code.

普通は、xy は同じモードでなければならない。それ以外で compare が有効なのは、x のモードが、MODE_INT のクラスに属し、かつ、yVOIDmode モードの const_intconst_double の場合のみである。x のモードによって、比較が行われるモードが決まるので、x のモードは VOIDmode であってはならない。

オペランドの一方が定数であるなら、それは第二オペランドに置くべきであり、そうすることによって比較のためのコードが適切に調整される。

compare で、VOIDmode の定数を二つ指定するのは無効である。というのは、どのモードで比較を実行すべきか知りようがないからである。比較は、コンパイル中に畳み込まれるか、先頭のオペランドがそのモードがわかっているレジスタにロードされるかしなければならない。

(neg:m x)
x で表現される値の符号を反転した(0 から引いた)値を表現する。m のモードで演算が行われる。
(mult:m x y)
xy で表される値の符号付きの積を表現する。積は、モード m で行われる。

機種によっては、オペランドよりも大きな積を生成する乗算をサポートしている。その場合には、次のようにパターンを書くこと。

(mult:m (sign_extend:m x) (sign_extend:m y))

ここで、m は、xy のモードよりも大きいモードである。xy のモードは同じでなくても良い。

符号無しの、大きな積を生じる乗算の場合には、zero_extend を使って同じように書けば良い。

(div:m x y)
マシンモード mxy で割った、符号付きの商を表す。m が浮動小数点モードなら、厳密な商を表す。そうでなければ、整数化した商を表す。

マシンによっては、オペランドと商の幅が全部同じではない場合の除算命令を持っていることがある。そういう命令を表現するには、以下のように、truncatesign_extend を使う。

(truncate:m1 (div:m2 x (sign_extend:m2 y)))

(udiv:m x y)
div とほぼ同じだが、符号無しの除算を表す。
(mod:m x y)
(umod:m x y)
divudiv と似ているが、商の代わりに剰余を表す。
(smin:m x y)
(smax:m x y)
xy の小さいほう(sminの場合)または大きいほう(smax の場合)を表す。この場合、モード m の符号付き整数として解釈が行なわれる。
(umin:m x y)
(umax:m x y)
sminsmax とほぼ同じだが、符号無しの整数として解釈が行なわれる。
(not:m x)
x で表される値のビット毎の補数を表現する。この演算はモード m で行なわれる。m は、固定小数点モードでなければならない。
(and:m x y)
xy で表される値のビット毎の論理積を表現する。ビット毎の論理積はモード m で実行される。このモードは、固定少数点数のモードでなければならない。
(ior:m x y)
xy で表される値のビット毎の論理和を表現する。ビット毎の論理和はモード m で実行される。このモードは、固定少数点数のモードでなければならない。
(xor:m x y)
xy で表される値のビット毎の排他的論理和を表現する。ビット毎の排他的論理和はモード m で実行される。このモードは、固定少数点数のモードでなければならない。
(ashift:m x c)
x を左に c 回算術シフトした結果を表現する。x のモードは m であり、固定少数点数のモードである。c は、固定小数点数モードか、モードが VOIDmode の定数である。c のモードがどちらになるかは、マシン記述中の左シフト命令のエントリに対して呼び出されるモードにより決定される。例えば、Vax では、c のモードは、m に関わらず、QImode である。
(lshiftrt:m x c)
(ashiftrt:m x c)
右シフトである点を除いて、ashift と同じである。左シフトの場合と違って、この二つの演算は異なる物である。
(rotate:m x c)
(rotatert:m x c)
同様に、左右のローテーションを表す。c が定数なら、rotate の方を使うこと。
(abs:m x)
モード m で計算した、xの絶対値を表現する。
(sqrt:m x)
モード m で計算した、x の平方根を表現する。ほとんどの場合、m は浮動小数点モードになる。
(ffs:m x)
x の、 1 であるビットのうちの最下位のビットの位置に 1 を足したものを、モード m の整数として表現する。(x がゼロであれば、この値は0 になる。) x のモードは m でなくても良い。ターゲットの機種により、色々なモードの組合せが有効である。


Node:Comparisons, Next:, Previous:Arithmetic, Up:RTL

比較演算

比較演算子は、二つのオペランドについてある関係が成り立つかどうかを調べ、その関係が成り立つなら 0 でない値、成り立たないなら 0 を表す。0 でない値の方は、機種依存であり、 STORE_FLAG_VALUE (see Misc)で記述されるが、この値に等しくなる必要はない。比較演算のモードは、比較対象のデータのモードには関係ない。比較演算が、条件判定に使われる(例えば、if_then_else の第一オペランドとして使われる)場合は、モードは VOIDmode でなければならない。あるいは、比較演算の結果、変数に格納すべきなんらかのデータを生じるなら、モードは MODE_INT のクラスに入っていなければならない。データを生成する全ての比較演算は同じモードを使わなければならない。どのモードになるかは機種依存である。

比較演算の使われ方には二通りある。比較演算子を使って、条件コード (cc0) をゼロと比較することができる。例えば、(eq (cc0) (const_int 0)) のようにである。こういう構文では、条件コードを設定する先行命令の結果を実際に参照している。条件コードを設定する命令は、条件コードを使用する命令の直前になければならない。これらの命令の間に置いて良いのは、note insn だけである。

あるいは、比較演算は二つのデータオブジェクトを直接比較しても良い。比較のモードはオペランドにより決定される。どちらのオペランドもある共通のマシンモードに対して有効でなければならない。両方のオペランドが定数である比較は、モードを決めることができないので無効である。しかし、そのような比較は、定数畳み込みにより、RTL 中には決して存在しないはずである。

上の例だと、(cc0) が直前で (compare x y) に設定されているなら、比較演算は (eq x y) に等価である。普通は、ある特定のマシンでは、どちらか一方の形式のだけの比較がサポートされている。しかし、組合せパスは演算をマージして、特定の insn が含まれている文脈に存在するなら、このような eq 式を生成することを試みる。

不等比較は、符号付きと符号なしの二種類がある。このため、符号付きと符号なしの「大なり」に対応して、gtgtu の異なる式コードがある。これらは、同じ整数値の組合せに対して異なる結果を生じることもある。例えば、1 は符号付きでは -1 より「大なり」であるが、符号なしでは「大なり」ではない。-1 は符号なしとして扱われると、実際には 0xffffffff となり、 1 より大きいからである。

符号付き比較はまた浮動小数点値にも使われる。浮動小数点比較は、オペランドのマシンモードにより区別される。

(eq:m x y)
xy で表現される値が等しければ 1 で、等しくなければ 0 である。
(ne:m x y)
xy で表現される値が等しくなければ 1 で、等しければ 0 である。
(gt:m x y)
xy より大きければ 1 である。両者とも固定小数点であれば、符号付きで比較が行なわれる。
(gtu:m x y)
符号無しで比較が行なわれ、そのため固定小数点数についてのみ使われるという点を除いて、gt と同じである。
(lt:m x y)
(ltu:m x y)
gtgtu と同様だが、「より小さい」かどうかを判定する。
(ge:m x y)
(geu:m x y)
gtgtu と同様だが、「以上」かどうかを判定する。
(le:m x y)
(leu:m x y)
gtgtu と同様だが、「以下」かどうかを判定する。
(if_then_else cond then else)
これは、比較演算ではないが、ここで挙げておく。というのは、必ず比較演算と関連して使われるからである。正確に言うと、cond は比較式である。if_then_else 式は、cond により、then で表される値とelse で表される値のどちらかの選択肢を表す。

ほとんどの機種では、if_then_else 式は条件ジャンプを表す場合にのみ有効である。

(cond [test1 value1 test2 value2 ...] default)
if_then_else と同様だが、もっと一般的である。test1test2... がそれぞれ順番に実行される。cond 式の結果は、最初に非 0 となったテストに対応する value となる。あるいは、非 0 となったテストがなければ、default になる。

この式は、現時点では命令パターンに対しては使用できない。insn の属性にたいしてのみ使用できる。See Insn Attributes.


Node:Bit Fields, Next:, Previous:Comparisons, Up:RTL

ビットフィールド

特別な式コードがあり、ビットフィールド命令を表現することができる。この型の式は、RTL 中で左辺値となる。代入式の左辺に置くことが可能で、その式で指定されたビットフィールドにある値を代入することを指示する。

(sign_extract:m loc size pos)
これは、loc(メモリかレジスタの参照)に含まれるか、そこで始まっている符号拡張されたビットフィールドへの参照を表す。このビットフィールドは幅が size ビットで、ビット位置 pos から始まっている。コンパイル時の選択により、BITS_BIG_ENDIAN が、メモリ単位のどちらの端から pos を数えるかを指定する。

loc がメモリ中に置かれているなら、そのモードは一バイト整数のモードでなければならない。loc がレジスタに置かれているなら、使うべきモードは、パターン insv または extv (see Standard Names) のオペランドとして指定されたものになり、通常は全語の整数モードである。何も指定がないときのデフォルトは全語の整数モードになる。

pos のモードはマシン固有であり、パターン insv またはextv でも指定される。

モード m は、loc がレジスタなら、それに使われるモードと同じである。

(zero_extract:m loc size pos)
sign_extract と同様だが、符号なし、あるいはゼロ拡張されたビットフィールドを参照する。同じビット列が抽出されるが、符号拡張ではなくゼロで埋め尽くされる。


Node:Conversions, Next:, Previous:Bit Fields, Up:RTL

変換

マシンモード間の変換は全て、明示的な変換演算で表す必要がある。例えば、あるバイトとある全語の和を表す式を、(plus:SI (reg:QI 34) (reg:SI 80)) と書くことはできない。なぜなら、plus という演算では、二つのオペランドは同じマシンモードを持つ必要があるからである。このため、バイトの大きさのオペランドを変換演算で以下のように包む必要がある。

(plus:SI (sign_extend:SI (reg:QI 34)) (reg:SI 80))

変換演算は単なるプレースホルダーではない。というのは、指定された変換前のモードから変換後のモードへ変換する方法はひとつだけではないからである。変換演算のコードで、変換方法を指定するのである。

以下のどの変換演算でも、xVOIDmode であってはならない。変換を行なうべきがモードが判らないからである。変換は、コンパイル時に行なうか、x をレジスタに保持するかのどちらかでなければならない。

(sign_extend:m x)
x をマシンモード m へ符号拡張した結果を表現する。m は固定小数点モードでなければならず、x は、m より幅の狭いモードの固定小数点値でなければならない。
(zero_extend:m x)
x をマシンモード m へゼロ拡張した結果を表現する。m は固定小数点モードでなければならず、x は、m より幅の狭いモードの固定小数点値でなければならない。
(float_extend:m x)
x をマシンモード m に拡張した結果を表現する。m は浮動小数点モードでなければならず、x は、m より幅の狭いモードの浮動小数点数値でなければならない。
(truncate:m x)
x をマシンモード m に打切った結果を表現する。m は固定小数点モードでなければならず、xm より幅の広いモードの固定少数点値でなければならない。
(float_truncate:m x)
x をマシンモード m に打切った結果を表現する。m は浮動小数点モードでなければならず、xm より幅の広いモードの浮動少数点値でなければならない。
(float:m x)
固定小数点値 x を符号付きとみなし、浮動小数点モード m に変換した結果を表す。
(unsigned_float:m x)
固定小数点値 x を符号無しとみなし、浮動小数点モード m に変換した結果を表す。
(fix:m x)
m が固定小数点モードの場合、浮動小数点値 x をモード m の符号付き整数に変換した結果を表現する。丸めをどのように行なうかは規定されないので、C プログラムをコンパイルするときにこの演算が正しく使えるのは、オペランドが整数値を持つ時だけである。
(unsigned_fix:m x)
浮動小数点値 x をモード m の符号なし整数に変換した結果を表現する。丸めをどのように行なうかは規定されない。
(fix:m x)
m が浮動小数点モードの場合、浮動小数点値 x(モードm で有効) を整数に変換した結果を表現する。この結果は浮動小数点モード m で表現される。丸めは 0 に向かって行なわれる。


Node:RTL Declarations, Next:, Previous:Conversions, Up:RTL

宣言

宣言式コードは、算術演算を表すのではなく、オペランドの状態に関する表明を表す。

(strict_low_part (subreg:m (reg:n r) 0))
この式コードはただ一つの文脈でのみ使われる。set 式の目的オペランドとしてだけ使われる。さらに、この式のオペランドは矛盾のない subreg 式でなければならない。

strict_low_part があると、モード n では意味があるが、モード m の一部ではないようなレジスタの一部が、変更すべきでないことを示す。通常、m の幅がワードより狭いときは、このようなサブレジスタに代入を行なうと、そのレジスタの他の部分に予期しない影響を与える。


Node:Side Effects, Next:, Previous:RTL Declarations, Up:RTL

副作用式

ここまで説明してきた式コードは値を表すものであり、動作を表すものではなかった。しかし機械命令というものは決して値を生み出すものではない。機械命令は、マシンの状態に副作用を与えるという点でのみ意味を持つ。特別な式コードを使って、副作用を表現する。

命令の本体は、必ず以下の副作用を表すコードの一つである。これまで説明してきた、値を表現するコードは、これらのオペランドとしてのみ現れるのである。

(set lval x)
x の値を lval で表される場所に格納する動作を表現する。lval は、その中に格納可能であるような場所を表す式である。すなわち、reg(あるいは subreg、または strict_low_part)、mempccc0 のどれかである。

lval が、regsubregmem のどれかなら、マシンモードを持つ必要がある。その場合、x は、そのモードで有効でなければならない。

lval が、マシンモードがそのレジスタの全幅より小さいようなreg であれば、そのマシンモードにより指定されたレジスタの部分には指定された値が与えられ、レジスタのその他の部分は未定義値となる。同様に、lval が、レジスタのモードより狭いモードの subreg なら、レジスタのその他の部分がどのように変更されるかは不定である。

lval が、subregstrict_low_part なら、subreg のマシンモードで指定されたレジスタの部分は、値 x が与えられ、その他の部分は変更されない。

lval(cc0) なら、マシンモードがないので、xcompare 式か、任意のモードを持つ値で良い。後者の場合は、"test" 命令を表現する。(set (cc0) (reg:m n)) という式は、(set (cc0) (compare (reg:m n) (const_int 0))) という式に等価である。前者の式を使ったほうが、コンパイル中のメモリを節約できる。

lval(pc) なら、それはジャンプ命令であり、x の取りうる値は非常に限られてくる。x は、label_ref 式とすることができる(無条件ジャンプ)。if_then_else (条件ジャンプ)とすることもでき、その場合、第二オペランドか第三オペランドのどちらかが (pc) (ジャンプしない場合に使われる)でなければならず、またもう一方は label_ref (ジャンプする場合に使われる)でなければならない。また、xmem または (plus:SI (pc) y) でも良い。ここで、yregmem である。この最後のパターンは分岐テーブル経由のジャンプを表現するのに使われる。

lval(cc0) でも (pc) でもなければ、lval のモードは VOIDmode としてはならず、x のモードはlval のモードとして有効でなければならない。

lvalSET_DEST マクロで、xSET_SRC マクロでアクセスするようにするのが良い。

(return)
パターン中に単独の式として書くことで、現在の関数から戻ることを表す。ただし、VAX のように一命令で戻ることができるマシンに限られる。関数から戻るためには、複数の命令からなる「エピローグ」を実行する必要があるマシンでは、関数からの復帰は、エピローグの直前に置かれるラベルへジャンプすることで行なわれるので、return 式コードが使われることはない。

if_then_else 式の中に置いた場合は、呼び出し元に戻るための pc に置かれる値を表す。

(return) というパターンは、論理的には (set (pc) (return)) と等価であるが、後者の形式が使われることはない。

(call function nargs)
関数呼び出しを表現する。functionmem 式であり、この式のアドレスは、呼び出される関数のアドレスである。nargs は二つの目的で使われる式である。あるマシンでは、スタックに積まれた引数のバイト数を表現する。あるいは、引数レジスタの数を表現する。

どのマシンも function が持たなければならない標準的なマシンモードを持っている。マシン記述では、FUNCTION_MODE というマクロを、その不可欠のモード名に展開されるように定義している。このモードの目的は、どの種類のアドレッシングが許されるかがアドレスの対象となるマシンモードに依存するマシンにおいて、どの種類のアドレッシングが許されているかを指定することである。

(clobber x)
予期できない値を x に格納すること、または格納する可能性があることを表す。x は、reg 式か、scratch 式か、mem 式のどれかでなければならない。

これが使われるのは一つは、標準的な値を特定のハードレジスタに格納する文字列命令においてである。格納される値を記述する手間をかける必要はないが、文字列命令を越えてその値を保持しようとしないように、コンパイラにレジスタの値が変更されることを知らせるのが本質的な事である。

もし x(mem:BLK (const_int 0)) なら、全メモリ位置が上書きされると見なされなければならないことを意味する。

マシン記述では、ある種類のハードレジスタを「呼びだし時破壊」("call-clobbered") として分類していることに注意。全ての関数の呼びだし命令は、デフォルトでこれらのレジスタを破壊すると仮定されているので、この事実を示すために clobber 式を使う必要はない。また、各関数呼び出しは、その関数が const と宣言されていない限り、任意のメモリ位置を変更する可能性があると仮定されている。

parallel の最後の組の式が、それぞれ regmatch_scratch 式 (see RTL Template)を引数とするclobber 式なら、組合せフェーズは、そうすることでパターンがマッチするようになるなら、適切な clobber 式を、構築されたばかりのinsn に追加する。

この機能は、例えば、乗算命令と加算命令は MQ レジスタを使わないが、アキュムレータへの加算命令が MQ レジスタを上書きするようなマシンで使うことができる。一個の組み合わされた命令(? combined instruction)は一時レジスタを必要とするが、一方、それを構成する命令は一時レジスタを必要としない場合も同様である。

あるレジスタに対する clobber 式が、他に副作用のある parallel の中に現れた場合は、レジスタ確保部が、そのレジスタがその insn の前後どちらにおいても占有されることがないことを保証する。しかし、選ばれた選択肢に対して制約 & が指定されていない限り、再ロードパスが入力の一つとして使われたレジスタを確保する場合がある(see Modifiers)。特定のハードレジスタ、または疑似レジスタ、あるいは scratch 式のどれかを上書きすることができる。後の二つの場合には、GNU CC は、その時点で一時的に使用可能なハードレジスタを確保する。

一時レジスタを必要とする命令については、疑似レジスタの代わりにscratch を使うべきである。そうしておくと、組合せフェーズが必要なときに clobber を追加することを許すからである。このためには (clobber (match_scratch ...)) と書けば良い。疑似レジスタを上書きするなら、他のどこにも現れていないものを使うこと。つまり、そのたびに新しいものを生成して使うこと。そうしないと、CSE のフェーズが混乱する。

parallel 中で疑似レジスタを上書きすることのもう一つの使い道がある。insn の入力オペランドの一つがやりその insn により上書きされる場合である。この場合、insn 中の clobber の中と、別のところとに同じ疑似レジスタを使うと期待どおりの結果が得られる。

(use x)
x の値が使われるということを表す。プログラムのこの時点での x の値が必要であることを示す。たとえ、なぜ必要であるかがはっきりしていなくてもである。このため、GCC は、x に値を格納するという効果しか持たない命令が直前にあっても、その命令を削除しない。x は、reg 式でなければならない。

再ロードフェーズの間、パターンとして use がある insn は、reg_equal ノートを保持することが可能である。このような use insn は、再ロードフェーズが終了する前に削除される。

遅延分岐スケジューリングのフェーズの間は、x は insn でも良い。これは、x が以前にコード中のこの場所にあって、そのデータ依存関係を考慮する必要があるということを意味する。このような use insn は、遅延分岐スケジューリングのフェーズの終了前に削除される。

並列に実行される様々な副作用を表す。大カッコはベクトルを表す。parallel のオペランドは式を要素とする一個のベクトルである。x0x1 等は個々の副作用を表す式である。これらの式のコードは、setcallreturnclobberuse のどれかである。

「並列に」という意味は、最初に個々の副作用で使われる全ての値が計算され、次に全ての副作用が実行されることを表す。

(parallel [(set (reg:SI 1) (mem:SI (reg:SI 1)))
           (set (mem:SI (reg:SI 1)) (reg:SI 1))])

例えば、上の式はハードレジスタ 1 の値と、ハードレジスタ 1 により指定されるメモリ位置の値を交換するということを曖昧さなしに表している。(reg:SI 1) がメモリアドレスとして現れているところでは、どちらも、insn を実行するのレジスタ 1 の値を参照している。

このため、parallel を使ったときに、ある一つの set の結果が次の set で使えると考えるのは間違いということになる。例えば、人は良く、条件が 0 なら分岐する命令を以下のように表そうとする。

(parallel [(set (cc0) (reg:SI 34))
           (set (pc) (if_then_else
                        (eq (cc0) (const_int 0))
                        (label_ref ...)
                        (pc)))])

しかし、この書き方は間違いである。何故なら、これだと分岐条件はこの命令の前の条件コードの値に依存しており、この命令により設定される新しい値を使っていないからである。

のぞき穴最適化は、最終フェーズのアセンブリコード出力と一緒に行なわれる。この最適化により、一個の parallel からなるパターンの insn を生成することができる。この場合、parallel の各要素は、結果となるアセンブラコードを出力するのに必要なオペランド--多くの場合、reg あるいは mem、定数式である。これは、他のどのコンパイル過程でも適切な形式の RTL ではないが、その後には、もはや実行すべき最適化過程が残っていないので、問題ないのである。ただし、マクロ NOTICE_UPDATE_CC をもし定義するなら、その定義では、なんらかののぞき穴最適化を定義するなら上記のような insn を取り扱わなければならない。

(sequence [insns ...])
ある insn の列を表す。ベクトル中に現れる insns のそれぞれは、insn の連鎖に現れるのに適したものであるために、insnjump_insncall_insncode_labebarriernote のどれかでなければならない。

sequence RTX は、RTL 生成の間は実際の insn には決して置かれることがない。この RTX は define_expand から生ずる insn の列を表しており、それは、insn が emit_insn に渡され、insn の連鎖に挿入されるまえに行なわれる。実際に挿入された時点で、個々のサブ insn が分離し、sequence が捨てられる。

遅延スロットスケジューリングが完了した後、ある insn とその遅延スロットに置かれている全ての insn は一まとめにされて、一個の sequence に収められる。遅延スロットを必要とする insn は、ベクトル中の先頭のinsn である。その後ろに続く insn は遅延スロットに置かれる。

遅延スロット中の insn には INSN_ANNULLED_BRANCH_P が設定され、遅延スロット中の insn の効果を条件により無効化するような分岐 insn を使うべきであることを指示する。

以下の式コードは副作用の代わりに、insn の本体として現れる。だが、厳密に言えばいつでも副作用を表すわけではない。

(asm_input s)
文字列 s で表されるアセンブラコードそのものを表す。
(unspec [operands ...] index)
(unspec_volatile [operands ...] index)
operands についてのマシン固有の演算を表す。index で、複数のマシン固有演算の一つを選び出す。unspec_volatile を使って、揮発性の演算とトラップを起こす可能性のある演算を表す。その他の演算には unspec が使われる。

これらのコードは insn の pattern の内側、parallel の内側、式の内側に現れる可能性がある。

(addr_vec:m [lr0 lr1 ...])
ジャンプ先アドレスのテーブルを表す。ベクトルの要素 lr0... 等は label_ref 式である。モード m で各アドレスにどれだけのメモリを与えるかを指定する。普通は mPmode になる。
(addr_diff_vec:m base [lr0 lr1 ...] min max flags)
ジャンプ先アドレスを base からのオフセットで表したテーブルを表す。ベクトルの要素 lr0... 等は、label_ref 式であり、baselabel_ref 式である。モード m で各アドレスの差分にどれだけのメモリを与えるかを指定する。minmax は分岐の近距離化により設定され、それぞれ最小と最大のアドレスを持つラベルを保持する。flags は、それを保持する insn に対する baseminmax と、base に対する minmax の相対的な位置を表す。詳細については rtl.def を参照のこと。


Node:Incdec, Next:, Previous:Side Effects, Up:RTL

アドレスの埋め込み副作用

メモリアドレスとして現れる、特別な副作用式コードが 6 つある。

(pre_dec:m x)
x を標準量だけデクリメントする副作用を表す。また、x がデクリンメントされた後の値も表す。xregmem でなければならず、ほとんどのマシンでは reg しか許していない。m はそのマシンのポインタ用のマシンモードでなければならない。x のデクリメントされる量は、アドレスとして振る舞う式のメモリ参照を含むマシンモードの長さをバイト数で表したものである。以下に使い方の例を示す。
(mem:DF (pre_dec:SI (reg:SI 39)))

これは、疑似レジスタ 39 を DFmode の値の長さだけデクリメントし、その結果を DFmode の値のアドレスとして使う事を示している。

(pre_inc:m x)
同様だが、デクリンメントではなく x のインクリメントを指定する。
(post_dec:m x)
pre_dec と同じ副作用を表すが、異なる値になる。これにより表される値は、デクリメントされる前の x の値である。
(post_inc:m x)
同様だが、デクリンメントではなく x のインクリメントを指定する。
(post_modify:m x y)
xy に設定する副作用を表現し、かつ x が修正を受ける前のx を表現する。xregmem でなければならない。だが、多くの機種では reg しか許していない。m は使われている機種でのポインタのマシンモードでなければならない。x がデクリメントされる量は、この式がアドレスの役割をするメモリ参照のマシンモードの長さをバイトで表したものである。これは、現在実装されていないことに注意。

y は次の三つの形式のうちの一つでなければならない。

(plus:m x z) (minus:m x z) (plus:m x i)
ここで z はインデックス・レジスタで、i は定数である。

使い方の例を示す。

(mem:SF (post_modify:SI (reg:SI 42) (plus (reg:SI 42) (reg:SI 48))))

これは、疑似レジスタ 42 を、疑似レジスタ 48 の内容をそれに加算する形で変更することを示している。ただし、42 が指し示していた内容が使われた後で行われる。

(pre_modify:m x expr)
同様に、x の内容を使う前に副作用が発生する。

これらの組み込み副作用式は注意して使わなければならない。命令パターンでは使わない。コンパイラの flow パスに至るまでは、スタックへのプッシュを表現するのに使われるだけである。flow パスは、レジスタが一個の命令でインクリメントまたはデクリメントされ、かつ、その直前または直後でアドレスとして使われている場合を探す。そのような場合は、プリ/ポスト・インクリメント/デクリメントを使うように変換する。

これらの式のオペランドとして使われているレジスタが、ある insn の別のアドレス中で使われていると、そのレジスタの元の値が使われる。レジスタをアドレス以外に使うことは、同一 insn 内で埋め込み副作用式として使うのは許されない。なぜなら、そういう式は、異なる機種では異なる振る舞いをし、そのため、取扱いが曖昧になるので許されない。

組み込み副作用式で表現可能な命令は、また、アドレスレジスタがどのように変更されるかを記述する追加の set を含む parallel を使って表現することもできる。だが、これは行なわれない。何故ならこのような操作をともかく許す機種では、典型的には、メモリアドレスが要求される場所ならどこでもそういう操作を許すからである。これらの操作を付加的な並列格納として記述すると、マシン記述のエントリ数が二倍必要になる。


Node:Assembler, Next:, Previous:Incdec, Up:RTL

式としてのアセンブラ命令

RTX コード asm_operands は、ユーザが指定したアセンブラ命令により生成される値を表現する。引数付きの asm 文を表現するのに使われる。出力オペランドが一つの asm 文は以下のようになる。

asm ("foo %1,%2,%0" : "=a" (outputvar) : "g" (x + y), "di" (*z));

この asm 文は、値が outputvar に格納されることを表現する、一個の asm_operands RTX を使って以下のように表現される。

(set rtx-for-outputvar
     (asm_operands "foo %1,%2,%0" "a" 0
                   [rtx-for-addition-result rtx-for-*z]
                   [(asm_input:m1 "g")
                    (asm_input:m2 "di")]))

ここで、asm_operands RTX のオペランドは、アセンブラテンプレート文字列、出力オペランドについての制限子、指定されたオペランドの中での出力オペランドの番号、入力オペランド RTX のベクトル、それに、入力オペランドのモードと制約のベクトルからなる。モード m1 は、和 x+y のモードであり、m2 は、*z のモードである。

asm 文に複数の出力値がある場合は、その insn は parallel の内側に幾つかの set RTX を持つ。setはそれぞれ asm_operands を含んでいる。これらの set は全て、同じアセンブラテンプレートとベクトルを共有しているが、それぞれ出力オペランドに応じた制約を保持している。


Node:Insns, Next:, Previous:Assembler, Up:RTL

Insns

関数のコードの RTL 表現は、insn と呼ばれるオブジェクトの二重線形リストである。insn は他に用途のない特別なコードを持つ式である。insn の一部は実際の命令である。switch 文のための分岐テーブルを表現するものもある。その他、分岐先ラベルや様々な宣言的な情報を表現するものもある。

各 insn は、それ自身固有のデータを持つほか、現在の関数内の他の insn と区別するための一意的な識別番号(遅延分岐スケジューリングの後で、同じ識別番号を持つ insn のコピーが一つの関数内で複数存在することがあるが、これらのコピーは全く同じであり、sequence の中にしか現れない)、それに直前と直後の insn を指すポインタを持っている。この三つのフィールドはどの insn においても、insn の式コードによらずに、同じ位置にある。この三つのフィールドは XEXPXINT を使ってアクセスしても良いが、以下のような特別なマクロが三つあり、いつでも使うことができる。

INSN_UID (i)
insn i に一意的な識別番号をアクセスする。
PREV_INSN (i)
i の直前の insn へのポインタをアクセスする。i が先頭の insn なら、ヌルポインタになる。
NEXT_INSN (i)
i の直後の insn へのポインタをアクセスする。i が末尾の insn なら、ヌルポインタになる。

insn のリストの先頭の insn は、get_insns で得ることができる。末尾の insn は、get_last_insn を使って得ることができる。先頭の insn から末尾の insn の範囲内では、NEXT_INSNPREV_INSN のポインタは常に対応している必要がある。つまり、insn が先頭の insn でなければ、

NEXT_INSN (PREV_INSN (insn)) == insn

上の式は常に真であり、また、insn が末尾の insn でなければ、

PREV_INSN (NEXT_INSN (insn)) == insn

は常に真である。

遅延分岐スケジューリング後、リスト中の insn の幾つかはsequence 式である可能性がある。sequence は、insn のベクトルを含んでいる。このベクトルの中の insn の NEXT_INSN の値は、最後の insn を除いて、ベクトルの中での次の insn を指す。ベクトルの最後の insn の NEXT_INSN の値は、その insn を含むsequence に対する NEXT_INSN の値と同じである。PREV_INSN についても同様である。

つまり、先に述べた恒等式は、sequence の中の insn については必ずしも真ではないのである。特に、insnsequence の先頭の insn なら、NEXT_INSN (PREV_INSN (insn)) は、sequence 式を含む insn になり、同様に、PREV_INSN (NEXT_INSN (insn)) は、sequence 式の最後の insn になる。これらの式を使って sequence 式を含む insn を取り出すことができる。

どの insn も以下のような6個の式コードの一つを持っている。

insn
式コード insn は、ジャンプも関数呼び出しも行わない命令に対して使う。sequence 式は、その中の insn の一つがジャンプや関数呼び出しを行なっても、常にコード が insn である insn に含まれる。

コードが insn である insn は、上記の三つの必須フィールドの他に、四つのフィールドを持つ。この四つのフィールドについては後出の表で説明する。

jump_insn
式コード jump_insn はジャンプを行なう可能性のある命令(あるいは、もっと一般的に言うと、label_ref 式を含む命令)で使われる。現在の関数から復帰する命令があるなら、やはり jump_insn になる。

jump_insn の insn には、コード insn の insn と同じ追加のフィールドがあり、同じようにしてアクセスされ、さらにジャンプ最適化が完了したときに一度だけ定義される JUMP_LABLE というフィールドも保持している。

単純な、条件ジャンプと無条件ジャンプの場合は、このフィールドはcode_label を保持しており、ここに insn が(条件分岐の場合もある) 分岐していく。もっと複雑なジャンプでは、JUMP_LABEL が insn が参照しているラベルの一つを記録している。その他のラベルを探すには insn の本体全体を走査するしかない。

関数から復帰する insn はジャンプ insn として数えるが、何もラベルを参照していないので、JUMP_LABLE フィールドは 0 になる。

call_insn
式コード call_insn は、関数呼びだしを行なう可能性のある命令に対して使われる。これらの命令を区別するのは重要である。なぜなら、特定のレジスタやメモリ位置の値を、予測できない形で変えてしまう可能性があるからである。

call_insn insn は insn insn と同じ追加のフィールドを持ち、同じ方法で参照する。さらに付け加えて、CALL_INSN_FUNCTION_USAGE というフィールドを持っており、このフィールドは一つのリスト(expr_list 式の連鎖である)を保持している。このリストは、被呼びだし関数により使われたか、あるいは上書きされたハードレジスタを示す use 式とclobber 式を含んでいる。このリストの clobber に指定されたレジスタは、call_insn の実行の、変更される。一方、call_insn の本体の clobber で指定されたレジスタは、insn の実行が完了する前に上書きされる。このリストの clobber 式は CALL_USED_REGISTERS で指定されたレジスタを増やす。(see Register Basics)。

code_label
code_labe insn は、分岐命令の分岐先となりうるラベルを表す。標準の三つのフィールドに加えて二つの特別なフィールドがある。CODE_LABEL_NUMBER を使って ラベル番号、すなわち、コンパイル単位(現在の関数の中だけではない)の全てのラベルの中から、このラベルを一意的に特定する番号を保持する。最終的には、このラベルはアセンブラ出力ではアセンブララベルとして表現される。これは、通常は Ln という形式になる。ここで n はラベル番号である。

code_label が RTL 式に現れるときは、普通はそのラベルのアドレスを表す label_ref の中に、番号として現れる。

フィールド LABEL_NUSES は、ジャンプ最適化フェーズが完了した時に一度だけ定義され、現在の関数の中でこのラベルが参照された回数を保持する。

barrier
バリアは、命令ストリームの、制御の流れが越えることのできない地点に置かれる。無条件ジャンプ命令の後ろに置かれ、ジャンプが無条件であることを知らせる。また、volatile 関数呼び出しの後ろにも置かれる。これらの関数が戻る事はない(例えば exit である)。これらは、三つの標準フィールド以外の情報は持っていない。
note
note insn は、付加的な、デバッグ情報および宣言に関する情報を表すのに使われる。この insn には、非標準のフィールドが二つある。一つは整数で、マクロ NOTE_LINE_NUMBER で参照され、もう一つは文字列で、マクロ NOTE_SOURCE_FILE で参照される。

NOTE_LINE_NUMBER が正なら、そのノートはソース行の位置を表し、NOTE_SOURCE_FILE は、その行が含まれるソースファイル名を表す。このノートは、アセンブラ出力に行番号データを生成するの使われる。

NOTE_LINE_NUMBER が正でないなら、実際の行番号ではなくては、以下の値の一つを持つコードである。この場合、NOTE_SOURCE_FILE はヌルポインタでなければならない。

NOTE_INSN_DELETED
このノートは完全に無視できる。幾つかのフェーズでは、insn を削除するのを、それらの insn をこの種類のノートに変えてしまうことで行なっている。
NOTE_INSN_BLOCK_BEG
NOTE_INSN_BLOCK_END
この型のノートは、変数名のスコープレベルの開始位置と終了位置を表す。デバッグ情報の出力を制御する。
NOTE_INSN_EH_REGION_BEG
NOTE_INSN_EH_REGION_END
この型のノートは、例外処理のスコープレベルの開始位置と終了位置を表す。NOTE_BLOCK_NUBMER で、どの CODE_LABEL が指定された領域に付属するかを特定する。
NOTE_INSN_LOOP_BEG
NOTE_INSN_LOOP_END
この型のノートは、while または for ループの開始位置と終了位置を表す。これらにより、ループ最適化部が素早くループを見つけられるようになる。
NOTE_INSN_LOOP_CONT
ループの中の、continue 文の飛び先位置に現れる。
NOTE_INSN_LOOP_VTOP
このノートは、終了テストが複製されるようなループにおいて、終了テストが始まる位置を示す。この位置は、ループ不変量を考えるときのもう一つの仮想的なループの開始位置となる。
NOTE_INSN_FUNCTION_END
関数本体の終り近く、(一個の命令では関数から戻れないマシンでは) return 文の飛び先ラベルの直前に現れるノートである。
NOTE_INSN_SETJMP
setjmp や関係する関数の呼び出し毎に、その直後に現れる。

これらのコードは、デバッギングダンプにはシンボルで表示される。

insn のマシンモードは普通は VOIDmode だが、フェーズによってはモードを色々な目的で使用する。

共通部分式削除パスでは、処理済みのブロックの先頭の insn の場合、その insn のモードを QImode に設定する。

二回目の Haifa スケジューリングパスでは、複数命令の同時発行が可能なターゲットに対しては、insn が同時に発行される命令のグループの始まりの命令であると思われる場合は、その insn のモードを TImode に設定する。つまり、その命令は直前の命令と同時に発行できないものである。以降のパス、特に機種依存の命令並べ替えではこれはに頼っている。

以下は、insnjump_insncall_insn insn の追加フィールドの表である。

PATTERN (i)
この insn により発生する副作用を表す式。これは次のコードのどれか一つでなければならない。setcalluseclobberreturnasm_inputasm_outputaddr_vecaddr_diff_vectrap_ifunspecunspec_volatileparallelsequence。もし parallel なら、parallel の各要素もこれらのコードでなければならない。ただし、parallel 式はネストできないこと、addr_vecaddr_diff_vecparallel 式の内側では許されないという例外がある。
INSN_CODE (i)
マシン記述中のどのパターンがこの insn にマッチするかを特定する整数である。照合がまだ行なわれていないなら -1 を返す。

useclobberasm_inputaddr_vecaddr_diff_vec のどれか一個を使った式からなるパターンを持つ insn については、照合は行なわれず、このフィールドは -1 のまま変わらない。

asm 文から生じる insn の場合も照合は行なわれない。これらの insn は少なくとも一個の asm_operands 式を含む。このような insn に対して、関数 asm_noperands は非負の値を返す。

デバッグ出力では、このフィールドは数字の後に記号名表現が出力される。この記号名表現は、md ファイル中のパターンの位置を、名前付きパターンからの小さな正または負のオフセットとして示す。

LOG_LINKS (i)
基本ブロック内の命令間の依存関係についての情報を与えるリスト(insn_list 式の連鎖)。ジャンプやラベルは、関係のある insn の間には入らない。
REG_NOTES (i)
insn について種々雑多な情報を与えるリスト(expr_list 式とinsn_list 式の連鎖)。その insn で使われているレジスタに関係する情報であることが多い。

insn の LOG_LINKS フィールドは、insn_list 式の連鎖である。それぞれの insn_list 式はオペランドを二つ取る。一番目はある insn であり、二番目は別の insn_list 式(連鎖の次のもの) である。連鎖の最後の insn_list では、二番目のオペランドはヌルポインタとなる。連鎖について重要なことは、どの insn が(insn_list 式の一番目のオペランドとして)その中に現れるかということである。順序は重要ではない。

このリストは最初、フロー解析パスにより設定される。それまではヌルポインタになっている。フロー解析パスは、命令組合せで使用可能なデータ依存関係についてのリンクを追加するだけである。フロー解析パスは、insn 毎に、この insn で始めて使われる値をレジスタに格納する insn へのリンクを追加する。命令スケジューリングパスは、余分のリンクを追加して、あらゆる依存関係が表現されるようにする。リンクは、データ依存関係、逆依存関係、出力依存関係を表す。リンクのマシンモードがこの三つの型を区別する。逆依存関係のモードは REG_DEP_ANTI であり、出力依存関係のモードは REG_DEP_OUTPUT であり、データ依存関係のモードは VOIDmode である。

insn の REG_NOTES フィールドは、LOG_LINKS と同様の一個の連鎖であるが、insn_list 式に加えて expr_list 式も含んでいる。色々な種類のレジスタノートがあり、それらはマシンモードにより区別され、あるレジスタノート中では、実際に enum reg_note であると理解される。このノートの第一オペランド op は、ノートの種類によって意味の異なるデータである。

マクロ REG_NOTE_KIND (x) は、レジスタノートの種類を返す。これと対をなすマクロ PUT_REG_NOTE_KIND(x, newkind) は、x のレジスタノートのタイプを newkind に設定する。

レジスタノートには三つのクラスがある。何か insn への入力に関するもの、何か insn の出力に関するもの、それに、二つの insn の間のリンケージを作るものである。また、LOG_LINKS でしか使われない値が一セットある。

以下のレジスタノートは、insn への入力についての注釈である。

REG_DEAD
op の中の値がこの insn で死ぬ。つまり、この insn の直後でこの値を書き換えても、プログラムの以後の動作には影響を与えない。

これは、必ずしも、レジスタ op がこの insn 以後意味のある値を持たないということを意味しない。この insn の出力にもなることがあるからである。しかし、その場合、REG_DEAD ノートは冗長であり、普通は再ロードパス迄は存在しない。だが、このことを前提としているコードはない。

REG_INC
レジスタ op は、この insn 内に埋め込まれた副作用によりインクリメント(あるいは、デクリメント。このレベルでは違いはない) される。すなわち、これは post_inc 式、または pre_inc式、post_dec 式、pre_dec 式に現れる。
REG_NONNEG
この insn に到達したとき、レジスタ op は非負の値を持つことが知られている。これを使って、例えば m68k の dbra のような、デクリメントして 0 でない間は分岐する(decrement and branch until zero) 命令がマッチすることが可能になる。

REG_NONNEG ノートが insn に付加されるのは、マシン記述に decrement_and_branch_until_zero というパターンがある場合のみである。

REG_NO_CONFLICT
この insn は、たとえ衝突を引き起こすように見えても、op とこの insn により設定されるアイテムとの間の衝突を引き起こさない。言い換えると、そうなっていないと代入先レジスタと op が同じレジスタに割り当てられる場合でも、この insn はその割当を妨げない。

このノートがある insn は、通常、あるブロックの一部である。このブロックは複数ワードの疑似レジスタを指定する一個の clobber insn で始まり、それぞれが一ワードの値を設定し、REG_NO_CONFLICT が付随している insn のグループが一つ、最後に、計算される式を与えるREG_EQUAL ノートをつけて、出力をそれ自身にコピーする insn が来る。このブロックは、先頭と末尾の insn について、それぞれ REG_LIBCALL ノートと REG_RETVAL ノートで包み込まれている。

REG_LABEL
この insn は opcode_label を使うが、jump_insn ではない。このノートにより、op が実際に使われることをジャンプ最適化に対して知らせる。

以下のノートは、insn の出力の属性を記述する。

REG_EQUIV
REG_EQUAL
このノートは、一個のレジスタだけを設定する insn についてのみ有効であり、そのレジスタが実行時には op に等しいことを示す。これが等しくなる範囲は、二つのノートのタイプで異なる。この insn が明示的にそのレジスタにコピーする値は op とは違って見えるかもしれないが、実行時には等しくなる。一個の set の出力が strict_low_part 式なら、このノートは subreg 式の SUBREG_REG に含まれているレジスタを参照している。

REG_EQUIV の場合は、レジスタは関数全体を通して op に等価であり、全て op で正当に置き換えることができる。(ここで「正当に」はプログラムのデータ流を指す。単純な置き換えは幾つかの insn を不正にする。) 例えば、ある定数が、他の値が決して代入されることのない、あるレジスタにロードされるとき、この種類のノートが使われる。

ある仮引数が関数の入り口点で疑似レジスタにコピーされるとき、この種類のノートが仮引数が渡されたスタックスロットに等価なレジスタを記録する。この場合、レジスタは他の insn により設定されることもあるが、その関数内でそのレジスタをスタックスロットに置き換えることはなお有効である。

REG_EQUIV は、仮引数を格納可能なスタックスロットがある場合、ある関数の入り口でレジスタ仮引数を疑似レジスタにコピーする命令で使われる。他の insn がその疑似レジスタを設定する可能性もあるが、コンパイラにとっては、関数全体で疑似レジスタをそのスタックスロットに置き換えるのは正当である。ただし、コンパイラは、そのスタックスロットが、最初のコピー命令での同じように置き換えを行なうことで適切に初期化されていることを保証されている場合である。これは、呼び出し規約でレジスタ仮引数についてスタックスペースを割り当てるようになっている機種で使われる。Stack ArgumentsREG_PARM_STACK_SPACE を参照のこと。

REG_EQUAL の場合は、この insn により設定されるレジスタは、この insn の最後では実行時に op に等価になるが、関数内の他の場所では必ずしも等価ではない。この場合、op は算術式であることが多い。例えば、ライブラリ呼び出しのような insn 列が、ある算術演算を実行するのに使われるとき、この種類のノートが最終的な値を生成したりコピーする insn に付随する。

これらの二つのノートは、コンパイラのパス群により異なる方法で使われる。REG_EQUAL は、レジスタ割当に先立つパス(例えば、共通部分式削除とループ最適化)により使われ、その値をどう考えれば良いかをそのパスに知らせる。REG_EQUIV ノートは、レジスタ割当により使われ、利用可能なレジスタが足りなければ、レジスタの代わりに使われる代入式(定数か、スタック上の仮引数の位置を表す mem 式) が利用可能であることを示す。

仮引数のスタックのホームとそのライフタイムを通じてメモリ位置に等かな疑似レジスタを除いて、全ての等価なものは、付随する REG_EQUAL ノートにより最初に示される。ここで、仮引数のスタックホームは、REG_EQUIV ノートにより指示され、最適化の最初の方のパスでは役に立たない。また、メモリ位置に等価な疑似レジスタは、コンパイルの後の段階になるまで検出されない。op が定数であり、その insn がその代入先レジスタの組を一つしか表現しないのであれば、レジスタ割当の初期の段階で、REG_EQUAL ノートは REG_EQUIV ノートに変えられる。

こうして、レジスタ割当より前のコンパイラのパスでは、REG_EQUAL ノートだけを検査する必要があり、レジスタ割当の後のパスではREG_EQUIV ノートだけを検査すれば良い。

REG_UNUSED
この insn により設定されるレジスタ op は、次の insn では使われない。REG_DEAD ノートとの違いは、REG_DEAD の方は、入力中の値が後で使われることがないことを示す点にある。この二つのノートは独立であり、同じレジスタに対して両方とも存在してもかまわない。
REG_WAS_0
この insn の一個の出力は、この insn の前にゼロを含んでいた。op が、ゼロに設定した insn である。このノートが存在し、かつ op が削除されていたり、note に変換されたりしていなければ、このノートを信頼することができる。このノートが存在しない場合は、何も意味しない。

以下のノートは、insn 間のリンケージを記述する。これらは、対で現れる。一個の insn には、ノートの対があり、それらは二番目の insn を指す。二番目の insn には、最初のinsn を指す逆のノートがある。

REG_RETVAL
この insn は、複数の insn から成る列(例えば、ライブラリ呼び出し)の値をコピーする。op は、列の先頭の insn である(ライブラリ呼び出しの場合は、ライブラリ呼び出しの引数を設定するように生成された先頭の insn である)。

ループ最適化はこのノートを使って、コードの移動の目的のために、このような列を一個の演算として取り扱う。また、フロー解析ではこのノートを使って、このような列で結果が死んでいるものを削除する。

通常、REG_EQUAL ノートもこの insn に付属し、この列により計算される式を提供する。

これらのノートは再ロード後に削除される。もはや不正確だったり役に立たなかったりするからである。

REG_LIBCALL
これは、REG_RETVAL の逆である。これは複数 insn の列の先頭の insn に置かれ、最後の insn を指す。

これらのノートは再ロード後に削除される。もはや不正確だったり役に立たなかったりするからである。

REG_CC_SETTER
REG_CC_USER
cc0 を使う機種では、cc0 を設定したり使ったりするinsn はお互いに近くにある。だが、遅延分岐スロットを埋める処理が行なわれると、もはや近くにあるとは言えなくなる可能性がある。その場合、REG_CC_USER ノートが、cc0 を設定する insn に置かれて、cc0 を使う insn を指し、REG_CC_SETTER ノートがcc0 を使う insn に置かれて、cc0 を設定する insn を指すようになる。

以下の値は、LOG_LINKS フィールドでのみ使われ、各リンクが表現する依存関係の型を指し示す。データ依存関係(書き込み後の読み込み依存関係, read after write dependence) を指し示すリンクはどのコードも使わず、単にモードが VOIDmode であり、何の説明文もなく出力される。

REG_DEP_ANTI
これは逆依存関係(WAR、読み込み後の書き込み依存) を示す。
REG_DEP_OUTPUT
これは出力依存関係(WAW、書き込み後の書き込み依存)を示す。

これらのノートは gcov によるプロファイルデータから収集した情報を記述する。insn の REG_NOTES フィールドに expr_list として格納される。

REG_EXEC_COUNT
プロファイルデータに基づく、基本ブロックの実行回数を示す。このノートは、基本ブロックの先頭の insn に付加される。
REG_BR_PROB
プロファイルデータに基づく、ある分岐 insn の、分岐が行なわれた回数と行なわれなかった回数の比を示す。0 と REG_BR_PROB_BASE の間の値として格納される。値が大きくなると、分岐が成立する確率がより高くなることを示す。
REG_BR_PRED
このノートは、遅延分岐スケジューリングが起きた後のジャンプ insn に現れる。これらは、ジャンプの方向と可能性を示す。フォーマットは、ATTR_FLAG_* 値のビットマスクである。
REG_FRAME_RELATED_EXPR
これは、RTX_FRAME_RELATED_P insn で使われる。この insn では、付属した式が、実際の insn パターンの代わりに使われる。これは、パターンが複雑か間違っている場合に行われる。

便宜上、insn_listexpr_list 中のマシンモードは、デバッグダンプでは、これらのシンボリックコードで出力される。

式コード insn_listexpr_list の唯一の相違点は、insn_list の先頭のオペランドは insn であると仮定され、デバッグダンプ中では insn の一意的な ID として出力されること、expr_list の先頭のオペランドは式として通常の方法で出力される点にある。


Node:Calls, Next:, Previous:Insns, Up:RTL

関数呼び出し insn の RTL 表現

サブルーチンを呼び出す insn は、RTL 式コードが call_insn になる。サブルーチン呼び出し insn は特別な規則に従う必要があり、本体部分で特別な RTL 式コード call を使わなければならない。

call 式は、以下のようにオペランドを二つ取る。

(call (mem:fm addr) nbytes)

ここで、nbytes は、サブルーチンに渡される引数データのバイト数を表すオペランドである。fm はマシンモードであり、addr はサブルーチンのアドレスを表す。fm は、マシン記述の FUNCTION_MODE マクロの定義と同じでなければならない。

値を返さないサブルーチンについては、上に示した call 式そのものがinsn の全体になる。ただし、use 式か clobber 式をその他に含んでいる必要がある。

戻り値があり、そのモードが BLKmode でないサブルーチンについては、戻り値はハードレジスタに置かれる。このレジスタの番号が r なら、call insn の本体は以下のようになる。

(set (reg:m r)
     (call (mem:fm addr) nbytes))

この RTL 式は、この insn で、適切なレジスタに有効な値が置かれることを(最適化パスに対して)はっきりさせる。

サブルーチンが BLKmode の値を返すなら、その値を格納すべき位置のアドレスをサブルーチンに渡すという処理が行なわれる。このため、call insn 自身はどんな値も返さないので、値を返さない呼び出しと同じ形式の RTL になる。

マシンによっては、call 命令自身が幾つかのレジスタを、例えば戻り先アドレスを保持するために、破壊する。そういうマシンでの call_insn insn の本体は、call 式と clobber 式の両方を持つ、一個の parallel とすべきである。この clobber 式は、どのレジスタが破壊されるかを示す。同様に、call 命令が、スタックポインタ以外に、RTL で明示的に指定されていないレジスタを必要とするときは、use 副式がそのレジスタについて言及すべきである。

呼び出される関数は、コンフィギュレーションマクロ CALL_USED_REGISTERS (see Register Basics)に列挙されている全てのレジスタを修正し、const 関数とライブラリ呼びだしを例外として、全メモリを修正すると仮定される。

単に use 式を含む insn は、どのレジスタが関数への入力を保持しているかを示す call_insn の直前に位置する。同様に、CALL_USED_REGISTERS で指定されている以外のレジスタが呼び出された関数により上書きされるなら、単独の clobber を含む insn は、それがどのレジスタかを示すために、その呼び出しの直後に置かれる。


Node:Sharing, Next:, Previous:Calls, Up:RTL

構造の共有の前提

GNU CC は、ある種類の RTL 式は一意的であることを仮定している。すなわち、同じ値を表す二つの異なるオブジェクトは存在しないと仮定しているのである。一方、それとは逆の、ある種類の RTL 式オブジェクトは、それを含む構造の中では 2 回以上現れることはないという仮定をしている場合もある。

これらの仮定は一個の関数に関するものである。グローバル変数や外部関数を記述する RTL オブジェクト、それに小さな整数定数のような2,3の基本的なオブジェクトを除いて、二つの関数に共通の RTL オブジェクトは存在しない。


Node:Reading RTL, Previous:Sharing, Up:RTL

RTL の読み込み

ファイルから RTL オブジェクトを読み込むには、read_rtx 関数を使う。引数は、標準入力ストリーム一つであり、一個の RTL オブジェクトを返す。

ファイルから RTL を読む処理は非常に遅い。現時点ではこれは問題ではない。RTL の読み込みは、コンパイラを構築するときにのみ行われるからである。

RTL をテキストとしてファイルにセーブして、GNU CC の言語フロントエンドとその他の部分とのインターフェースとして使おうと考える人が良くいるが、これは実現不可能である。

GNU CC は、RTL を内部表現として使うようにしか設計されていない。ある与えられたプログラムに対する正しい RTL は、特定のターゲットマシンに著しく依存する。しかも、RTL は、そのプログラムについての情報を全部は含んでいないのである。

GNU CC と新しい言語フロントエンドのインターフェースを取る正しい方法は、「tree」データ構造を使う事である。このデータ構造について書いたマニュアルはないが、tree.htree.def で説明されている。


Node:Machine Desc, Next:, Previous:RTL, Up:Top

機械記述

マシン記述は二つの部分からなる。機械命令のパターンを記述するファイル(.md ファイル) と C のマクロ定義を記述するヘッダファイルである。

あるターゲットマシン向けの .md ファイルは、そのマシンがサポートしている各機械命令(あるいは、少なくとも、GCC が知っていたほうが良い機械命令) のパターンを記述する。このファイルにはコメントを書くことができる。コメントはセミコロンから始まり行末までとなる。ただし、セミコロンが引用符つき文字列中にある場合を除く。

C のヘッダファイルについては、次章を見ていただきたい。


Node:Patterns, Next:, Previous:Machine Desc, Up:Machine Desc

命令パターンの全て

各命令パターンには、後で埋められる部分を持つ不完全な RTL 式と、各部分がどのように埋められるかを限定するオペランド制約、それに、出力パターンまたはアセンブラ出力を生成する C コードが含まれており、全て define_insn 式中に記述される。

define_insn は一つの RTL 式で、四つか五つのオペランドを持つ。それぞれのオペランドは以下の通りである。

  1. 名前。無くても良い。名前があると、その命令パターンが、GCC の RTL生成パスにおいてある決まった仕事を成しうるということを意味する。RTL生成パスは一定のパターン名を知っていて、マシン記述に定義されている名前であれば、その名前の命令パターンを使おうとする。

    名前を書くべき位置に空文字列を書くと名前がないということになる。名無しの命令パターンは RTL コードの生成に使われることはありえない。しかし、名無しの命令パターンを使うと、様々なより単純な insn を後で結合させることが出来る。

    つまり、RTL生成時に知られていない、あるいは使われもしない名前は何の効果ももたらさない。名無しと全く同じである。

  2. RTL テンプレート (see RTL Template) は、不完全な RTL 式を要素とするベクトルであり、命令がどのように見えるかを示す。不完全というのは、その命令のオペランドの代理である、match_operandmatch_operatormatch_dup 等の式を含むからである。

    RTL テンプレート・ベクトルに要素が一つしかなければ、その要素は命令パターンのテンプレートである。ベクトルに要素が複数あれば、その命令パターンは列挙された要素を含む parallel 式である。

  3. 条件。これは文字列であり、insn 本体がパターンにマッチするかどうかを最終的に決定するための条件を C 言語の式で表したものである。

    名前を持つパターンについては、条件は(もしあれば)、マッチする insn 中のデータには依存せず、ターゲット機種の型のフラグにのみ依存する。GCC は、初期化時にこの条件を調べて、どういう名前の命令が一回毎の実行時に利用できるのかを厳密に調べる必要がある。

    名無しのパターンについては、条件は個々の insn とのマッチングを行なう時と、insn が、そのパターンの評価テンプレートにマッチした後にのみ適用される。insn のオペランドは、ベクトル operands に入っている。

  4. 出力テンプレート。 マッチした insn をどのようにアセンブラコードとして出力するかを指示する文字列である。文字列中の % は、オペランドの値をどこに代入するかを指示する。See Output Template.

    単なる置き換えでは充分でないときは、C コードの断片を指定して、計算を行なったうえで出力させることも出来る。See Output Statement.

  5. このパターンにマッチする insn の属性値を含むベクトル。省略可能である。 See Insn Attributes.


Node:Example, Next:, Previous:Patterns, Up:Machine Desc

define_insn の例

以下は、命令パターンの実例である。68000/68020 向けである。

(define_insn "tstsi"
  [(set (cc0)
        (match_operand:SI 0 "general_operand" "rm"))]
  ""
  "*
{ if (TARGET_68020 || ! ADDRESS_REG_P (operands[0]))
    return \"tstl %0\";
  return \"cmpl #0,%0\"; }")

これは、汎用レジスタの値に基づいて条件コードをセットする命令である。条件の指定がないので、RTL 記述が指定された形を持つ任意の命令が、このパターンに従って扱われる。tstsi という名前は、"test a SImode value"(SImode の値をテストする)という意味で、RTL 生成パスに対して、SImode の値をテストする必要があるときは、それを行う命令はこのパターンを使って構成せよということを指示する。

出力制御文字列は、C コードの断片であり、どの出力テンプレートを返すかを、オペランドの種類とコードを生成しようとしている CPU の特定の型に基づいて選択する。

"rm" は、オペランド制約(constraint)である。この意味は以下で説明する。


Node:RTL Template, Next:, Previous:Example, Up:Machine Desc

RTL テンプレート

RTL テンプレートを使い、どの insn が特定のパターンにマッチするのか、および、そのオペランドの見つけ方を定義する。名前付きパターンの場合は、RTL テンプレートは、指定されたオペランドからどのように insn を構築するかについても指示する。

構築するということには、指定されたオペランドをテンプレートのコピーに代入することも含まれる。照合することには、一致しようとしている insn のオペランドの役割を果たす値を決定することも含まれる。どちらの動作も、照合とオペランドの代入を指示する特別な式の型により制御される。

(match_operand:m n predicate constraint)
この式は、insn の n 番目のオペランドのプレースホルダーである。insn の構築時に、n番目のオペランドがここに挿入される。insn の照合時には、insn のこの位置に現れるものは何であれ、n 番目のオペランドとして扱われる。ただし、その場合 predicate を満たしている必要があり、さもなければこの命令パターンは全くマッチしない。

オペランド番号は、各命令パターンにおいて 0 から始まる数字にならなければならない。各オペランド番号について、パターンにはmatch_operand 式が一個だけ存在し得る。普通は、オペランドは match_operand 式群に現れた順に番号が付く。define_expand の場合には、match_dup 式でのみ使用されるオペランド番号はどれも、他のどのオペランド番号よりも大きな値になる。

predicate は、ある C の関数名を表す文字列でり、その関数は二つの引数、すなわち一個の式と一個のマシンモードを受け付ける。照合が行なわれる間に、式として仮想的なオペランド、モード引数として m を使ってその関数が呼び出される。(m が指定されない場合は、VOIDmode が使われ、predicate は任意のモードを受け付けることになる。) この関数が 0 を返した場合は、この命令パターンの照合に失敗することになる。predicate は空の文字列であっても良い。その場合、オペランドについては何のテストも行なわれず、この位置に現れるものは何でも有効になる。

ほとんどの場合、predicatem 以外のモードを受け付けない。ただし、いつでも受け付けないわけではない。例えば、述語(predicate) address_operand は、m を、そのアドレスが有効なメモリ参照のモードとして使う。多くの述語は、それらのモードが VOIDmode であっても const_int ノードを受け付ける。

constraint は再ロードとある値に最適なレジスタクラスの選択を制御する。これについては後で説明する (see Constraints)。

制約と述語の違いが良く判らないという人が多い。述語は、ある与えられた insn がパターンにマッチするかどうかを判断する手助けをする。一方、制約は、この判断には関与しない。代わりに、insn がパターンにマッチした場合の色々な判断を制御するのである。

CISC では、最も良く出てくる述語は、"general_operand" である。これは、仮想オペランドが、定数であるのか、レジスタなのか、メモリ参照なのかを調べ、それがモード m で有効なのものかどうかを確かめる。

レジスタでなければならないオペランドの場合は、述語としては"register_operand" を使うべきである。再ロード過程で"general_operand" を使っても、任意の非レジスタオペランドをレジスタにコピーするという処理を行うので大丈夫だが、そうすると GCC に余計な仕事をさせることになるし、ループからの不変オペランド(例えば定数)の除去や最適なレジスタ割り付けの妨げにもなる。RISC の場合には、述語としては、制約が許す範囲のオブジェクトのみを受け付けるようにするのが一般には最も効率が良い。

定数であるはずのオペランドの場合には、述語として "immediate_operand" を使うか、命令パターンの付加条件が定数を要求するようにするか、あるいは両方を行うようにする必要がある。制約を使えば同じことが出来るだろうと考えてはいけない。制約の方が定数のみを許すようになっていても、述語がそれ以外のものを許しているなら、実際にそのケースが発生したときにGCC は落ちてしまうのである。

(match_scratch:m n constraint)
この式もオペランド番号 n のプレースホルダであり、オペランドはscratch 式か reg 式でなければならないことを指定する。

パターン照合の際には、これは、以下の式と等価である。

(match_operand:m n "scratch_operand" pred)

しかし、RTL 生成フェーズでは、これは (scratch:m) という式を生成する。

parallel の中の最後の幾つかの式が clobber 式であり、その clobber 式のオペランドがハードレジスタか match_scratch なら、結合器(combiner) は必要なときにそういうオペランドを追加したり、削除したりすることができる。

(match_dup n)
この式もオペランド番号 n のプレースホルダーである。オペランドが insn の二箇所以上に現れる必要があるときに使われる。

構築の際には、match_dup はちょうど match_operand と同様に動作する。オペランドは、構築されつつある insn に代入される。しかし、マッチングでは、match_dup の動作は異なる。オペランド番号 n は認識テンプレートに先に現れる match_operand により既に決まっており、見た目が同一の式にしかマッチしないということを想定している。

(match_operator:m n predicate [operands...])
このパターンは、可変な RTL 式コードの一種のプレースホルダーである。

insn 構築の際には、ある RTL 式を表す。この RTL 式の式コードは、オペランド n から取られ、オペランドはパターンの operands から構築される。

式と照合する際は、関数 predicate がその式についてゼロでない値を返し、かつ パターンの operands がその式のオペランドにマッチしたときに、その式にマッチする。

関数 commutative_operator が以下のように定義されているとする。演算子が RTL の交換可能な算術演算子の一つで、モードが mode である任意の式にマッチするように定義されている。

int
commutative_operator (x, mode)
     rtx x;
     enum machine_mode mode;
{
  enum rtx_code code = GET_CODE (x);
  if (GET_MODE (x) != mode)
    return 0;
  return (GET_RTX_CLASS (code) == 'c'
          || code == EQ || code == NE);
}

そうすると、以下のパターンは、二つの一般オペランドに適用される交換可能な演算子を含む任意の RTL 式にマッチする。

(match_operator:SI 3 "commutative_operator"
  [(match_operand:SI 1 "general_operand" "g")
   (match_operand:SI 2 "general_operand" "g")])

ここでベクトル [operands...] は、二つのパターンを含んでいる。なぜなら、マッチすべき式は全て二つのオペランドを含んでいるからである。

このパターンがマッチしたとき、交換可能な演算子の二つのオペランドは、この insn のオペランド 1 とオペランド 2 として記録される。(これは、二つの match_operand により行なわれる。) この insn のオペランド 3 は、交換可能な式全体である。

match_operator のマシンモード m は、match_operand のものと同様に振る舞う。述語関数の二番目の引数として渡され、その関数だけが、マッチすべき式がそのモードを「持っているか」どうかを決定する責任がある。

insn を構築する際には、生成関数の第三引数が、作成されるべき式の演算(すなわち式コード)を指定する。この引数は一個の RTL 式であるべきで、その式コードが、生成関数の引数 1 と 2 をオペランドとする新しい式にコピーされる。引数 3 のサブ式は使われない。式コードだけが問題になる。

match_operator が、insn と照合されるパターンで使われているとき、その match_operator のオペランド番号が、その insn の実際のオペランド番号よりも大きいのが通常は最善である。これによりレジスタ割当が改良される。レジスタ割当では、insn のオペランド 1 と 2 を見て、レジスタの結び付けが可能かどうかを見るからである。

match_operator に制約を指定する方法はない。match_operator に対応する insn のオペランドはどんな制約も持つことはない。全体として再ロードされることがないからである。だが、その operands の一部が match_operand パターンにより照合が行なわれると、その一部はそれ自身の制約があって良い。

(match_op_dup:m n[operands...])
match_dup に似ているが、オペランドではなく演算子に適用される。insn を構築するときは、オペランド番号 n がここに代入される。しかし、マッチングの際には match_op_dup の動作は異なる。オペランド番号 n は認識テンプレートに先に現れる match_operator により既に決まっており、見た目が同一の式にしかマッチしないということを想定している。
(match_parallel n predicate [subpat...])
このパターンは、可変数要素の parallel 式一個からなる insn のプレースホルダーである。この式は、insn パターンの最上位レベルにのみ現れるべきである。

insn を構築する際には、オペランド番号 n がこの点で置き換えられる。insn との照合の際には、insn 本体が parallel 式であり、このparallel 式が、少なくとも match_parallel 中の subpat 式の insn ベクトルの要素数と同じ要素数を持つのであれば、各 subpatparallel の対応する要素に一致し、かつ、関数 predicate が insn の本体である parallel に対してゼロでない値を返すなら、一致が起きる。match_parallel に列挙されたもの以外の parallel の要素を確認するのは述語の役割である。

match_parallel の代表的な使い方は、ロードマルチプル式とストアマルチプル式にマッチさせることである。例えば、

(define_insn ""
  [(match_parallel 0 "load_multiple_operation"
     [(set (match_operand:SI 1 "gpc_reg_operand" "=r")
           (match_operand:SI 2 "memory_operand" "m"))
      (use (reg:SI 179))
      (clobber (reg:SI 179))])]
  ""
  "loadm 0,0,%1,%2")

この例は、a29k.md から取ったものである。関数 load_multiple_operations は、a29k.c で定義されており、parallel 中の後続の要素が、このパターンの中のset と同じであるかどうかを検査している。その要素が、後続のレジスタとメモリ位置を参照している場合を除く。

このパターンにマッチする insn は以下のような形式である。

(parallel
 [(set (reg:SI 20) (mem:SI (reg:SI 100)))
  (use (reg:SI 179))
  (clobber (reg:SI 179))
  (set (reg:SI 21)
       (mem:SI (plus:SI (reg:SI 100)
                        (const_int 4))))
  (set (reg:SI 22)
       (mem:SI (plus:SI (reg:SI 100)
                        (const_int 8))))])

(match_par_dup n [subpat...])
match_op_dup と同様だが、match_operator ではなくmatch_parallel 用である。
(match_insn predicate)
完全な insn にマッチする。他の match_* 認識器とは異なり、match_insn はオペランド番号を取らない。

match_insn のマシンモード m は、match_operand と同様の働きをする。述語関数の第二引数として渡され、マッチした式のモードがそのモードになっているかどうかを決定する責任はその関数にだけある。

(match_insn2 n predicate)
完全な insn にマッチする。

match_insn2 のマシンモード m は、match_operand と同様の働きをする。述語関数の第二引数として渡され、マッチした式のモードがそのモードになっているかどうかを決定する責任はその関数にだけある。

(address (match_operand:m n "address_operand" ""))
この複雑な式は、「ロードアドレス」命令中のオペランド番号 n のプレースホルダーである。このオペランドは普通はメモリ位置を指定するが、実際のオペランド値として使われるのはその位置のアドレスであり、その位置の内容ではない。

address 式は RTL コードには決して現れず、マシン記述でのみ使われる。そして、オペランド制約の機能を使わないマシン記述でしか使われることがない。オペランド制約が使われる場合は、制約の文字 p がこの目的を果たす。

m は、アドレスとなるメモリ位置のマシンモードであり、アドレス自身のマシンモードではない。このモードは、ある与えられたターゲットマシン上では常に同じなので(Pmode で、これは普通は SImode である)、それをわざわざ明記する意味はない。つまり、address 式にはマシンモードは書かないのである。いつの日か、異なる種類のオブジェクトのアドレスが異なって見えたり、(PDP-10 のように)使い方が異なっていたりするマシンがサポートされたら、異なる形式はおそらく異なるマシンモードを必要とし、そのモードをaddress 式に書くことになるだろう。


Node:Output Template, Next:, Previous:RTL Template, Up:Machine Desc

出力テンプレートとオペランド置換

出力テンプレートは文字列であり、ある命令パターンに対するアセンブラコードをどのように出力するかを指定する。テンプレートのほとんどの部分は、固定文字列であり、そのまま出力される。文字 % を使って、オペランドが代入される位置を指定する。また、アセンブラに変種があるために異なる構文を必要とする場所を特定するのにも使われる。

一番単純な場合では、% の数字 n が続いた場合は、文字列のその部分にオペランド n を出力することを示す。

% の直後に英字1文字と数字1文字が続くと、オペランドの出力形式を別のものに変えることを意味する。英字としては四つの文字が標準で組み込み済の意味を持っており、以下で解説する。マシン記述マクロ PRINT_OPERAND を使って、標準ではない意味を持つ文字を追加定義することができる。

%cdigit を使うと、通常は即値オペランドである事を示す構文を使わなくても、定数値であるオペランドを置き換えることができる。

%ndigit は、表示前に定数値が否定を取られることを除けば %cdigit に同じである。

%adigit を使ってそれがあたかもメモリ参照であるかのように、あるオペランドをアドレスとして扱われる実際のオペランドと置き換えることができる。これは、「ロードアドレス」命令を出力する際に役に立つ。そういう命令のアセンブラ構文では、オペランドをあたかもメモリ参照であるかのように書くことを要求することが多いからである。

%ldigit は、ジャンプ命令に label_ref を代入するのに使われる。

%= は、各命令に対し、コンパイルの全過程で一意的な番号を出力する。これは、複数のアセンブラ命令を生成する一個のテンプレート中で二回以上参照されるローカルラベルを作るときに便利である。

% の後ろに区切り文字が続くと、オペランドを使わない置き換えであることを指定する。標準的な使い方は一個だけである。%% とするとアセンブラコードに % を出力する。その他の非標準的な場合は、マクロ PRINT_OPERAND で定義することができる。また、どの区切り文字が有効かをマクロ PRINT_OPERAND_PUNCT_VALID_P で定義しなければならない。

テンプレートは複数のアセンブラ命令を生成して良い。その場合には、各命令を \; で区切って書く。

RTL にオペランドが二つあり、制約によりその二つが互いに一致することが要求されている場合には、出力テンプレートでは、数字の小さい方のオペランドしか参照してはならない。一致したオペランドはいつも同じではなく、コンパイラの残りの部分で、数字の小さい方のオペランドに出力する適切な RTL 式を置くように調整する。

% の後ろに標準でない英文字や区切り文字を置く使い方の一つに、同一のマシンに対する異なるアセンブラ言語を区別することがある。例えば、68000 には Motorola 形式と MIT 形式がある。Motorola 形式では、ほとんどのオペコード名にピリオドを使うのに対し、MIT 形式では使わない。例えば、MIT 形式で movel と書くオペコードは、Motorola 形式では move.l となる。両方の出力形式に対して同じパターンファイルを使用するが、Motorola 形式でピリオドが必要な場所には文字シーケンス %. を使うようにする。マクロ PRINT_OPERAND は、Motorola 形式では、ピリオドを出力するシーケンスを定義し、MIT 形式向けには何もしないマクロとして定義する。

特別な場合として、テンプレートが一個の文字 # から成っているとコンパイラに対し、最初に insn を分割し、次にその結果の命令を別々に出力することを指示する。これは、出力テンプレートの冗長性を消去するのに役立つ。複数のアセンブラ命令を出力する必要がある define_insn があり、マッチする define_split が既に定義されているなら、出力テンプレートとして単に # を使うことができ、複数のアセンブラ命令を出力する出力テンプレートを書く必要はない。

マクロ ASSEMBLER_DIALECT が定義されていれば、テンプレートで {option0|option1|option2}という形式の構文を使うことができる。アセンブラ言語の文法の複数の方言を記述する。See Instruction Output.


Node:Output Statement, Next:, Previous:Output Template, Up:Machine Desc

アセンブラ出力用の C 言語の文

一個の固定テンプレート文字列だけでは、一つの命令パターンで認識される全てのケースに対して、正確で効率の良いアセンブラコードを生成するのが難しいということが良くある。例えば、オペコードはオペランドの種類に依存することがある。あるいは、オペランドの組合せが悪いと余分の機械命令が必要なこともある。

そういうときは、出力制御文字列を @ で開始すると、一行に一個ずつ置いたテンプレートの列とすることが出来る。(空行や行頭の空白、タブは無視される。) このテンプレート群は、命令パターン中の制約の選択肢に対応する(see Multi-Alternative)。例えば、ターゲットの機種が、アドレスを二つ取る加算命令として、レジスタに加算する命令 addr とレジスタの値をメモリ中に加算する命令addm の二つの命令を持っている場合、以下のようにパターンを書くことができる。

(define_insn "addsi3"
  [(set (match_operand:SI 0 "general_operand" "=r,m")
        (plus:SI (match_operand:SI 1 "general_operand" "0,0")
                 (match_operand:SI 2 "general_operand" "g,r")))]
  ""
  "@
   addr %2,%0
   addm %2,%0")

出力制御文字列が * で始まっている場合は、出力テンプレートそのものではなくて、テンプレートを生成する C のコード断片であることを示す。この C コード断片は、return 文を使って、テンプレート文字列を返す必要がある。このテンプレートは C の文字列リテラルを使う場合が多い。文字列リテラルの場合は区切り記号として二重引用符が必要である。テンプレート文字列に二重引用符を含めるには、\ でエスケープする必要がある。

オペランドは、operands という、rtx [] 型の配列に収められている。

即値オペランドが、ある一定の範囲内におさまるかどうかによって、異なるアセンブラコードの生成方法を選択するのは非常に良く行なわれる。しかし、その場合には注意が必要である。とうのは、INTVAL の結果はホストマシンでの整数になるからである。ホストマシンの int のビット数が、ターゲットマシンの定数で使われるモードのビット数より大きければ、INTVAL から得られるビットのいくつかは余計なものである。正しい結果を得るためには、この余分なビットによる値を注意深く取り除かなければならない。

サブルーチン output_asm_insn を使って、あるアセンブラ命令を出力し、その後出力を続けたり、さらに計算を行なうことが可能である。この関数は引数を二つ取る。テンプレート文字列とオペランドのベクトルである。ベクトルは operands であっても良いし、あるいは読者がローカルに宣言し、自分で初期化した、別の rtx の配列でも良い。

ある insn のパターンで、制約に複数の選択肢がある場合は、アセンブラコードの見かけはどの選択肢にマッチしたかでほとんど決まることが多い。その場合、C のコードでは、変数 which_alternative をテストすることができる。この変数は、実際に条件にあった選択肢の順番を表す数(先頭の選択肢は 0で、二番目は 1、等々)である。

例えば、ゼロを格納する命令には、二つのオペコードがあるとしよう。レジスタの場合にはclrreg、メモリ位置の場合は clrmem である。以下に、あるパターンでどのように which_alternative を使って、オペコードを選択するかを示す。

(define_insn ""
  [(set (match_operand:SI 0 "general_operand" "=r,m")
        (const_int 0))]
  ""
  "*
  return (which_alternative == 0
          ? \"clrreg %0\" : \"clrmem %0\");
  ")

この例は、生成すべきアセンブラコードが選択肢だけで決まるなら、出力制御文字を @ で始めるようにすれば、以下のように指定することもできる。

(define_insn ""
  [(set (match_operand:SI 0 "general_operand" "=r,m")
        (const_int 0))]
  ""
  "@
   clrreg %0
   clrmem %0")


Node:Constraints, Next:, Previous:Output Statement, Up:Machine Desc

オペランド制約

ある命令パターンにおいて、match_operand のそれぞれに、許されるオペランドの型についての制約を指定することができる。制約により、次のような指定が可能である。あるオペランドがレジスタに置かれているかどうか、置かれているならどの種類のレジスタか。オペランドとしてメモリ参照が可能かどうか、可能ならどの種類のアドレスか。オペランドとして即値が可能かどうか、可能ならどういう値が可能か。制約は二つのオペランドが一致することを要求することもできる。


Node:Simple Constraints, Next:, Previous:Constraints, Up:Constraints

単純制約

最も単純な種類の制約は全部が英文字からなる文字列である。その一つ一つの文字が、許されるオペランドの一つの種類を記述する。以下に許される英文字を示す。

m
メモリオペランドを指定する。その機種が一般にサポートしているアドレスならどれでも良い。
o
メモリオペランドを指定する。ただし、許されるアドレスは「オフセット指定可能な」アドレスだけである。つまり、そのアドレスに小さな整数(実際には、マシンモードにより決まる、バイト数で表したオペランドの幅に収まる数)を加算した結果もまた有効なメモリアドレスとなる。

例えば、アドレスが定数であれば、それはオフセット指定可能である。一個のレジスタと一個の定数(ちょっと大きめの定数もその機種でサポートされている範囲のアドレスのオフセットになっている限り) の和もオフセット指定可能である。しかし、自動インクリメント、自動デクリメントのアドレスはオフセット指定可能でない。もっと複雑な間接/インデックス修飾アドレスがオフセット指定可能かどうかは、その機種がサポートする他のアドレッシングモードに依存する。

別のオペランドにマッチ可能な出力オペランドにおいては、制約文字 oは、<(ターゲット機種に事前デクリメントアドレッシングがあれば)と>(ターゲット機種に事前インクリメントアドレッシングがあれば)の両方を伴う場合にのみ有効である。

V
オフセット指定可能でないメモリオペランドを指定する。言い換えると、制約 m には収まるが、o には収まらないものは何でもここに入る。
<
自動デクリメントのアドレスのメモリオペランドを指定する。プリデクリメントでもポストデクリメントのどちらでも良い。
>
自動インクリメントのアドレスのメモリオペランドを指定する。プリインクリメントでもポストインクリメントのどちらでも良い。
r
レジスタオペランドが許される。ただし、レジスタは汎用レジスタである。
d, a, f, ...
他の文字は、機種依存の方法で、特定のレジスタクラスを表すように定義することができる。68000/68020 では、daf が定義されており、それぞれ、データレジスタ、アドレスレジスタ、浮動小数点レジスタを表す。
i
整数の即値オペランド(定数値のもの)が許される。これには、値がアセンブル時にならないとわからないシンボリックな定数も含まれる。
n
既知の数値を持つ整数即値のオペランドが許される。多くのシステムでは、語長よりも小さいオペランドにはアセンブル時の定数は使えない。そのようなオペランドの制約には i ではなく n を使うべきである。
I, J, K, ... P
他の、IP の間にある文字は、機種依存の方法で、指定された範囲の明示された整数値を持つ整数の即値オペランドを許すように定義することができる。例えば、68000 では、I は、1 〜 8 の範囲の値を表すと定義されている。これは、シフト命令で許されているシフト幅の範囲である。
E
浮動小数点の即値オペランド(式コードは const_double)が許される。ただし、ターゲットの浮動小数点形式がホストマシン(コンパイラが動作するマシン)のものと同じ場合に限られる。
F
浮動小数点の即値オペランド(式コードは const_double)が許される。
G, H
GH は、機種依存の方法で、特定の範囲の値の浮動小数点即値オペランドを許すように定義することができる。
s
値が明示的な整数ではない、整数即値オペランドが許される。

これは奇異に聞こえるかもしれない。もし、ある insn がコンパイル時には決まっていない値をもつ定数オペランドを許すなら、当然、どんな既知の値でも許さなければならないはずだ。どうして、i の代わりに s を使うのか? その方が、良いコードが生成されることがあるからなのだ。

例えば、68000 の全ワードの命令では即値オペランドを使うことができる。しかし、即値の範囲が -128 と 127 の間にあるなら、その値をレジスタにロードして、そのレジスタを使った方が良いコードになるのである。これは、レジスタへのロードが moveq 命令で行なえるからである。我々はこれが起きるように、文字 K が「-128 と 127 の範囲の外側の整数」という意味を持つように定義し、オペランドの制約にKs と指定している。

g
任意のレジスタ、メモリ、整数の即値のオペランドが許される。ただし、汎用レジスタでないレジスタは除く。
X
どんなオペランドでも、たとえ general_operand を満たさないものであっても許される。これは、通常、特定の選択肢が実際にはスクラッチレジスタを必要としないときに、match_scratch の制約で使われる。
0, 1, 2, ... 9
指定したオペランド番号にマッチするオペランドが許される。数字を同じ選択肢の中で英文字と組み合わせて使うなら、数字は最後に書くこと。

これは、照合制約と呼ばれており、それが実際に意味することは、アセンブラには二つの役割を果たす一個のオペランドしかないということである。この二つの役割は RTL insn で別のものと考えられている。例えば、add insn は RTL には、二つの入力オペランドと一つのオペランドを持っているが、多くの CISC マシンでは、add 命令にはオペランドが二つしかなく、その一つは入力と出力兼用オペランドである。

addl #35,r12

照合制約は以下の状況で使われる。もっと正確に言えば、マッチする二つのオペランドのうち、一つは入力専用で、もう一つは出力専用でなければならない。さらに、数字は制約で使われているオペランド数より小さな数でなければならない。

ある特定の場合にマッチするオペランドは普通それらが見かけが同じであるRTL 式になっているということを意味する。しかし、2,3の特別な場合には特定の種類の違いは許される。例えば、入力オペランドとしての *x は出力オペランドとしての *x++ にマッチする。このような場合に正しい結果を得るには、出力テンプレートではオペランドを出力するさいに常に出力オペランドの番号を使う必要がある。

p
有効なメモリアドレスであるオペランドが許される。これは、「ロード・アドレス」命令と「プッシュ・アドレス」命令向けである。

制約の中の p には、match_operand の述語のように、address_operand が付随しなければならない。この述語は、match_operand で指定されたモードを、アドレスが有効であるメモリ参照のモードとして解釈する。

Q, R, S, ... U
Q から U の範囲の文字は、機種依存の形式で定義して、任意のオペランド型を表すのに使える。マシン記述マクロ EXTRA_CONSTRAINT には、一番目の引数としてそのオペランドが、二番目の引数として制約文字が渡される。

これの典型的な使い方は、他の insn のオペランドに影響するメモリ参照の一定の型を区別することである。

これらの制約文字は、レジスタ選択(reg)を受け付けるようには定義しないこと。再ロードパスが想定していないことであり、正しく扱えないだろう。

アセンブラコードを正しいものにするために、各オペランドはその制約を満たさなければならない。しかし、制約を満たさなくても、そのパターンがある insn に適用されるのを妨げるものではない。代わりに、コンパイラがコードを修正して、制約が満足されるようにする。通常これはオペランドをレジスタにコピーすることにより行なわれる。

このため、以下の二つの命令パターンを比べてみよう。

(define_insn ""
  [(set (match_operand:SI 0 "general_operand" "=r")
        (plus:SI (match_dup 0)
                 (match_operand:SI 1 "general_operand" "r")))]
  ""
  "...")

これにはオペランドが二つあり、そのうちの一つは二箇所に現れなければならない。そして、

(define_insn ""
  [(set (match_operand:SI 0 "general_operand" "=r")
        (plus:SI (match_operand:SI 1 "general_operand" "0")
                 (match_operand:SI 2 "general_operand" "r")))]
  ""
  "...")

こちらは、オペランドが三つあり、そのうちの二つは制約により等しいことが要求される。以下の形の insn を考えてみると、

(insn n prev next
  (set (reg:SI 3)
       (plus:SI (reg:SI 6) (reg:SI 109)))
  ...)

最初のパターンは全く適合しない。この insn には、正しい場所に二つの同じ部分式がないからである。最初のパターンは、「加算命令には見えないので、他のパターンを試してね。」と言うだろう。一方、二番目のパターンは、「うん、これは加算命令だ。だけどちょっと間違ってるな。」と言うだろう。コンパイラの再ロードパスに対して insn を追加で生成させ、制約が満たされるようにすることを指示する。その結果は以下のようになるだろう。

(insn n2 prev n
  (set (reg:SI 3) (reg:SI 6))
  ...)

(insn n n2 next
  (set (reg:SI 3)
       (plus:SI (reg:SI 3) (reg:SI 109)))
  ...)

各パターンの各オペランドが、それぞれのオペランド向けに存在しうる、どんな RTL 式も扱えるような制約を持つことを保証するのは読者の責任である。(複数の選択肢が使われている場合は、各パターンは、オペランド式の可能な組合せ毎に、その組合せを扱うことが出来る選択肢を少なくとも一つ持たなければならない。) その制約は可能なオペランドをなんでも許す必要はない。なんでも許すのであればそれは制約ではない。だが、その制約は少なくとも、それに適するような何らかの可能なオペランドを再ロードする方法を指し示す必要がある。

オペランドの述語はレジスタを認識できるが、制約の方はレジスタを許さない場合はコンパイラが落ちる可能性がある。このオペランドがレジスタになったとき、再ロードパスがうまくいかなくなる。レジスタを一時的にメモリにコピーする方法が分からないためである。

述語が単項演算子を受け付けるなら、制約はそのオペランドに適用される。例えば、ISA レベル 3 の MIPS プロセッサは、SImode の二つのレジスタを加算して、DImode の結果を生成する命令をサポートしているが、これはレジスタが正しく符号拡張される場合だけである。入力オペランドに対するこの述語は、ある SImode のレジスタのsign_extend を受け付ける。sign_extend のオペランドとして必要なレジスタのタイプを示すように制約を書くこと。


Node:Multi-Alternative, Next:, Previous:Simple Constraints, Up:Constraints

複数の制約の選択肢

一個の命令が可能なオペランドの複数の選択肢の組を持つことが時々ある。例えば、68000 では論理和命令はレジスタか即値をメモリと組み合わせることができる。あるいは、任意の種類のオペランドをレジスタと組み合わせることができる。だが、一つのメモリ位置をもう一つのメモリ位置と組み合わせることはできない。

このような制約は複数の選択肢として表現される。ある選択肢は、各オペランド毎に、文字の連なりで記述される。あるオペランドに対する制約は全体としては、最初の選択肢に現れるこのオペランド用の文字、カンマ、第二の選択肢に現れるこのオペランド用の文字、カンマ、... が最後の選択肢まで続く。これが、68000 の全ワードの論理和命令ではどのようになされているかを以下に示す。

(define_insn "iorsi3"
  [(set (match_operand:SI 0 "general_operand" "=m,d")
        (ior:SI (match_operand:SI 1 "general_operand" "%0,0")
                (match_operand:SI 2 "general_operand" "dKs,dmKs")))]
  ...)

最初の選択肢は、オペランド0には m(メモリ)、オペランド 1 には0(これはオペランド 0 に一致しなければならないことを意味する)、オペランド 2 には dKs となる。第二の選択肢は、オペランド0には d(データ・レジスタ)、オペランド 1 には 0、オペランド 2 には dmKs となる。制約中の =% は全選択肢に適用される。それらの意味は次の節 (see Class Preferences)で説明する。

全てのオペランドがどれか一つの選択肢に収まれば、その命令は有効である。収まらない場合には、選択肢毎に、コンパイラが、選択肢を適用可能にするためには、オペランドをコピーするための命令を幾つ追加しなければならないかを数え上げる。最もコピーが少なくて済む選択肢が選ばれる。もし二つの選択肢のコピー数が同じなら、先に現れるものが選ばれる。この選択方法は文字 ?1 を使って変えることが出来る。

?
どの選択肢も厳密には適用できないときの選択として、? が現れる選択肢をちょっとだけ低く評価する。GNU CC は、この選択肢を、そこに現れる ? 毎に、一単位分コストが余計にかかるとみなす。
!
!が現れる選択肢を大幅に低く評価する。この選択肢は再ロードなしで収まる場合には依然として使うことができるが、再ロードが必要な場合は、何か他の選択肢が使われる。

insn のパターンが、その制約に複数の選択肢を持つ場合は、アセンブラコードの見た目は、どの選択肢が一致したかによりほとんどの場合決まる。その場合は、アセンブラコードを書き出す C のコードで、変数 which_alternative を使うことが出来る。which_alternative は、何番目の選択肢が実際に満たされるかを示す番号である。第一の選択肢は 0、第二の選択肢は 1 といった具合である。See Output Statement


Node:Class Preferences, Next:, Previous:Multi-Alternative, Up:Constraints

レジスタクラス選択

オペランド制約にはもう一つの機能がある。コンパイラが、疑似レジスタを割り当てるのにどの種類のハードウェアレジスタが最適かを決定することを可能にする。コンパイラは疑似レジスタを使っている insn に適用される制約を調べ、レジスタクラスを指定する da のような機種依存文字を探す。疑似レジスタは、最も「得票」の多いクラスに置かれる。制約文字 gr も投票する。汎用レジスタの好みについて投票するのである。マシン記述がどのレジスタが汎用と考えられるかを指定する。

当然、機種によっては全てのレジスタが等価であり、レジスタクラスが定義されない場合もある。その場合には、上記のような複雑さは関係なくなる。


Node:Modifiers, Next:, Previous:Class Preferences, Up:Constraints

制約修飾子文字

以下に制約の修飾子となる文字を示す。

=
オペランドが書き込み専用であることを意味する。このオペランドに以前保持されていた値は捨てられ、出力データで置き換えられる。
+
オペランドが読み込みと書き込みの両方に使われることを意味する。

コンパイラが、オペランドを制約を満たすように修正する際に、どのオペランドが命令に対する入力で、どのオペランドが出力かを知っている必要がある。= は、出力であることを示す。+ は、オペランドが入力と出力の両方に使われることを示す。それ以外のオペランドは入力専用と仮定される。

&
(ある特定の選択肢において)このオペランドが早期破壊 オペランドであることを意味する。早期破壊オペランドとは、命令が入力オペランドを使い終わる前に変更されるオペランドである。このため、このオペランドは、入力オペランドや任意のメモリアドレスの一部として使われるレジスタには置かれない。

& は、記述されている選択肢に対してしか適用されない。複数の選択肢のある制約では、一つの選択肢は & を必要とするが他の選択肢は必要としないということが時々ある。そういう例については、68000 の movdf insn を参照のこと。

入力オペランドは、それが入力として使われるのが以前の結果が書き込まれる前なら、早期破壊オペランドに結び付けることができる。この形式の選択肢を追加すると、入力の一部しか早期破壊により影響を受けない場合は、GCC の生成するコードが良くなることが多い。例えば、ARM の mulsi3 insn を参照のこと。

& があっても、= を書く必要はなくならない。

%
このオペランドと次のオペランドが交換可能であることを指示する。これは、コンパイラにとって、二つのオペランドを交換するのが全ての制約を満たすようにするには最もコストの低い方法であれば、その方法を取ることを可能にする。この制約は、オペランドを二つしか取らない加算命令向けのパターンで良く使われる。以下に、68000 の半語の加算命令の定義例を示す。
(define_insn "addhi3"
  [(set (match_operand:HI 0 "general_operand" "=m,r")
     (plus:HI (match_operand:HI 1 "general_operand" "%0,0")
              (match_operand:HI 2 "general_operand" "di,g")))]
  ...)

#
次に続く文字からコンマまでの全ての文字を制約としては使わないことを示す。それらの文字は、レジスタ選択でのみ意味を持つ。
*
次に続く文字がレジスタ選択の際には無視されることを示す。* は、制約としての制限の意味と再ロードには影響を与えない。

次に例を示す。68000 は、データ・レジスタ中の半語を符号拡張する命令を持っており、また、アドレス・レジスタにコピーすることで符号拡張を行なうことも出来る。どちらの種類のレジスタも受け入れ可能な場合、アドレスレジスタをコピー先とした場合の制約がより限定が緩いので、レジスタ割当がアドレスレジスタを最終目標とするのが最適である。このため、* を使って、制約文字 d (データレジスタ用)が好ましいレジスタを選択するときには無視されるようにする。

(define_insn "extendhisi2"
  [(set (match_operand:SI 0 "general_operand" "=*d,a")
        (sign_extend:SI
         (match_operand:HI 1 "general_operand" "0,g")))]
  ...)


Node:Machine Constraints, Next:, Previous:Modifiers, Up:Constraints

特定の機種用の制約

asm の引数には、可能な限り、汎用の制約文字を使ったほうが良い。その方が読む人に意味が伝わりやすくなるからだ。汎用の制約文字では駄目な場合は、色々なアーキテクチャで同じような意味を持つ制約文字を使うようにする。最も共通して良く使われるのは、mr である。それぞれ、メモリと汎用レジスタを表す。see Simple Constraints それに、I が、最も一般的な即値定数の形式を表す文字として使われる。

マシンアーキテクチャ毎に、config/machine.h というファイルで、固有の制約を追加定義している。これらの制約は、asm 文だけでなく、コンパイラ自身の命令の生成に使われる。このため、制約のうちいくつかは、asm 文に使うにはあまり意味のないものがある。制約は以下のマクロ群によって定義される。

REG_CLASS_FROM_LETTER
レジスタクラスの制約(普通は小文字だけである)。
CONST_OK_FOR_LETTER_P
即値定数の制約。ワード長、あるいはそれより短い精度の、非浮動小数点定数向けである。通常、大文字である。
CONST_DOUBLE_OK_FOR_LETTER_P
即値定数の制約。全ての浮動小数点定数とワード長を越える精度の定数向けである。通常、大文字である。
EXTRA_CONSTRAINT
レジスタまたはメモリの特別な場合。このマクロは必須ではなく、少数のマシンでのみ定義されている。

本コンパイラのソースの、読者のマシン向けのマクロ定義を調べるのが、正しい制約を使っているかどうかを確認するのに一番良い方法である。とはいうものの、以下に幾つかの特定の機種で使える機種依存の制約を要約しておく。

ARM family--arm.h
f
浮動小数点レジスタ
F
浮動小数点定数 0.0, 0.5, 1.0, 2.0, 3.0, 4.0, 5.0, 10.0 のどれか一つ
G
符号反転したときに制約 F を満たす浮動小数点定数
z
FPR-GPR 間移動用の FPMEM スタックメモリ
I
データ処理命令の即値オペランドとして有効な整数。すなわち、0 から 255 の間の整数を 2 の倍数分回転したものである。
J
-4095 〜 4095 の範囲の整数
K
ビット反転(1の補数)したときに制約 I を満たす整数
L
符号反転(2の補数)したときに制約 I を満たす整数
M
0 〜 32 の範囲の整数
Q
正確なアドレスが一個のレジスタにある場合のメモリ参照(asm 文の場合には、m の方が良い)。
R
定数領域に置かれるデータ
S
現在ファイルのテキストセグメント中のシンボル

AMD 29000 family--a29k.h
l
ローカルレジスタ 0
b
バイトポインタ(BP)レジスタ
q
Q レジスタ
h
特殊目的のレジスタ
A
第一アキュムレータレジスタ
a
他のアキュムレータレジスタ
f
浮動小数点レジスタ
I
0 より大きく、0x100 より小さい定数
J
0 より大きく、0x1000 より小さい定数
K
上位 24 ビットがオン(1)の定数
L
上位 8 ビットがオン(1) の 16 ビット定数
M
上位 16 ビットがオン(1) の 32 ビット定数
N
8ビットに収まる 32ビットの負の定数。
O
定数 0x80000000か、あるいは、29050 の場合は、下位16ビットが 0 である任意の32ビット定数。
P
8ビットに収まる 16ビットの負の定数。
G
H
浮動小数点定数(asm 文では、代わりに機種独立の EF を使うこと。)

IBM RS6000--rs6000.h
b
アドレスベースレジスタ
f
浮動小数点レジスタ
h
MQ, CTR, LINK レジスタ
q
MQ レジスタ
c
CTR レジスタ
l
LINK レジスタ
x
CR レジスタ(条件レジスタ)の 0 番
y
CR レジスタ(条件レジスタ)
z
FPR-GPR 間転送用の FPMEM スタックメモリ
I
符号付きの 16 ビット定数
J
下位16ビットが 0 の定数
K
上位の 16 ビットが 0 の定数
L
マスク用オペランドとして適切な定数
M
31 より大きい定数
N
2 の正確な冪乗
O
ゼロ
P
符号反転したものが符号付き 16 ビット定数になる定数
G
一ワードにつき一回の命令でレジスタにロード可能な浮動小数点定数。
Q
あるレジスタからのオフセットであるメモリオペランド(asm 文の場合は、m の方が良い)。
R
AIX の TOC エントリ
S
64ビットのマスク・オペランドとして適した定数。
U
System V Release 4 の小データ領域の参照

Intel 386--i386.h
q
abcd レジスタ
A
ad レジスタ(64ビット int 向け)
f
浮動小数点レジスタ
t
第一(スタックの一番上の)浮動小数点レジスタ
u
第二浮動小数点レジスタ
a
a レジスタ
b
b レジスタ
c
c レジスタ
d
d レジスタ
D
di レジスタ
S
si レジスタ
I
0〜31 の定数(32ビットのシフト用)
J
0〜63 の定数(64ビットのシフト用)
K
0xff
L
0xffff
M
0、1、2、3(lea 命令のシフト数である)
N
0 から 255 の範囲の定数(out 命令用)
G
80387 標準の浮動小数点定数

Intel 960--i960.h
f
浮動小数点レジスタ(fp0 から fp3)
l
ローカルレジスタ(r0 から r15)
b
グローバルレジスタ(g0 から g15)
d
任意のローカルまたはグローバルレジスタ
I
0 から 31 の整数
J
0
K
-31 から 0 の整数
G
浮動小数点の 0
H
浮動小数点の 1

MIPS--mips.h
d
汎用整数レジスタ
f
浮動小数点レジスタ(もしあれば)
h
Hi レジスタ
l
Lo レジスタ
x
Hi または Lo レジスタ
y
汎用整数レジスタ
z
浮動小数点ステータスレジスタ
I
符号付き 16 ビット定数(算術演算命令向け)
J
ゼロ
K
ゼロ拡張された 16 ビット定数(論理命令向け)
L
下位16ビットがゼロの定数(lui でロード可能)
M
32ビット定数のうち、ロードするのに 2 命令必要なもの(I でもK でも L でもない定数)
N
負の16ビット定数
O
二の冪乗
P
正の 16 ビット定数
G
浮動小数点のゼロ
Q
一個以上の命令でロード可能なメモリ参照(asm 文の場合は、m の方が良い)。
R
一個の命令でロード可能なメモリ参照(asm 文の場合は、m の方が良い)。
S
外部 OSF/rose PIC 形式でのメモリ参照(asm 文の場合は、m の方が良い)。

Motorola 680x0--m68k.h
a
アドレスレジスタ
d
データレジスタ
f
利用可能なら、68881 の浮動小数点レジスタ
x
利用可能なら、Sun の FPA の浮動小数点レジスタ。
y
利用可能なら、Sun の FPA の浮動小数点レジスタの最初の 16 個。
I
1 〜 8 までの整数
J
16 ビットの符号付きの数
K
絶対値が 0x80 より大きい符号付き整数。
L
-8 〜 -1 の整数
M
絶対値が 0x100 より大きい符号付き整数。
G
68881 の定数ではない浮動小数点定数。
H
Sun の FPA で使用可能な浮動小数点定数。

SPARC--sparc.h
f
32 ビットまたは 64 ビットの値を保持できる浮動小数点レジスタ。
e
64 ビットまたは 128 ビットの値を保持できる浮動小数点レジスタ。
I
13ビットの符号付き定数
J
ゼロ
K
下位12ビットが 0 の 32ビット定数(sethi 命令でロード可能な定数)
G
浮動小数点数のゼロ。
H
13 ビットの符号付き定数で、32 ビットまたは 64 ビットに符号拡張される。
Q
1命令でロード可能なメモリ参照(m の方が、asm 文にはもっと適している。)
S
定数、またはメモリアドレス
T
8バイト境界に整合されたメモリアドレス
U
偶数レジスタ


Node:No Constraints, Previous:Machine Constraints, Up:Constraints

制約を使わないということ

マシンによっては、アーキテクチャがきれいなのでオペランドの制約を必要としないものもある。例えば、Vax では、オペランドがある文脈で有効なら、その他のどの文脈でも有効である。そういうマシンでは、各オペランド制約はg になるだろう。例外は、"load address" 命令のオペランドだけである。"load adress" 命令は、指定されたメモリ位置の内容を参照するかのような書き方をするが、実際はアドレスを参照するだけである。この場合には制約は p になる。

このようなマシンでは全部の制約について gp と書く代わりに、制約を空にすることもできる。その場合には、各 match_operand の制約を "" とすれば良い。アドレスオペランドは、address 式で match_operand 囲むように書くことによって認識されるのであり、制約によって認識されるのではない。

マシン記述の制約が単に空なら、コンパイル過程の特定の部分が省略され、コンパイルが速くなる。だが、制約を必要としない機種は実際にはほとんど存在しない。現在存在するマシン記述は全て制約を使っている。


Node:Standard Names, Next:, Previous:Constraints, Up:Machine Desc

RTL生成用標準パターン名

以下に、RTL 生成パスで意味を持つ命令パターン名の一覧を示す。ある命令パターンに以下の名前の一つを与えると、RTL 生成パスは、ある一定の仕事を達成するためにそのパターンを使って良いということがわかる。

movm
ここで m は、二文字からなるマシンモード名を小文字で表したものである。この命令パターンは、指定されたマシンモードのデータをオペランド 1 からオペランド 0 に移動する。例えば、movsi は全ワードのデータを移動する。

オペランド 0 が、モードが m より広いレジスタの、モード msubreg であるなら、この命令の効果はモード m に対応するレジスタの一部に指定された値を格納することである。レジスタの他の部分に対する効果は未定義である。

このクラスのパターンは色々な点で特殊である。まず第一に、これらの名前はそれぞれ定義されなくてはならない。なぜなら、データをある場所から他の場所にコピーする方法が他にはないからである。

第二に、これらのパターンは RTL 生成パスだけで使われるのではない。再ロードパスにおいても、値をスタックスロットから一時レジスタにコピーするmove insn を生成する可能性がある。その時、オペランドの一つはハードレジスタであり、他の一つは、レジスタに再ロードされる必要となる可能性があるオペランドである。

このため、このようなオペランドの対が与えられたとき、このパターンは再ロードを必要とせず、一時レジスタ-オペランド以外のレジスタを必要としない RTL を生成しなければならない。例えば、define_expand でそのパターンをサポートするなら、その場合、define_expandforce_reg や新しい疑似レジスタを生成するような他の関数は呼び出してはならない

RISCマシンのサブワードモードについても、その機種でメモリからサブワードモードを取り出すのに複数の命令と一時レジスタが必要なら、この要求は存在する。この要求を満たすにはどうすれば良いかは spur.md を参照のこと。

再ロードの最中、無効なアドレスのメモリ参照がオペランドとして渡される可能性がある。そういうアドレスは、再ロードパスの後の方で有効なアドレスに置き換えられる。この場合、そのままでは、そのアドレスに対してはそれを使うという以外には何も行なわれない。もしそれがコピーされたとすると、有効なアドレスには置き換えられない。そういうアドレスを有効なアドレスに変えようとする試みは全く行なわれず、(change_address のような)そういう処理をする関数も呼ばれない。general_operand をそのようなアドレスに適用すると失敗することに注意。

グローバル変数 reload_in_progress(これは必要なら明示的に宣言しなければならない)を使って、そのような特別な取扱いが必要かどうかを決定することができる。

再ロードされるオペランドの種類は、マシン記述のその他の部分に依存するが、RISC 機種では普通はハードレジスタを割り当てることの出来なかった疑似レジスタに限られる。一方、それ以外の機種では明示的なメモリ参照は再ロードされる可能性がある。

あるオブジェクトをメモリへ、あるいはメモリから移動するのに、スクラッチレジスタが必要な場合は、生死解析に先だって gen_reg_rtx を使って割り当てることができる。

再ロード後にスクラッチレジスタが必要になる場合があるなら、SECONDARY_INPUT_RELOAD_CLASS を定義しなければならない。また、それらを検出するためにおそらく SECONDARY_OUTPUT_RELOAD_CLASS も定義しなければならない。それから、それらに対する取扱いのために、reload_inm パターンか reload_outm パターンを定義しなければならない。See Register Classes

グローバル変数 no_new_pseudos を使って、新しい疑似レジスタを作るのが危険かどうかを決定することができる。この変数がゼロでないときは、gen_reg_rtx を使って新しい疑似レジスタを割り当てるのは危険である。

movem についての制約は、任意のハードレジスタから別の任意のハードレジスタへの移動を許さなければならない。ただし、HARD_REGNO_MODE_OK がどちらのレジスタもモード m であることを許し、これらのレジスタのクラスに REGISTER_MOVE_COST を適用した場合に 2 という値が返ってくるという前提がある。

固定小数点値を保持できる任意のレジスタについて、値を出し入れできる浮動小数点 movm 命令をサポートするのは必須である。なぜなら共用体や構造体(モードは SImodeDImode)はそのようなレジスタに入れることができ、浮動小数点メンバが存在する可能性があるからである。

また、浮動小数点レジスタから値を出し入れする固定小数点 movm 命令も必要である。ただ、残念なことに著者はどうしてそうしたのだったかを忘れてしまっており、現在でもその通りであるかどうかがわからない。HARD_REGNO_MODE_OK が浮動小数点レジスタに固定小数点値を入れるのを拒絶するなら、固定小数点 movm 命令の制約は浮動小数点レジスタに再ロードするのを避けるように定義しなければならない。

reload_inm
reload_outm
movm と同様だが、オペランド 0 とオペランド 1 の間で移動を行なうのにスクラッチレジスタが必要な場合に使われる。オペランド 2 がそのスクラッチレジスタを記述する。see Register Classes のマクロ SECONDARY_RELOAD_CLASS の議論を参照のこと。
movstrictm
movm と同様だが、オペランド 0 が、その自然なモードがもっと広いようなレジスタのモード msubreg であるなら、movstrictm 命令は、モード m に属する部分を除いて、そのレジスタをなんら変更しないことが保証される。
load_multiple
幾つかの連続したメモリ位置から幾つかの連続したレジスタにロードする。オペランド 0 は連続するレジスタの先頭のレジスタであり、オペランド 1 は、メモリ位置の先頭であり、オペランド 2 は、連続するレジスタ数を指定する定数である。

これを定義するのは、ターゲットマシンが実際にこのような命令を持っている場合に限る。メモリから連続するレジスタへロードするのに最も効率が良い方法が、一個一個ロードすることであれば、このマクロは定義してはいけない。

マシンによっては、どの連続するレジスタがメモリに格納可能であるかについて制限がある。例えば、先頭や末尾のレジスタ番号が特定のものでなくてはいけないとか、有効なレジスタ数の範囲内でのみ可能である、などである。このような制限がある場合は、define_expand(see Expander Definitions) を使って、制限が満たされない場合はそのパターンが失敗するようにする。

生成される insn は一個の parallel として書き、その要素は一個のレジスタを適切なメモリ位置に設定する set とする(また、use あるいは clobber の要素も必要である)。match_parallel (see RTL Template)を使って、その insn を認識する。この insn パターンの使い方の例としては、a29k.mdrs6000.md を参照のこと。

store_multiple
load_multiple と同様だが、複数の連続したレジスタを連続したメモリ位置に格納する。オペランド 0 が連続したメモリ位置の先頭で、オペランド 1 が先頭のレジスタ、オペランド 2 がある定数で、連続するレジスタの数を表す。
addm3
オペランド 2 と 1 を加算し、結果をオペランド 0 に格納する。オペランドは全てモードが m でなければならない。2オペランドのマシンでも使用可能である。その場合は、オペランド 1 とオペランド 0 が同じ位置にあるという制約を課せば良い。
subm3, mulm3
divm3, udivm3, modm3, umodm3
sminm3, smaxm3, uminm3, umaxm3
andm3, iorm3, xorm3
他の算術演算についても同様である。
mulhisi3
オペランド 1 と 2 を乗算する。どちらもモードは HImode である。SImode の乗算の結果をオペランド 0 に格納する。
mulqihi3, mulsidi3
他の幅の、乗算の結果がオペランドの幅よりも大きくなる命令についても同様である。
umulqihi3, umulhisi3, umulsidi3
符号なしの乗算を行なう、乗算の結果がオペランドの幅よりも大きくなる命令についても同様である。
mulm3_highpart
オペランド 1 と 2 の符号付き乗算を行なう。モードは m である。積の上位半分をオペランド 0 に格納する。積の下位半分は捨てられる。
umulm3_highpart
mulm3_highpart と、乗算が符号なしで行なわれる点を除いて、同じである。
divmodm4
商と剰余の両方を生成する符号付き除算である。オペランド1 をオペランド 2 で割り、商がオペランド 0 に、剰余がオペランド 3 に格納される。

商と剰余の両方を生成する命令がある機種では、divmodm4 のパターンを定義し、divm3modm3 のパターンは定義しないようにすること。これにより、商と剰余の両方を計算するという比較的良くある場合に最適化が可能になる。

単に商か剰余のどちらかを生成する命令が存在し、両方を生成する命令よりも効率が良い場合は、divmodm4 の出力ルーチンを、find_reg_note を呼び出して、商か剰余についての REG_UNUSED ノートを見つけ、適切な命令を生成するように書く。

udivmodm4
divmodm4 と、除算が符号なしで行なわれる点を除いて、同じである。
ashlm3
オペランド 1 を、オペランド 2 で指定されたビット数だけ左に算術シフトし、結果をオペランド 0 に格納する。ここで、mは、オペランド 0 とオペランド 1 のモードである。オペランド 2 のモードは、命令パターンにより指定され、コンパイラは命令を生成する前にオペランドをそのモードに変換する。
ashrm3, lshrm3, rotlm3, rotrm3
その他のシフトとローテート命令群。ashlm3 と同様である。
negm2
オペランド 1 の符号を反転し、その結果をオペランド 0 に格納する。
absm2
オペランド 1 の絶対値をオペランド 0 に格納する。
sqrtm2
オペランド 1 の平方根をオペランド 0 に格納する。

C の組み込み関数 sqrt は、常に C 言語のデータ型 double に対応するモードを使用する。

ffsm2
オペランド 0 に、1 と、オペランド 1 のビットが 1 のうち最下位のもののインデックスを足したものを格納する。オペランド 1 がゼロなら、ゼロを格納する。m はオペランド 0 のモードである。オペランド 1 のモードは命令パターンにより指定され、コンパイラが命令を生成する前にオペランド 1 をそのモードに変換する。

C の組み込み関数 ffs は、C のデータ型 int に対応するモードを常に使う。

one_cmplm2
オペランド 1 のビット毎の補数をオペランド 0 に格納する。
cmpm
オペランド 0 とオペランド 1 を比較し、条件コードを設定する。RTL パターンは以下のようにする必要がある。
(set (cc0) (compare (match_operand:m 0 ...)
                    (match_operand:m 1 ...)))

tstm
オペランド 0 とゼロを比較し、条件コードを設定する。RTL パターンは以下のようにする必要がある。
(set (cc0) (match_operand:m 0 ...))

(cc0) を使わない機種では、tstm パターンを定義すべきでない。定義すると、どの set 演算が比較なのかはっきりしなくなってしまうために最適化パスが混乱する。代わりに、cmpm パターンを使うべきである。

movstrm
ブロック移動命令である。移動先と移動元の文字列のアドレスが最初の二つのオペランドであり、どちらも Pmode モードである。

移動すべきバイト数を三番目のオペランドで、モード m で指定する。普通は、m として word_mode を指定する。しかし、有効な長さの範囲が全ワードで表せる範囲より狭いことが分かっているなら、より良いコードを生成することができるという場合には、効率良く扱える値の範囲に対応するモード(例えば、0-127の範囲の値の場合なら QImode とする。負の数に見えるものは避けることに注意)のパターンとword_mode のパターンの両方を提供すべきである。

四番目のオペランドは、移動元と移動先で共通の既知のアライメントをconst_int rtx の形で表したものである。つまり、コンパイラが移動元も移動先もワード境界にアライメントされていることを知っているなら、このオペランドには 4 という値が与えられる。

複数の movstrm パターンを記述するのは、より小さなモードに対するそれらのパターンについて、第一、第二、第四オペランドについての制限がより少ない場合にのみ、有益である。movstrm のモード m は、ブロック中の個々の移動されたデータ単位のモードには、なんら制限を与えないことに注意。

このパターンは、移動元と移動先の文字列が重なっている可能性は、特に考えなくて良い。

clrstrm
ブロックのクリア命令である。対象文字列のアドレスが第一オペランドであり、モード Pmode である。クリアすべきバイト数が第二オペランドであり、モード m である。モードの選択についての議論は、movstrm を参照のこと。

三番目のオペランドは、目的先の既知のアラインメントを const_int RTX の形で表したものである。つまり、コンパイラが目的先がワード整合されていることを知っているなら、このオペランドの値を 4 とする。

複数の clrstrm の使い方は、movstrm と同じである。

cmpstrm
ブロック同士の比較命令で、オペランドは5つある。オペランド 0 には出力が置かれ、モードは m である。その他の4つのオペランドは、movstrm のオペランドと同様である。指定された二つのメモリブロックがバイト毎に辞書順で比較される。この命令の結果、オペランド 0 に格納された値の符号が、比較結果になる。
strlenm
文字列の長さを計算する。オペランドは三つある。オペランド 0 は結果(モードは m)を格納する。オペランド 1 は、文字列の先頭の文字を参照する mem である。オペランド 2 は、検索すべき文字(通常はゼロ)である。オペランド 3 は、文字列の開始位置の既知のアラインメントを記述する定数である。
floatmn2
符号付き整数オペランド 1(固定小数点モード m として有効) を浮動小数点モード n に変換し、オペランド 0 (モード n)に格納する。
floatunsmn2
符号なし整数オペランド 1(固定小数点モード m として有効) を浮動小数点モード n に変換し、オペランド 0 (モード n)に格納する。
fixmn2
オペランド 1(浮動小数点モード m として有効)を符号付き数として固定小数点モード n に変換し、オペランド 0(モード n) に格納する。この命令の結果は、オペランド 1 の値が整数の場合にのみ定義される。
fixunsmn2
オペランド 1(浮動小数点モード m として有効)を符号なし数として固定小数点モード n に変換し、オペランド 0(モード n) に格納する。この命令の結果は、オペランド 1 の値が整数の場合にのみ定義される。
ftruncm2
オペランド 1(浮動小数点モード m として有効) を整数値に変換する。ただし、依然として浮動小数点モード m で表現される。結果は、オペランド 0(浮動小数点モード m として有効)に格納される。
fix_truncmn2
fixmn2 と同様だが、モードが m の任意の浮動小数点値について、その値を整数に変換することにより、動作する。
fixuns_truncmn2
fixunsmn2 と同様だが、モードが m の任意の浮動小数点値について、その値を整数に変換することにより、動作する。
truncmn2
(モード m で有効な)オペランド1をモード n に切り詰め、結果を(モードが nの)オペランド 0 に格納する。両方のモードが固定小数点モードか、両方のモードが浮動小数点モードでなければならない。
extendmn2
(モード m で有効な)オペランド1をモード n に符号拡張し、結果を(モードが nの)オペランド 0 に格納する。両方のモードが固定小数点モードか、両方のモードが浮動小数点モードでなければならない。
zero_extendmn2
(モード m で有効な)オペランド1をモード n にゼロ拡張し、結果を(モードが nの)オペランド 0 に格納する。どちらのモードも固定小数点モードでなければならない。
extv
オペランド 1(レジスタかメモリオペランド)からビットフィールドを抽出する。オペランド2 でビット幅を指定し、オペランド3で開始ビットを指定する。結果をオペランド 0 に格納する。オペランド 0 は、word_mode モードでなければならない。オペランド 1 は、byte_modeword_mode である。word_mode はレジスタにしか許されないことが多い。オペランド 2 と 3 は、word_mode として有効でなくてはならない。

RTL 生成パスは、オペランド 2 とオペランド 3 が定数の場合しかこの命令を生成しない。

ビットフィールドの値は、オペランド 0 に格納される前に全語の整数に符号拡張される。

extzv
extv との違いは、ビットフィールドの値がゼロ拡張される点である。
insv
オペランド 3(word_mode として有効でなくてはならない)をオペランド 0 のビットフィールドに格納する。オペランド 1 でビット幅を指定し、オペランド 2 で開始ビットを指定する。オペランド 0 は、byte_modeword_mode である。word_mode はレジスタにしか許されないことが多い。オペランド 1 と 2 は、word_mode として有効でなくてはならない。

RTL 生成パスは、オペランド 1 とオペランド 2 が定数の場合しかこの命令を生成しない。

movmodecc
条件付きで、オペランド 2 またはオペランド 3 を、オペランド 1 に入っている比較にしたがって、オペランド 0 に移動する。比較が真ならオペランド 2 がオペランド 0 に移動され、偽ならオペランド 3 が移動される。

比較されるオペランドのモードは、移動されるオペランドのモードと同じである必要はない。例えば sparc64 のような機種には、浮動小数点の条件コードに基づいて整数を条件付きで移動したり、その逆を行なう命令がある。

条件付き移動命令を持たない機種では、このパターンは定義しないこと。

scond
条件コードにしたがって、ゼロか非ゼロをオペランドに格納する。条件 cond が真なら格納される値は非ゼロである。cond は、比較演算式コードの名前で、例えば、eqltleu 等がある。

match_operand 式を書くときにオペランドが持たなければならないモードを指定する。コンパイラはどのモードを使ったかを見て、自動的にそのモードのオペランドを提供する。

条件が真の場合に格納される値は、下位ビットが 1 か、あるいは負でなければならない。そうなっていないと、その命令は適切でないので、マシン記述から取り除くべきである。マクロ STORE_FLAG_VALUE (see Misc) を定義することで正確にはどの値がストアされるかということを GCC に対して指示する必要がある。全ての scond パターンに対して使用可能な指示が見つからない場合は、これらの演算をマシン記述から取り除くべきである。

これらの演算は失敗する可能性があるが、失敗して良いのは比較的珍しいケースだけである。整数の比較を含む良くあるケースで失敗することがあるなら、そういうパターンは取り除くのが良い。

そういう演算が取り除かれると、GNU CC は、定数 1 をターゲットにコピーし、そのターゲットにゼロを代入している付近に分岐する。このコードが、scond パターンで使われる潜在的な命令に、結果を SImode の 1 か ゼロに変換するのに必要な命令が続けたものより、効率が良いのなら、マシン記述から scond という演算を取り除くべきである。

bcond
条件分岐命令。オペランド 0 は、ジャンプ先のラベルを参照するlabel_ref である。条件コードが条件 cond に一致した場合にジャンプする。

機種によっては、個々で想定した、比較命令の後には条件分岐命令が続くというモデルに従わないものもある。その場合、cmpm (と tstm) パターンでは、オペランドを単に格納しておき、条件分岐演算を表す define_expand (see Expander Definitions) で必要とされる全ての insn を生成すべきである。bcond パターンを展開する全ての呼び出しの直前には、cmpm パターンかtstm パターンを展開する呼び出しが置かれる。

条件コード値を表すのに疑似レジスタを使っていたり、比較に使われるモードがテストされる条件に依存する機種でも、やはり上記の方法を使うべきである。 See Jump Patterns.

上の議論は、movmodeccscond のパターンにも当てはまる。

call
値を返さないサブルーチン命令呼びだしである。オペランド 0 は呼び出すべき関数であり、オペランド 1 はconst_int としてスタックに積まれた引数のバイト数である。オペランド 2 はオペランドとして使われるレジスタの数である。

ほとんどのマシンでは、オペランド 2 は実際には RTL パターンには格納されない。この情報をアセンブラコードに置く必要のある、いくつかの RISC 機種のために提供されている。オペランド 1 の代わりに RTL に置くことができる。

オペランド 0 は、アドレスがその関数のアドレスである mem RTX であるべきである。だが、このアドレスは、ターゲット機種上での正当なメモリアドレスになっていなくても、symbol_ref になりうることに注意して欲しい。また、call 命令の正しい引数でない場合も、この演算用のパターンは、アドレスをレジスタに置き、そのレジスタをcall 命令で使うような define_expand (see Expander Definitions) になっている必要がある。

call_value
値を返すサブルーチン呼び出し命令である。オペランド 0 は、値が返されるハードレジスタである。さらにオペランドが三つあり、それらは call 命令の三つのオペランドと同じである(オペランド番号は一ずつ増えている)。

BLKmode のオブジェクトを返すサブルーチンは call insn を使う。

call_pop, call_value_pop
callcall_value と同様だが、定義されていて、かつ、RETURN_POPS_ARGS がゼロでない場合に使われる点が異なる。これらのパターンは、関数呼び出しとフレームポインタに対してなされた調整を表す set の両方を含む parallel を生成すべきである。

RETURN_POPS_ARGS がゼロでない値になりうる機種では、これらのパターンを使うと、望まれている場合には、フレームポインタを消去可能な関数の数が増えることになる。

untyped_call
任意の型の値を返すサブルーチン呼びだし命令である。オペランド 0 が呼び出すべき関数、オペランド 1 が関数を呼び出した結果を格納すべきメモリ位置、オペランド 2 が parallel 式である。この parallel 式の各要素は、関数の戻り値を結果のブロックへセーブすることを示す set 式である。

この命令パターンは、任意個数の引数のサブルーチンを呼び出したり、戻り値をセーブするのに特別な命令を必要とするマシンで、__builtin_apply を動作させるために定義する必要がある。この命令パターンは、戻り値を保持できるレジスタが複数ある(すなわち、FUNCTION_VALUE_REGNO_P が二個以上のレジスタに対して真である)マシンで必要とされる。

return
サブルーチンから戻る命令である。この命令パターン名は、一個の命令だけで、関数から戻る処理の全てを行なえる場合にのみ定義するべきである。

movm パターンと同様、このパターンも RTL 生成以後のフェーズでも使われる。その場合、関数から戻るのに通常複数の命令が必要だが、関数のクラスによっては、戻るのに命令を一個しか必要としないものもあるような機種を支援するためである。通常、利用可能な関数は、なんらレジスタをセーブしたり、スタック空間を割り当てたりする必要がないような関数になる。

このような機種については、このパターンで指定された条件は、reload_completed がゼロでなく、関数のエピローグがただ一つの命令になる場合にのみ真とならなければならない。レジスタウィンドウのある機種については、leaf_function_p ルーチンを使って、レジスタウィンドウのプッシュが必要かどうかを決定することができる。

条件付きリターン命令のある機種では以下のようにパターンを定義すべきである。

(define_insn ""
  [(set (pc)
        (if_then_else (match_operator
                         0 "comparison_operator"
                         [(cc0) (const_int 0)])
                      (return)
                      (pc)))]
  "condition"
  "...")

ここで、condition は普通は、名前付き return パターンで指定されるのと同じ条件である。

untyped_return
型指定なしのサブルーチンからの復帰命令。この命令パターンは、任意の型の値を返すのに特別な命令を必要とする機種では、__builtin_return をサポートするために定義すべきである。

オペランド 0 は、__builtin_apply により関数を呼び出した結果が格納されるメモリ位置である。オペランド 1 は、parallel 式であり、この式の各要素はその結果のブロックから関数の戻り値をリストアすることを指示する set 式である。

nop
ノップ命令。この命令パターン名は常に定義する必要があり、アセンブラコードでノップを出力しなければならない。(const_int 0) は RTL パターンとしての役割を果たす。
indirect_jump
オペランド 0 のアドレスにジャンプする命令。このパターンは全機種で必須である。
casesi
ディスパッチテーブルを通してのジャンプ命令であり、範囲チェックを含む。この命令は次の5つのオペランドを取る。

  1. ディスパッチ先のインデックス。モードは SImode である。
  2. テーブルのインデックスの下限であり、整数定数である。
  3. テーブルのインデックスの全範囲。最大のインデックスから最小のインデックスを引いたものである。最大、最小とも範囲に含まれる
  4. テーブル自身に先行するラベル。
  5. インデックスの値が範囲外にあるときにジャンプすべきラベル。マシン記述マクロ CASE_DROPS_THROUGH が定義されていると、範囲外のインデックスの場合は、このラベルにジャンプする代わりに、ジャンプテーブルに続くコードにそのまま落ちて行く。その場合、このラベルは casesi 命令では実際には使われない。

このテーブルは、jump_insn の中の addr_vecaddr_diff_vec である。このテーブルの要素数は、上限値と下限値の差に 1 を加えたものである。

tablejump
可変アドレスにジャンプする命令。これは低レベルの機能であり、casesi パターンがない場合に分岐テーブルを実装するのに使うことが出来る。

このパターンにはオペランドが二つ必要である。アドレスまたはオフセット、それとジャンプ表の直前に置くべきラベルである。マクロCASE_VECTOR_PC_RELATIVE を評価した結果ゼロでない値になれば、最初のオペランドはその表のアドレスからのオフセットである。定義されていない場合は、ジャンプ先の絶対アドレスである。どちらの場合も、最初のオペランドのモードは Pmode である。

tablejump insn は、常に、それを使うジャンプ表の前にある最後のinsn になる。このアセンブラコードは普通は第二のオペランドを使う必要がないが、それを RTL パターンに取り込むことで 、ジャンプ最適化フェーズがその表を到達不能コードとして削除しないようにしなければならない。

canonicalize_funcptr_for_compare
オペランド 1 にある関数ポインタを正規化し、その結果をオペランド 0 に格納する。

オペランド 0 は常に reg であり、モードは Pmode である。オペランド 1 は、regmemsymbol_refconst_int 等であり、モードは Pmode である。

関数ポインタの正規化には、間接呼び出しの文脈で関数ポインタが使われた場合呼び出される関数のアドレスを計算することが通常含まれる。

ターゲット機種の関数ポインタが、間接の呼び出しに使われた場合、値は異なりうるが、呼び出す関数は同じという場合にだけ、このパターンを定義すること。

save_stack_block
save_stack_function
save_stack_nonlocal
restore_stack_block
restore_stack_function
restore_stack_nonlocal
多くの機種には、モード Pmode のオブジェクトへコピーしたり、あるいはそのオブジェクトからコピーすることで、スタックポインタをセーブしたり、リストアする。そういう機種ではこれらのパターンを定義しないこと。

機種によっては、スタックポインタのセーブとリストアには特別な取扱いが必要なものもある。そういう機種では、非標準のケースに対応するパターンを、必要とされる insn を生成する define_expand (see Expander Definitions) を使って、定義する。セーブとリストアには以下の三つのタイプがある。

  1. save_stack_block は可変長オブジェクトを割当要るブロックの開始点でのスタックポインタをセーブする。restore_stack_block はそのブロックを抜けた時点でスタックポインタをリストアする。
  2. save_stack_functionrestore_stack_function は、関数の最も外側のブロックに対して同様の処理を行ない、その関数が可変長オブジェクトを確保したり、alloca を呼び出したときに使われる。リストアされたスタックポインタを使うのはエピローグだけなので、機種によってはセーブやリストアの命令列が簡単になる。
  3. save_stack_nonlocal は、ネストした関数から分岐してくるラベルを含む関数の中で使われる。これは、内側の関数がresotre_stack_nonlocal を使ってスタックポインタをリストアできるような方法で、スタックポインタをセーブする。GCC はフレームポインタと引数ポインタのレジスタをリストアするコードを生成するが、機種によっては、その他に、例えば、レジスタウィンドウ情報やスタックのバックチェーンのようなデータをセーブ、リストアする必要があるものがある。これらのパターンに insn を置いて、そういう必要なデータをセーブ、リストアする。

スタックポインタをセーブするときは、オペランド 0 がセーブ領域であり、オペランド 1 がスタックポインタである。セーブ領域を確保するのに使うモードはデフォルトでは VOIDmode になるが、マクロSTACK_SAVEAREA_MODE (see Storage Layout) を定義することで上書きできる。整数モードか、あるいは、特定のタイプのセーブの場合はセーブ領域がひつようでない場合はVOIDmode を指定しなければならない。リストアの場合は、オペランド 0 がスタックポインタで、オペランド 1 がセーブ領域である。save_stack_block が定義されているなら、オペランド 0 は VOIDmode であってはならない。こういうセーブは好きなだけ重ねられるからである。

セーブ領域は、スタックポインタが非局所 goto で使うためにセーブされるときは、ある mem であり、virtual_stack_vars_rtx から一定のオフセットにある。他の二つの場合は、reg である。

allocate_stack
オペランド 1 をスタックポインタから減算(STACK_GROWS_DOWNWARD が定義されていれば加算)することで、動的に確保するデータ用のスペースを作る。

このスペースを指す、減算(あるいは加算)後のポインタをオペランド 0 に格納する。主スタックからスペースを割り当てているなら、これはvirtual_stack_dynamic_rtx をオペランド 0 にコピーする移動命令を生成することで行なうこと。その他の場所からスペースを割り当てている場合は、スペースのその位置をオペランド 0 にコピーするコードを生成すること。後者の場合、主スタック上の対応するスペースが解放された時に、このスペースが解放されることを保証しなければならない。

やらなければならないことがこの減算だけであるならこのパターンは定義しないこと。機種によっては、その他の、スタック探針やバックチェーンの維持等の操作を必要とするものがある。その場合には、このパターンで、スタックポインタの更新に加えてそれらの操作を生成するように定義する。

probe
機種によっては、スタックからスペースを割り当てた後に実行すべき命令を必要とする場合がある。例えば、スタックの基底への参照を生成するためである。

スタックの調整が完了するまえに命令群を出す必要があるなら、その命令群を allocate_stack パターンに入れるようにする。その必要がなければ、probe パターンが必要な命令を出すように定義する。

オペランドはない。

check_stack
スタック検査を行なうのに、ロード命令あるいはストア命令を使ってスタックを探査する方法(see Stack Checking)が使えないシステムでは、このパターンを定義して、必要な検査を行ない、スタックがオーバーフローしたなら、エラーを発するようにする。オペランドは一つで、検査する必要のある現在のスタックポインタから最も遠いスタック上の位置である。このパターンが必要な機種では、普通、スタックの限界は、グローバルまたスレッド固有である、変数またはレジスタから得ることになる。
nonlocal_goto
非局所 goto すなわち、ある関数から外側の関数中のラベルへのジャンプを生成するコードを出す。このパターンには引数が四つあり、それぞれがジャンプで使われる値を表す。先頭の引数は、フレームポインタにロードされる、二番目の引数は、分岐先アドレス(実際のラベルへディスパッチするコード)である。三番目は、スタックがセーブされる位置のアドレスであり、最後の引数は、ラベルのアドレスであり、入力静的連鎖の位置に置かれるものである。

ほとんどの機種ではこのパターンを定義する必要がない。GNU CC が既に正しいコードを生成しているからである。この正しいコードでは、フレームポインタと静的連鎖をロードし、スタックをリストアし(定義されていれば restore_stack_nonlocal パターンを使って)、ディスパッチ部へ間接的にジャンプする。このコードでは正しく動作しない機種の場合だけ、このパターンを自分で定義する必要がある。

nonlocal_goto_receiver
このパターンは、定義されていれば、非局所 goto の飛び先に GNU CC が生成済みのコードの後で必要なコードが入っている。普通はこのパターンを定義する必要はない。このパターンが必要な理由の典型的なものは、ある値、例えばグローバルな表へのポインタのようなものが、フレームポインタがリストアされたときにリストアされなくてはならない場合である。非局所 goto は翻訳単位内でしか起こらないので、指定されたモジュールの全ての関数により共有されるグローバル・テーブル・ポインタをリストアする必要はない。引数はない。
exception_receiver
このパターンは、定義されていれば、非局所 goto の位置には必要ないが、例外ハンドラの位置では必要とされるコードが入っている。普通はこのパターンを定義する必要はない。このパターンが必要な理由の典型的なものは、ある値、例えばグローバルな表へのポインタのようなものが、制御の流れが例外ハンドラに分岐した後でリストアされなくてはならない場合である。引数はない。
builtin_setjmp_setup
このパターンは、定義されていれば、jmp_buf を初期化するのに必要な追加のコードを保持している。普通は、このパターンを定義する必要はない。このパターンが必要になる代表的な理由としては、何かの値、例えばグローバル変数テーブルへのポインタのような値がリストアする必要がある場合である。そのようなポインタ値は可能な限り(例えばラベルのアドレスが与えられているような場合)再計算するのが望ましいのではあるが。引数は一つであり、jmp_buf へのポインタである。このバッファは 5語長であり、最初の 3語分は普通は汎用的な機構が使うことに注意。
builtin_setjmp_receiver
このパターンは、定義されていれば、非局所 goto の位置には必要ないが、組み込みの setjmp の位置では必要とされるコードが入っている。普通はこのパターンを定義する必要はない。このパターンが必要な理由の典型的なものは、ある値、例えばグローバルな表へのポインタのようなものが、リストアされなくてはならない場合である。これは引数を一つ取る。それは制御を渡してきた builtin_longjmp に付くラベルである。このパターンはそのラベルから小さなオフセット分だけ後に生成される。
builtin_longjmp
このパターンは、定義されていれば、longjmp の全動作を実行する。builtin_setjmp_setup も定義しているのでない限り、普通はこのパターンを定義する必要はない。引数は一個で、jmp_buf へのポインタである。
eh_epilogue
このパターンは、__builtin_eh_return、それに伴って __throw の構築方法に影響を与える。例外処理機構とそのターゲット向けの通常のエピローグコードとの間の通信を可能にすることを意図している。

このパターンには引数が三つある。一番目は、例外今テキストポインタである。これは、ポインタに適した関数戻りレジスタに既にコピーされているであろう。普通はこれを無視出来る。二番目の引数は、スタックポインタに加算すべきオフセットである。これはある勝手な呼出し時破壊ハードレジスタにコピーされるので、再ロード後、通常のエピローグが生成される間での間生き残る。三番目の引数は、この関数が戻るべき例外ハンドラのアドレスである。これは通常、このパターンによりある特別なレジスタにコピーされる必要がある。

このパターンは、もし RETURN_ADDR_RTX が、何か信頼性があり永久的な修正が可能であるもの、例えば固定ハードレジスタやスタックメモリ参照のようなものを生み出さない場合は、定義しなければならない。

prologue
このパターンが定義されていると、関数の入り口点に対する RTL を生成する。関数の入り口点には、スタックフレームの設定、フレームポインタレジスタの初期化、被呼出し側セーブレジスタのセーブ等の役割がある。

prologue パターンの方が、FUNCTION_PROLOGUE を定義するよりも、プロローグ用アセンブリ・コードを生成する方法として一般に望ましい。

prologue パターンは、命令スケジューリングを行うターゲットには特に有効である。

epilogue
このパターンが定義されていると、関数の出口点に対する RTL を生成する。関数の出口点には、スタックフレームの解放、被呼出し側セーブレジスタのリストア、リターン命令の生成等の役割がある。

epilogue パターンの方が、FUNCTION_EPILOGUE を定義するよりも、エピローグ用アセンブリ・コードを生成する方法として一般に望ましい。

prologue パターンは、命令スケジューリングを行ったり、リターン命令に遅延スロットが伴うターゲットには特に有効である。

sibcall_epilogue
このパターンが定義されていると、最終的に呼出し元関数へ分岐して戻らない関数の出口点に対する RTL を生成する。このパターンは、任意の同族呼出し(別名末尾呼出し)位置の前に生成される。

sibcall_epilogue パターンは、パラメータの受渡しに使われる引数や現在の関数に渡された引数用のスタックスロットはどれも破壊してはならない。


Node:Pattern Ordering, Next:, Previous:Standard Names, Up:Machine Desc

パターンの順序が問題になる時

ある insn が複数の命令パターンにマッチ可能なことが時々ある。その時は、マシン記述に最初に現れるパターンが使われる。このため、より限定されるパターン(マッチするものがより少ないパターン)やより高速のパターン(マッチしたときにより良いコードを生成するパターン)を通常はマシン記述で先に置くべきである。

場合によっては、パターンの順番の効果を使って、有効でないパターンを隠すこともできる。例えば、68000 は、フルワードを浮動小数点に変換する命令ともう一つ別のバイトを浮動小数点に変換する命令を持っている。整数を浮動小数点に変換する命令はどちらにもマッチし得る。我々は、フルワードを変換するパターンを先において、バイトを変換するパターンではなくてフルワードを変換する方が使われることを保証している。(そうしないと、大きな整数が一バイトの即値量として生成されてしまい、動作しなくなる。) このパターンの順序を使う代わりに、バイトを変換するパターンを任意の定数値を適切に扱えるように賢いものにすることも可能である。


Node:Dependent Patterns, Next:, Previous:Pattern Ordering, Up:Machine Desc

パターン間の依存関係

どのマシン記述でも、条件分岐名 bcond のそれぞれについて名前付きパターンがなければならない。この場合、許されるテンプレートは常に以下の形でなければならない。

(set (pc)
     (if_then_else (cond (cc0) (const_int 0))
                   (label_ref (match_operand 0 "" ""))
                   (pc)))

さらに、どのマシン記述でも、条件を逆にした分岐毎に名無しのパターンがなければならない。テンプレートは以下の形となる。

(set (pc)
     (if_then_else (cond (cc0) (const_int 0))
                   (pc)
                   (label_ref (match_operand 0 "" ""))))

これらが必要なのは、ジャンプ最適化で順条件分岐が逆条件分岐に変換されることがあるためである。

match_operator を使って、分岐に対し指定しなければならないパターンの数を押さえるということを良く行なう。例えば、以下のようにする。

(define_insn ""
  [(set (pc)
        (if_then_else (match_operator 0 "comparison_operator"
                                      [(cc0) (const_int 0)])
                      (pc)
                      (label_ref (match_operand 1 "" ""))))]
  "condition"
  "...")

場合によっては、一個以上のオペランドのマシンモードを除けば同じになる命令をサポートしている機種がある。例えば、"sign-extend halfword" と "sign-extend byte" という命令があり、そのパターンは以下のようになる。

(set (match_operand:SI 0 ...)
     (extend:SI (match_operand:HI 1 ...)))

(set (match_operand:SI 0 ...)
     (extend:SI (match_operand:QI 1 ...)))

整数定数はマシンモードを指定しないので、定数値を拡張する命令はどちらのパターンにもマッチし得る。実際にマッチするパターンは、ファイルで先に現れたものになる。正しい結果を得るためには、先に置くのは最も幅の広いモード(ここではHImode) のものでなければならない。パターンが QImode の命令にマッチした場合、定数値がこのモードに実際に収まらない場合は正しくない結果になる。

定数を拡張するような命令は最適化の際になくなるので、滅多に生成されることはないが、最適化をしないコンパイルでは時々出てくる。

あるパターンのある制約が定数を許すなら、再ロードパスが、いくつかのケースの制約で許されているなら、レジスタを定数で置き換える可能性がある。メモリ参照についても同様である。この置き換えがあるので、インクリメントとデクリメント命令に別々のパターンを与えるべきではない。代わりに、同一のパターンから生成されるようにする必要がある。このパターンは、オペランドを調べて適切な機械命令を生成するようなレジスタ同士の加算 insn をサポートする必要がある。


Node:Jump Patterns, Next:, Previous:Dependent Patterns, Up:Machine Desc

ジャンプ命令のパターンを定義する

ほとんどの機種について、GNU CC は、その機種に条件コードがあることを想定している。比較 insn が条件コードを設定し、与えられたオペランドについての、符号付き比較と符号なし比較の両方の結果を記録する。それとは別の分岐 insn が、条件コードをテストし、その値にしたがって分岐したり、しなかったりする。分岐 insn は、符号付きと符号無しでは違ってくる。良く知られた機種、例えば、Vax や 68000、32000 等はこのように動作する。

機種によっては、符号付きと符号なしで別の比較命令を持っているが、条件分岐命令は、どちらか一方向けのセットしかないというものがある。こういう機種を扱うのに一番簡単な方法は、アセンブリコードが書き出される最後の段階までは、それ以外の機種と全く同じように扱うことである。この最後の段階で、比較命令用のコードを出力するときに、next_cc0_user (insn) を使って後続の分岐を先読みするのである。(変数 insn は、ある命令パターンの出力を書き出すコードの中では、出力中の insn を参照している。) その RTL を見て、符号なし分岐であれば、符号なし比較を出力し、さもなければ符号付き比較を出力する。その分岐自体を出力するときは、符号付き分岐と符号なし分岐を全く同一に扱うことができる。

こんなことが可能なのは、GNU CC が連続する RTL insn の対を生成するからである。間に note insn が入ってもよい。この対の一つは、条件コードを設定し、もう一つがそれをテストする。GNU CC は、この対を最後までいじらないようにする。

この方法を取るには、マシン記述マクロ NOTICE_UPDATE_CCCC_STATUS_INIT を実行するように定義しなければならない。言い換えると、余計な比較命令はない。

機種によっては比較-分岐命令はあるが、条件コードはないというものがある。こういう機種についても同様の方法が使える。比較命令を「出力」すべき時が来たら、そのオペランドを二つの静的変数に記録する。次に続く「条件コードにより分岐」命令を出力するときは、実際には記録したオペランドを使う、比較-分岐命令を出力する。

比較-分岐命令向けにパターンを定義するのでも良い。最適化ありのコンパイルでは、比較命令と分岐命令の組をこのパターンに従って組み合わせる。だが、これは最適化を要求しない場合は行なわれない。このため、読者が定義するなんらかの特別なパターンに加えて、上記の解決策の一つを取る必要がある。

RISC 機種の多くでは、条件コードに影響する命令はほとんどなく、独立した条件コードレジスタさえないこともある。こういう機種では、条件コードの定義と使用は連続した insn でなければならないという制限は必要ないし、重要な最適化を妨げてしまう。例えば、IBM RS/6000 では、条件コードレジスタが条件分岐の三つ前の命令で設定されていない限り、成立した分岐に対して遅延が生じる。条件コードレジスタの定義と使い方を分離することが許されていないと、命令スケジューラは、この最適化を行なうことができない。

こういう機種では、(cc0) を使わず、代わりに条件コードを表すレジスタを使うこと。専用の条件コードレジスタが存在する場合には、ハードレジスタを使うこと。条件コードや比較の結果をどの汎用レジスタにでも置くことが出来るのなら、あるいは条件コードレジスタが複数あるなら、疑似レジスタを使うこと。

機種によっては、生成される分岐命令のタイプは条件コードの生成のされ方に依存する。例えば、68k と SPARC では、加算命令や減算命令で直接的に条件コードを設定すると、テスト命令が行なうような、オーバフロービットのクリアを行なわないので、ある種の条件分岐に対しては異なる分岐命令を使う必要がある。(cc0) を使う機種では、条件コードの設定と使用は、連続して置かなければならず(間に置いて良いのは note insn だけ)、cc_status 中のフラグを使えるようにしなければならない。(See Condition Code。) また、比較 insn と分岐 insn は、関数 prev_cc0_setternext_cc0_user によってお互いを見つけることができる。

だが、(cc0) を使わない機種ではこの事は正しくない。(cc0) を使わない機種では、比較 insn と分岐 insn が連続しているという仮定を置くことは出来ず、上記の方法は使えない。代わりに、条件コードレジスタのマシンモードを使って、条件コードレジスタの異なる形式を記録するようにする。

条件コードの値をストアするのに使うレジスタのモードは、クラス MODE_CC のモードでなければならない。普通は、CCmode になる。他にモードが必要になる場合は(上で述べた、Sparc の add の例について言えば)、マクロ EXTRA_CC_MODES を定義して、追加で必要なモードを列挙する(see Condition Code)。また、EXTRA_CC_NAMES を定義して、追加するモードの名前を列挙し、SELECT_CC_MODE を定義して、比較のオペランドに与えられたモードを選択するようにする。

RTL 生成の間、異なるモードが必要な事が判っている場合(例えば、IBM のほとんどのプロセッサのように、符号付きと符号なしで別々の比較命令を持っている機種の場合である)、RTL 生成時に指定することができる。

異なるモードが要求されるのが、命令組合せにより発生する場合は、マクロ SELECT_CC_MODE が比較の結果に対してどのマシンモードを使うべきかを決定する。そのパターンはこのモードを使って書く必要がある。上で議論した SPARC での加算の場合を考えると、パターンを以下のようにする必要がある。

(define_insn ""
  [(set (reg:CC_NOOV 0)
        (compare:CC_NOOV
          (plus:SI (match_operand:SI 0 "register_operand" "%r")
                   (match_operand:SI 1 "arith_operand" "rI"))
          (const_int 0)))]
  ""
  "...")

SPARC での SELECT_CC_MODE マクロは、引数が plus である比較に対しては CC_NOOVmode を返す。


Node:Insn Canonicalizations, Next:, Previous:Jump Patterns, Up:Machine Desc

命令の正規化

複数の RTL 式がある一個の機械命令で実行される演算を表す場合が良くある。これは、論理命令、分岐命令、積和命令で良くあることである。そういう場合、コンパイラは複数の RTL 式を一個の正規形に変換して、必要とする insn パターンの数を減らそうとする。

代数的な単純化に加えて、以下の正規化が行なわれる。


Node:Peephole Definitions, Next:, Previous:Insn Canonicalizations, Up:Machine Desc

機種固有の覗き穴最適化

命令パターンに加えて、ファイル md には、機種固有の覗き穴最適化の定義を書いても良い。

組合せフェーズが、特定の覗き穴最適化に気付かないときがある。それはどういう時かというと、プログラムのデータの流れを見ても、その覗き穴最適化を試すべきであるということが判らない時である。例えば、二つの連続する insn の目的が関係している場合は、二番目の insn が最初の insn で計算したレジスタを使わないように見える場合でも、組合せが行なえることがある。機種固有の覗き穴最適化器はそのような機会を検出する。

A definition looks like this:

(define_peephole
  [insn-pattern-1
   insn-pattern-2
   ...]
  "condition"
  "template"
  "optional insn-attributes")

最後の文字列オペランドは、マシン記述で機種固有の情報をなんら使っていないのなら、省略可能である。省略しない場合は、define_insn と同じ規則に従わなければならない。

このスケルトンでは、insn-pattern-1 等は連続する insn のマッチすべきパターンである。insn-pattern-1 が insn 列の先頭のものに、insn-pattern-2 がその次に、という具合にマッチするなら、その insn 列に最適化が適用される。

覗き穴によりマッチする各 insn は define_insn にもマッチしなければならない。覗き穴はコード生成の直前の最終段階でしか検査されない。このため、覗き穴にはマッチするものの define_insn にはマッチしないinsn は、最適化を行なわないコンパイルの場合のコード生成で、あるいは色々な最適化の段階で、異常終了を引き起こす。

insn のオペランドは、通常同様、match_operandsmatch_operatormatch_dup にマッチする。通常と違うのは、オペランド番号が定義の中にある全ての insn パターンに適用されるという点である。このため、二つの insn にある同じオペランドを検査するのに、片方の insn では match_operand を、もう一方ではmatch_dup を使うことができる。

match_operand パターンで使われるオペランド制約は、覗き穴が適用されるかどうかについては、なんら直接的な効果は持たない。だが、後で検証されるので、この制約は、覗き穴がマッチするときはいつでも適用できるぐらい一般的なものになっていることを確認して欲しい。覗き穴にはマッチするが、制約が満たされない場合は、コンパイラが落ちるだろう。

覗き穴最適化の場合は、全てのオペランドの制約を省略しても安全である。あるいは、制約を書いて、既にテスト済みの規準を二重に検査することにしても良い。

ある insn の列がそのパターンに一度一致すると、condition が検査される。condition は一個の C の式であり、この最適化を実行するかどうかを最終的に決定する(この式がゼロでなければ最適化を行なう)。condition が指定されていないと(言い換えると、文字列が空の場合)、この最適化はそのパターンに一致する、あらゆる insn の列に適用される。

定義された覗き穴最適化はレジスタ割当が完了した後に適用される。このため、このため、覗き穴最適化の定義では、どのオペランドが最終的にどの種類のレジスタに割り当てられたかを、単にそのオペランドを見ることで調べることができる。

condition でオペランドを参照するには、オペランド番号が i なら operands[i] と書く((match_operand i ...) によりマッチする)。マッチしつつある insn 群の最後のものを参照するには変数 insn を使う。先行する insn 群を見つけるにはprev_active_insn を使う。

中間結果の計算を最適化するときは、condition を使って、その中間結果が他の場所で使われない時にのみ一致させることができる。C の式 dead_or_set_p (insn, op) を使うこと。ここで、insn は、最後に使われると想定している値が入っている insn である(insn の値から、prev_nonnote_insn を組み合わせて得られる)。op は、中間結果である(operands[i] から得られる)。

最適化を適用するということは、insn 列を一個の新たな insn で置き換えるということを意味する。template が、この組み合わされたinsn のアセンブラコードの最終的な出力を制御する。template は、define_insn のテンプレートと全く同じように動作する。このテンプレートのオペランド番号は、元の insn 列とマッチするのに使われたのと同じ番号である。

定義した覗き穴最適化の結果は、マシン記述の insn パターンのどれにもマッチする必要はない。実は一致する機会すらないのである。覗き穴最適化の定義は、それ自身が insn がどのように出力されるかを制御する insn のパターンとして働く。

定義された覗き穴最適化はアセンブラコードが出力されるときに実行されるので、生成される insn はどんな方法でも組み合わされたり、並べ替えられたりすることはない。

以下の例は、68000 のマシン記述から取ったものである。

(define_peephole
  [(set (reg:SI 15) (plus:SI (reg:SI 15) (const_int 4)))
   (set (match_operand:DF 0 "register_operand" "=f")
        (match_operand:DF 1 "register_operand" "ad"))]
  "FP_REG_P (operands[0]) && ! FP_REG_P (operands[1])"
  "*
{
  rtx xoperands[2];
  xoperands[1] = gen_rtx (REG, SImode, REGNO (operands[1]) + 1);
#ifdef MOTOROLA
  output_asm_insn (\"move.l %1,(sp)\", xoperands);
  output_asm_insn (\"move.l %1,-(sp)\", operands);
  return \"fmove.d (sp)+,%0\";
#else
  output_asm_insn (\"movel %1,sp@\", xoperands);
  output_asm_insn (\"movel %1,sp@-\", operands);
  return \"fmoved sp@+,%0\";
#endif
}
")

この最適化により

jbsr _foobar
addql #4,sp
movel d1,sp@-
movel d0,sp@-
fmoved sp@+,fp0

が、以下のようになる。

jbsr _foobar
movel d1,sp@
movel d0,sp@-
fmoved sp@+,fp0

insn-pattern-1 等は、ほぼ define_insn の第二オペランドに同じである。重要な違いが一つある。define_insn の第二オペランドは、鍵括弧で囲まれた一つ以上のRTX からなる。普通は一つだけである。その場合、同じ動作を define_peephole の要素として書くことができる。しかし、define_insn に複数の動作があるときは、暗黙のうちにparallel で囲まれる。その場合、define_peephole では、parallel とその中に鍵括弧を明示的に書かなければならない。こうして、ある insn パターンが

(define_insn "divmodsi4"
  [(set (match_operand:SI 0 "general_operand" "=d")
        (div:SI (match_operand:SI 1 "general_operand" "0")
                (match_operand:SI 2 "general_operand" "dmsK")))
   (set (match_operand:SI 3 "general_operand" "=d")
        (mod:SI (match_dup 1) (match_dup 2)))]
  "TARGET_68020"
  "divsl%.l %2,%3:%0")

のようになていたとすると、この insn を覗き穴に書くには以下のようにする。

(define_peephole
  [...
   (parallel
    [(set (match_operand:SI 0 "general_operand" "=d")
          (div:SI (match_operand:SI 1 "general_operand" "0")
                  (match_operand:SI 2 "general_operand" "dmsK")))
     (set (match_operand:SI 3 "general_operand" "=d")
          (mod:SI (match_dup 1) (match_dup 2)))])
   ...]
  ...)


Node:Expander Definitions, Next:, Previous:Peephole Definitions, Up:Machine Desc

コード生成のための RTL 列の定義

機種によっては、RTL 生成用の標準のパターン名を一個の insn では扱えないが、RTL insn の列なら表現できるという場合がある。そのようなターゲット機種の場合は、define_expand を書くことでその RTL 列を生成する方法を指定することができる。

define_expand は、ある一個の RTL 式であり、ほぼ define_insn と同じである。しかし、define_expand は、define_insn と違って、RTL 生成にのみ使われ、一個以上の RTL insn を生成することができる。

define_expand RTX にはオペランドが4つある。

define_expand により生成されるRTL insn はどれも、マシン記述中のdefine_insn のどれかにマッチしなければならない。どれにもマッチしない場合、その insn 用のコードを生成しようとしたり、最適化しようとしたときに異常終了してしまう。

RTL テンプレートは、RTL insn の生成を制御することに加えて、このパターンが使われるときに指定する必要があるオペランドをも記述する。特に、各オペランドに述語を与える。

真のオペランドは、パターンから RTL を生成するために指定する必要があり、RTL テンプレートの先頭に現れる match_operand で記述する必要がある。これにより、オペランドの述語についての情報が、その手の情報を記録する表に入力される。GNU CC はこの情報を使って、正しい RTL コードとして必要なら、オペランドをレジスタに事前ロードする。このオペランドが複数回参照されているなら、それ以降で参照するときはmatch_dup を使う必要がある。

RTL テンプレートは、内部「オペランド」も参照する。内部オペランドとは、一時レジスタやラベルであり、define_expand で作られる列の中でしか使われない。内部オペランドは、match_dup により RTL テンプレートに代入される。match_operand で代入されることはない。内部オペランドの値は、GNU CC がこのパターンを使う必要があるときに引数として渡されることはない。代わりに、準備文により、パターン内で計算が行なわれる。準備文は、値を計算し、operands の適切な要素に格納するので、match_dup がそれを見つけられるようになる。

準備文の中で使う特別なマクロが二つ定義されている。DONEFAIL である。これらは後ろにセミコロンを付けて文として使うこと。


DONE
マクロ DONE を使って、このパターンに対する RTL 生成を終了させる。この時にパターンから作られる RTL insn は、準備文の中で emit_insn を明示的に呼び出すことによって既に出力済みのものだけになる。RTL テンプレートは生成されない。
FAIL
パターンに対する照合を失敗させる。あるパターンが照合に失敗すると、そのパターンが利用できないことを意味する。GNU CC の呼びだし側ルーチンは、他のパターンを使って、コード生成の別の戦略を試す。

失敗は、現在、二項演算(加算、乗算、シフト等)とビットフィールド演算(extvextzvinsv)でのみ使える。

次の例は、SPUR チップの左シフトの定義である。

(define_expand "ashlsi3"
  [(set (match_operand:SI 0 "register_operand" "")
        (ashift:SI
          (match_operand:SI 1 "register_operand" "")
          (match_operand:SI 2 "nonmemory_operand" "")))]
  ""
  "
{
  if (GET_CODE (operands[2]) != CONST_INT
      || (unsigned) INTVAL (operands[2]) > 3)
    FAIL;
}")

この例では、define_expand を使って、シフト量がサポート範囲の 0 から 3 の間に収まっていればシフトを行なうRTL insn を生成することができるようにしているが、機械命令が使えないようなそれ以外の場合には失敗するようにしている。失敗した場合には、別のパターン(例えば、ライブラリ呼びだしなど)を使った別の戦略を試みる。

GNU CC が、名前付きパターンの自明でない条件文字列を扱うことが出来たなら、define_insn をその場合に使うことができる。以下に、define_expand の威力をさらに利用する別の例(68000 でのゼロ拡張である)を示す。

(define_expand "zero_extendhisi2"
  [(set (match_operand:SI 0 "general_operand" "")
        (const_int 0))
   (set (strict_low_part
          (subreg:HI
            (match_dup 0)
            0))
        (match_operand:HI 1 "general_operand" ""))]
  ""
  "operands[1] = make_safe_from (operands[1], operands[0]);")

ここでは二つの RTL insn が生成される。一つは出力オペランド全体をクリアし、もう一つは入力オペランドを出力オペランドの下位半分にコピーする。この insn 列は、入力オペランドが出力オペランド(の古い値)を参照している場合は、正しくなくなる。そのため、準備文でそうならないことを保証している。関数 make_safe_from は、operands[1]operands[0] を参照していれば、operands[1] を一時レジスタにコピーする。そのコピーは、もう一つの RTL insn を生成することにより行なう。

最後に、三番目の例で内部オペランドの使い方を説明する。SPUR チップのゼロ拡張は、結果を半語のマスクとの and を取ることで行なわれる。だが、このマスクは、定数値としては、この機種で正しいものになるには大きすぎて、const_int では表現できない。このため、force_reg でレジスタにコピーして、そのレジスタを and の中で使わなければならない。

(define_expand "zero_extendhisi2"
  [(set (match_operand:SI 0 "register_operand" "")
        (and:SI (subreg:SI
                  (match_operand:HI 1 "register_operand" "")
                  0)
                (match_dup 2)))]
  ""
  "operands[2]
     = force_reg (SImode, GEN_INT (65535)); ")

注意: define_expand を標準的な二項演算や単項演算、あるいはビットフィールド演算に使うときは、それが最後に生成する insn は、code_labelbarriernote であってはならない。insnjump_insncall_insn でなくてはならない。最後に実際の insn を置く必要がなければ、演算の結果を自分自身にコピーするinsn を生成する。そういう insn はコードはなんら生成しないが、GCC に問題が起きるのを回避する。


Node:Insn Splitting, Next:, Previous:Expander Definitions, Up:Machine Desc

命令の分割方法を定義する

あるパターンを複数の insn に分割する方法を指定しなければならない場合が二つある。遅延スロット(see Delay Slots)を必要とする命令や出力が複数サイクルの間利用できない命令(see Function Units)を持つ機種では、これらのケースを最適化するコンパイラフェーズでは、insn を一つの命令の遅延スロットに移動できる必要がある。しかし、insn の中には複数の機械命令を生成するものもある。そういう insn は遅延スロットに置くことはできない。

一個の insn を個々の insn のリストに書き直せることが多い。この場合、個々の insn はそれぞれ一個の機械命令に対応する。こうすると不利な点は、コンパイルが遅くなり、必要とするメモリスペースが多くなることである。書き換え後の insn が複雑過ぎると、そのためにいくつかの最適化を妨げることにもなる。命令スケジューリングまたは遅延スロットスケジューリングが改善されると信じる根拠がある場合は、コンパイラは insn を分割する。

insn の組合せフェーズでは、交換可能な insn の分割も行なう。三つの insn が複雑な式の一つの insn に統合されたものの、なんらかの define_insn パターンにマッチすることが不可能になった場合、組合せフェーズは複雑なパターンを認識できる二つの insn に分割しようとする。普通は、複雑なパターンをいくつかの部分式に分割することで二つのパターンに分ける。だが、場合によっては、RISC 機種で、ある大きな定数の加算を二つの insn で行なうような場合、その加算を二つの insn に分割する方法は機種依存である。

define_split の定義で、GNU CC に対し、複雑な insn をいくつかのもっと単純な insn に分割する方法を指定する。

(define_split
  [insn-pattern]
  "condition"
  [new-insn-pattern-1
   new-insn-pattern-2
   ...]
  "preparation statements")

insn-pattern は、分割する必要のあるパターンであり、condtiondefine_insn の場合と同様、最後にテストされる条件である。insn-pattern にマッチし、condition を満たす insn が見つかると、その insn は、insn のリストの中で、new-insn-pattern-1new-insn-pattern-2 等で与えられるinsn に置き換えられる。

preparation statements は、define_expand ( see Expander Definitions)で指定される文と同様のもので、生成されるコードの準備をしたり、パターンが固定していない insn をいくつか生成したりするために、新しい RTL が生成される前に実行される。ただし、define_expand にあるものと違って、これらの文は疑似レジスタを新たに生成してはならない。また、再ロードが一度完了したら、スタックフレームからスペースを割り当ててはならない。

パターンが insn-pattern とマッチするのには、二つの異なる状況がある。ある insn が遅延スロットスケジューリングや命令スケジューリング向けに分割する必要がある場合は、その insn は有効であることが既に知られている。この事は、何かの define_insn にマッチしていなければならず、reload_completed がゼロでなければ、その define_insn の制約を満たすことが知られているということを意味する。その場合、新しい insn パターンも何かの define_insn にマッチしなければならず、reload_completed がゼロでなければ、その定義の制約を満たさなければならない。

この define_split の使い方の例として、a29k.md から取った以下の例を考えてみる。この例では、HImode から SImode への sign_extend を二つのシフト insn の対に分割している。

(define_split
  [(set (match_operand:SI 0 "gen_reg_operand" "")
        (sign_extend:SI (match_operand:HI 1 "gen_reg_operand" "")))]
  ""
  [(set (match_dup 0)
        (ashift:SI (match_dup 1)
                   (const_int 16)))
   (set (match_dup 0)
        (ashiftrt:SI (match_dup 0)
                     (const_int 16)))]
  "
{ operands[1] = gen_lowpart (SImode, operands[1]); }")

命令組合せ過程が insn パターンを分割しようとするのは、いつでも、そのパターンがどの define_insn にもマッチしない場合である。組合せ過程は、最初に一個の set 式を分割しようとし、次に parallel の中にあるが、スクラッチレジスタとして使うための疑似レジスタの clobber が後ろに続くような、同じ set 式を分割する。これらの場合、組合せ過程は、新しい insn パターンがちょうど二つ生成されることを想定する。組合せ過程がこれらのパターンがなんらかの define_insn による定義にマッチするかどうかを検査するので、読者が自分で define_split の中でこの検査を行なう必要はない(当たり前だが、マッチする insn を決して生成しないように define_split を書くのは意味がない)。

以下に define_split のこの使い方の例を示す。rs6000.md から取ったものである。

(define_split
  [(set (match_operand:SI 0 "gen_reg_operand" "")
        (plus:SI (match_operand:SI 1 "gen_reg_operand" "")
                 (match_operand:SI 2 "non_add_cint_operand" "")))]
  ""
  [(set (match_dup 0) (plus:SI (match_dup 1) (match_dup 3)))
   (set (match_dup 0) (plus:SI (match_dup 0) (match_dup 4)))]
"
{
  int low = INTVAL (operands[2]) & 0xffff;
  int high = (unsigned) INTVAL (operands[2]) >> 16;

  if (low & 0x8000)
    high++, low |= 0xffff0000;

  operands[3] = GEN_INT (high << 16);
  operands[4] = GEN_INT (low);
}")

ここで述語 non_add_cint_operand は、一個の加算 insn の有効なオペランドではない const_int にマッチする。小さな変位付きの加算は、次の演算のアドレスに代入できるように書かれる。

同じファイルから、スクラッチレジスタの使い方の例を見てみる。この例では、レジスタと大きな定数の等値性比較を生成している。

(define_split
  [(set (match_operand:CC 0 "cc_reg_operand" "")
        (compare:CC (match_operand:SI 1 "gen_reg_operand" "")
                    (match_operand:SI 2 "non_short_cint_operand" "")))
   (clobber (match_operand:SI 3 "gen_reg_operand" ""))]
  "find_single_use (operands[0], insn, 0)
   && (GET_CODE (*find_single_use (operands[0], insn, 0)) == EQ
       || GET_CODE (*find_single_use (operands[0], insn, 0)) == NE)"
  [(set (match_dup 3) (xor:SI (match_dup 1) (match_dup 4)))
   (set (match_dup 0) (compare:CC (match_dup 3) (match_dup 5)))]
  "
{
  /* Get the constant we are comparing against, C, and see what it
     looks like sign-extended to 16 bits.  Then see what constant
     could be XOR'ed with C to get the sign-extended value.  */

  int c = INTVAL (operands[2]);
  int sextc = (c << 16) >> 16;
  int xorv = c ^ sextc;

  operands[4] = GEN_INT (xorv);
  operands[5] = GEN_INT (sextc);
}")

混乱を避けるために、一個の define_split を、ある define_insn にマッチする insn とマッチしない insn を同じように受け付けるように書いてはならない。代わりに、二つの define_split を別々に書いて、一つを有効な insn 用とし他方を有効でない insn 用とすること。


Node:Insn Attributes, Previous:Insn Splitting, Up:Machine Desc

命令の属性

ターゲット機種でサポートされている命令の記述に加えて、md ファイルでは、属性 のグループとそれぞれの属性の値を定義することも出来る。生成される各 insn には、属性毎に一つの値が割り当てられる。取る得る属性の一つとしては、insn がその機種の条件コードについて持つ効果がある。そして、この属性を使って NOTICE_UPDATE_CC が条件コードを追跡することができる。


Node:Defining Attributes, Next:, Previous:Insn Attributes, Up:Insn Attributes

属性とその値の指定方法

define_attr 式を使って、ターゲットマシンで必要とされる各属性を定義する。以下のような形式になる。

(define_attr name list-of-values default)

name は、定義しようとしている属性の名前を指定する文字列である。

list-of-values は、属性に割り当てられる、コンマで区切った値のリストを指定する文字列か、その属性が数値を取ることを示すヌル文字列のどちらかである。

default は、ある属性式であり、この属性に対する明示的な値を含まない定義を持つパターンにマッチする insn のこの属性の値を与える。デフォルトの扱いについてのもっと詳細な情報は、See Attr Example。特定の insn に依存しない属性についての情報は、See Constant Attributes

定義されている各属性毎に、たくさんの定義がファイル insn-attr.h に書き込まれる。属性に対して明示的な値の組が指定されている場合は、以下のように定義されている。

例えば、md ファイルに以下のように書いてあったとすると、

(define_attr "type" "branch,fp,load,store,arith" ...)

ファイル insn-attr.h には以下のように出力される。

#define HAVE_ATTR_type
enum attr_type {TYPE_BRANCH, TYPE_FP, TYPE_LOAD,
                 TYPE_STORE, TYPE_ARITH};
extern enum attr_type get_attr_type ();

属性が数値を取るなら、enum 型は定義されず、属性値を取得する関数は int を返す。


Node:Expressions, Next:, Previous:Defining Attributes, Up:Insn Attributes

属性値として使用可能な式

属性を定義するのに使われる RTL 式は、前出のコードに加えて、以下で議論する、属性定義に固有のコードを幾つか使っている。属性値式は、以下の形のどれか一つでなければならない。

(const_int i)
整数 i が、数値属性の値を指定する。i は非負でなければならない。

数値属性の値は、const_int か、const_string で文字列で表現した整数、eq_attr(以下参照)、attrsymbol_ref、単純算術式のどれかで指定することができ、set_attr は特定の命令を上書きする(see Tagging Insns)。

(const_string value)
文字列 value は、定数属性値を指定する。value"*" として指定されると、その属性のデフォルト値が、この式を含む insn に対して使われることを意味する。"*" は、明らかに、define_attrdefault 式で使うことはできない。

値が指定されている属性が数値的なら、value は非負の整数(この場合、普通 const_int)を含む文字列でなければならない。数値的でなければ、その属性に対して有効な値の一つを含んでいなければならない。

(if_then_else test true-value false-value)
test は属性テストを指定する。その形式は以下で定義される。この式の値は、test が真であれば true-value であり、真でなければ false-value となる。
(cond [test1 value1 ...] default)
この式の第一オペランドはあるベクトルであり、偶数個の式をもち、test 式と value 式の対からなる。cond 式の値は最初の真である test 式に対応する値のものである。真となる test 式がない場合は、cond 式の値は default 式の値である。

test 式は、以下の形のうちの一つを取る。

(const_int i)
このテストは、i がゼロでなければ真になり、さもなければ偽になる。
(not test)
(ior test1 test2)
(and test1 test2)
これらのテストは、指定された論理関数が真になれば、真である。
(match_operand:m n pred constraints)
このテストは、属性値が決定されようとしている insn のオペランドn のモードが m であり(テストのこの部分は、mVOIDmode なら無視される)、かつ文字列 pred で指定される関数が、オペランド n とモード m を渡したときにゼロでない値を返したときに、真になる(テストのこの部分は、pred がヌル文字列なら無視される)。

オペランド constraints は無視されるので、ヌル文字列とすべきである。

(le arith1 arith2)
(leu arith1 arith2)
(lt arith1 arith2)
(ltu arith1 arith2)
(gt arith1 arith2)
(gtu arith1 arith2)
(ge arith1 arith2)
(geu arith1 arith2)
(ne arith1 arith2)
(eq arith1 arith2)
これらのテストは、二つの算術式について指定された比較の結果が真になれば、真となる。算術式は、plusminusmultdivmodabsnegandiorxornotashiftlshiftrtashiftrt といった式から構成される。

const_intsymbol_ref は常に有効な項である(追加の形式については see Insn Lengths)。symbol_ref は一個の文字列であり、一個の C の式を示す。この式は、get_attr_... ルーチンで評価されたときに int を生じる。普通はグローバル変数にならないといけない。

(eq_attr name value)
name は、属性名を指定する文字列である。

value は文字列であり、属性 name の有効な値であるか、幾つかの値をカンマで区切ったリストか、あるいは ! の後に一個の値か値のリストを続けたものである。value! で始まっていなければ、このテストは、現在の insn の属性 name の値が value で指定されたリストの中に入っていれば、真となる。value! で始まっていると、このテストは属性値が指定されたリストに入っていない時に真となる。

例えば

(eq_attr "type" "load,store")

は、次の式に等価である。

(ior (eq_attr "type" "load") (eq_attr "type" "store"))

namealternative の属性を指定するものなら、それはGNU CC の変数 which_alternative の値を参照し(see Output Statement)、その値は小さな整数でなくてはならない。例えば、

(eq_attr "alternative" "2,3")

は、次の式に等価である。

(ior (eq (symbol_ref "which_alternative") (const_int 2))
     (eq (symbol_ref "which_alternative") (const_int 3)))

ほとんどの属性に対して、テスト eq_attr は、テストされる属性の値が、ある特定のパターンにマッチする全ての insn に対して知られているなら、簡略化される。これは非常に良くあるケースである。

(attr_flag name)
attr_flag 式の値は、name で指定されたフラグが現在スケジューリング中の insn に対して真になるなら、真となる。

name はある文字列であり、テストすべきフラグの固定したセットを一つ指定する。フラグ forwardbackward をテストして、条件分岐の方向を決定する。フラグ very_likerylikelyvery_unlikelyunlikely をテストして、条件分岐が成立すると予想されるかどうかを決定する。

フラグ very_likely が真なら、フラグ likely もまた真になる。very_unlikelyunlikely についても同様である。

この例では、条件分岐の遅延スロットを記述している。このスロットは、分岐が成立する前方への分岐(真の無効化)か分岐が成立しない場合の後方への分岐(偽の無効化)が無効化される。

(define_delay (eq_attr "type" "cbranch")
  [(eq_attr "in_branch_delay" "true")
   (and (eq_attr "in_branch_delay" "true")
        (attr_flag "forward"))
   (and (eq_attr "in_branch_delay" "true")
        (attr_flag "backward"))])

フラグ forwardbackward は、現在スケジュールされつつあるinsn が条件分岐でなければ、偽になる。

フラグ very_likelylikely は、スケジュールされつつあるinsn が条件分岐でなければ、真になる。フラグ very_unlikelyunlikely は、スケジュールされつつあるinsn が条件分岐でなければ、偽になる。

attr_flag は、遅延スロットスケジューリングの間でだけ使われ、他のパスには何の意味も持たない。

(attr name)
別の属性の値を返す。数値属性に対して最も役に立つが、同様に、非数値属性にたいしても eq_attrattr_flag がより効率の良いコードを生成する助けとなる。


Node:Tagging Insns, Next:, Previous:Expressions, Up:Insn Attributes

属性値の insn への割り当て

ある insn のある属性に割り当てられる値は、主に、その insn により照合される(あるいは define_peephole が生成する)パターンにより決定される。各 define_insndefine_peephole は、オプションの最後の引数を持つことができ、一致する insn の属性値を指定することができる。ある特定の insn において指定されていない属性値は全て、その属性のデフォルト値に設定される。このデフォルト値は、その属性の define_attr で指定される。属性のデフォルト値を多用すると、ほとんどの insn パターンの定義で一つか二つの属性値を指定するだけで済む。次の節の例を参照のこと。

define_insndefine_peephole の最後のオプションの引数は、式のベクトルであり、それぞれの式がある一個の属性の値を定義する。属性値を割り当てる最も一般的な方法は、set 式を使い、その第一オペランドを設定する属性名を与える attr 式とすることである。この set 式の第二のオペランドは属性式(see Expressions)であり、属性の値を与える。

属性値が属性 alternaitve に依存するとき(すなわち、それが、その insn の制約にある利用可能な選択肢である)は、set_attr_alternative 式を使うことができる。これは属性式のベクトルを指定することを許す。ベクトルの中のそれぞれの式が各属性を表す。

任意の属性式ほど一般的な機能が必要ない場合、もっと簡単なset_attr 式を使うことができる。この式を使うと、一個の文字列を指定することで、一個の属性値か、あるいは各選択肢毎に一個の属性値を与えるリストを表すことができる。

上記の指定方法をそれぞれ以下に示す。どちらの場合も、name は、設定すべき属性を指定する文字列である。

(set_attr name value-string)
value-string は、希望の属性値を与える文字列か、あるいは一連の属性値をカンマで区切ったリストを表す文字列である。この要素数は、insn パターンの制約の選択肢数と一致しなければならない。

選択肢のどれかに * を指定することができる。その場合、属性値は、その選択肢にマッチする insn のデフォルト値になる。

(set_attr_alternative name [value1 value2 ...])
insn の選択肢により、この値は指定された値のうちの一つになる。これは、属性 alternativecond を使ってのテストの省略形である。
(set (attr name) value)
この set の第一オペランドは、特別な RTL 式 である attr 式でなければならない。この式の唯一のオペランドは、設定する属性の名前を指定する文字列である。value は、その属性の値である。

以下に同じ属性値の指定を表す、三つの異なる方法を示す。

(set_attr "type" "load,store,arith")

(set_attr_alternative "type"
                      [(const_string "load") (const_string "store")
                       (const_string "arith")])

(set (attr "type")
     (cond [(eq_attr "alternative" "1") (const_string "load")
            (eq_attr "alternative" "2") (const_string "store")]
           (const_string "arith")))

define_asm_attributes 式は、asm 文から生成されたinsn に割り当てられた属性を指定する方法を提供する。次の形を取る。

(define_asm_attributes [attr-sets])

ここで、atr-sets は、define_insndefine_peephole 式両方に指定するのと同じものである。

これらの値は、普通はその属性値の「最悪の場合」になる。例えば、条件コードが破壊されることを示したりする。

length 属性の指定は特別に扱われる。一個の asm insn の長さを計算するには、式 define_asm_attributes で指定された長さに、asm 文に指定されている機械命令の数を掛けたものになる。asm 文中の機械命令数は、命令文字列中のセミコロンと改行の数で決まる。このため、define_asm_attributes で指定されるlength 属性の値は、一個の機械命令の可能な最大長にしなくてはならない


Node:Attr Example, Next:, Previous:Tagging Insns, Up:Insn Attributes

属性割り当ての例

デフォルトをうまく使うのが、insn の属性を効率良く使うには重要である。通常、insn は types と、type と呼ばれている属性に分けられる。type は、このデフォルト値を表すのに使われる。この属性は、普通は他の属性のデフォルト値を定義するのにしか使われない。例を使ってこの属性の使い方を説明する。

ある RISC マシンを考えよう。このマシンには条件コードがあり、レジスタで実行されるのは全語の演算だけである。全ての命令をロード、ストア、(整数)算術演算、浮動小数点演算、分岐に分割できるとしよう。

ここでは、ある insn の条件コードに対する効果を決定することに注意を集中することにし、さらに可能な効果として次のものに限定する。条件コードは、予測できない形で設定され得る(破壊される)、変更されない、演算結果に一致するように設定される、以前に条件コードに設定した項目が修正されたときにのみ変更される。

そういう機種用の md ファイルの例の一部を示す

(define_attr "type" "load,store,arith,fp,branch" (const_string "arith"))

(define_attr "cc" "clobber,unchanged,set,change0"
             (cond [(eq_attr "type" "load")
                        (const_string "change0")
                    (eq_attr "type" "store,branch")
                        (const_string "unchanged")
                    (eq_attr "type" "arith")
                        (if_then_else (match_operand:SI 0 "" "")
                                      (const_string "set")
                                      (const_string "clobber"))]
                   (const_string "clobber")))

(define_insn ""
  [(set (match_operand:SI 0 "general_operand" "=r,r,m")
        (match_operand:SI 1 "general_operand" "r,m,r"))]
  ""
  "@
   move %0,%1
   load %0,%1
   store %0,%1"
  [(set_attr "type" "arith,load,store")])

上の例で我々は、マシンワードより小さな量について算術演算を実行すると、それにより条件コードに全ワードの結果に対応する値を設定するので、条件コードが破壊されると仮定していることに注意。


Node:Insn Lengths, Next:, Previous:Attr Example, Up:Insn Attributes

insn の長さの計算

多くの機種では、複数のタイプの分岐命令が提供されており、それぞれ分岐の変位の長さが異なる。大部分の場合は、アセンブラが正しい命令を選ぶ。だが、アセンブラが不可能な場合は、特別な属性、length 属性が定義されているときは GCC が行なうことができる。この属性は、define_attr でヌル文字列を指定することで数値を持つように定義しなければならない。

length 属性の場合は、さらに算術項の二つの形式があり、テスト式で使うことができる。

(match_dup n)
これは、現在の insn のオペランド n のアドレスを参照している。このアドレスは label_ref でなければならない。
(pc)
現在の insn のアドレスを参照する。これを次の insn のアドレスとする使い方の方がより一貫性が保てるのだろうが、そうすると現在の insn の長さを計算するときに混乱する可能性がある。

通常の insn については、長さは length 属性の値により決まる。addr_vecaddr_diff_vec の insn パターンの場合は、長さはベクトル数に各ベクトルの大きさを掛けたものとして計算される。

長さは、アドレス可能な記憶域の単位(バイト)で測る。

以下のマクロを使って長さの計算を洗練されたものにすることができる。

FIRST_INSN_ADDRESS
insn の length 属性が使われているとき、このマクロはある関数の先頭の insn のアドレスに代入されるべき値を指定する。これが指定されていないと、0 が使われる。
ADJUST_INSN_LENGTH (insn, length)
定義されていると、命令 insn に、それが使われている文脈の関数として割り当てられている長さを修正する。length は左辺値であり、最初に計算した insn の長さが入っている。これは、その insn の正しい長さに更新する必要がある。

このマクロは通常は必要とされない。必要となる場合の一つは、ROMP である。この機種では、addr_vec insn の大きさは、アラインメントが必要とされるかも知れないという事実を補償するために、2 づつ増加しなければならない。

get_attr_length(length 属性の値)を返すルーチンを出力ルーチンの中で使うと、以下の例が示すように、書き出すべき分岐命令の形を決めることができる。

可変長分岐の指定の例として、IBM 360 を考える。あるレジスタに、ある関数の開始アドレスが設定されるという規約を採用したとすると、その開始点から 4k バイト以内のラベルには一個の 4 バイト命令でジャンプすることが出来る。それ以外の場合は、6バイトの命令列を使って、メモリからアドレスをロードし、次にそのアドレスに分岐する必要がある。

こういう機種では、分岐命令のパターンは以下のような指定になる。

(define_insn "jump"
  [(set (pc)
        (label_ref (match_operand 0 "" "")))]
  ""
  "*
{
   return (get_attr_length (insn) == 4
           ? \"b %l0\" : \"l r15,=a(%l0); br r15\");
}"
  [(set (attr "length") (if_then_else (lt (match_dup 0) (const_int 4096))
                                      (const_int 4)
                                      (const_int 6)))])


Node:Constant Attributes, Next:, Previous:Insn Lengths, Up:Insn Attributes

定数である属性の定義

define_attr の特別な形式、つまり、デフォルト値の式が const 式の場合、ある特定のコンパイラの実行については定数である属性を示す。定数属性は、どの種類のプロセッサが使われるかを指定するのに使われる。例えば、以下のようになる。

(define_attr "cpu" "m88100,m88110,m88000"
 (const
  (cond [(symbol_ref "TARGET_88100") (const_string "m88100")
         (symbol_ref "TARGET_88110") (const_string "m88110")]
        (const_string "m88000"))))

(define_attr "memory" "fast,slow"
 (const
  (if_then_else (symbol_ref "TARGET_FAST_MEM")
                (const_string "fast")
                (const_string "slow"))))

定数属性用に生成されたルーチンには、どの特定の insn にも依存しないので、パラメータはない。定数属性の値を定義するのに使われる RTL 式は、symbol_ref 形式を使っても良いが、insn の属性を含む、match_operand 形式や eq_attr 形式は使ってならない。


Node:Delay Slots, Next:, Previous:Constant Attributes, Up:Insn Attributes

遅延スロットの定義

insn の属性の機構を使うと、ターゲットマシンに遅延スロットがもしあれば、遅延スロットを必要であると指定することができる。ある命令は、物理的にその直後に置かれている命令群が、その命令の前に置かれているかのように実行されるとき、遅延スロットを必要とすると言われる。古典的な例では、分岐命令と呼び出し命令が該当し、分岐や呼び出しが実行される前に後続の命令を実行することがある。

機種によっては、条件分岐命令が、遅延スロットに置かれている命令を選択的に無効化することができる。これは、遅延スロットにある命令が、分岐の結果によっては実行されないということを意味する。分岐が真のときに無効化を行なう命令と分岐が偽の時に無効化を行なう命令の両方がサポートされている。

遅延スロット空けジューリングが命令スケジューリングと異なるのは、ある命令が遅延スロットを必要とするかどうかを決めるには、生成される命令の型にだけ依存し、命令間のデータ流には依存しないという点にある。データ依存の命令スケジューリングに関する議論については次の節を参照のこと。

ある insn が一個以上の遅延スロットを必要とするという要件は、define_delay 式により指示される。define_delay 式は以下の形式を取る。

(define_delay test
              [delay-1 annul-true-1 annul-false-1
               delay-2 annul-true-2 annul-false-2
               ...])

test は、属性のテストであり、この define_delay がある特定のinsn に適用されるかどうかを指示する。もし適用されるのであれば、必要な遅延スロットの数が二番目の引数として指定されるベクターの長さにより決定される。遅延スロット n に置かれている insn は、属性テスト delay-n を満足しなければならない。annul-true-n は属性テストであり、分岐が真の時にどの insn が無効化されるかを指定する。同様に、annul-false-n は分岐が偽の時に、遅延スロットにあるうちのどの insn が無効化されるかを指定する。遅延スロットの無効化がサポートされていないなら、(nil) を指定すること。

例えば、良くある場合として分岐 insn と呼び出し insn が一個の遅延スロットを必要とし、そのスロットには分岐あるいは呼び出し以外の任意の insn を置くことができる場合、以下のコードを md ファイルに置くことになる。

(define_delay (eq_attr "type" "branch,call")
              [(eq_attr "type" "!branch,call") (nil) (nil)])

define_delay 式は複数指定することができる。その場合、各 define_delay 式は、別々の遅延スロット要件を指定し、二つの define_delay 式のテストで両方真になる insn があってはならない。

例えば、分岐には一個の遅延スロットを必要とするが、呼び出しには二つの遅延スロットが必要で、遅延スロットには分岐 insn も呼び出し insn も置くことができず、分岐用の遅延スロットに有効な任意の insn が分岐が真の場合には無効化可能であるという機種では、以下のように表現する。

(define_delay (eq_attr "type" "branch")
   [(eq_attr "type" "!branch,call")
    (eq_attr "type" "!branch,call")
    (nil)])

(define_delay (eq_attr "type" "call")
              [(eq_attr "type" "!branch,call") (nil) (nil)
               (eq_attr "type" "!branch,call") (nil) (nil)])


Node:Function Units, Previous:Delay Slots, Up:Insn Attributes

insn スケジューリングに必要な情報の指定

多くの RISC マシンでは、特定のサイクル数またないとその結果が得られないような命令が存在する。良く見られるのは、メモリからデータをロードする命令である。多くのマシンでは、ロード命令の後、あまり早くロードされるデータを参照すると、パイプラインがストールする。

さらに、最近の多くのマイクロプロセッサは、複数の機能ユニット、普通は一個の整数向けのユニットと一個の浮動小数点ユニットを持っており、そのため、必要とされる結果が用意できていないときに良くパイプラインがストールする。

この節では、ある命令の実行から、その結果が使えるようになるまでにどれだけの時間が経過する必要があるかを指定する方法を説明する。また、ある命令の実行することにより、機能ユニットの競合にのために、同種の命令の実行を遅らせることがあるのはどういう場合かを指定する方法についても説明する。

この節で説明する指定方法のために、マシンを機能ユニットに分割し、各機能ユニットは特定の種類の命令を first-in-first-out 順に実行するものとする。各サイクル毎に一つの命令を受付、続く命令でその結果が利用できる(フォワーディングによることが多い)機能ユニットについては、指定を行う必要がない。古典的な RISC マイクロプロセッサは、通常機能ユニットは一つしかなく、それをメモリ と呼ぶことが出来る。最近のスーパースカラ・プロセッサは、浮動小数点演算用の機能ユニットを複数持つことが多い。少なくとも、一個の浮動小数点加算器と乗算器を持つのが普通である。

ある insn のクラスによるある機能ユニットの使用方法は、define_function_unit 式で指定される。それは以下のようになる。

(define_function_unit name multiplicity simultaneity
                      test ready-delay issue-delay
                     [conflict-list])

name は、機能ユニット名を指定する文字列である。

multiplicity は整数であり、プロセッサの持つ同等のユニット数を指定する。二個以上のユニットが指定された場合は、各ユニットは独立にスケジュールされる。本当に独立なユニット数を指定すべきである。パイプライン化されたユニットは一個のユニットとして指定すべきである。(一個の命令クラスに対し複数の機能ユニットがあり、それらが真に独立しており、パイプライン化されていない機種の良く知られている例としては、CDC 6600 の二つの乗算ユニットと二つの増分ユニットがあるのみである。)

simultaneity は、各機能ユニットの実態で同時に実行できる命令の最大数か、機能ユニットがパイプライン化されていて制限がないのであればゼロを指定する。

機能ユニット name を参照している、全ての define_function_unit の定義は、multiplicitysimultaneity について同じ名前と値を持たなければならない。

test は属性テストであり、この定義において記述しようとしているinsn を選択する。一個の insn は、複数の機能ユニットを使っても良く、一個の機能ユニットは複数の define_function_unit で指定されていても良いということに注意して欲しい。

ready-delay はある整数であり、ストールなしで命令の結果が使えるようになるまでのサイクル数を指定する。

issue-delay はある整数であり、test 式に一致した命令がこの機能ユニットを使い始めてから、後続の命令が使い始められるまでのサイクル数を指定する。コストが N だと N-1 サイクルの遅延を表す。後続の命令は、以前の命令がより大きな値の ready-delay を持っている場合にも遅延する可能性がある。このブロックの効果は、simultaneityready-delayissue-delayconflict-list といった項から計算される。普通のパイプライン化されていない機能ユニットについては、simultaneity は 1 であり、このユニットは、実行している命令のready-delay サイクルの間ブロックされる。より小さな値のissue-delay は無視される。

conflict-list はオプションのリストであり、この機能ユニットの衝突の詳細なコストを与える。指定されていると、条件のテスト式のリストになっており、その式は、name で実行されるように選ばれたinsn に適用される。その insn の後に、既に name で実行中のtest にマッチする特定の insn が続く。リストのそれぞれの insn に対し、issue-delay が衝突のコストを指定する。リストに無い insn については、コストはゼロである。指定されていない場合は、conflict-list は、機能ユニットを使う全ての命令がデフォルトになる。

このベクトルが使われる典型的な場合としては、浮動小数点機能ユニットが単精度演算か倍精度演算のどちらかはパイプライン化できるが両方は出来ない場合や、メモリユニットがロード命令はパイプライン化できるがストア命令はできない場合等がある。

例として古典的な RISC マシンを考えてみよう。ロード命令の結果は二サイクルの間利用できず(一個の「遅延」命令が必要)、ロード命令は同時には一個しか実行できないとする。これは以下のように指定できる。

(define_function_unit "memory" 1 1 (eq_attr "type" "load") 2 0)

浮動小数点機能ユニットが単精度か倍精度のどちらかはパイプライン処理できるが、両方はできないという場合、以下のように指定することができる。

(define_function_unit
   "fp" 1 0 (eq_attr "type" "sp_fp") 4 4 [(eq_attr "type" "dp_fp")])
(define_function_unit
   "fp" 1 0 (eq_attr "type" "dp_fp") 4 4 [(eq_attr "type" "sp_fp")])

注意: スケジューラは、機能ユニットの衝突を避け、define_function_unit の全ての指定を使おうとする。我々は最近、これらの指定では、複数のパイプラインユニットを使う命令を持つ、いくつかの新しめの「スーパスカラ」プロセッサをモデル化できないということに気が付いた。これらの命令は、第二の機能ユニットがそれらの命令を実行するのに使われている間に潜在的な衝突を起こす可能性があり、その衝突を表現する方法がないのである。このようなプロセッサの機能ユニットの衝突の仕組みの例や、その表現方法について提案があれば、知らせて欲しい。


Node:Target Macros, Next:, Previous:Machine Desc, Up:Top

ターゲット記述マクロ

マシン記述は、ファイル machine.md の他に、machine.h という名前の C ヘッダファイルから構成される。このヘッダファイルは、多数のマクロを定義するものであり、.md ファイルに記述しきれないターゲット機種の情報を伝える。tm.h というファイルは、machine.h へのリンクにならねばならない。そして、ヘッダファイル config.htm.h をインクルードしており、ほとんどのソースファイルがconfig.h をインクルードしている。


Node:Driver, Next:, Previous:Target Macros, Up:Target Macros

コンパイラドライバ gcc の制御

コンパイラドライバの制御に関するマクロを以下に示す。

SWITCH_TAKES_ARG (char)
一個のC の式。オプション -char が引数を取るかどうかを指定する。この式の値は、オプションが取る引数の数である。多くのオプションでは 0 になる。

このマクロは、デフォルトでは、DEFAULT_SWITCH_TAKES_ARG に定義される。DEFAULT_SWITCH_TAKES_ARG は、標準のオプションを正しく扱う。引数を取るオプションを新たに追加しない限り SWITCH_TAKES_ARG を定義する必要はない。定義する場合には、まず DEFAULT_SWITCH_TAKES_ARG を呼び出してから、追加したオプションの検査を行なうようにすること。

WORD_SWITCH_TAKES_ARG (name)
C の式であり、オプション -name が引数を取るかどうかを指定する。この式の値は、オプションが取る引数の数である。多くのオプションでは 0 になる。複数文字からなるオプション名の場合には、SWITCH_TAKES_ARG の代わりにこちらを使う。

このマクロは、デフォルトで DEFAULT_WORD_SWITCH_TAKES_ARG に定義されており、標準のオプションを正しく扱うことができる。定義し直す場合には、まず DEFAULT_WORD_SWITCH_TAKES_ARG を呼び出してから、追加したオプションの検査を行うようにする必要がある。

SWITCH_CURTAILS_COMPILATION (char)
一個の C の式であり、-char というオプションが、実行形式の生成の前でコンパイルを止めるかどうかを決定する。この式の値は、ブール型であり、オプションが実行形式の生成を止めるならゼロでない値であり、止めないならゼロである。

デフォルトでは、このマクロは DEFAULT_SWITCH_CURTAILS_COMPILATION として定義される。DEFAULT_SWITCH_CURTAILS_COMPILATION は標準のオプションを正しく取り扱う。実行形式の生成に影響を与えるオプションを追加するのでない限り、SWITCH_CURTAILS_COMPILATION を定義する必要はない。再定義するなら、DEFAULT_SWITCH_CURTAILS_COMPILATION をまず呼び出して、次に追加したオプションの検査を行うようにする必要がある。

SWITCHES_NEED_SPACES
文字列を値とする C の式であり、リンカに渡すオプションのうち、オプションとその引数との間に空白を必要とするものを列挙する。

このマクロが定義されない場合、デフォルトは "" になる。

CPP_SPEC
一個の C の文字列定数。CPP に渡すオプションを GNU CC のドライバプログラムに 知らせる。これは同時に、ユーザが指定したオプションをGNU CC が CPP に渡すオプションに変換する方法を指定することも出来る。

何もする必要が無いときには、このマクロは定義しないこと。

NO_BUILTIN_SIZE_TYPE
このマクロが定義されていると、プリプロセッサは組み込みマクロ__SIZE_TYPE__ を定義しない。その場合は代わりに、マクロ __SIZE_TYPE__CPP_SPEC で定義する必要がある。

SIZE_TYPE がプリプロセッサからは参照できないターゲット依存のフラグに依存するなら、このマクロを定義すべきである。その他の場合は、定義すべきでない。

NO_BUILTIN_PTRDIFF_TYPE
このマクロを定義した場合、プリプロセッサは組み込みマクロ__PTRDIFF_TYPE__ を定義しない。その場合は代わりに __PTRDIFF_TYPE__ を、CPP_SPEC で定義する必要がある。

PTRDIFF_TYPE がプリプロセッサからは参照できないターゲット依存のフラグに依存するなら、このマクロを定義すべきである。その他の場合は、定義すべきでない。

SIGNED_CHAR_SPEC
このマクロは C の文字列定数に定義し、CPP に渡すべきオプションをGNU CC のドライバプログラムに知らせる。デフォルトでは、cc1charunsigned char と同じように扱うなら、-D__CHAR_UNSIGNED__ というオプションを渡すように定義されている。

デフォルトの定義を変える必要がないのであれば、このマクロは定義しないこと。

CC1_SPEC
GNU CC のドライバプログラムが cc1 に渡すオプションをC の文字列定数で定義する。これは同時に、ユーザが指定したオプションをGNU CC が cc1 に渡すオプションに変換する方法を指定することも出来る。

何もする必要が無いときには、このマクロは定義しないこと。

CC1PLUS_SPEC
C の文字列定数であり、GNU CC のドライバプログラムに対し、cc1plus に渡すべきオプションを知らせる。

何もする必要がなければ、このマクロは定義しないこと。

ASM_SPEC
C の文字列定数であり、GNU CC のドライバプログラムに対し、アセンブラに渡すべきオプションを知らせる。さらに、GNU CC に与えられたオプションを、GNU CC がアセンブラに渡すべきオプションに変換する方法の指定も行う。例としては sun3.h を参照のこと。

何もする必要がなければ、このマクロは定義しないこと。

ASM_FINAL_SPEC
C の文字列定数であり、GNU CC のドライバプログラムに対し、通常のアセンブラの後に後処理を行うプログラムを実行する方法を知らせる。通常は、この後処理は不要である。この例としては、mips.h を参照のこと。

何もする必要がなければ、このマクロは定義しないこと。

LINK_SPEC
C の文字列定数であり、GNU CC のドライバプログラムに対し、リンカに渡すべきオプションを知らせる。さらに、GNU CC に与えられたオプションを、GNU CC がリンカに渡すべきオプションに変換する方法を指定する。

何もする必要がなければ、このマクロは定義しないこと。

LIB_SPEC
C の文字列定数で、LINK_SPEC に良く似た使われ方をする。違いは、LIB_SPEC はリンカに指定されたコマンドの最後に置かれることである。

このマクロが定義されていない場合は、デフォルトは普通置かれている場所から標準 C ライブラリをロードすることになる。gcc.c を参照のこと。

LIBGCC_SPEC
C の文字列定数で、GNU CC のドライバプログラムに、いつどのように、libgcc.a への参照をリンカのコマンド行に置くかを指示する。この定数は、LIB_SPEC の値の前後両方に置かれる。

このマクロが定義されていない場合は、GNU CC のドライバはデフォルトでは、-shared オプションが指定されていない限り、文字列 -lgcc をリンカに渡す。

STARTFILE_SPEC
LINK_SPEC と良く似ている、やはり別の C の文字列定数である。違いは、STARTFILE_SPEC がリンカに渡されるコマンド行引数の先頭で使われる点である。

このマクロが定義されていなければ、デフォルトは C の標準的なスタートアップファイルを通常の場所からロードするという定義になる。gcc.c を参照のこと。

ENDFILE_SPEC
LINK_SPEC と良く似ている、もう一つのやはり別の C の文字列定数である。違いは、ENDFILE_SPEC がリンカに渡されるコマンド行引数の最後で使われる点である。

何もする必要がなければ、このマクロは定義しないこと。

EXTRA_SPECS
このマクロで、specs ファイルに追加する指定を定義する。ここで追加した指定は、CC1_SPEC の様な様々な指定で使用できる。

定義は、構造体の配列の初期化子とすべきである。この構造体は、指定名を定義する文字列定数と指定そのものを与える文字列定数を含む。

何もする必要がなければ、このマクロは定義しないこと。

EXTRA_SPECS が役に立つのは、ある一つのアーキテクチャに関連するいくつものターゲットがあるときである。そのような場合、互いに似通った ..._SPECS がいくつもあり、保守者はこれらの定義を一箇所で集中管理したいであろう。

例えば、PowerPC の System V.4 のターゲットは、EXTRA_SPECS を使って、System V の呼びだしシーケンスを使うときは _CALL_SYSV を、古い AIX ベースの呼びだしシーケンスを使うときは _CALL_AIX を定義している。

ターゲットファイル config/rs6000/rs6000.h では以下のような定義を行なっている。

#define EXTRA_SPECS \
  { "cpp_sysv_default", CPP_SYSV_DEFAULT },

#define CPP_SYS_DEFAULT ""

ターゲットファイル config/rs6000/sysv.h では以下のような定義を行なっている。

#undef CPP_SPEC
#define CPP_SPEC \
"%{posix: -D_POSIX_SOURCE } \
%{mcall-sysv: -D_CALL_SYSV } %{mcall-aix: -D_CALL_AIX } \
%{!mcall-sysv: %{!mcall-aix: %(cpp_sysv_default) }} \
%{msoft-float: -D_SOFT_FLOAT} %{mcpu=403: -D_SOFT_FLOAT}"

#undef CPP_SYSV_DEFAULT
#define CPP_SYSV_DEFAULT "-D_CALL_SYSV"

一方、config/rs6000/eabiaix.h の定義は以下の通りである。

#undef CPP_SYSV_DEFAULT
#define CPP_SYSV_DEFAULT "-D_CALL_AIX"

LINK_LIBGCC_SPECIAL
ライブラリ libgcc.a はドライバプログラム自身が探すべきであり、リンカには -L オプションを渡すべきでなければ、このマクロを定義する。このマクロを定義した場合、ドライバプログラムは、引数 -lgcc をリンカに渡して libgcc.a の検索を行なわせ、検索を行なうディレクトリを -L オプションでリンカに渡す。
LINK_LIBGCC_SPECIAL_1
ドライバプログラムがライブラリ libgcc.a を探すべきであるなら、このマクロを定義する。このマクロが定義されていない場合、引数 -lgcc をリンカに渡して libgcc.a の検索を行なわせる。このマクロは LINK_LIBGCC_SPECIAL とほぼ同じだが、-L オプションを渡さない点が異なる。
LINK_COMMAND_SPEC
C の文字列定数。リンカを実行するの必要な完全なコマンド行を指定する。これを定義するときは、gcc.c にあるリンクのためのコマンド行に変更が加わる度に読者の移植部分を更新する必要がある。このため、リンカを起動するコマンド行を完全に再定義する必要があり、かつ、読者が必要な効果を得るための方法が他にない場合だけ、このマクロを定義すること。
MULTILIB_DEFAULTS
このマクロは、C の文字列の配列の初期化式として定義して、ドライバプログラムに対し、どのオプションがこのターゲットのデフォルトなのか、そして、どれが MULTILIB_OPTIONSを使った場合に特別に扱う必要がないオプションかを知らせる。

MULTILIB_OPTIONS がターゲットの makefile 断片で定義されていない場合や、 MULTILIB_OPTIONS に列挙されているオプションの中にデフォルトで指定されるものが無い場合は、このマクロは定義しないこと。

RELATIVE_PREFIX_NOT_LINKDIR
このマクロを定義すると、gcc は、プレフィックスが絶対パスの場合は、-B で指定されたプレフィックスをリンカの -L オプションについてだけ変換する。
STANDARD_EXEC_PREFIX
コンパイラの実行形式ファイル群を検索する時のデフォルトの接頭辞である、/usr/local/lib/gcc-lib/ を別のものに置き換えたい場合は、このマクロを、それを表す C の文字列定数として定義する。
MD_EXEC_PREFIX
このマクロが定義されていれば、STANDARD_EXEC_PREFIX の後で、これを接頭辞として追加で検索が行なわれる。-b オプションが指定されたり、クロスコンパイラとして構築された場合は、MD_EXEC_PREFIX の検索は行なわれない。MD_EXEC_PREFIX を定義する場合は、それを configure.in 中の、アセンブラを検索するのに使われるディレクトリのリストに追加するのを忘れないこと。
STANDARD_STARTFILE_PREFIX
crt0.o のようなスタートアップファイルを検索する時のデフォルトの接頭辞である、/usr/local/lib/ を別のものに置き換えたい場合は、このマクロを、それを表す C の文字列定数として定義する。
MD_STARTFILE_PREFIX
このマクロが定義されていれば、標準の接頭辞でスタートアップファイル検索が行なわれた後で、このマクロを接頭辞として追加で検索が行なわれる。-b オプションが指定されたり、クロスコンパイラとして構築された場合は、MD_STARTFILE_PREFIX の検索は行なわれない。
MD_STARTFILE_PREFIX_1
このマクロが定義されていれば、標準の接頭辞でスタートアップファイル検索が行なわれた後で、このマクロを接頭辞としてさらにもう一度追加で検索が行なわれる。-b オプションが指定されたり、クロスコンパイラとして構築された場合は、この接頭辞での検索は行なわれない。
INIT_ENVIRONMENT
ドライバから呼び出されるプログラム、例えばアセンブラやローダに対して環境変数を指定したければ、このマクロを C の文字列定数として定義する。ドライバは、このマクロの値を putenv に渡して、必要な環境変数の初期化を行なう。
LOCAL_INCLUDE_DIR
ローカルのヘッダファイルを検索するときのデフォルトの接頭辞である、/usr/local/include の代わりのものを使いたいときは、それを C の文字列定数としてこのマクロに定義する。LOCAL_INCLUDE_DIR は、SYSTEM_INCLUDE_DIR の前に検索される。

クロスコンパイラの場合はこのマクロは使わないし、/usr/local/include やその代わりの場所は検索しない。

SYSTEM_INCLUDE_DIR
標準のディレクトリの前にヘッダファイルを検索したい、システム固有のディレクトリがあれば、このマクロで C の文字列定数として定義する。SYSTEM_INCLUDE_DIR は、 STANDARD_INCLUDE_DIR の前に検索される。

クロスコンパイラの場合はこのマクロは使わないし、これで指定されたディレクトリを検索しない。

STANDARD_INCLUDE_DIR
ヘッダファイルを検索するときのデフォルトの接頭辞である、/usr/include を別のものに置き換えたいときは、このマクロでC の文字列として定義する。

クロスコンパイラの場合はこのマクロは使わないし、/usr/include やその代わりのディレクトリを検索しない。

STANDARD_INCLUDE_COMPONENT
STANDARD_INCLUDE_DIR に対応する「成分」である。成分の説明については以下の INCLUDE_DEFAUTLS を参照のこと。このマクロを定義しない場合は、成分は一つも使われない。
INCLUDE_DEFAULTS
インクルードファイルのデフォルトの検索パス全体を上書きしたい場合は、このマクロを定義する。ネイティブコンパイラの場合は、デフォルトの検索パスは通常は、GCC_INCLUDE_DIRLOCAL_INCLUDE_DIRSYSTEM_INCLUDE_DIRGPLUSPLUS_INCLUDE_DIRSTANDARD_INCLUDE_DIR から成る。さらに、GPLUSPLUS_INCLUDE_DIRGCC_INCLUDE_DIRMakefile で自動的に定義され、GCC に固有の検索パスを指定する。ディレクトリ GPLUSPLUS_INCLUDE_DIR は、C++ プログラムについてだけ使われる。

このマクロは、構造体の配列の初期化子として定義しなければならない。配列の各要素は、それぞれ四つの要素を持つ。ディレクトリ名(文字列定数)、成分名、C++ 向けディレクトリ用フラグ、C++ プログラムをコンパイルするときには、そのディレクトリのインクルード行をextern "C" で囲む必要がないかどうかを示すフラグ、である。配列の終りはヌルの要素で示す。

成分名は、インクルードファイルがどの GNU パッケージのものかを示す。これは全て大文字で記す。例えば、GCCBINUTILS とする。インクルードファイルの入っているパッケージが、ベンダ提供のオペレーティングシステムの一部である場合は、成分名は 0 と書くようにする。

例えば、VAX/VMS 向けの定義は以下のようになる。

#define INCLUDE_DEFAULTS \
{                                       \
  { "GNU_GXX_INCLUDE:", "G++", 1, 1},   \
  { "GNU_CC_INCLUDE:", "GCC", 0, 0},    \
  { "SYS$SYSROOT:[SYSLIB.]", 0, 0, 0},  \
  { ".", 0, 0, 0},                      \
  { 0, 0, 0, 0}                         \
}

実行形式ファイルのプレフィックスを試す順序を以下に示す。

  1. ユーザにより -B で指定されたプレフィックス。
  2. もし指定されていれば、環境変数 GCC_EXEC_PREFIX
  3. 環境変数 COMPILER_PATH で指定されたディレクトリ。
  4. マクロ STANDARD_EXEC_PREFIX
  5. /usr/lib/gcc/
  6. 指定されていれば、マクロ MD_EXEC_PREFIX

開始ファイルは、以下のプレフィックスを順番に探す。

  1. ユーザが -B で指定したプレフィックス。
  2. 定義されていれば、環境変数 GCC_EXEC_PREFIX
  3. 環境変数 LIBRARY_PATH で指定されたディレクトリ群(ネイティブの場合のみ。クロスコンパイラでは使われない。)
  4. マクロ STANDARD_EXEC_PREFIX
  5. /usr/lib/gcc/.
  6. 定義されていれば、マクロ MD_EXEC_PREFIX
  7. 定義されていれば、マクロ MD_STARTFILE_PREFIX
  8. マクロ STANDARD_STARTFILE_PREFIX
  9. /lib/.
  10. /usr/lib/.


Node:Run-time Target, Next:, Previous:Driver, Up:Target Macros

実行時ターゲット指定

以下に実行時のターゲット指定を示す。

CPP_PREDEFINES
C の文字列定数を定義する。この文字列には、マシンとシステムを特定する事前定義マクロを定義する、-D オプションを指定する。ここで指定されたマクロは、-ansi オプションが指定されない限り定義済となる。

さらに、これらのマクロ名の前後に __ を付加した名前のマクロのセットが並行して定義済となる。これら __ 付きのマクロは ANSI 標準により許されており、-ansi オプションの指定の有無に関わらず、定義済となる。

例えば、Sun では、次のような指定をすることができる。

"-Dmc68000 -Dsun -Dunix"

この結果、マクロ __mc68000____sun____unix__ が無条件に定義され、mc68000sununix-ansi オプションが指定されないときに定義される。

extern int target_flags;
この宣言は必須である。
TARGET_...
この一連のマクロを定義することで、コンパイラのコマンド行引数により、ターゲット機種の選択的機能の使用を有効/無効にすることができる。例えば、一個のマシン記述で 68000 と 68020 の両方に対応できるので、コマンド行引数で、コンパイラに 68020 固有の命令を使うかどうかを指定できる。コマンド行引数が動作する仕組みは、target_flags 中のビットが立っているかどうかをテストする TARGET_68020 というマクロによるものである。

このようなオプション毎に TARGET_featurename というマクロを定義する。この定義では、target_flags 中のビットが立っているかどうかをテストしなければならない。例えば、以下のように書く。

#define TARGET_68020 (target_flags & 1)

こういったマクロが使われるのは、一つには、命令パターン中の条件式である。TARGET_68020 が、68000 のマシン記述ファイル、m68k.md にどれぐらい現れるか注意してみると良いだろう。

TARGET_SWITCHES
このマクロでは、target_flags 中のビットをセットしたりクリアするコマンド行オプションの名前を定義する。この定義は、各コマンド行オプション毎にグループ分けした初期化子とする。

各グループは、オプション名を定義する文字列定数、target_flags にセットすべきビット群を含む数値、それに --help オプションを指定したときに表示される説明となる第二の文字列から成る。数値が負の数の場合、その数値で指定されるビットを立てる代わりに、クリアする。説明文字列が、存在はするが空の場合、そのオプションについてのヘルプ情報は何も表示されないが、隠しオプションには数えない。実際のオプション名は、ここで指定した名前に -m を付加したものになる。

ヌル文字列を持つグループが一個存在する必要がある。このグループで指定する数値が、target_flags のデフォルト値になる。どのターゲットオプションも最初はこのデフォルト値に対して作用する。

以下の例では -m68000-m68020 をお互いに反対の意味を持つように定義し、後者をデフォルトとしている。

#define TARGET_SWITCHES \
  { { "68020", 1, "" },      \
    { "68000", -1, "Compile for the 68000" }, \
    { "", 1, "" }}

TARGET_OPTIONS
TARGET_SWITCHES と同様のマクロだが、値を持つコマンド行オプションの名前を定義する。この定義は、コマンド行オプション毎のグループ分けした初期化子とする。

各グループはそれぞれ、フィールドとして、オプション名の固定部分を定義する文字列定数、ある変数のアドレス、それに説明文字列を持つ。この変数は、char * 型であり、指定したオプションの固定部分がマッチした場合、変動部分がこの変数に設定される。実際のオプション名は、指定した名前に -m を付加したものになる。

以下の例では、-mshort-data-number というオプションを定義している。指定されたオプションが -mshort-data-512 なら、変数 m88k_short_data には、文字列 "512" がセットされる。

extern char *m88k_short_data;
#define TARGET_OPTIONS \
 { { "short-data-", &m88k_short_data, "Specify the size of the short data section" } }

TARGET_VERSION
このマクロは C の文として定義する。この文は、選択された特定のマシン記述を説明する文字列を stderr に出力するようにする。どのマシン記述でも必ず TARGET_VERSION を定義して欲しい。以下に定義例を示す。
#ifdef MOTOROLA
#define TARGET_VERSION \
  fprintf (stderr, " (68k, Motorola syntax)");
#else
#define TARGET_VERSION \
  fprintf (stderr, " (68k, MIT syntax)");
#endif

OVERRIDE_OPTIONS
場合によっては、コマンド行オプションのある組合せが、ある特定のターゲット機種では意味をなさないことがある。そういう場合を考慮に入れるにはマクロ OVERRIDE_OPTIONS を定義する。このマクロは、定義されていると、全てのコマンド行オプションがパーズされた直後に一回だけ実行される。

このマクロを使って、-O オプションを指定したときに色々な特別の最適化を実行するようにしてはいけない。そのためには、OPTIMIZATION_OPTIONS というマクロがある。

OPTIMIZATION_OPTIONS (level, size)
このマクロは、定義されていれば、最適化レベルが決まった直後で、コマンド行オプションの残りがパースされる前に一回だけ実行される。このマクロに設定されている値は、他のコマンド行オプションのデフォルト値として使われる。

level は指定された最適化レベルであり、-O2 が指定されれば 2 であり、-O が指定されれば 1、どちらも指定されなければ0 である。

size は、-Os が指定されていればゼロでない値であり、指定されていなければゼロである。

このマクロを使って機種固有ではないオプションを変えるべきではない。機種固有でないオプションは、全てのサポートされている機種で同じ最適化レベルによって統一的に選択されるべきである。このマクロは、機種固有の最適化を有効にするのに使うこと。

このマクロの中で、write_symbols を調べてはいけない。 デバッグ用オプションは、生成コードを変えるとは想定されていない。

CAN_DEBUG_WITHOUT_FP
フレームポインタ無しでもデバッグできるようにするなら、このマクロを定義する。このマクロが定義されていると GNU CC は、-O が指定されていれば必ず -fomit-frame-pointer オプションを有効にする。


Node:Storage Layout, Next:, Previous:Run-time Target, Up:Target Macros

記憶領域のレイアウト

以下に示すテーブルでは、データのサイズやアラインメントをビット単位で表すマクロの定義を示している。注意して欲しいのは、これらのマクロは定数である必要はないということである。target_flags のような静的変数を参照する C の式でもかまわないのである。See Run-time Target.

BITS_BIG_ENDIAN
バイトの中で最上位のビットが最下位の数を保持しているなら、このマクロを1 に定義する。そうでなければ、0 に定義する。1 に定義した場合は、ビットフィールド命令はビットを最上位ビットから数える。ビットフィールド命令がない場合でも、このマクロは定義しなければならない。その場合は、どんな値に定義してもかまわない。このマクロは定数である必要はない。

このマクロは、構造体のフィールドがバイトまたはワードにどのように詰め込まれるかには影響しない。それは、BYTES_BIG_ENDIAN により制御される。

BYTES_BIG_ENDIAN
ワードの中の最下位バイトが最下位の数を保持しているなら、このマクロを 1 に定義する。このマクロは定数である必要はない。
WORDS_BIG_ENDIAN
複数のワードからなるデータ中で最上位のワードが最下位の数を保持しているなら、このマクロを 1 に定義する。これは、メモリとレジスタの両方に適用される。GNU CC は基本的に、メモリ中のワードの順番とレジスタ中のワードの順番が同じであると仮定している。このマクロは定数である必要はない。
LIBGCC2_WORDS_BIG_ENDIAN
WORDS_BIG_ENDIAN が定数でない場合はこのマクロを定義する。これは WORDS_BIG_ENDIAN と同じ意味を持つ定数値でなければならない。この値は、CPP マクロに基づいて設定されることが多い。
FLOAT_WORDS_BIG_ENDIAN
DFmode または XFmodeTFmode の浮動小数点数がメモリ中に格納されるときに、符号ビットを含むワードが最下位アドレスに置かれる場合は、このマクロを値 1 として定義する。このマクロが定数である必要はない。

メモリ中に格納されるワードの順序が、複数ワードの整数の場合と同じなら、このマクロを定義する必要はない。

BITS_PER_UNIT
アドレス可能な格納単位(バイト)中のビット数を定義するマクロである。通常は 8 になる。
BITS_PER_WORD
ワードのビット数。普通は 32 である。
MAX_BITS_PER_WORD
ワード中の最大ビット数。定義されていない場合は、デフォルトでBITS_PER_WORD になる。定義する場合は、BITS_PER_WORD が実行時に取りうる最大値である定数値とする。
UNITS_PER_WORD
ワード中の格納単位数。普通は 4 である。
MIN_UNITS_PER_WORD
ワード中の格納単位の最小数。定義されていない場合は、デフォルトでUNITS_PER_WORD になる。定義する場合は、UNITS_PER_WORD が実行時に取りうる最小値となる定数値とする。
POINTER_SIZE
ポインタの幅をビット数で表す。Pmode の幅よりも大きな値を指定してはならない。Pmode の幅と同じでない場合は、POINTERS_EXTEND_UNSIGNED を定義しなければならない。
POINTERS_EXTEND_UNSIGNED
C の式で、その値は、POINTER_SIZE ビット幅から Pmode に拡張する必要があるポインタがゼロ拡張されるならゼロでない値とし、符号拡張されるなら 0 とする。

POINTER_SIZEPmode の幅に同じならこのマクロを定義する必要はない。

PROMOTE_MODE (m, unsignedp, type)
あるオブジェクトが、型が type であり、指定されたモード m と符号 unsignedp を持ち、レジスタに格納されることになっているなら、このマクロは munsignedp を更新する。

多くの RISC マシンでは、全ワードに対して操作を行なう演算しか持っていないので、mBITS_PER_WORD よりも幅の狭い整数モードならこのマクロで mword_mode に設定するように定義する。大部分の場合、整数モードの場合だけ拡幅すべきである。何故なら、精度の高い浮動小数点演算は、普通は精度の低いものより高くつくからである。

多くの機種では、このマクロの定義で unsignedp を変えることはしていない。だが、機種によっては特定のモードについては符号付きか符号なしかのどちらかの量を優遇する命令を持っている。例えば、DEC Alpha では、メモリからの 32ビットのロードと 32ビットの加算命令は結果を 64 ビットに符号拡張する。そういう機種では、どちらの拡張が効率が良いかにしたがって unsignedp を設定するようにする。

m を更新することが絶対にないのであればこのマクロは定義しないこと。

PROMOTE_FUNCTION_ARGS
PROMOTE_MODE で記述される格上げを関数の出力(?)引数に対しても行なうべきなら、このマクロを定義する。
PROMOTE_FUNCTION_RETURN
PROMOTE_MODE で記述される格上げを関数の戻り値に対しても行なうべきなら、このマクロを定義する。

このマクロが定義されるなら、FUNCTION_VALUEPROMOTE_MODE によりなされるのと同じ格上げを実行しなければならない。

PROMOTE_FOR_CALL_ONLY
PROMOTE_MODE で記述される格上げを、関数の出力引数か関数の戻り値に対してのみPROMOTE_FUNCTION_ARGSPROMOTE_FUNCTION_RETURN で指定されているように、行なうべきなら、このマクロを定義する。
PARM_BOUNDARY
スタック上の関数のパラメータに通常必要とされるアラインメントをビット数で表す。スタックに置かれるパラメータは全て、データ型によらず、少なくともこの量だけのアラインメントが取られる。多くのマシンでは、この大きさは整数の大きさと同じである。
STACK_BOUNDARY
スタックポインタに保証されているアラインメントがあるなら、このマクロを定義する。定義は、望まれるアラインメントをビット単位で表す C の式とする。この値は、PREFERRED_STACK_BOUNDARY が定義されていない場合のデフォルトとして使われる。
PREFERRED_STACK_BOUNDARY
スタックポインタについて一定のアラインメントを保持したいのであればこのマクロを定義する。定義は、望ましいアラインメントをビット数で表す C の式とする。STACK_BOUNDARY も定義されている場合は、このマクロを評価したなら、STACK_BOUNDARY 以上の値になるようにしなければならない。

PUSH_ROUNDING が定義されていなければ、スタックは常に指定された境界に整合される。PUSH_ROUNDING が定義されていて、アラインメントの制限の指定がPREFERRED_STACK_BOUNDARY より緩ければ、スタックは引数をプッシュしている間一時的に整合が取られないことがある。

FUNCTION_BOUNDARY
関数の入り口点で必要とされるアラインメントをビット数で表す。
BIGGEST_ALIGNMENT
対象機種で任意のデータ型が要求するうちで最大のアラインメントをビット数で表したもの。
MINIMUM_ATOMIC_ALIGNMENT
定義されていれば、最小のアラインメントをビット数で表したものである。これは、隣り合うオブジェクトを煩わせることなく、一回の操作で参照可能なオブジェクトに与えることができるものである。通常、BITS_PER_UNIT になるが、バイト単位あるいはハーフワード単位のストア演算がないマシンではもっと大きくなりうる。
BIGGEST_FIELD_ALIGNMENT
この機種で任意の構造体のフィールドが要求するアラインメントをビット数で表したもの。これが定義されていると、構造体のフィールドに関してはBIGGEST_ALIGNMENT に優先する。
ADJUST_FIELD_ALIGN (field, computed)
通常の方法で計算したアラインメントが computed である場合の、ある構造体フィールド field のアラインメントを表す式。GNU CC は、これが定義されていれば、構造体のフィールドに限って、BIGGEST_ALIGNMENTBIGGEST_FIELD_ALIGNMENT の値の代わりにこの値を使う。
MAX_OFILE_ALIGNMENT
対象機種向けのオブジェクトファイル形式でサポートされている最大のアラインメント。このマクロで、__attribute__ ((aligned (n))) という構文を使って指定できるアラインメントを制限する。これが定義されていない場合は、デフォルト値は BIGGEST_ALIGNMENT になる。
DATA_ALIGNMENT (type, basic-align)
定義するなら、静的メモリ領域に置かれる変数のアラインメントを計算する C の式とする。type はデータの型であり、basic-align はそのオブジェクトが通常持つであろうアラインメントである。通常のアラインメントの代わりに、このマクロの値を使ってそのオブジェクトのアラインメントを取る。

このマクロが定義されなければ、basic-align が使われる。

このマクロの使い道は、一つには、より少ないキャッシュラインに収まるように、中間の大きさのデータのアラインメントを大きくすることにある。もう一つの使い方は、文字の配列をワード境界に整合することを強制することで、定数を文字配列にコピーするような strcpy の呼び出しをインライン展開可能にすることにある。

CONSTANT_ALIGNMENT (constant, basic-align)
メモリに置かれる定数に与えるべきアラインメントを計算する C の式を定義する。constant が定数で、basic-align がそのオブジェクトの通常のアライメントである。このマクロの値が、上記のアラインメントの代わりに、このオブジェクトを整合境界に置くのに使われる。

このマクロが定義されていなければ、basic-align が使われる。

このマクロの典型的な使い方は、文字列定数をワード境界に整合することを強制することで、定数をコピーする strcpy の呼び出しをインライン展開可能にすることにある。

LOCAL_ALIGNMENT (type, basic-align)
定義されていれば、一個の C の式であり、局所的なメモリ領域に置かれる変数のアラインメントを計算する。type はデータ型であり、basic-align はそのオブジェクトが通常取るであろうアラインメントである。このマクロの値が、上記のアラインメントの代わりに、このオブジェクトを整合境界に置くのに使われる。

このマクロが定義されていない場合は、basic-align が使われる。

このマクロの使い道の一つは、中間の大きさのデータのアラインメントをより少ないキャッシュ・ラインに全て収まるように大きくすることである。

EMPTY_FIELD_BOUNDARY
int : 0; のような空のビットフィールの後に続くビットフィールドに指定すべきビット単位のアラインメントである。

PCC_BITFIELD_TYPE_MATTERSもまた、空のビットフィールドから生じるアラインメントに影響を及ぼすことに注意してほしい。

STRUCTURE_SIZE_BOUNDARY
構造体や共用体の大きさが、その倍数になるべきビット数。各構造体や共用体の大きさは、この定数の倍数に切り上げられる。

このマクロを定義しない場合は、デフォルトは BITS_PER_UNIT と同じになる。

STRICT_ALIGNMENT
指定されたデータが満足すべきアラインメントにあっていない場合、命令が正しく動作しないなら、このマクロの値を 1 に定義する。命令が単に遅くなるだけなら、0 に定義する。
PCC_BITFIELD_TYPE_MATTERS
ビットフィールドとビットフィールド含む構造体のアラインメントの扱いを、他の多くの C コンパイラが取っている方法に合わせる場合は、このマクロを定義する。

この場合の動作は、ビットフィールドに指定した型(intshort、またはその他の整数型)が、構造体全体のアライメントに制約を課す。これは、その構造体が、その型の普通の(ビットフィールドではない)フィールドを持っているかのようになる。さらに、このビットフィールドは、その普通のフィールド内に収まるように構造体内で配置される。普通のフィールドの境界を越えることはない。

つまり、多くの機種では型が int のビットフィールドは4バイト境界を越えることはないし、構造体全体のアライメントは4バイトに強制される。(実際に使われる場合、このアライメントは 4 バイトでないこともある。他のアラインメント関係のパラメータにより制御される。)

このマクロは、C の式として定義する。この式の値が 0 でなければ上記の動作を有効にする。

このマクロが定義されていなかったり、値がゼロの場合は、ビットフィールドの中にはアラインメント境界を越えるものもありうる。メモリを直接参照できる、insvextvextzv insn があれば、コンパイラはそのような参照をサポート出来る。

ビットフィールドを使えるようにするもう一つの有名な方法は、STRUCTURE_SIZE_BOUNDARYBIGGEST_ALIGNMENT と同じ大きさに定義することである。そうすると、どの構造体もワード単位でアクセスできる。

対象の機種がビットフィールドを持っていないか、STRUCTURE_SIZE_BOUNDARY を上記のように定義しない限り、PCC_BITFIELD_TYPE_MATTERS が 0 でない値を持つようにしなければならない。

目的が、何か別のコンパイラで使われているビットフィールドの配置規約と同じ規約を GNU CC に使わせることにあるなら、以下に示す方法で、他のコンパイラがどうなっているかを調べることができる。このプログラムをコンパイルして実行すれば良い。

struct foo1
{
  char x;
  char :0;
  char y;
};

struct foo2
{
  char x;
  int :0;
  char y;
};

main ()
{
  printf ("Size of foo1 is %d\n",
          sizeof (struct foo1));
  printf ("Size of foo2 is %d\n",
          sizeof (struct foo2));
  exit (0);
}

これが 2 と 5 を出力するなら、コンパイラの動作はPCC_BITFIELD_TYPE_MATTERS から得られるものである。

BITFIELD_NBYTES_LIMITED
PCC_BITFIELD_TYPE_MATTERS と同様だが、その効果は構造体内のビットフィールドの整合に限られる。
ROUND_TYPE_SIZE (type, computed, specified)
このマクロは、一個の型(type により木ノードとして与えられる) 全体の大きさを表す式を定義する。これを定義するのは、普通の方法で計算した大きさがcomputed であり、アラインメントがspecified となっている場合である。

デフォルトは、computedspecified の倍数に切り上げる。

ROUND_TYPE_ALIGN (type, computed, specified)
このマクロは、一個の型(type により木ノードとして与えられる) のアラインメントを表す式を定義する。これを定義するのは、通常の方法で計算したアラインメントがcomputed であり、明示的に指定されたアラインメントがspecified となっている場合である。

デフォルトでは、specified の方が大きければそれを使う。さもなければ、computedBIGGEST_ALIGNMENT の小さいほうを使う。

MAX_FIXED_MODE_SIZE
実際に使われるべき最大整数のマシンモードの大きさをビット数で表す整数式。この大きさ以下の全ての整数マシンモードは、適切な大きさの構造体と共用体に使うことができる。このマクロが定義されていない場合は、GET_MODE_BITSIZE (DImode) が仮定される。
STACK_SAVEAREA_MODE (save_level)
定義されていれば、enum machine_mode 型の式であり、save_stack_level という名前付きパターン(see Standard Names) のセーブ領域オペランドのモードを指定する。save_level は、SAVE_BLOCKSAVE_FUNCTIONSAVE_NONLOCAL のどれかであり、三つの名前付きパターンのうち、どれのモードが指定されているかを選択する。

必ず Pmode を返すのであれば、このマクロを定義する必要はない。このマクロを定義するのは、save_stack_level パターンが32 ビットモードと 64 ビットモードの両方をサポートする必要がある場合が一番多いだろう。

STACK_SIZE_MODE
定義されていれば、enum machine_mode 型の式であり、allocate_stack という名前付きパターン(see Standard Names) のサイズ・インクリメント・オペランドのモードを指定する。

必ず word_mode を返すのであれば、このマクロを定義する必要はない。このマクロを定義するのは、allocate_stack パターンが32 ビットモードと 64 ビットモードの両方をサポートする必要がある場合が一番多いだろう。

CHECK_FLOAT_VALUE (mode, value, overflow)
(double 型の)値 value がモード mode として有効かどうかを検査する C の式である。対象とするターゲット機種のモード mode で表せる範囲の値に、value が収まるかどうかを検査するということを意味する。モード mode のクラスは常に MODE_FLOAT である。overflow は、その値が既に範囲からはみでていることがわかっている場合は、ゼロでない値になる。

value が有効でないか、overflow がゼロでなければ、overflow を 1 に設定し、何らかの有効な値を value に割り当てるべきである。無効な値をそのままにしておくと、コンパイラが不正なアセンブラコードを出力し、Unix のアセンブラを異常終了させる可能性がある。

なすべき処理がなければこのマクロを定義する必要はない。

TARGET_FLOAT_FORMAT
ターゲットマシンの浮動小数点数形式を識別するためのコード。定義済の値が三つある。
IEEE_FLOAT_FORMAT
IEEE 形式の浮動小数点数であることを示す。これがデフォルトになるので、IEEE 形式を使っている時はこのマクロを定義する必要はない。
VAX_FLOAT_FORMAT
VAX で使用されている固有の形式であることを示す。
UNKNOWN_FLOAT_FORMAT
このコードは、何か他の形式であることを示す。

このマクロの値を HOST_FLOAT_FORMAT(see Config)と比べて、ターゲットマシンのフォーマットがホストマシンと同じかどうかを決める。何か他の形式が、サポートされている機種で実際に使われているのなら、そのための新しいコードで定義する必要がある。

メモリ中に格納された浮動小数点数のワードの並び方は、ターゲットマシンについては FLOAT_WORDS_BIG_ENDIAN で、ホストマシンについては HOST_FLOAT_WORDS_BIG_ENDIAN で制御される。

DEFAULT_VTABLE_THUNKS
GNU CC は、C++ の仮想関数テーブル(vtable)の実装方法を二種類サポートしている。伝統的な方法と「thunks」と呼ばれる方法である。-fvtable-thunk オプションでどちらかの方法を選択する。このオプションのデフォルト値を表す C の式としてこのマクロを定義する。DEFAULT_VTABLE_THUNKS が 0 なら、GNU CC はデフォルトでは伝統的な実装方法を取る。「thunk」の実装の方が効率が良い(特に、ASM_OUTPUT_MI_THUNK を実装している場合。Function Entry を参照)。だが、伝統的な実装でコンパイルされたコードとのバイナリ互換性がない。新規に移植を行うなら、DEFAULT_VTABLE_THUNKS を 1 に定義しよう。

このマクロを定義しなければ、-fvtable-thunk のデフォルトは 0 になる。


Node:Type Layout, Next:, Previous:Storage Layout, Up:Target Macros

ソース言語のデータ型のレイアウト

以下のマクロ群で、コンパイルされるプログラムで使用される基本データ型の大きさと特徴を定義する。前節のマクロと違うのは、C 言語、C 言語に関係する言語に固有の特徴を示すものであり、基本的なストレージ配置を示すものではないという点にある。

INT_TYPE_SIZE
ターゲットマシンの int 型の大きさをビット数で表す C の式。これを定義しない場合は、デフォルトで1ワードになる。
MAX_INT_TYPE_SIZE
ターゲットマシンの int 型の大きさの最大値をビット数であらわしたもの。定義されていない場合は、デフォルトで INT_TYPE_SIZE になる。定義する場合は、INT_TYPE_SIZE が実行時に取りうる最大の定数値に定義する。これは、cpp で使われる。
SHORT_TYPE_SIZE
ターゲットマシンの short 型の大きさをビット数で表す C の式。これを定義しない場合は、デフォルトで半ワードになる。(もしこれが一ストレージ単位よりも小さくなるなら、一単位に切り上げられる。)
LONG_TYPE_SIZE
ターゲットマシンの long 型の大きさをビット数で表す C の式。これを定義しない場合は、デフォルトで一ワードになる。
MAX_LONG_TYPE_SIZE
ターゲットマシンの long 型の大きさの最大値をビット数であらわしたもの。定義されていない場合は、デフォルトで LONG_TYPE_SIZE になる。定義する場合は、LONG_TYPE_SIZE が実行時に取りうる最大の定数値に定義する。これは、cpp で使われる。
LONG_LONG_TYPE_SIZE
ターゲットマシンの long long 型の大きさをビット数で表す C の式。これを定義しない場合は、デフォルトで二ワードになる。GNU Ada をサポートする場合には、このマクロの値は少なくとも 64 でなければならない。
CHAR_TYPE_SIZE
ターゲットマシンの char 型の大きさをビット数で表す C の式。これを定義しない場合は、デフォルトで1/4ワードになる。(もしこれが一ストレージ単位よりも小さくなるなら、一単位に切り上げられる。)
MAX_CHAR_TYPE_SIZE
ターゲットマシンの char 型の大きさの最大値をビット数であらわしたもの。定義されていない場合は、デフォルトで CHAR_TYPE_SIZE になる。定義する場合は、CHAR_TYPE_SIZE が実行時に取りうる最大の定数値に定義する。これは、cpp で使われる。
FLOAT_TYPE_SIZE
ターゲットマシンの float 型の大きさをビット数で表す C の式。これを定義しない場合は、デフォルトで1ワードになる。
DOUBLE_TYPE_SIZE
ターゲットマシンの double 型の大きさをビット数で表す C の式。これを定義しない場合は、デフォルトで2ワードになる。
LONG_DOUBLE_TYPE_SIZE
ターゲットマシンの long double 型の大きさをビット数で表す C の式。これを定義しない場合は、デフォルトで2ワードになる。
WIDEST_HARDWARE_FP_SIZE
ハードウェアでサポートされている最大精度の浮動小数点形式の大きさをビット数で表す C の式。このマクロを定義する場合は、LONG_DOUBLE_TYPE_SIZE 以下の値を指定しなければならない。このマクロを定義しない場合は、LONG_DOUBLE_TYPE_SIZE の値がデフォルトになる。
DEFAULT_SIGNED_CHAR
値が 1 か 0 になる式で、それぞれchar 型がデフォルトでは符号付きか符号無しかを示す。ユーザは、いつでも -fsigned-char-funsigned-char オプションで変更できる。
DEFAULT_SHORT_ENUMS
enum 型に、その型の取りうる値の範囲を表現するのに必要なバイト数のみを割り当てるかどうかを指定する C の式を定義する。ゼロでない値を指定すると必要なバイト数のみを割り当てる。値がゼロなら、全ての enum 型は int と同じく割り当てられる。

このマクロを定義しなければ、デフォルトは 0 である。

SIZE_TYPE
大きさを示す値に使うデータ型名を表す文字列を指定する C の式を定義する。typedef 名 size_t は、この文字列の内容を使って定義される。

この文字列にはキーワードを二つ以上書いても良い。その場合、キーワード同士を空白で区切り、最初に長さを表すキーワードを書き、次に必要なら unsigned を、最後に int を書くようにする。この文字列は、c-decl.c というファイルの関数 init_decl_processing で定義されているデータ型名の一つに厳密に一致しなければならない。int を省略したり、順序を変えたりしてはならない。そうすると、起動時にコンパイラが異常終了してしまう。

このマクロを定義しないと、デフォルトは "long unsigned int" になる。

PTRDIFF_TYPE
二つのポインタ同士の引き算の結果に使うデータ型名を表す文字列を指定する C の式を定義する。typedef 名 ptrdiff_t は、この文字列の内容を使って定義される。詳細は上の SIZE_TYPE を参照のこと。

このマクロを定義しないと、デフォルトは "long int" になる。

WCHAR_TYPE
幅広文字に使うデータ型名を表す文字列を指定する C の式を定義する。typedef 名 wchar_t は、この文字列の内容を使って定義される。詳細は上の SIZE_TYPE を参照のこと。

このマクロを定義しないと、デフォルトは "int" になる。

WCHAR_TYPE_SIZE
幅広文字に使うデータ型の大きさをビット数で表した C の式。これは cpp で使われる。cpp は、WCHAR_TYPE を使うことができない。
MAX_WCHAR_TYPE_SIZE
幅広文字のデータ型の最大の大きさをビット数で表したもの。これが定義されていない場合は、デフォルトは WCHAR_TYPE_SIZE になる。定義されている場合は、WCHAR_TYPE_SIZE が実行時に取りうる最大値となる定数値になる。これは、cpp で使われる。
OBJC_INT_SELECTORS
Objective C のセレクタの型を int とすべきなら、このマクロを定義する。

このマクロが定義されていなければ、セレクタは struct objc_selector * 型になる。

OBJC_SELECTORS_WITHOUT_LABELS
コンパイラが、全てのセレクタを一つのベクトルに統合することができ、そのベクトルの開始点のラベル一つだけを使う場合には、このマクロを定義する。定義しない場合は、コンパイラは各セレクタに各々のアセンブララベルを与えなければならない。

一部の機種では、各セレクタに別々のラベルを与えることが大事で、そうすることによってリンカが重複したセレクタを消去出来るようになる。

TARGET_BELL
C の定数式で、エスケープ・シーケンス \a に対応する整数値を表す。
TARGET_BS
TARGET_TAB
TARGET_NEWLINE
C の定数式で、それぞれ、エスケープ・シーケンス \b\t\n に対応する整数値を表す。
TARGET_VT
TARGET_FF
TARGET_CR
C の定数式群で、それぞれ、エスケープ・シーケンス \v\f\r に対応する整数値を表す。


Node:Registers, Next:, Previous:Type Layout, Up:Target Macros

レジスタの使用方法

この節では、ターゲットマシンにどんなレジスタがあり、一般的にはどのように使うことができるかを記述する方法を説明する。

ある特定の命令でどのレジスタが使用できるかは、レジスタクラスを使って記述する。Register Classes を参照のこと。レジスタを使ってスタックフレームをアクセスするための情報については、Frame Registers を参照のこと。レジスタを使って値を渡す方法については、Register Arguments を、レジスタで値を返す方法については、Scalar Return を参照。


Node:Register Basics, Next:, Previous:Registers, Up:Registers

レジスタの基本的特徴

レジスタには色々な特徴がある。

FIRST_PSEUDO_REGISTER
コンパイラに知らせるべきハードウェアレジスタの数。ハードウェアレジスタの番号は、0 から FIRST_PSEUDO_REGISTER-1 になる。つまり、最初の疑似レジスタ番号は FIRST_PSEUDO_REGISER になる。
FIXED_REGISTERS
コンパイルされたコード全体を通して決まった目的で使用され、そのために一般の目的で使用することのできないレジスタを指定するための初期化子である。このようなレジスタとしては、スタックポインタ、フレームポインタ(フレームポインタを必要としないときは汎用レジスタとして使うことができるような機種の場合は除く)、アドレス可能なレジスタの一つとして考えることのできる機種ではプログラムカウンタ、あるいはある標準的な使い方をするように番号が付けられた他のレジスタ等がある。

この情報は、一連の数字コンマで区切り、中括弧で囲んで表す。n 番目の数字は、レジスタ n が固定であれば 1 で、固定でなければ 0 である。

このマクロで初期化されたレジスタの表、それに以下のマクロのどれかで初期化された表は、次のどちらかの方法で上書きされる可能性がある。つまり、マクロ CONDITIONAL_REGISTER_USAGE の作用により自動的にか、あるいはユーザが指定したコマンド行オプション -ffixed-reg-fcall-used-reg-fcall-saved-reg により書き換えられる。

CALL_USED_REGISTERS
FIXED_REGISTERS とほぼ同様だが、固定レジスタに加えて、(一般には)関数呼び出しで破壊されるレジスタについても 1 とする。このため、このマクロにより、関数呼び出しを越えて保存されなければならない値の一般的な割当には利用できないレジスタを識別する。

あるレジスタの CALL_USED_REGISTERS での値が 0 なら、そのレジスタが関数内で使われていれば、コンパイラは自動的に、そのレジスタを関数の入り口点でセーブし、関数の終了点でリストアする。

HARD_REGNO_CALL_PART_CLOBBERED (regno, mode)
一個の C の式。この式は、モード mode の値を、その一部が破壊されることなく呼出しを越えて、ハードレジスタ番号regno に格納するのが許されない時はゼロでない値になる。ほとんどの機種ではこのマクロを定義する必要はない。レジスタの全内容を呼出しを越えては保存しない機種でのみ必要になる。
CONDITIONAL_REGISTER_USAGE
0個以上の C の文で、四つの変数 fixed_regscall_used_regsglobal_regs(この三つは char [] 型)、reg_class_contents (HARD_REG_SET 型)を条件により更新する。このマクロが呼ばれる前に、fixed_regscall_used_regsreg_class_contents がそれぞれ、FIXED_REGISTERSCALL_USED_REGISTERSREG_CLASS_CONTENTS により初期化され、global_regs がクリアされ、コマンド行オプション-ffixed-reg-fcall-used-reg-fcall-saved-reg がどんなものであれ適用される。

これは、固定レジスタや呼び出し破壊レジスタがターゲットのフラグに依存する場合に必要になる。

することがなければ、このマクロを定義する必要はない。

あるクラスのレジスタ全体の使用法がターゲットのフラグに依存する場合は、そのことを GCC に知らせるのにこのマクロを使うことができる。このマクロで、GCC で使うべきでないクラスのレジスタのそれぞれについて、fixed_regscall_used_regs を 1 になるように更新する。また、マクロ REG_CLASS_FROM_LETTER を定義して、使うべきでないクラスの文字を引数として呼ばれた場合は、NO_REGS を返すようにする。

(だが、このクラスが GENERAL_REGS に含まれておらず、このクラスを許す制約を持つ全ての insn のパターンが、ターゲットスイッチにより制御されるなら、GCC は、ターゲットスイッチが反対しているならこれらのレジスタを使うのを自動的に避ける。)

NON_SAVING_SETJMP
このマクロが定義されていてかつその値がゼロでない場合は、setjmp とその関連関数がレジスタのセーブに失敗するか、あるいは longjmp がレジスタのリストアに失敗するということを意味する。これを補償するために、コンパイラはsetjmp を使っている関数ではレジスタに変数を置くのを避ける。
INCOMING_REGNO (out)
ターゲット機種にレジスタウィンドウがあればこのマクロを定義する。これは C の式であり、呼び出し側関数からは out と見えるレジスタ番号に対応するレジスタを、被呼び出し側関数から見た場合のレジスタ番号を返す。レジスタ番号 out が外向きのレジスタでなければout を返す。
OUTGOING_REGNO (in)
ターゲット機種にレジスタウィンドウがあればこのマクロを定義する。これは C の式であり、被呼び出し側関数からは in と見えるレジスタ番号に対応するレジスタを、呼び出し側関数から見た場合のレジスタ番号を返す。レジスタ番号 in が内向きのレジスタでなければin を返す。


Node:Allocation Order, Next:, Previous:Register Basics, Up:Registers

レジスタの割当順

レジスタの割り当てには順番がある。

REG_ALLOC_ORDER
定義されていれば、整数のベクトルの初期化子である。GNU CC が優先して使うべき順番に並んでいる、ハードレジスタ番号群を含む。(最も優先すべきものから最も優先度の低いものへという順番である。)

このマクロが定義されていないと、レジスタは一番小さい番号から先に使われる(等しいもの以外は全て)。

このマクロの使い道の一つは、一番大きな番号のレジスタを常にセーブする必要があり、かつ、 複数のレジスタをセーブする命令が連続したレジスタの列しかサポートしていない機種の場合である。そういう機種では、REG_ALLOC_ORDER を、割当可能な一番大きな番号のレジスタを先に列挙する初期化子になるように定義する。

ORDER_REGS_FOR_LOCAL_ALLOC
一個の C の文(セミコロンなし)であり、基本ブロックに局所的な疑似レジスタ用のハードレジスタを割り当てる順番を選択する。

希望のレジスタの順番を配列 reg_alloc_order に格納する。要素 0 は最初に割り当てるレジスタとすべきである。要素 1 がその次のレジスタで、以下同様である。

マクロの本体では、このマクロの実行前の reg_alloc_order の内容について何も仮定してはいけない。

大部分の機種では、このマクロを定義する必要はない。


Node:Values in Registers, Next:, Previous:Allocation Order, Up:Registers

レジスタへの値の収まり方

この節では、どんな種類の値(特に、どのマシンモード)を各レジスタが保持できるのか、そして、指定されたモードに必要な連続するレジスタはいくつ必要なのかを記述するマクロについて説明する。

HARD_REGNO_NREGS (regno, mode)
レジスタ番号は regno から始まり、モード mode の値を保持するのに必要とされる、連続するハードレジスタの数を表す C の式である。

全てのレジスタがちょうど一ワードである機種では、このマクロの適切な定義は以下のようになる。

#define HARD_REGNO_NREGS(REGNO, MODE)            \
   ((GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1)  \
    / UNITS_PER_WORD))

ALTER_HARD_SUBREG (tgt_mode, word, src_mode, regno)
一個の C の式であり、以下の式に対し調整済みハードレジスタ数を返す。
(subreg:tgt_mode (reg:src_mode regno) word)

これは、ターゲット機種に、SPARC V9 のように、サイズの入り交じったビッグエンディアンのレジスタがある場合に必要になるかもしれない。

HARD_REGNO_MODE_OK (regno, mode)
モード mode の値を regno 番のハードレジスタ(あるいは、そのレジスタで始まる複数のレジスタ)に格納することが可能なら、ゼロでない値を取る C の式。全てのレジスタが同じ大きさの機種では、適切な定義は以下のようになる。
#define HARD_REGNO_MODE_OK(REGNO, MODE) 1

固定レジスタの数を検査するコードをこれに入れる必要はない。割当機構はそれらが常に占有されていると想定しているからである。

機種によっては、倍精度の値は偶数番と奇数番のレジスタ対に保持しなければならない。これを実装するには、倍精度のモードでは奇数番のレジスタをはじくように、このマクロを定義すれば良い。

あるモードをあるレジスタにいれても大丈夫なための最低限の要件は、movmode 命令パターンがそのレジスタと、同じクラスの他のハードレジスタの間での移動をサポートし、かつ、ある値をそのレジスタに移動して取り出してもその値を変えないことである。

word_mode を移動するのに使ったのと同じ命令が、それより幅の狭い全ての整数モードに対して動作するので、れを利用する movhi 等のパターンを定義していれば、どのマシンでも HARD_REGNO_MODE_OK がこれらのモードを区別する必要はない。これは、HARD_REGNO_MODE_OKMODES_TIEABLE_P の間の相互作用のために便利である。全ての整数モードが結合可能であることが望まれる。

多くの機種には、浮動小数点算術演算用の特別なレジスタがある。浮動小数点マシンモードは浮動小数点レジスタでのみ許されると思ってしまう人がよくいる。それは正しくない。整数を保持できるどんなレジスタでも、浮動小数点マシンモードを安全に保持できる。これは、浮動小数演算がそのレジスタで行なえるかどうかには関係しない。整数の移動命令を使って、この浮動小数点値を移動することができる。

だが、機種によっては、その逆は真である。固定小数点マシンモードは浮動小数点レジスタに入れることができない。これは、浮動小数点レジスタが、そこに格納された値を正規化する場合に真になる。なぜなら、浮動小数点数でない値を格納すると正しくない値に変えられてしまうからである。それに該当する場合は、HARD_REGNO_MODE_OK では、浮動小数点レジスタ中の固定小数点マシンモードを拒絶すべきである。だが浮動小数点レジスタが自動的には正規化を行なわない場合は、任意のビットパターンをそのレジスタに格納することができ、問題なく、その値を変えずに取り出すことができるなら、どのマシンモードも浮動小数点レジスタに入れることができ、このマクロをそうするように定義できる。

特別な浮動小数点レジスタで一番大事なことは、浮動小数点算術命令で受け付けるレジスタであるということである。だが、これは HARD_REGNO_MODE_OK とは何の関係もない。そういう命令については適切な制約を書くことで扱える。

機種によっては、浮動小数点レジスタはアクセスが特に遅いことがあるので、浮動小数点演算を行なわないのであれば、浮動小数点レジスタよりもスタックフレームに値を格納したほうが良いだろう。浮動小数点レジスタがクラス GENERAL_REGS に入っていない限り、何かのパターンの制約で要求しない限り浮動小数点レジスタが使われることはない。

MODES_TIEABLE_P (mode1, mode2)
モード mode1 の値を、コピーすることなしに、モード mode2 でアクセス可能ならゼロでない値を持つ C の式。

HARD_REGNO_MODE_OK (r, mode1)HARD_REGNO_MODE_OK (r, mode2) が、どの r についても常に同じなら、MODES_TIEABLE_P (mode1, mode2) はゼロでない値になるべきである。任意の r について両者が異なるなら、何か他の機構により、より狭いモードでその値をアクセス出来ることが保証されない限りは、このマクロが 0 を返すようにすべきである。

このマクロは、可能な限り多くの場合にゼロでない値を返すように定義すべきである。そうしておくと、GNU CC のレジスタ割当がより良いものになる。

AVOID_CCMODE_COPIES
GCC が CCmode レジスタとの間のコピーを避けるべきならこのマクロを定義する。CCmode との間のコピーのサポートが不完全な場合だけこのマクロを定義すること。


Node:Leaf Functions, Next:, Previous:Values in Registers, Up:Registers

末端関数の扱い

機種によっては、末端関数(すなわち、他の関数の呼び出しがない関数)は、その関数自身のレジスタウィンドウを作らないのであれば、より効率良く実行させることができる。これが意味することは、通常届けられるレジスタの代わりに、呼びだし側によって渡されたレジスタで引数を受け取る必要があるということである。

末端関数が特別に取り扱われるのは、一般には他に幾つかの条件も満たされるときに限られる。例えば、末端関数ではレジスタをその関数自身の変数や一時領域にしか使わない場合が多い。我々は「末端関数」という言葉で、この特別な取扱いが可能な関数を指すことにする。このため、関数呼び出しのない関数は必ずしも「末端関数」とは限らないことになる。

GNU CC は、関数が末端関数としての取扱いに向いているかどうかを知る前にレジスタ番号を割り当てる。そのため、末端関数を出力するにはレジスタ番号の付け替えをする必要がある。以下のマクロでこの処理を行なう。

LEAF_REGISTERS
あるベクトルの C の初期化子。ハードレジスタ番号が添え字となる。末端関数処理の対象候補で使えるレジスタに対しては要素が 1 となる。

末端関数用の処理の中にレジスタ番号の付け替えがあるなら、ここで印を付けたレジスタは番号付け替えの前のものであり、GNU CC が普通に割り当てたものである。番号付け替えの後で、アセンブラコード中で実際に使われるレジスタは、このベクトルの中で 1 と印を付けるべきである。

ターゲット機種が末端関数の取扱いを最適化する手段を提供している場合にだけこのマクロを定義すること。

LEAF_REG_REMAP (regno)
一個の C の式で、その値は、関数が末端関数として取り扱われるときは、regno を番号付け替えした後のレジスタ番号になる。

regno が、番号付け替えの前には末端関数に現れるべきでないレジスタ番号なら、この式の値は -1 となるべきで、そうするとコンパイラがアボートする。

このマクロは、ターゲット機種が末端関数の扱いを最適化する手段を提供しており、そのためにはレジスタの番号付け替えが必要である場合にのみ、定義する。

通常、FUNCTION_PROLOGUEFUNCTION_EPILOGUE は末端関数を特別に取り扱わなければならない。C の変数である current_function_is_leaf を調べてゼロでなければ末端関数である。current_function_is_leaf はローカルレジスタの割当に先だって設定され、以降のコンパイラパスで有効である。また、C の変数 current_function_uses_only_leaf_regs を調べてゼロでなければ、末端レジスタしか使わない末端関数である。変数 current_function_uses_only_leaf_regs は、再ロード後に有効になり、LEAF_REGISTERS が定義されている場合にのみ意味がある。


Node:Stack Registers, Next:, Previous:Leaf Functions, Up:Registers

スタックを形成するレジスタ

「レジスタ」の幾つかがスタックを形成するような計算機を扱う特別な機能が存在する。このような計算機には 80386 向けの 80387 コプロセッサがある。スタック・レジスタは、通常、スタックにプッシュされることにより書き込まれ、スタックのてっぺんから相対的に番号が付けられる。

現在、GNU CC は、スタック状レジスタのグループを一つしか扱えず、しかも、そのレジスタは連続した番号になっていなければならない。

STACK_REGS
マシンに何らかのスタック様レジスタがあれば、これを定義する。
FIRST_STACK_REG
先頭のスタック様レジスタの番号。これはスタックの一番上にあるものである。
LAST_STACK_REG
最後のスタック様レジスタの番号。これはスタックの底にあるものである。


Node:Obsolete Register Macros, Previous:Stack Registers, Up:Registers

レジスタの使用法を調整する古いマクロ

以下の機能はあまりちゃんとは動いていない。これらが存在するのは、80386 の 80387 コプロセッサ向けのコードを正しく生成するのに必要とされるからである。これはもはやマシン記述では使われておらず、将来のバージョンでは削除される可能性がある。なので使わないように。

OVERLAPPING_REGNO_P (regno)
定義されていれば、C の式である。この式は、ハードレジスタ番号regno がオーバーラップレジスタなら、ゼロでない値となる。これは、あるハードレジスタが異なる番号のハードレジスタとオーバーラップしているということを意味する。(このオーバーラップは望ましくないことだが、これがないとサポートできないようなマシンをサポートすることができる。) このマクロは、お互いにオーバーラップしている全てのレジスタについてゼロでない値を返さなければならない。GNU CC は、オーバーラップレジスタをある限られた方法でしか使うことができない。基本ブロック内の割当に使うことができ、再ロードで落とされてしまう可能性がある。それで全てである。

このマクロが定義されていないと、お互いにオーバーラップするハードレジスタはないということになる。それが普通だ。

INSN_CLOBBERS_REGNO_P (insn, regno)
定義されていれば、C の式である。この式の値は、insn insn が、ハードレジスタ番号 regno の内容を未知の力により破壊されてしまう効果を持っている場合はゼロでない値にすべきである。「未知の力」とはこの場合、その insn の RTL 式はそのような効果を記述していないということである。

このマクロが定義されていないと、未知の力でレジスタの内容を破壊する insn は存在しないということを意味する。それが普通の状況である。その他のものがすべて同じなら、RTL 式を見ればその全ての動作がわかるというのが最も良いのである。


Node:Register Classes, Next:, Previous:Registers, Up:Target Macros

レジスタクラス

多くのマシンでは、番号のついたレジスタが全て等価であるとは限らない。例えば、あるレジスタ群はインデックスアドレッシングには使用できないとか、あるレジスタ群は一部の命令では使用できない等々。このようなマシンによる制限は、レジスタクラス を使って、コンパイラに知らせる。

レジスタクラスはたくさん定義することができ、それぞれに名前を与えて、どのレジスタがそのクラスに所属するかを指定する。そうしておけば、オペランドとして許されるレジスタクラスを特定の命令パターンに対して指定することができる。

一般に、各レジスタは色々なクラスに所属することになる。事実、ALL_REGS というクラスを作り、全てのレジスタを所属させなくてはならない。もう一つ別の、NO_REGS というクラスを作らなくてはならず、このクラスに所属するレジスタはない。二つのクラスの和を作ると別のクラスになることもあるが、必須ではない。

必須のクラスの一つに GENERAL_REGS がある。この名前には何も特別な意味はないが、オペランドの制約文字 rg はこのクラスを指す。GENERAL_REGSALL_REGS が同じなら、単に ALL_REGS に展開されるマクロとして定義する。

クラスを順序付けて、クラス x がクラス y に含まれるなら、x のクラス番号は y の番号より小さくなるようにする。

GENERAL_REGS 以外のクラスのオペランド制約での指定方法は、機種依存のオペランド制約文字によって行なわれる。色々なクラスに対応する制約文字を定義し、オペランド制約でそれを使うことができる。

ある命令が二つのクラスを両方とも許すような場合は常に、その二つのクラスの和となるクラスを定義すべきである。例えば、ある命令のある特定のオペランドとして、浮動小数点(コプロセッサ) レジスタと汎用レジスタのどちらでも使えるなら、その両方を含む、FLOAT_OR_GENERAL_REGS というクラスを定義すべきである。そうしないと生成されるコードが最上のものではなくなる。

また、そのレジスタクラスについて、ある種の冗長な情報を指定しなければならない。クラス毎に、そのクラスを含んでいるクラスと、そのクラスに含まれるクラスを指定し、クラスの対毎に、その対の和に含まれる最大のクラスを指定する。

複数の連続するレジスタを占める値がある特定のクラスに入ることが期待されるときは、それに使われるレジスタが全てそのクラスに所属しなければならない。このため、レジスタクラスを使って、レジスタ対を偶数番レジスタで始まるように強制的に要求することは出来ない。そのためには、HARD_REGNO_MODE_OK を使う。

ビット毎の論理積やシフト命令の入力オペランドに使われるレジスタクラスには特別な要件がある。そのようなクラスはそれぞれ、固定小数点マシンモード毎に、そのモードからメモリへ、あるいはメモリからそのモードへ転送可能なレジスタのサブクラスがなければならない。例えば、機種によっては、一バイト値(QImode)についての演算は特定のレジスタに限られる。その場合、ビット毎の論理積やシフト命令で使われる各レジスタクラスは、それから一バイト値をロードしたりストア可能なレジスタからなるサブクラスがなければならない。これは、PREFERRED_RELOAD_CLASS が常に可能な値を返すことができるようにするためである。

enum reg_class
ある列挙型で、全てのレジスタクラス名を列挙値として定義しなければならない。NO_REGS は先頭に来なければならない。ALL_REGS は最後のレジスタクラスとならなくてはならず、その後にさらに一個の列挙値 LIM_REG_CLASSES が続く。LIB_REG_CLASSES は、レジスタクラスではないが、クラスが幾つあるかを知らせるためにある。

各レジスタクラスは番号を持っており、それは クラス名を int 型にキャストした値である。この番号は、以下に説明する多くの表の添え字として使われる。

N_REG_CLASSES
区別できるレジスタクラスの数であり、以下のように定義される。
#define N_REG_CLASSES (int) LIM_REG_CLASSES

REG_CLASS_NAMES
レジスタクラス名を C の文字列定数として持つ初期化子。この名前は、デバッグ出力で使われることがある。
REG_CLASS_CONTENTS
レジスタクラスの内容をビットマスクである整数として含む初期化子。n 番目の整数は、クラス n の内容を指定する。整数 mask は次のように解釈される。もし、mask & (1 << r) が 1 なら、レジスタ r はそのクラスに所属する。

レジスタが 32 より多い機種では、このためには一個の整数では足りない。その時は、整数は副初期化子で置き換えられる。副初期化子は、複数の整数を中括弧で囲んだものである。各副初期化子は、hard-reg-set.h で定義されている HARD_REG_SET 型の初期化子として適切でなければならない。

REGNO_REG_CLASS (regno)
ハードレジスタ regno を含むレジスタクラスを表す値を持つ C の式。一般にはそのようなクラスは複数ある。その場合、「最小」のクラス、つまり、そのレジスタを含むそれ以上小さなクラスがないようなクラスを選ぶ。
BASE_REG_CLASS
ベースレジスタとして有効なレジスタが所属しなければならないクラス名を定義するマクロである。ベースレジスタとは、レジスタの値に変位を加算したものをアドレスとするときに使われるレジスタである。
INDEX_REG_CLASS
インデックスレジスタとして有効なレジスタが所属しなければならないクラス名を定義するマクロである。インデックスレジスタとは、その値をスケール因子分掛けたものか、別のレジスタに加算した(同様に変位にも加算される)ものをアドレスとするときに使われるレジスタである。
REG_CLASS_FROM_LETTER (char)
レジスタクラスについての機種依存のオペランド制約文字を定義するC の式。char があるオペランド制約文字なら、この値は対応するレジスタクラスとなる。オペランド制約文字以外なら、この値は NO_REGS とする。GENERAL_REGS クラスに対応するレジスタ文字 r は、このマクロには渡されないであろうから、それを扱う必要はない。
REGNO_OK_FOR_BASE_P (num)
レジスタ番号 num がオペランドのアドレスのベースレジスタとして使うのに適当なものなら、0 でない値を持つ C の式。適切なハードレジスタか、あるいは適切なハードレジスタが割り当て済の疑似レジスタのどちらでも良い。
REGNO_MODE_OK_FOR_BASE_P (num, mode)
REGNO_OK_FOR_BASE_P と同様の C の式だが、この式は mode のメモリ参照のモードを調べる。メモリ参照のモードが、あるレジスタをベースレジスタとして使って良いかどうかに影響するなら、このマクロを定義する。このマクロが定義してあると、コンパイラは REGNO_OK_FOR_BASE_P の代わりにこちらを使う。
REGNO_OK_FOR_INDEX_P (num)
レジスタ番号 num がオペランドのアドレスのインデックスレジスタとして使うのに適当なものなら、0 でない値を持つ C の式。適切なハードレジスタか、あるいは適切なハードレジスタが割り当て済の疑似レジスタのどちらでも良い。

インデックスレジスタとベースレジスタの違いは、インデックスレジスタはスケーリングされることである。あるアドレスが二つのレジスタの和を含んでいて、そのどちらもスケーリングされないのであれば、どちらか一つが「ベース」となり、他方は「インデックス」というラベルが貼られる。だが、どちらのラベル付が使われても、レジスタがそれぞれの役割を果たす、その機種の制約に収まらなければならない。コンパイラは両方のラベル付を試して、有効なものを一つ見つけ出し、どちらのラベル付も動作しない場合にのみ、一方のレジスタ、あるいは両方のレジスタを再ロードする。

PREFERRED_RELOAD_CLASS (x, class)
x をクラス class のレジスタにコピーする必要があるときに使うレジスタクラスについて制限を追加する C の式。この式の値はあるレジスタクラスである。おそらく class か、別のより小さなクラスである。多くの機種では、以下の定義が安全である。
#define PREFERRED_RELOAD_CLASS(X,CLASS) CLASS

より制限の強いクラスを返したほうが良いコードが出るということが時々ある。例えば、68000 の場合には、xmoveq 命令で有効な範囲内にある整数定数であるときは、このマクロの値は class がデータレジスタを含んでいる限り、常に DATA_REGS になる。

xconst_dobule の場合、NO_REGS を返すことにより x を強制的にメモリ定数とすることができる。これは、浮動小数点即値をある種のレジスタにはロード出来ないようなマシンで役に立つ。

PREFERRED_OUTPUT_RELOAD_CLASS (x, class)
PREFERRED_RELOAD_CLASS と同様だが、入力の再ロードではなく出力の再ロード向けである。このマクロを定義しない場合は、デフォルトは class がそのまま使われる。
LIMIT_RELOAD_CLASS (mode, class)
一個の C の式。モード mode の値を、通常 クラス class が使われる再ロード・レジスタで保持することが可能であることが必要な場合に使うレジスタクラスについて制限を追加する。

PREFERRED_RELOAD_CLASS とは違って、このマクロは単純にはある再ロードクラスに入らない、ある種のモードが存在するときに使われるべきである。

この値はレジスタクラスである。おそらく、class か何か別のより小さなクラスであろう。

このマクロは、ターゲット機種の制限により、このマクロで何か自明ではないことをする必要があるとき以外は定義しないこと。

SECONDARY_RELOAD_CLASS (class, mode, x)
SECONDARY_INPUT_RELOAD_CLASS (class, mode, x)
SECONDARY_OUTPUT_RELOAD_CLASS (class, mode, x)
多くの機種では、直接メモリへ、あるいはメモリからコピーできないレジスタがある。あるいは、他の型のレジスタからのコピーさえもできないレジスタが存在することもある。例えば、MQ レジスタは、多くの機種で、汎用レジスタとの間でしかコピー出来ず、メモリとの間でのコピーはできない。機種によっては全てのレジスタとメモリ間でのコピーを許しているものがあるが、あるメモリ位置(例えば、RT のシンボリック・アドレスや、PIC をコンパイルする時の SPARC の特定のシンボリック・アドレス等)を格納するにはスクラッチレジスタを必要とするものがある。場合によっては、中間レジスタとスクラッチレジスタの両方が必要である。

このマクロを定義して、再ロード・パスに、再ロードのためには、データを保持するレジスタに加えて、少なくとも一個のレジスタを割り当てる必要があることを知らせるようにすべきである。特に、xmode のレジスタ class にコピーするのに中間レジスタが必要な場合は、SECONDARY_INPUT_RELOAD_CLASS を定義して、それに属する全てのレジスタが中間レジスタやスクラッチレジスタとして使えるような最大のレジスタを返すようにすべきである。

mode のレジスタ classx にコピーするのに中間レジスタやスクラッチレジスタが必要な場合は、SECONDARY_OUTPUT_RELOAD_CLASS を定義して、必要とされる最大のレジスタを返すようにすべきである。入力再ロードと出力再ロードの要件が同じなら、これらの二つのマクロを同じ定義にする代わりに、マクロ SECONDARY_RELOAD_CLASS を使うべきである。

これらのマクロが返す値はしばしば GENERAL_REGS となる。予備のレジスタが必要でない場合は NO_REGS を返す。これは、x と モード mode でクラス class のレジスタの間で、スクラッチレジスタなしで直接コピー可能な場合である。常に NO_REGS を返すのならこのマクロは定義しないこと。

スクラッチレジスタが必要な場合(中間レジスタの必要の有無に関わらず)、see Standard Names で必要とされる、reload_inmreload_outm のパターンを定義すべきである。これらのパターンは、通常 define_expand で実装され、オペランド 2 がスクラッチレジスタである点を除いて、movm のパターンと同じにすべきである。

一個のレジスタクラスを含む再ロードレジスタとスクラッチレジスタに対する制約を定義する。元の再ロードレジスタ(クラスが class)がパターンで指定された制約に当てはまるなら、このマクロが返す値がスクラッチレジスタのクラスとして使われる。当てはまらないのであれば、再ロードレジスタが二つ追加で必要になる。その二つのレジスタのクラスは、insn パターンの制約から得られる。

x は、疑似レジスタか疑似レジスタの subreg でなければならない。これらは、ハードレジスタかメモリのどちらかにある。どちらにあるかは、true_regnum を使って調べる。疑似レジスタがメモリにあれば -1 を返し、レジスタにあればハードレジスタ番号を返す。

このマクロは、ある特定のクラスのレジスタはメモリにだけコピー可能であり、もう一つの別のクラスのレジスタにはコピーできないという場合は使うべきでない。その場合、二番目の再ロードレジスタは不要であり役に立たない。代わりに、スタック位置を使ってコピーを行なわなければならず、movm パターンはメモリを中間の格納場所として使うべきである。これは、浮動小数点レジスタと汎用レジスタの間で良く起こることである。

SECONDARY_MEMORY_NEEDED (class1, class2, m)
特定の機種には、レジスタの幾つかはメモリを使わないと他のレジスタにコピーできないという性質がある。そういう機種では、このマクロを次のような一個の C の式に定義する。すなわち、この式は、class1 のレジスタにあるモード m のオブジェクトがクラスclass2 のレジスタにコピーできるのは、class1 のレジスタをメモリにストアしてそのメモリ位置を class2 のレジスタにロードする場合だけなら、ゼロでない値となる。

このマクロは、値が常にゼロになるようなら定義しないこと。

SECONDARY_MEMORY_NEEDED_RTX (mode)
SECONDARY_MEMORY_NEEDED が定義されていると普通、コンパイラがレジスタのコピーに必要なメモリ位置用のスタックスロットを割り当てる。このマクロが定義されていると、コンパイラは代わりに、このマクロで定義されるメモリ位置を使う。

SECONDARY_MEMORY_NEEDED を定義しない場合は、このマクロを定義しないこと。

SECONDARY_MEMORY_NEEDED_MODE (mode)
コンパイラが、モード mode の二つのレジスタ間でコピーするのに第二のメモリ位置を必要とするときは、普通は、BITS_PER_WORD ビットの量を保持するのに充分なメモリを確保し、ストアとロード操作を、多ビット幅でそのクラスが mode のクラスと同じであるモードで実行する。

これはほとんどの機種でなすべき正しいことである。レジスタの全ビットがコピーされ、レジスタを狭いモードでアクセスするのを抑止しているからである。これにより、機種によっては浮動小数点レジスタを禁止する。

だが、このデフォルトの動作が正しくない機種もある。例えば、DEC Alpha がそうで、short 型の整数を浮動小数点レジスタにストアする仕方と整数レジスタにストアする仕方が異なる。こういう機種では、デフォルトの拡幅が正しく動作しないので、このマクロを定義して、ある場合には拡幅を抑制しなければならない。詳細については alpha.h を参照のこと。

SECONDARY_MEMORY_NEEDED を定義しない場合や、modeBITS_PER_WORD ビット長のモードに広げるのが正しい機種の場合は、このマクロを定義しないこと。

SMALL_REGISTER_CLASSES
機種によっては、ハードレジスタを任意の insn 群を越えて生存させるのは危険が伴う場合がある。こういう機種は普通、特定のレジスタ(例えばアキュムレータ)に値が入っていないといけない命令を持っているので、必要とされるハードレジスタがこのような insn を越えて、別の目的に使われると、再ロードに失敗する。

そういう機種では、SMALL_REGISER_CLASSES をゼロでない値を持つ式として定義する。このマクロの値がゼロでないと、コンパイラはハードレジスタの生存期間を最小化することを試みる。

このマクロをゼロでない値に定義するのは常に安全である。だが、不必要に定義すると、ある場合に実行可能な最適化の程度が減ることになる。必要な場合にこのマクロをゼロでない値に定義しないと、コンパイラはスピルレジスタを使いつくし、致命的エラーのメッセージを出力する。ほとんどの機種では、このマクロは何も定義すべきでない。

CLASS_LIKELY_SPILLED_P (class)
一個の C の式。この式の値は、クラス class のレジスタに割り当てられた疑似レジスタが、class のレジスタはスピルレジスタとして必要であるために、スピルされそうならゼロでない値となる。

このマクロのデフォルト値は、class にレジスタがちょうど一個ある場合は 1 を返し、それ以外の場合はゼロを返す。ほとんどの機種では、このデフォルトを使うべきである。このマクロを何か他の式に定義するのは、local-alloc.c で割り当てられた疑似レジスタが、それ用のハードレジスタがスピルレジスタ用に必要であるために、結局メモリに取られる場合だけにすること。このマクロが指定されたクラスに対してゼロでない値を返すなら、そのクラスの疑似レジスタは global.c でだけ割り当てられる。global.c は、疑似レジスタを別のレジスタに再割当する方法を知っている。再割当に使える別のレジスタがない場合は、このマクロの定義を変えるべきでない。なぜなら、そういう場合は、定義を変えるとレジスタの割当を遅くするだけであるから。

CLASS_MAX_NREGS (class, mode)
C の式。モードが mode の値を保持するのに必要な、クラス class の連続するレジスタの最大数を表す。

これは、マクロ HARD_REGNO_NREGS と密接に関係する。実際、マクロ CLASS_MAX_NREGS (class, mode) の値は、クラス class の全ての regno の値について、HARD_REGNO_NREGS (regno, mode) の最大値となるべきである。

このマクロは、再ロードパスにおいて複数ワードの値の扱いを制御する手助けをする。

CLASS_CANNOT_CHANGE_SIZE
一個の C の式。定義されていれば、レジスタにロードしたときのモードと同じサイズのモードでコンパイラが常にアクセスしなければならないレジスタを含むクラスを表す。

例えば、Alpha の場合は、32ビットの整数オブジェクトか浮動小数点オブジェクトを浮動小数点レジスタにロードすると、64ビットに拡張される。したがって、64ビットのオブジェクトをロードし、次に 32 ビットのオブジェクトとしてストアすると、普通のレジスタがそうであるように、下位の 32 ビットはストアされない。このため、alpha.h ではこのマクロを FLOAT_REGS として定義している。

他に特別なマクロが三つあって、どのオペランドがどの制約文字に収まるかを記述する。

CONST_OK_FOR_LETTER_P (value, c)
一個の C の式。この式は、特定の範囲の整数値を指定する、機種依存のオペランド制約文字(IJK... P) を定義する。c がこれらの文字のどれかであれば、この式で、ある整数である value が適切な範囲にあるかどうかを調べ、そうであれば1 を返し、それ以外の場合は 0 を返す。c がこれらの文字でなければ、value の値によらずにこの式の値は 0 とすべきである。
CONST_DOUBLE_OK_FOR_LETTER_P (value, c)
一個の C の式。この式は、特定の範囲の const_double の値を指定する機種依存のオペランド制約文字を定義する(GH)。

c がこれらの文字のどれかであれば、この式で、コード const_double の RTX である value を調べて、適切な範囲にあれば 1 を返し、それ以外の場合は 0 を返す。c がこれらの文字でなければ、value に関わらず、この式の値は 0 とすべきである。

const_double は、全ての浮動小数点定数と DImode の固定小数点定数に使われる。与えられた文字は、どちか片方の値、あるいは両方の値を受け入れることができる。GET_MODE を使ってこの二つの種類を区別することができる。

EXTRA_CONSTRAINT (value, c)
一個の C の式。オプションの機種依存制約文字(QRSTU)を定義する。これらの式を使って、ターゲット機種の特定の型のオペランド、普通はメモリ参照を区別することができる。普通は、このマクロは定義されない。ある特定のターゲット機種で必要な場合は、value が、制約文字 c で表現されるオペランドの型に対応するなら 1 を返す必要がある。c が追加の制約として定義されていない場合は、返される値は value に関わらずに 0 にならなければならない。

例えば、ROMP では、ロード命令は、メモリ参照がシンボリックアドレスを含んでいれば、出力を r0 に置くことができない。制約文字 Q が、シンボリックアドレスを含まないメモリアドレスを表現するものとして定義されている。ある選択肢が、入力に制約 Q が、出力に r が指定されている。次の選択肢は、入力に m が、出力には r0 を含まないレジスタクラスが指定されている。


Node:Stack and Calling, Next:, Previous:Register Classes, Up:Target Macros

スタックレイアウトと呼び出し規約

以下では、スタックのレイアウトと呼び出し規約について述べる。


Node:Frame Layout, Next:, Previous:Stack and Calling, Up:Stack and Calling

基本的なスタックレイアウト

基本的なスタック配置について説明する。

STACK_GROWS_DOWNWARD
ワードをスタック上にプッシュした場合に、スタックポインタの値が小さなアドレス方向に移動するなら、このマクロを定義する。

以下で「もし ... ならこのマクロを定義する」と書いてある場合は、コンパイラはこのマクロを #ifdef で調べるだけなので、何に定義されているかの詳細は関係がない。

FRAME_GROWS_DOWNWARD
局所変数用のスロットのアドレスのフレームポインタからのオフセットが負であれば、このマクロを定義する。
ARGS_GROW_DOWNWARD
関数の一連の引数がスタック上でアドレスが減少する方向に置かれるなら、このマクロを定義する。
STARTING_FRAME_OFFSET
確保すべき局所変数のスロットの、フレームポインタからのオフセットである。

FRAME_GROWS_DOWNWARD であれば、次のスロットのオフセットを、STARTING_FRAME_OFFSET から先頭のスロットの長さを差し引くことで求める。FRAME_GROWS_DOWNWARD でなければ、先頭のスロットの長さをSTARTING_FRAME_OFFSET に加算することで求める。

STACK_POINTER_OFFSET
スタックポインタレジスタから、出力引数が置かれる先頭の位置へのオフセットを定義する。これが指定されていない場合は、デフォルト値のゼロが使われる。多くの機種ではゼロが適切な値である。

ARGS_GROW_DOWNWARD が定義されている場合は、これは、出力引数が置かれている先頭の位置の直前の位置へのオフセットになる。

FIRST_PARM_OFFSET (fundecl)
引数ポインタレジスタからの先頭の引数のアドレスのオフセットを定義する。マシンによっては、関数の戻り値型に依存する。

ARGS_GROW_DOWNWARD が定義されている場合は、これは、先頭の引数のアドレスの直前の位置へのオフセットになる。

STACK_DYNAMIC_OFFSET (fundecl)
スタックポインタレジスタから、例えば alloca により、スタック上に動的に確保されるものへのオフセットを定義する。

このマクロのデフォルト値は、STACK_POINTER_OFFSET に出力引数の長さを足したものある。多くの機種ではこのデフォルト値で正しい値である。詳細は、function.c を参照のこと。

DYNAMIC_CHAIN_ADDRESS (frameaddr)
呼び出し側フレームへのポインタが格納されているスタックフレームのアドレスを表す RTL を値とする C の式。frameaddr は、スタックフレーム自身のアドレスを表す RTL 式であると仮定する。

このマクロを定義しない場合のデフォルトは、frameaddr の値を返すことである。すなわち、スタックフレームのアドレスが、前のフレームを指すスタックのワードのアドレスでもある。

SETUP_FRAME_ADDRESSES
定義されていれば、任意のフレームがアクセスできるようにスタックを設定する機種固有のコードを生成する C の式である。例えば、Sparc では、任意のスタックフレームをアクセス可能になる前に全てのレジスタ・ウィンドウをスタックにフラッシュしなければならない。このマクロを定義する必要は滅多にないだろう。
BUILTIN_SETJMP_FRAME_VALUE
定義されていれば、C の式であり、現在のフレームのアドレスを組み込みの setjmp バッファに格納するのに使われる rtx を保持する。デフォルト値である virtual_stack_vars_rtx が、ほとんどの機種で正しい値である。このマクロを定義する必要が出てくる理由の一つは、hard_frame_pointer_rtx が読者の機種でこのマクロに適した値の場合があるからである。
RETURN_ADDR_RTX (count, frameaddr)
一個の C の式。その値は、プロローグの後、現在のフレームから count 段さかのぼったフレームの戻りアドレス値を表す RTL である。frameaddr は、count 番目のフレームのフレームポインタか、RETURN_ADDR_IN_PREVIOUS_FRAME が定義されているなら、count - 1 番目のフレームポインタである。

この式の値は count がゼロの場合は常に正しいアドレスにならなければならない。だが、他のフレームの戻りアドレスを決める方法がない場合は NULL_RTX でも良い。

RETURN_ADDR_IN_PREVIOUS_FRAME
ある特定のスタックフレームの戻りアドレスが直前のスタックフレームのフレームポインタからアクセスされるなら、このマクロを定義する。
INCOMING_RETURN_ADDR_RTX
一個の C の式。この式の値は、任意の関数の先頭で、プロローグの前においての入力戻りアドレスの位置を表す RTL である。この RTL はある REGか、ある MEM のどちらかである。REG は、戻り値が REG にセーブされることを示し、MEM はスタック上の位置を表す。

このマクロを定義する必要があるのは、DWARF 2 で提供されているような呼び出しフレームデバッグ情報をサポートしたいときだけである。

INCOMING_FRAME_SP_OFFSET
一個の C の式。この式の値は、任意の関数の先頭で、プロローグの前においてのスタックポインタレジスタの値から、スタックフレームの頂上までのオフセットをバイト数で与える整数である。フレームの頂上は、直前のフレームでのコール命令の直前でのスタックポインタの値として定義される。

このマクロを定義する必要があるのは、DWARF 2 で提供されているような呼び出しフレームデバッグ情報をサポートしたいときだけである。

ARG_POINTER_CFA_OFFSET
C の式である。引数ポインタから正規フレームアドレス(canonical frame address (cfa))へのオフセットをバイト数で表した整数である。最終的な値は、INCOMING_FRAME_SP_OFFSET で計算した値と一致する必要がある。残念なことに、INCOMING_FRAME_SP_OFFSET はレジスタが仮想的な実体である間は使えないのである。

このマクロを定義する必要があるのは、DWARF 2 で提供されているような呼び出しフレームデバッグ情報をサポートしたいときだけである。


Node:Stack Checking, Next:, Previous:Frame Layout, Up:Stack and Calling

スタック検査方法の指定

GNU CC は、-fstack-check が指定された場合は、スタックの参照がスタックの境界内に収まっているかどうかを検査する。検査方法は以下の三つの内の一つである。

  1. マクロ STACK_CHECK_BUILTIN の値がゼロでなければ、GNU CC は、スタック検査をコンフィギュレーションファイルの適切な場所、例えば FUNCTION_PROLOGUE で設定済みであると想定する。GNU CC は他には特別な処理は行なわない。
  2. STACK_CHECK_BUILTIN がゼロで、mdファイルで名前付きパターンcheck_stack を定義していれば、GNU CC はそのパターンを、スタック値と比較するアドレスである引数を一つ付けて、呼び出す。スタックポインタが範囲外にある場合はエラーを報告するように、このパターンを設定しなければならない。
  3. 上のどちらも真でない場合は、GNU CC は、以下で定義するマクロの値を使って、定期的にスタックポインタを探るコードを生成する。

普通は以下のマクロの値としてデフォルト値が使われるので、GNU CC は三番目の方法を取ることになる。

STACK_CHECK_BUILTIN
スタック検査が、機種依存の方法でコンフィギュレーションファイルにより行なわれるなら、ゼロでない値となる。読者の機種の ABI がスタック検査を要求しているか、GNU CC の移植性の良い方法よりも幾らか効率の良いスタック検査を行なわせたいのなら、このマクロを定義すべきである。このマクロのデフォルト値はゼロである。
STACK_CHECK_PROBE_INTERVAL
GNU CC がスタックの探針用命令を生成しなければならない間隔を表す整数である。普通は、スタック領域の終りの「ガード・ページ」の大きさよりも大きくならないように、このマクロを定義する。デフォルト値の 4096 がほとんどのシステムで適切である。
STACK_CHECK_PROBE_LOAD
GNU CC がスタック探針をロード命令として実行すべきならゼロでない整数となり、ストア命令を使うべきならゼロとなる。デフォルトはゼロであり、ほとんどのシステムで最も効率の良い選択である。
STACK_CHECK_PROTECT
スタックのオーバフローから回復するのに必要なスタックのバイト数。デフォルト値の 75 ワードがほとんどの機種で適切である。
STACK_CHECK_MAX_FRAME_SIZE
あるスタックフレームの最大の大きさをバイト数で表す。GNU CC は、非末端関数では、少なくともこれだけのバイト数のスタックが利用可能であることを保証する探針命令を生成する。スタックフレームがこの大きさよりも大きいときは、スタック検査は信頼できなくなり、GNU CC は警告を発する。デフォルトは、GNU CC がほとんどのシステムで一個の命令しか生成しないように選ばれる。普通は、このマクロのデフォルト値は変えるべきではない。
STACK_CHECK_FIXED_FRAME_SIZE
GNU CC はこの値を見て、上述の警告メッセージを生成する。これは、ある関数で使われるフレームの固定部分の大きさを表し、非呼びだし側セーブのレジスタ、一時変数とユーザ定義変数の領域は含まない。この量については上限を指定するだけで良く、普通はデフォルトの 4 ワードを使う。
STACK_CHECK_MAX_VAR_SIZE
-fstack-check が指定された場合に、GNU CC がスタックフレームの固定領域に置くオブジェクトの最大の大きさをバイト数で表したもの。GNU CC は、上記のマクロの値からデフォルト値を計算する。普通はそのデフォルトを書き換える必要はない。


Node:Frame Registers, Next:, Previous:Stack Checking, Up:Stack and Calling

スタックフレームを扱うレジスタ

スタックフレームを指すレジスタについて説明する。

STACK_POINTER_REGNUM
スタックポインタレジスタのレジスタ番号である。FIXED_REGISTERS により固定レジスタとして指定されていなければならない。大抵の機種では、このレジスタはハードウェアによって決められている。
FRAME_POINTER_REGNUM
フレームポインタレジスタのレジスタ番号である。フレームポインタは、スタックフレーム中の自動変数を参照するのに使われる。マシンによっては、このレジスタがハードウェアによって決められている場合がある。ハードウェアによって決められていない場合は、好きなレジスタをフレームポインタとして使うことができる。
HARD_FRAME_POINTER_REGNUM
マシンによっては、フレームポインタと自動変数の開始オフセットとのオフセットが、レジスタの確保が完了するまで分からない場合がある。(例えば、セーブされたレジスタがこの二つの位置の間にあるような場合である。) この種類のマシンでは、FRAME_POINTER_REGNUM として特別な固定したレジスタを定義し、オフセットが分かるまでは内部的にこれを使うようにする。そして、HARD_FRAME_POINTER_REGNUM は、フレームポインタとして実際に使われるハードレジスタ番号を定義する。

このマクロは次のような非常に希な場合にだけ定義するべきである。その場合とは、フレームポインタと自動変数の間のオフセットがレジスタ割当が完了するまで計算できないという場合である。このマクロが定義されている場合は、ELIMINABLE_REGS の定義で、FRAME_POINTER_REGNUM を消去して、HARD_FRAME_POINTER_REGNUMSTACK_POINTER_REGNUM に置き換える方法も示さなければならない。

FRAME_POINTER_REGNUM と同じになる場合は、このマクロは定義しないこと。

ARG_POINTER_REGNUM
引数ポインタレジスタのレジスタ番号である。このレジスタは、関数の引数リストをアクセスするのに使われる。機種によっては、フレームポインタレジスタと同じである。また、機種によっては、ハードウェアによりどのレジスタかが決まっている場合もあるし、引数ポインタレジスタとして任意のレジスタを自分で選択出来る場合もある。引数レジスタがフレームポインタレジスタと同じではない場合は、FIXED_REGISTERS に従って、それに固定レジスタである印を付けるか、それを消去可能になるように調整しなければならない。(see Elimination)
RETURN_ADDRESS_POINTER_REGNUM
戻りアドレスポインタレジスタのレジスタ番号。これは、現在の関数の戻りアドレスをスタックからアクセスするのに使われる。機種によっては、戻りアドレスが、フレームポインタやスタックポインタや引数ポインタからの固定のオフセットにない場合がある。このレジスタはスタック上の戻りアドレスを指すように定義でき、ELIMINABLE_REGS により、フレームポインタかスタックポインタに変換される。

スタックから戻りアドレスを得る方法が他にあるのなら、このマクロは定義しないこと。

STATIC_CHAIN_REGNUM
STATIC_CHAIN_INCOMING_REGNUM
関数の静的チェーンポインタを渡すのに使うレジスタの番号である。レジスタ・ウィンドウが使われる場合は、呼び出された関数から見えるレジスタ番号は STATIC_CHAIN_INCOMING_REGNUM である。一方、呼びだし側関数から見えるレジスタ番号は STATIC_CHAIN_REGNUM である。この二つのレジスタが同じなら、STATIC_CHAIN_INCOMING_REGNUM は定義しなくて良い。

静的チェーンレジスタは固定レジスタである必要はない。

静的チェーンがメモリで渡されるなら、これらのマクロは定義すべきではない。代わりに次の二つのマクロを定義すべきである。

STATIC_CHAIN
STATIC_CHAIN_INCOMING
静的チェーンがメモリで渡されるなら、これらのマクロは、それらがどこに格納されるかを示す mem 式を与える RTX を提供する。STATIC_CHAINSTATIC_CHAIN_INCOMING は、それぞれ、呼びだし側関数と呼び出された関数から見える位置を表す。前者はスタックポインタからのオフセットの位置にあり、後者はフレームポインタからのオフセット位置にあることが多い。

変数 stack_pointer_rtxframe_pointer_rtxarg_pointer_rtx が、これらのマクロの使用に先だって初期化されるので、マクロを参照するのにはこちらの変数を使うべきである。

静的チェーンがレジスタで渡されるなら、先の二つのマクロを代わりに定義すべきである。


Node:Elimination, Next:, Previous:Frame Registers, Up:Stack and Calling

フレームポインタと引数ポインタの消去

フレームポインタと引数ポインタの消去について説明する。

FRAME_POINTER_REQUIRED
ある関数がフレームポインタを持たなければならず、かつ使う必要がある場合はゼロでない値を持つ C の式を定義する。この式は、再ロードのパスで評価される。この式の値がゼロでなければ、その関数はフレームポインタを持つようになる。

原理的にはこの式で現在の関数を調べてその結果に従ってフレームポインタの有無を決定することができるが、ほとんどのマシンでは定数 0 か定数 1 を使えば充分である。そのマシンがフレームポインタなしで生成したコードを許し、かつ、フレームポインタを使わないことで時間や空間の節約になるなら、0 を使う。フレームポインタを使わないことに何の利点もなければ、1 を使う。

場合によっては、フレームポインタなしには正しいコードを生成する方法が分からない場合がある。GNU CC はそういう場合を認識し、FRAME_POINTER_REQUIRED の値に関わらず自動的に関数にフレームポインタを与える。読者が心配することはない。

フレームポインタを必要としない関数では、固定レジスタとしていない限り、フレームポインタレジスタを通常の使用目的に確保することができる。詳細は FIXED_REGISTERS の項を参照のこと。

INITIAL_FRAME_POINTER_OFFSET (depth-var)
関数のプロローグの直後の時点でのフレームポインタとスタックポインタの値の差を変数 depth-var に格納する作業を行なう、C の文である。この値は、get_frame_size () の結果と二つのレジスタのテーブル、regs_ever_livecall_used_regs 等の情報から計算することができる。

ELIMINABLE_REGS が定義されているなら、このマクロは使われないので定義する必要がない。ELIMINABLE_REGS が定義されていなければ、FRAME_POINTER_REQUIRED が常に真になるように定義されていても、このマクロを定義しなければならない。FRAME_POINTER_REQUIRED が常に真の場合は、depth-var には何を設定しても良い。

ELIMINABLE_REGS
このマクロが定義されていれば、レジスタ対のテーブルを指す。このレジスタ対のテーブルは、スタックフレーム中を指すレジスタのうち不要なものを消去するために使うものである。このマクロが定義されていない場合は、GNU CC が試みる消去は、フレームポインタへの参照をスタックポインタへの参照に置き換えることだけである。

このマクロの定義は構造体の初期化式のリストからなり、リストの各要素は、置き換え前のレジスタと置き換え後のレジスタ対を指定する。

マシンによっては、引数ポインタの位置はコンパイルが完了するまでは分からない場合がある。そう言う場合は、別個のハードレジスタを引数ポインタとして使わなければならない。このハードレジスタは、フレームポインタか引数ポインタかのどちらかで置き換えることで消去可能である。どちらになるかは、フレームポインタが消去されたかどうかにより決まる。

この場合、以下のように指定しなければならない。

#define ELIMINABLE_REGS  \
{{ARG_POINTER_REGNUM, STACK_POINTER_REGNUM}, \
 {ARG_POINTER_REGNUM, FRAME_POINTER_REGNUM}, \
 {FRAME_POINTER_REGNUM, STACK_POINTER_REGNUM}}

引数ポインタをスタックポインタで置き換える消去が先頭に指定されているのは、それが望ましい消去だからであることに注意。

CAN_ELIMINATE (from-reg, to-reg)
レジスタ番号 from-reg をレジスタ番号 to-reg で置き換える試みが許されているならゼロでない値を返す C の式である。このマクロは ELIMINABLE_REGS が定義されている場合にのみ定義すれば良く、通常は定数 1 になる。というのは、レジスタ消去を妨げるほとんどの場合は、GNU CC が既に知っていることだからである。
INITIAL_ELIMINATION_OFFSET (from-reg, to-reg, offset-var)
このマクロは、INITIAL_FRAME_POINTER_OFFSET に似ている。指定されたレジスタ対の差の初期値を指定する。ELIMINABLE_REGS が定義されているなら、このマクロを定義しなければならない。
LONGJMP_RESTORE_FROM_STACK
関数 longjmp が、setjmpが明示的に退避したレジスタではなく、スタックフレームからレジスタを復帰する場合は、このマクロを定義する。このような機種では、ある種の量は、setjmp の呼び出しを越えてレジスタに保存されてはならない。


Node:Stack Arguments, Next:, Previous:Elimination, Up:Stack and Calling

関数の引数のスタック渡し

この節で説明するマクロ群は、引数がスタック上にどのように渡されるかを制御する。引数のレジスタ渡しを制御するマクロについては、次の節で参照のこと。

PROMOTE_PROTOTYPES
プロトタイプ宣言で int 型より小さい整数型として宣言されている引数を、実際には int 型として渡すべきである場合にはこのマクロを定義する。ある種の型の不一致によるエラーを避けるだけでなく、マシンによってはより良いコードを生成することがある。
PUSH_ROUNDING (npushed)
ある命令が npushed バイトをプッシュしようとしたときに実際にスタックにプッシュされるバイト数を表す C の式を定義する。

ターゲットマシンにプッシュ命令がないのなら、このマクロは定義しないこと。このマクロが定義されていなければ、GNU CC は別の戦略をとる。つまり、引数全体のブロックを割り当て、引数をそこに格納する。

マシンによっては、

#define PUSH_ROUNDING(BYTES) (BYTES)

という定義で充分である。しかし、別のマシンでは、一バイトをプッシュするように見える命令が実際にはアラインメントを維持するために二バイトをプッシュすることがある。そういう場合は以下のように定義する。

#define PUSH_ROUNDING(BYTES) (((BYTES) + 1) & ~1)

ACCUMULATE_OUTGOING_ARGS
このマクロが定義されていると、出力引数に必要とされるメモリスペースの最大量は、計算されたうえで、current_function_outgoing_args_size という変数に置かれる。各呼び出しではスタックにはスペースはプッシュされない。代わりに、呼び出される関数のプロローグがこの量だけスタックフレームの大きさを増やす必要がある。

PUSH_ROUNDINGACCUMULATE_OUTGOING_ARGS の両方を定義するのは正しくない。

REG_PARM_STACK_SPACE (fndecl)
引数の値がレジスタで渡される場合でも、その引数用にスタックが割り当てられていると、関数の方で仮定すべきであるなら、このマクロを定義する。

このマクロの値は、fndecl で表される関数にレジスタで渡される引数用の領域の大きさをバイト数で表したものである。この値は、GNU CC がライブラリ関数を呼び出すときはゼロになりうる。

この領域は呼びだし側で割り当てることも可能だし、マシン依存のスタックフレームの一部であっても良い。OUTGOING_REG_PARM_STACK_SPACE でどちらかを指定する。

MAYBE_REG_PARM_STACK_SPACE
FINAL_REG_PARM_STACK_SPACE (const_size, var_size)
関数が、その引数値がレジスタで渡される場合でもスタックスペースを割り当てる場合は、上記のマクロに加えてこれらのマクロを定義する。これらのマクロは、レジスタにある引数用に割り当てられたスタックスペースが、その関数宣言に依存しない単なる定数ではない場合に使うべきである。

最初のマクロの値は、レジスタで渡される引数用に予約されると最初に仮定した領域の大きさをバイト数で表したものである。

二番目のマクロの値は、レジスタで渡される引数用に予約される領域の実際の大きさをバイト数で表したものである。このマクロは引数を二つ取る。スタック上に取られる固定長の引数のバイト数を表す整数と、スタック上に取られる可変長の引数のバイト数を表すツリーである。

これらのマクロが定義されていると、REG_PARM_STACK_SPACE は以下の関数に対してだけ呼び出される。すなわち、libcall 関数、現在の関数、それに、このようなスタックスペースを割り当てなければならないことが知られているとき呼び出される関数である。どの場合にも、このマクロの値は簡単に計算できる。

呼び出された関数がこのようなスタックスペースを必要とするか、必要な場合はどれだけのスペースを予約すれば良いのかを決めるときに、GNU CC はREG_PARM_STACK_SPACE の代わりにこの二つのマクロを使う。

OUTGOING_REG_PARM_STACK_SPACE
レジスタで渡された引数用の予約領域を割り当てるのが、呼び出し側の責任であるなら、これを定義する。

ACCUMULATE_OUTGOING_ARGS が定義されている場合は、このマクロは、これらの引数用領域をcurrent_function_outgoing_args_size の値に含めるかどうかを制御する。

STACK_PARMS_IN_REG_PARM_AREA
REG_PARM_STACK_SPACE は定義されているが、スタック上のパラメータがそれで指定された領域をスキップしない場合はこのマクロを定義する。

普通、パラメータがレジスタで渡されない場合は、REG_PARM_STACK_SPACE 領域を越えたスタック上に置かれる。このマクロを定義するとこの動作を抑制し、パラメータをスタック上の自然な位置に渡すようにする。

RETURN_POPS_ARGS (fundecl, funtype, stack-size)
関数が戻るときにポップする自分自身の引数のバイト数を表す C の式。あるいは、その関数は自分では引数をポップしないために呼びだし側が、その関数が戻った後で、全部ポップしなければならないときは、0 である。

fundecl は一個の C の変数であり、その値は問題の関数を記述する木ノードである。通常、このノードの型は、関数の宣言を記述する FUNCTION_DECL である。これから、その関数の DECL_MACHINE_ATTRIBUTES を得ることができる。

funtype は一個の C の変数であり、その値は問題の関数を記述する木ノードである。通常、このノードの型は、関数のデータ型を記述する FUNCTION_TYPE である。これから、戻り値と引数(既知であれば)のデータ型を得ることができる。

ライブラリ関数の呼び出しを考えるときは、fundecl にはそのライブラリ関数の識別子ノードが入る。つまり、色々なライブラリ関数を区別する必要があるときは、名前で区別することができるのである。ここで「ライブラリ関数」というのは、算術演算を行なうのに使われる関数で、コンパイラが特別にその名前を知っているものであり、コンパイルされるC のコードには現れないものである。

stack-size は、スタックで渡される引数のバイト数である。可変のバイト数が渡される場合は、stack-size はゼロになり、引数のポップは常に呼び出し側関数の責任になる。

VAX の場合は、全ての関数が引数をポップするので、このマクロの定義はstack-size になる。68000 では、標準の呼び出し規約を使うと、引数をポップする関数はないので、このマクロの値は常にゼロになる。ただし、別の呼び出し規約も利用可能で、その場合固定数の引数を取る関数はその引数をポップするが、それ以外の関数(例えば printf) は何もポップしない(呼び出し側が全部ポップする)。後者の規約が使われるときは、funtype を調べて、関数が固定数の引数を取るかどうかが決定される。


Node:Register Arguments, Next:, Previous:Stack Arguments, Up:Stack and Calling

引数のレジスタ渡し

この節では、色々な型の引数をレジスタで渡す方法、あるいはスタックで渡す方法を制御するマクロについて説明する。

FUNCTION_ARG (cum, mode, type, named)
関数の引数がレジスタで渡されるかどうか、そしてどのレジスタで渡されるのかを制御する C の式を定義する。

引数の cum は、以前の引数を全て要約する。mode は、引数のマシンモードである。type は、ツリーノードとしての引数のデータ型か、未知であれば 0 である(C サポートライブラリ関数の場合)。named は、通常の引数では 1 になり、呼び出される関数のプロトタイプの... に対応する引数では 0 になる。

この式の値は、引数を渡すハードレジスタについては reg RTX であり、引数をスタックで渡す場合は 0 である。

Vax や 68000 のような、通常全ての引数がプッシュされる機種では、ゼロという定義で充分である。

この式の値は parallel RTX とすることもできる。これは、一個の引数が複数の位置に置かれて渡される場合に使われる。この parallel のモードは引数全体のモードにすべきである。parallel は、任意の個数の expr_list 対を保持する。そのそれぞれが、引数の一部がどこに渡されるかを記述する。各 expr_list では、第一オペランドは、引数のこの部分を渡すハードレジスタを表す reg RTX でなければならない。そして レジスタ RTX のモードが引数のこの部分の大きさを表す。expr_list の第二オペランドは、const_int であり、引数全体のうち、この部分が始まる位置のオフセットを与える。特別な例外として、parallel RTX の先頭の expr_list の第一オペランドはゼロであっても良い。これは、expr_list の第二オペランドから始まるバイト列がスタックに格納され、レジスタには保持されないことを表す。

ANSI ライブラリ stdarg.h を、引数の幾つかが通常はレジスタで渡されるような機種で動作させるようにする普通の方法は、名前のない引数を代わりにスタックで渡すようにすることである。これは、named が 0 の場合には常に FUNCTION_ARG が 0 を返すようにすれば良い。

このマクロを定義するのに MUST_PASS_IN_STACK (mode, type) というマクロを使って、この引数がスタックで渡さなければならない型かどうかを決めることができる。REG_PARM_STACK_SPACE が定義されていない場合に、このような引数に対して FUNCTION_ARG がゼロでない値を返すと、コンパイラは異常終了する。REG_PARM_STACK_SPACE が定義されていると、この引数はスタックで計算された後、レジスタにロードされる。

MUST_PASS_IN_STACK (mode, type)
C の式である。これを評価すると、type 単独でレジスタで渡す方法がわからないときは、ゼロでない値になる。ファイル expr.h で通常適切な定義を定義している。詳細については expr.h を参照のこと。
FUNCTION_INCOMING_ARG (cum, mode, type, named)
ターゲットマシンに「レジスタウィンドウ」がある場合にはこのマクロを定義し、関数から見て引数が入っているレジスタと、呼び出し側が引数を渡したレジスタが必ずしも同じである必要はないということを指示する。

そういう機種では、FUNCTION_ARG が、呼び出し側が値を渡すレジスタを計算する。そして、FUNCTION_INCOMING_ARG を同様の形で定義して、呼び出される関数にどこに引数が到着するかを知らせるようにする。

FUNCTION_INCOMING_ARG が定義されていなければ、FUNCTION_ARG が両方の役割を果たす。

FUNCTION_ARG_PARTIAL_NREGS (cum, mode, type, named)
一個の C の式。ある引数の先頭で、レジスタに置かなければならないワード数を表す。この値は、全体がレジスタで渡されるか、全体がスタックにプッシュされる引数についてはゼロにならなければならない。

機種によっては、ある種の引数は部分的にレジスタとメモリに分かれて渡さなければならないことがある。そういう機種では、典型的には、先頭の n ワードの引数がレジスタで渡され、残りはスタックで渡される。ある一個の複数語の引数(double や構造体)がその境界をまたがるなら、その先頭の数ワードをレジスタで渡し、残りはスタックにプッシュしなければならない。このマクロはコンパイラに、これが何時発生するかとレジスタに行くべき語数を知らせる。

これらの引数に対して FUNCTION_ARG は、この引数に対して呼び出し側により使われる先頭のレジスタを返すべきである。同様に、FUNCTION_INCOMING_ARG は、呼び出された側により使われる先頭のレジスタを返すべきである。

FUNCTION_ARG_PASS_BY_REFERENCE (cum, mode, type, named)
引数が参照で渡されなければならない事を示す C の式。引数一個につき、その引数のコピーがメモリに作られ、そこへのポインタが、引数自体の代わりに渡される場合は、ゼロでない値となる。ポインタは、その型へのポインタを渡すのに適切な方法で渡される。

REG_PARM_STACK_SPACE が定義されない機種では、適切な定義は以下のようになる。

#define FUNCTION_ARG_PASS_BY_REFERENCE\
(CUM, MODE, TYPE, NAMED)  \
  MUST_PASS_IN_STACK (MODE, TYPE)

FUNCTION_ARG_CALLEE_COPIES (cum, mode, type, named)
一個の C の式。定義されていると、不可視の参照で渡された引数のコピーを作るのが呼び出された関数の責任であるのはいつかを示す。普通、呼び出し側がコピーを作り、そのコピーのアドレスを呼び出されるルーチンに渡す。FUNCTION_ARG_CALLEE_COPIES が定義されていて、それがゼロでなければ、呼び出し側はコピーを作らない。代わりに、「生の」値へのポインタを渡す。呼び出された関数はこの値を変更してはならない。この値が変更されないことに決められるなら、コピーを作る必要はない。それ以外の場合はコピーを作らなければならない。
CUMULATIVE_ARGS
ある C の型。この型は、FUNCTION_ARG の先頭の引数とその他の関連する値として使われる変数を宣言する。幾つかのターゲット機種用には、int 型で充分であり、これまでのところ、その引数のバイト数を保持可能である。

スタックで渡された引数については、CUMULATIVE_ARGS には一切記録する必要がない。コンパイラは、他の変数群でそれらを記録する。全ての引数がスタックで渡されるターゲット機種では、CUMULATIVE_ARGS には何も格納する必要がない。だが、このデータ構造は存在しなくてはならず、空であってはいけないので、その場合は int を使うこと。

INIT_CUMULATIVE_ARGS (cum, fntype, libname, indirect)
一個の C の文(セミコロンなし)。この文は、引数リストの先頭の状態を表す変数 cum を初期化する。変数の型は CUMULATIVE_ARGS である。fntype の値は、引数を受け取る関数のデータ型を表すツリーノードか、その引数がコンパイラがサポートしているライブラリ関数に対するものなら 0 である。indirect の値は、間接呼びだし、例えば、関数ポインタを通しての呼び出しの場合はゼロでない値である。indirect の値は明示的に指定された関数の呼び出しか、ライブラリ関数への呼びだし、あるいはコンパイル中の関数の引数を見つけるのに INIT_CUMULATIVE_ARGSが使われるときは、ゼロである。

コンパイラサポートライブラリ関数への呼び出しを処理する際には、libname がどれであるかを特定する。libname は、関数名を文字列として含む symbol_ref RTX である。libname は、普通の C の関数呼び出しが処理される場合は 0 である。つまり、このマクロが呼び出されると必ず、libnamefntype のどちらかはゼロでない。だが、両方同時にゼロでない値になることはない。

INIT_CUMULATIVE_INCOMING_ARGS (cum, fntype, libname)
INIT_CUMULATIVE_ARGS とほぼ同じだが、コンパイル中の関数の引数を見つける目的のために、それを上書きする。このマクロが定義されていないと、INIT_CUMULATIVE_ARGS が代わりに使われる。

libname に渡される値は常に 0 である。なぜなら、特別な呼びだし規約を使うライブラリルーチンは GNU CC でコンパイルされることは決してないからである。引数 libnameINIT_CUMULATIVE_ARGS との対称性のために存在する。

FUNCTION_ARG_ADVANCE (cum, mode, type, named)
一個の C の文(セミコロンなし)。要約変数 cum を更新して、引数リストの中のある引数を越えたところまで進める。modetypenamed の値がその引数を記述する。一旦これが行なわれると、変数 cum は、FUNCTION_ARG 等を使って 後続の引数の解析を行なうに適したものになる。

このマクロは、問題の引数がスタックで渡されたものなら何もする必要がない。コンパイラは、引数に使われるスタック領域の量を特別な助けがなくとも追跡する方法を知っている。

FUNCTION_ARG_PADDING (mode, type)
一個の C の式。定義されていれば、引数を余分なスペースで詰め込むかどうか、詰め込むならどちら向きにするかを決める。この式の値は、enum direction 型でなければならない。upward は引数の上側に詰め込み、downward は下側を詰め込む。none は詰め込みをしない。

詰め込みは、いつでも次の FUNCTION_ARG_BOUNDARY の倍数にちょうど達するだけの量である。このマクロはそれを制御しない。

このマクロには、ほとんどのシステムに対して正しくなる、デフォルトの定義がある。リトルエンディアンの機種では、デフォルトは上向きに詰め込みをする。ビッグエンディアンの機種では、int よりも小さい固定サイズの引数に対しては下向きに、その他の引数については上向きに詰め込みをする。

FUNCTION_ARG_BOUNDARY (mode, type)
一個の C の式。定義されていれば、指定されたモードとタイプの引数のアラインメント境界をビット単位で与える。これが定義されていないと、全ての引数について PARM_BOUNDARY が使われる。
FUNCTION_ARG_REGNO_P (regno)
regno が関数の引数が渡されることもあるハードレジスタ番号なら、ゼロでない値となる C の式である。この場合の引数には、静的チェーンと構造体値アドレスのような暗黙の引数は含まない。多くの機種では、この目的ではレジスタは使えない。関数の引数が全てスタックで渡されるからである。
LOAD_ARGS_REVERSED
定義されていると、引数がそれぞれ対応する引数レジスタにロードされる順番が反転され、最後の引数が最初にロードされる。このマクロが影響するのは、レジスタで渡す引数だけである。


Node:Scalar Return, Next:, Previous:Register Arguments, Up:Stack and Calling

スカラ関数値の返し方

この節では、スカラを値として返す方法を制御するマクロについて議論する。スカラ値とは、レジスタに収まる値である。

TRADITIONAL_RETURN_FLOAT
-traditional オプションを指定した場合、float を返すように宣言された関数がその値を double 型に変換させるようにすべきでなければ、このマクロを定義する。
FUNCTION_VALUE (valtype, func)
ある関数がデータ型 valtype の値を返す場所を表すRTL を作る C の式である。valtype は、あるデータ型を表す木ノードである。その型を表すのに使われるマシンモードを得るにはTYPE_MODE (valtype) を使う。多くの機種では、そのモードだけが適切である。(実際に、ほとんどの機種では、スカラ値は、モードに関わらず同じ場所に返される。)

この式の値は、通常、戻り値が格納されるハードレジスタについてはreg RTX となる。この値は、戻り値が複数の場所に置かれるなら、parallel RTX でも良い。parallel 形式の説明については、FUNCTION_ARG を参照のこと。

PROMOTE_FUNCTION_RETURN が定義されている場合は、valtype がスカラ型なら、PROMOTE_MODE で指定されているのと同じ規則を適用しなければならない。

呼び出される具体的な関数が分かっているのなら、func はその関数を表す木ノード(FUNCTION_DECL)である。分かっていない場合は、func はヌルポインタである。このため、特定の関数について、その呼び出し側が全部わかっている場合は、戻り値を返すのに異なる規約を使うことが可能になる。

FUNCTION_VALUE は集合型のデータ型の戻り値には使われない。これらはまた別の方法で返されるからである。以下の、STRUCT_VALUE_REGNUM と関連マクロを参照のこと。

FUNCTION_OUTGOING_VALUE (valtype, func)
ターゲット機種に「レジスタ・ウィンドウ」があるため、ある関数がその値を返すのに入れるレジスタが、呼び出し側がその値を見つけるレジスタと同じでない場合は、このマクロを定義する。

そういう機種では、FUNCTION_VALUE が、呼び出し側がその値を見いだすレジスタを計算する。FUNCTION_OUTGOING_VALUE は、同様な形式で定義し、その関数に値をどこに置くかを知らせるようにすべきである。

FUNCTION_OUTGOING_VALUE が定義されていない場合は、FUNCTION_VALUE が両方の目的を果たす。

FUNCTION_OUTGOING_VALUE は集合型のデータ型の戻り値には使われない。これらはまた別の方法で返されるからである。以下の、STRUCT_VALUE_REGNUM と関連マクロを参照のこと。

LIBCALL_VALUE (mode)
あるライブラリ関数がモードmode の値を返す場所を表すRTL を作り出す C の式である。呼び出される具体的な関数が分かっているのなら、func はその関数を表す木ノード(FUNCTION_DECL)である。分かっていない場合は、func はヌルポインタである。このため、特定の関数について、その呼び出し側が全部わかっている場合は、戻り値を返すのに異なる規約を使うことが可能になる。

ここで言う「ライブラリ関数」とは、コンパイラのサポートルーチンであり、算術演算を実行するのに使われることに注意すること。ライブラリ関数名は、コンパイラが特別に知っており、コンパイルされるC のコードには現れない。

LIBIRARY_VALUE の定義は、集合データ型については気にする必要はない。集合データを返すようなライブラリ関数は一つもないからである。

FUNCTION_VALUE_REGNO_P (regno)
regno が、呼び出された関数の値が戻ってくるハードレジスタの番号なら、ゼロでない値となる C の式。

値を戻すのに使われる役割が、レジスタ対(例えば、double 型の値用)の二番目に限定されているならレジスタなら、このマクロで認識する必要はない。このため、ほとんどの機種では、以下の定義で充分である。

#define FUNCTION_VALUE_REGNO_P(N) ((N) == 0)

レジスタウィンドウを持つ機種で、呼び出し側と被呼び出し側関数が戻り値に異なるレジスタを使う場合は、このマクロは呼び出し側のレジスタ番号だけを認識すべきである。

APPLY_RESULT_SIZE
untyped_calluntyped_return が、任意の戻り値のセーブとリストアについて FUNCTION_VALUE_REGNO_P で暗示されるよりも、多くのスペースを必要とするなら、このマクロを定義する。


Node:Aggregate Return, Next:, Previous:Scalar Return, Up:Stack and Calling

大きな値の返し方

関数値のモードが BLKmode の場合(そして他のいくつかの場合)、値は FUNCTION_VALUE にしたがっては返されない(see Scalar Return)。代わりに、呼びだし側が値を格納すべきメモリブロックのアドレスを渡す。このアドレスは、構造体値アドレス と呼ばれる。

この節では、構造体値をメモリに入れて返す方法を説明する。

RETURN_IN_MEMORY (type)
一個のCの式。この式により、戻り値の型によって、一定の関数の戻り値をレジスタで返すのを禁止することが可能である。この式の値がゼロでないと、大きな構造体を返す場合は常にそうであるように、関数の値をメモリに入れて返すことを表す。ここで type は、tree 型の C の式であり、戻り値のデータ型を表現する。

モード BLKmode の値は、このマクロで明示的に扱わなければならないことに注意。また、 -fpcc-struct-return は、このマクロに関係なく有効になる。ほとんどの機種では、このマクロを定義しなくても良い。定義しないとデフォルトの定義が使われ、その場合、このマクロの値はBLKmode の値の場合は 1 に、それ以外の場合は 0 になる。

構造体と共用体を常にメモリで返すように指示するのには、このマクロは使わないこと。そのためには、代わりに DEFAULT_PCC_STRUCT_RETURN を使うべきである。

DEFAULT_PCC_STRUCT_RETURN
全ての構造体と共用体の戻り値をメモリに入れなくてはならない場合はこのマクロを 1 に定義する。これを定義すると生成されるコードが遅いものになるので、他のコンパイラや ABI との互換性のために必要な場合にだけ定義するようにする。このマクロを 0 に定義すると、構造体と共用体の戻り値に対する規約は、マクロ RETURN_IN_MEMORY により決定される。

このマクロが定義されない場合は、デフォルトで 1 となる。

STRUCT_VALUE_REGNUM
構造体値のアドレスがレジスタで渡されるなら、STRUCT_VALUE_REGNUM はそのレジスタ番号とする必要がある。
STRUCT_VALUE
構造体値のアドレスがレジスタでは渡されないなら、STRUCT_VALUE をアドレスが渡される場所を表す RTX を返す式として定義する。それが 0 を返すと、アドレスは「見えない」先頭の引数として渡される。
STRUCT_VALUE_INCOMING_REGNUM
アーキテクチャによっては、被呼び出し関数が構造体値のアドレスを見つける場所が、呼び出し側が置いた場所と同じでないことがある。これは、レジスタ・ウィンドウのせいであったり、関数のプロローグが異なる場所へ移動するためであったりする。

入力引数の構造体値のアドレスが置かれる位置がレジスタの場合は、このマクロをレジスタ番号として定義する。

STRUCT_VALUE_INCOMING
入力位置がレジスタでない場合は、呼び出された関数がその値を探すべき位置を表す RTX の式として STRUCT_VALUE_INCOMING を定義すべきである。その値をスタック上で探すべきなら、このマクロをフレームポインタを参照するmem を作り出すように定義する。0 と定義すると、アドレスは「不可視」の第一引数として渡されることを意味する。
PCC_STATIC_STRUCT_RETURN
構造体や共用体を返すための、ターゲット機種でのシステムの通常の規約が呼び出された関数が構造体や共用体の値を含む静的変数のアドレスを返すというものであるなら、このマクロを定義する。

システムの通常の規約が呼び出し側がサブルーチンにアドレスを渡すものであるなら、このマクロは定義しないこと。

このマクロは -fpcc-struct-return を指定した場合に効果があるが、-freg-struct-return を指定した場合には何の効果もない。


Node:Caller Saves, Next:, Previous:Aggregate Return, Up:Stack and Calling

呼び出し側退避レジスタの割り当て

もし有効になっているなら、GNU CC は、関数呼び出しの前後でレジスタをセーブすることができる。これにより、呼び出し時破壊レジスタを関数呼び出しにまたがって生存しなければならない変数を保持するのに使えるようになる。

DEFAULT_CALLER_SAVES
ターゲット機種で関数呼び出しがどのレジスタも保存しないのであれば、このマクロを定義する。言い換えると、CALL_USED_REGISTERS が全てのレジスタで 1 の場合である。このマクロは、定義されていれば、デフォルトで全ての最適化レベルで -fcaller-saves を有効にする。最適化レベル 2 以上では、デフォルトで -fcaller-saves が有効になっているので、このオプションを指定しても効果がない。
CALLER_SAVE_PROFITABLE (refs, calls)
C の式。この式は、疑似レジスタを呼び出し時破壊レジスタに置き、各関数呼び出しの前後でセーブ/リストアすることを考える価値があるかどうかを決定する。その価値がある場合は式の値は 1 とし、ない場合は 0 とすべきである。

このマクロを定義しない場合のデフォルトは 4 * calls < refs であり、ほとんどの機種で適切なものである。

HARD_REGNO_CALLER_SAVE_MODE (regno, nregs)
一個の C の式。疑似レジスタ nregs を呼出し時破壊ハードレジスタregno にセーブするのに必要とされるモードを指定する。regno が呼出し側セーブに向いていなければ、VOIDmode を返さなければならない。ほとんどの機種ではこのマクロを定義する必要はない。GCC が最小の適切なモードを選ぶからである。


Node:Function Entry, Next:, Previous:Caller Saves, Up:Stack and Calling

関数の入口と出口

この節では、関数の入り口(プロローグ)と出口(エピローグ)コードを出力するマクロについて説明する。

FUNCTION_PROLOGUE (file, size)
関数の入り口点のアセンブラコードを出力する C の複文である。このプロローグコードは、スタックフレームの設定、フレームポインタレジスタの初期化、セーブしなければならないレジスタのセーブ、局所変数用のsize バイト分の記憶域の確保を行なう責任がある。size は整数である。file は、アセンブラコードの出力先を指定する標準入出力ストリームである。

関数の開始位置を表すラベルは、このマクロで出力する必要はない。このマクロが実行されるときに既に済んでいるはずである。

セーブすべきレジスタを決めるために、このマクロは配列 regs_ever_live を参照する。この配列の要素 r は、ハードレジスタ r がこの関数内のどこかで使われているならゼロ以外の値となる。つまり、call-used レジスタの一つでない限り、プロローグコードがレジスタ r をセーブすべきであるということになる。(FUNCTION_EPILOGUE も同様に regs_ever_live を使わなければならない。)

レジスタウィンドウを持つマシンでは、関数の入り口点コードは、レジスタウィンドウにあるレジスタのスタックへのセーブは行なわない。たとえ、そのレジスタが関数呼びだしの際に保存されるべきものであってもである。代わりに、その関数内で non-call-used なレジスタが使われている場合は、レジスタスタックに「プッシュ」するという独特の処理を行なう。

関数のフレームポインタがあってもなくても良いマシンでは、関数の入り口点コードもフレームポインタの有無に対応して変わらなければならない。要求されているのであればフレームポインタを設定しなければならず、要求されていなければ設定してはならない。フレームポインタが要求されているかどうか決めるために、このマクロから変数 frame_pointer_needed を参照することが可能である。実行時には、フレームポインタを必要とする関数の中ではこの変数の値は 1 になる。See Elimination

関数の入り口コードには、その関数に必要とされるだけのスタックスペースを確保する責任がある。このスタックスペースは、以下に示す領域から成る。多くの場合は、これらの領域は以下の順番に確保され、最後に示した領域がスタックのトップに最も近くなる。スタックのトップは、STACK_GROWS_DOWNWARD が定義されていれば最下位アドレスになり、定義されていなければ最上位アドレスになる。より便利であったり、互換性に理由から必要とされるマシンに対しては、異なった順番を使っても良い。規格やデバッガから要求される場合を除き、あるマシンのスタック構成がGCC で使われるものと他のコンパイラで使われるものとが一致しなければならない理由はない。

普通は、マクロ FUNCTION_PROLOGUEFUNCTION_EPILOGUE は末端関数を特別に扱う必要がある。C の変数 current_function_is_leaf は、そういう関数についてはゼロでない値となる。

EXIT_IGNORE_STACK
一個の C の式。リターン命令や関数のエピローグがスタックポインタの値を無視するならゼロでない値となる。言い換えると、関数から戻る前にスタックポインタの調整を行なう命令を削除しても安全な場合は、ゼロでない値となる。

このマクロの値が関係するのは、フレームポインタが維持されている関数に対してだけであることに注意。フレームポインタを持たない関数で、最後のスタック調整を削除するのは決して安全ではない。コンパイラは、EXIT_IGNORE_STACK に関わらず、このことを知っている。

EPILOGUE_USES (regno)
C の式を定義するマクロ。この式の値は、エピローグか return パターンでレジスタが使われるなら 0 でない値とする。スタックポインタとフレームポインタレジスタは、既に必要に応じて使われていると仮定されている。
FUNCTION_EPILOGUE (file, size)
関数の出口点のアセンブラコードを出力する C の複文である。このエピローグコードは、セーブされたレジスタとスタックポインタの値を関数が呼び出されたときの値に復帰させ、制御を呼び出し関数に戻す責任がある。引数は、マクロ FUNCTION_PROLOGUE と同じである。復帰すべきレジスタは、同様に、regs_ever_liveCALL_USED_REGISTERS から決定される。

機種によっては、一個の機械命令で関数からの復帰作業を全て行なうものがある。そういう機種では、その命令に return という名前を与え、マクロ FUNCTION_EPILOGUE は定義してはならない。

FUNCTION_EPILOGUE を使って欲しいのであれば、return という名前のパターンを定義してはならない。ターゲットスイッチで、return 命令を使うのか、あるいは、エピローグを使うのかを制御したい場合は、return パターンを、ターゲットスイッチを適切にテストする有効性を検査する条件を付けて定義すること。return パターンの有効性検査条件が偽であれば、エピローグが使われる。

関数がフレームポインタを持っても持たなくても良い機種では、関数の終了コードはそれに従って変わらなければならない。この二つの場合のコードが全く異なるということもある。フレームポインタを必要とするかどうかを決めるために、このマクロでは変数 frame_pointer_needed を参照することが出来る。この変数の値は、コンパイルしている関数がフレームポインタを必要とするなら1 となる。

通常、FUNCTION_PROLOGUEFUNCTION_EPILOGUE は、末端関数を特別に取り扱わなくてはならない。そのような関数については、C の変数 current_function_is_leaf がゼロでない値となる。See Leaf Functions.

幾つかの機種では、関数によっては、終了時に引数をポップするものがあったり、呼び出し側にまかせたりするものがある。例えば、68020 では、-mrtd オプションを指定すると、固定数の引数を取る関数の引数はポップする。

マクロ RETURN_POPS_ARGS の定義により、どの関数がその関数自身の引数をポップするかが決まる。FUNCTION_EPILOGUE はどちらに決まったかを知る必要がある。current_function_pops_args という変数が、ある関数がポップすべき引数のバイト数を表す。See Scalar Return.

DELAY_SLOTS_FOR_EPILOGUE
関数のエピローグに、その関数の他の部分から命令をそこに「移動」可能な遅延スロットがあるなら、このマクロを定義する。このマクロの定義は、C の式とし、その値は存在する遅延スロット数とすべきである。
ELIGIBLE_FOR_EPILOGUE_DELAY (insn, n)
insn をエピローグコードの遅延スロット番号 n に置くことが出来る場合は 1 を返す C の式。

引数 n は、今考えている遅延スロットを特定する整数である(というのは、異なるスロットは異なる適性を持つからである。) この整数は、負になることはなく、常にエピローグにある遅延スロット数(DELAY_SLOTS_FOR_EPILOGUE が返す値である)より小さい。ある指定された遅延スロットにある特定の insn を入れることを拒否する場合は、原則的には、すぐ後ろの遅延スロットに入れられるかどうかが再考される。また、他の insn が(少なくとも)原則的には、その時点までに埋められていない遅延スロットに入るかどうかが考慮される。

エピローグコード中の遅延スロットを埋めるべく受け入れられた insn はinsn_list オブジェクトで作られた RTL リストに置かれ、変数 current_function_epilogue_delay_list に格納される。先頭の遅延スロットに入る insn は、このリストの先頭に来る。マクロ FUNCTION_EPILOGUE は、このリスト中の insn を出力することにより遅延スロットを埋めるように定義すべきである。これは、普通は final_scan_insn を呼び出すことにより行なわれる。

DELAY_SLOTS_FOR_EPILOGUE を定義しないのなら、このマクロを定義する必要はない。

ASM_OUTPUT_MI_THUNK (file, thunk_fndecl, delta, function)
C の複文。この複文はサンク関数用のアセンブラコードを出力する。サンク関数は、C++の、多重継承を持つ仮想関数呼び出しを実装するのに使われる。サンクは、仮想関数のラッパーとして作用し、実際の関数へ制御を渡す前に暗黙のオブジェクトパラメータの調整を行なう。

まず、整数 delta を先頭の入力引数を含む位置に加算するコードを生成する。この引数はあるポインタを含んであり、C++ で this ポインタを渡すのに使われるものであると仮定する。これは、関数プロローグの前の入力引数、例えば SPARC では%o0 である。この加算は、他の全ての入力引数の値を保存しなければならない。

この加算の後、function にジャンプするコードを生成する。functionFUNCTION_DECL である。これは純粋な直接ジャンプであり、呼び出しではないので、戻りアドレスはいじらない。つまり、FUNCTION から戻ると、現在の thunk の呼び出し元に戻ることになる。

この効果は、あたかも functionが第一引数を調整したうえで直接呼び出されたかのようにならなければならない。このマクロは、サンク関数用のコードを全て生成する責任がある。FUNCTION_PROLOGUEFUNCTION_EPILOGUE は呼び出されない。

thunk_fndecl は冗長である。(これから、deltafunction が既に抽出済みである。) ターゲットによっては役に立つ可能性もあるが、多分そういうことはないだろう。

このマクロを定義しない場合は、C++ フロントエンドのターゲット非依存コードが、効率の落ちる、重量級のサンクを生成する。このサンクは、function にジャンプするのではなく、それを呼び出す。この汎用的な方法はvarargs はサポートしない。


Node:Profiling, Previous:Function Entry, Up:Stack and Calling

プロファイリング用コードの生成

以下のマクロは、プロファイル用コードの生成を助ける。

FUNCTION_PROFILER (file, labelno)
一個の C の文か複文で、file に、プロファイルサブルーチン mcount を呼び出すアセンブラコードを出力する。呼び出しの前に、このアセンブラコードはカウンタ変数のアドレスを、mcount がそのアドレスを見つけると想定しているレジスタにロードしなければならい。このカウンタ変数の名前は LP の後に、番号 labelno が付いたものなので、fprintfLP%d とすることでこの名前を生成できる。

アドレスが mcount にどのように渡されるかの詳細は、GNU CC ではなく、ユーザのオペレーティングシステム環境により決まる。それがどういうものであるか調べるには、小さいプログラムをシステムにインストール済みの C コンパイラを使ってプロファイリング用にコンパイルし、その結果生成されるアセンブラコードを見れば良い。

PROFILE_BEFORE_PROLOGUE
関数のプロファイリング用コードを関数のプロローグコードの前に置くべきならこのマクロを定義する。普通は、プロファイリング用コードはプロローグコードの後に来る。
FUNCTION_BLOCK_PROFILER (file, labelno)
一個の C の文か複文で、file に、現在のオブジェクトモジュールの基本ブロックのプロファイリングを初期化するアセンブラコードを出力する。グローバルなコンパイルフラグ profile_block_flag で二つのプロファイリングのモードを区別する。
profile_block_flag != 2
オブジェクトモジュール毎にサブルーチン __bb_init_func を一度だけ呼び出すコードを出力する。このサブルーチンにはただ一つの引数として、そのオブジェクトモジュール内に割り当てられたあるブロックのアドレスを渡す。

ブロック名はローカルシンボルであり、次の文で作られる。

ASM_GENERATE_INTERNAL_LABEL (buffer, "LPBX", 0);

もちろん、このマクロの定義だけではなくて、ASM_GENERATE_INTERNAL_LABEL の定義も書くわけだから、このマクロの定義をショートカットして、生成されるとわかっている名前を使っても良い。

このブロックの先頭のワードは、そのオブジェクトモジュールが既に初期化済みであればゼロでない値となるフラグである。そのため、まずこのワードを調べ、フラグがゼロでなければ __bb_init_func を呼ばないようにする。labelno には、__bb_init_func が呼ばれないときの分岐先ラベルを生成するのに使われる一意的な番号が入る。

アセンブラ言語で書くと、出力すべきコードは以下のようになる。

  cmp (LPBX0),0
  bne local_label
  parameter1 <- LPBX0
  call __bb_init_func
local_label:

profile_block_flag == 2
サブルーチン __bb_init_trace_func を呼び出し、二つのパラメータを渡すコードを出力する。第一のパラメータは __bb_init_func と同じである。二番目のパラメータは、labelno により与えられる関数の先頭の基本ブロックの番号である。__bb_init_trace_func は、オブジェクトモジュールが既に初期化済みの場合でも、必ず呼び出されなければならないことに注意して欲しい。

アセンブラ言語で書くと、出力すべきコードは以下のようになる。

parameter1 <- LPBX0
parameter2 <- BLOCK_OR_LABEL
call __bb_init_trace_func

BLOCK_PROFILER (file, blockno)
一個の C の文か、複文。この文は file に、基本ブロック番号 blockno に付随するカウンタをインクリメントするアセンブラコードを出力する。グローバルなコンパイルフラグ profile_block_flag で、以下の二つのプロファイルモードを区別する。
profile_block_flag != 2
カウンタを直接インクリメントするコードを出力する。基本ブロックは各コンパイル毎に別々にゼロから始まる番号が付けられる。基本ブロック番号 blockno に付随するカウンタは、ワードのベクトルの添え字 blockno の要素にある。この配列の名前は、以下の文で作られるローカルシンボルである。
ASM_GENERATE_INTERNAL_LABEL (buffer, "LPBX", 2);

もちろん、このマクロの定義だけではなくて、ASM_GENERATE_INTERNAL_LABEL の定義も書くわけだから、このマクロの定義をショートカットして、生成されるとわかっている名前を使っても良い。

アセンブラ言語で書くと、出力すべきコードは以下のようになる。

inc (LPBX2+4*BLOCKNO)

profile_block_flag == 2
グローバルな構造体 __bb を初期化し、関数 __bb_trace_func を呼び出すコードを出力する。__bb_trace_func は、カウンタをインクリメントする。

__bb は二つのワードからなる。最初のワードには、blockno で与えられる、現在の基本ブロックの番号が格納されなければならない。二番目のワードには、オブジェクトモジュール中に割り当てられたブロックのアドレスが格納されなければならない。このアドレスは、以下の文で作られるラベルで与えられる。

ASM_GENERATE_INTERNAL_LABEL (buffer, "LPBX", 0);

アセンブラ言語で書くと、出力すべきコードは以下のようになる。

move BLOCKNO -> (__bb)
move LPBX0 -> (__bb+4)
call __bb_trace_func

FUNCTION_BLOCK_PROFILER_EXIT (file)
一個の C の文か、複文。この文は、file に関数 __bb_trace_ret を呼び出すアセンブラコードを出力する。このアセンブラコードは、グローバルなコンパイルフラグ profile_block_flag == 2 の場合だけ出力すべきである。このマクロは、関数から戻るためのコードが生成される全ての場所で(例えば、FUNCTION_EPILOGUE)使う必要がある。FUNCTION_EPILOGUE の定義も同様に書かなければならないが、このマクロを定義することでコンパイラに対し、__bb_trace_ret の正しい呼び出しが生成されるよう指示しなければならない。
MACHINE_STATE_SAVE (id)
一個の C の文か、一個の複文。この文は、全レジスタをセーブする。レジスタは関数呼び出しにより破壊されるものであっても良く、条件コードを含む。この作業を扱うのに一番必要そうなのは、asm 文だろう。アセンブラコード中の局所ラベルを文字列 id と連結して、一意的なラベル名を得ることもできる。

FUNCTION_PROLOGUEFUNCTION_EPILOGUE により破壊されるレジスタや条件コードは、マクロ FUNCTION_BLOCK_PROFILERFUNCTION_BLOCK_PROFILER_EXITBLOCK_PROFILER により、それぞれ __bb_init_trace_func__bb_trace_ret__bb_trace_func の呼び出しに先だって、セーブしなければならない。

MACHINE_STATE_RESTORE (id)
MACHINE_STATE_SAVE によりセーブされた、条件コードを含む、全レジスタをリストアする C の文か複文。

FUNCTION_PROLOGUEFUNCTION_EPILOGUE により破壊されるレジスタや条件コードは、マクロ FUNCTION_BLOCK_PROFILERFUNCTION_BLOCK_PROFILER_EXITBLOCK_PROFILER により、それぞれ __bb_init_trace_func__bb_trace_ret__bb_trace_func の呼び出しの後で、リストアしなければならない。

BLOCK_PROFILER_CODE
ブロックプロファイリングをサポートするライブラリで必要な一つの、あるいは複数の関数。


Node:Varargs, Next:, Previous:Stack and Calling, Up:Target Macros

varargs マクロの実装

GNU CC には、varargs.hstdarg.h のある実装が付属しており、引数をスタック上で渡す機種では変更なしで動作する。そうでない機種ではそれ自身の varargs の実装が必要になり、その場合、機種独立の二つのヘッダファイルから条件付きで実装ファイルをインクルードしなければならない。

ANSI の stdarg.h は、旧来の varargs.h とは、va_start の呼び出し規約の点で主に異なっている。旧来の実装では、va_start は引数をただ一つだけ取り、それが引数ポインタを格納する変数になっている。ANSI の va_start の実装では、引数が一つ追加されている。プログラマは、関数の引数で名前が付いている最後のものを va_start の二番目の引数に書くことを要求される。

しかし、va_start はこの二番目の引数を使うべきではない。名前付き引数の最後を見つける方法は、以下に記述する組み込み関数で行なう。

__builtin_saveregs ()
この組み込み関数を使って、引数レジスタをメモリにセーブすることで、varargs の機構がそれらをアクセス可能になる。va_start の ANSI 版も旧来版もどちらも、代わりに SETUP_INCOMING_VARARGS(以下を参照)を使うのでない限り、__builtin_saveregs を使わなければならない。

機種によっては、__builtin_saveregs はマクロEXPAND_BUILTIN_SAVEREGS の制御の元で C 言語で書かれている。その他の機種では、アセンブラ言語で書かれたルーチンを呼び出す。これは、libgcc2.c にある。

__builtin_saveregs 呼び出し用に生成されたコードは、__builtin_saveregs の呼び出しが書かれている場所とは対照的に、そのコードが何をするかには関係なく、関数の先頭に現れる。これは、レジスタは、関数がそれ自身の目的でそのレジスタを使い始める前にセーブされなければならないものだからである。

__builtin_args_info (category)
この組み込み関数を使って、レジスタにある最初の無名引数を見つける。

一般に、一つの機種には、引数として使われるレジスタには色々なカテゴリがあり、それぞれ特定のデータ型のカテゴリに対して使われる。(例えば、ある機種では、浮動小数点レジスタは浮動小数点引数に使われる一方で、それ以外の引数は汎用レジスタで渡される。) 非 varargs 関数が正しい呼び出し規約を使用するようにするには、データ型 CUMULATIVE_ARGS を定義して、各カテゴリで何個のレジスタがこれまで使われたかを記録する必要がある。

__builtin_args_infoCUMULATIVE_ARGS 型と同じデータ構造を、それを使った通常の引数のレイアウトが終わった後で参照する。このとき、category がどのワードを参照すべきかを指定する。つまり、この値は与えられたカテゴリのレジスタで未使用のものの先頭を指す。

普通は、va_start の実装で __builtin_args_info を使い、各カテゴリを一度だけアクセスし、値を va_list オブジェクトに格納する。これは va_list がその値を更新しなければならないためであり、__builtin_args_info によりアクセスされる値を変える方法がないためである。

__builtin_next_arg (lastarg)
これは、スタック上の引数については、__builtin_args_info に等価である。先頭の無名スタック引数のアドレスを、void * 型で返す。ARGS_GROW_DOWNWARD が定義されていれば、先頭の無名スタック引数の上の位置のアドレスを返す。それを va_start で使って、スタックから引数を取り出すためのポインタを初期化する。また、va_start で、第二引数 lastarg が現在の関数の名前のある引数の最後であることを検証するのにも使われる。
__builtin_classify_type (object)
それぞれの機種には固有の規約があって、どの型のデータをどの種類のレジスタで渡すかを決めている。読者はその規約を具体化するようにva_arg を実装しなければならない。指定されたデータ型を分類する一番手っ取り早い方法は、__builtin_classify_typesizeof__alignof__ を組み合わせて使うことである。

__builtin_classify_typeobject の値は無視し、そのデータ型だけを見る。どんな型であるか--整数、浮動小数点、ポインタ、構造体などを記述する整数を返す。

ファイル typeclass.h である列挙型を定義していて、__builtin_classify_type の値を解釈するのに使うことができる。

以下のマシン記述マクロは varargs の実装を助ける。

EXPAND_BUILTIN_SAVEREGS (args)
定義されているなら、一個の C の式であり、__builtin_saveregs を呼び出すための機種固有のコードを生成する。このコードは関数の一番先頭の、仮引数のアクセスが行なわれる前に移動される。この関数の戻り値は、__builtin_saveregs の戻り値として使う値を含む RTX とすべきである。

引数 args は、__builtin_saveregs に渡された引数を含む、ある tree_list である。

このマクロが定義されていない場合は、コンパイラは通常の、ライブラリ関数 __builtin_saveregs の呼び出しを出力する。

SETUP_INCOMING_VARARGS (args_so_far, mode, type, pretend_args_size, second_time)
このマクロは、__builtin_saveregs の使い方とマクロEXPAND_BUILTIN_SAVEREGS の定義の仕方に別の選択肢を提供する。このマクロを使って、無名のレジスタ引数をスタックに格納し、全ての引数がスタック上に連続して渡されたように見せることができる。一旦これをやっておくと、varargs の標準の実装を使うことができる。varargs の標準の実装は、全ての引数をスタックで渡す機種に対して使うことができる。

引数 args_so_far はデータ構造 CUMULATIVE_ARGS である。このデータ構造は、名前つき引数を処理した後の値を含む。引数 modetype は最後の名前つき引数を、そのマシンモードとデータ型をツリーノードとして記述する。

このマクロの実装では次の二つを行なう必要がある。まず第一に、名前つき引数用に使われていない全ての引数レジスタをスタックにプッシュする。次に、このようにしてプッシュされたデータの大きさを int 型の値の変数に格納する。この変数の名前は、引数 pretend_args_size で提供される。ここで格納した値は、スタックフレームの設定で使われる追加のオフセットとして機能する。

無名引数をプッシュするコードを、コンパイル時にそのデータ型を知ることなしに生成しなければならないので、SETUP_INCOMING_VARARGS は、引数レジスタのカテゴリが一個しかなく、全データ型にたいして等しくそれを使う機種でのみ、意味がある。

引数 second_time がゼロでないと、この関数の引数が二回目に解析されることを意味する。これはインライン展開関数の場合に起こり、ソースファイルの終りに達するまで実際にコンパイルされない。マクロ SETUP_INCOMING_VARARGS は、この場合何も命令を生成すべきでない。

STRICT_ARGUMENT_NAMING
関数の引数が渡される位置が、その引数が名前付きの引数かどうかに依存するなら、このマクロをゼロでない値に定義する。

このマクロは、FUNCTION_ARG への引数 named がvarargs と stdarg 関数に対してどのようにして設定されるかを制御する。このマクロがゼロでない値を返すなら、引数 named は名前つき引数に対しては常に真になり、名無し引数では偽になる。このマクロが値ゼロを返すが、SETUP_INCOMING_VARARGS が定義されている場合は、全ての引数が名前つきとして扱われる。それ以外の場合は、全ての名前つき引数は、最後の引数を除いて、名前付きとして扱われる。

常にゼロを返すなら、このマクロを定義する必要はない。

PRETEND_OUTGOING_VARARGS_NAMED
ABI を条件により変更して、一方は SETUP_INCOMING_VARARGS が定義されている場合に動作するようにし、もう一方は、SETUP_INCOMING_VARARGSSTRICT_ARGUMENT_NAMING も定義されていないかのように動作させる必要がある場合には、このマクロを、SETUP_INCOMING_VARARGS が使われている場合にはゼロでない値を返すように定義し、使われていない場合にはゼロを返すようにする。該当しな場合は、このマクロを定義すべきではない。


Node:Trampolines, Next:, Previous:Varargs, Up:Target Macros

入れ子関数のトランポリン

トランポリン(trampoline)は、小さなコード断片であり、入れ子関数のアドレスを取るコードがあると、実行時に作成される。普通はにスタックに置かれる。これは、入れ子関数を含んでいる関数のスタックフレームの中になる。以下に説明するマクロは、トランポリンを確保したり、初期化するコードを生成する方法を GNU CC に知らせる。

トランポリン中の命令群は次の二つの作業を行なう必要がある。ある定数アドレスを静的チェーンレジスタにロードすること、およびネストした関数の実際のアドレスにジャンプすることである。m68k のような CISC マシンでは、このような場合二つの命令、つまり、一個の即値の移動命令と一個のジャンプ命令が必要である。そうすると、この二つのアドレスはトランポリン中ではワード長の即値オペランドとして存在する。RISC マシンでは、各アドレスを一個のレジスタにロードするのに二つの部分に分けて行なう必要があるものが多い。各アドレスの断片は、別々の即値オペランドを形成する。

トランポリンを初期化するために生成されたコードは、可変部分を命令の即値オペランドに格納しなければならない。可変部分とは、静的チェーンと関数のアドレスである。CISC の機種では、これは単に、各アドレスをトランポリンの先頭から適切なオフセットの地点のメモリ参照へコピーするという問題になる。RISC の機種では、アドレスの各断片を取りだして、別々にストアする必要がでてくる可能性がある。

TRAMPOLINE_TEMPLATE (file)
一個の C の文。この文は、ストリーム file に、あるトランポリンの固定部分を含むデータブロック用のアセンブラコードを出力する。このコードにはラベルを含めてはならない。ラベルの面倒は自動的にみてくれる。

このマクロを定義しないということは、ターゲットがテンプレートを必要としないということを意味する。トランポリンを決められた場所にコピーするブロック移動コードの大きさが、その場でトランポリンを生成するコードの大きさよりも大きいシステムではこのマクロを定義しないこと。

TRAMPOLINE_SECTION
サブルーチン名。このサブルーチンは、トランポリンのテンプレートを置くべきセクションへの切替えを行なう(see Sections)。デフォルトは readonly_data_section の値であり、その場合、読み出し専用データを入れるセクションにトランポリンが置かれる。
TRAMPOLINE_SIZE
整数値を取るC の式であり、トランポリンのバイト単位での大きさを表す。
TRAMPOLINE_ALIGNMENT
トランポリンに必要なアラインメントをビット数で表す。

このマクロが定義されていないと、BIGGEST_ALIGNMENT の値がトランポリンのアラインメントとして使われる。

INITIALIZE_TRAMPOLINE (addr, fnaddr, static_chain)
トランポリンの可変部分を初期化する C の文。addr は、トランポリンのアドレスの RTX である。fnaddr は、ネスト関数のアドレスの RTX である。static_chain は、関数が呼ばれたときにその関数に渡すべき静的チェーン値を表す RTX である。
ALLOCATE_TRAMPOLINE (fp)
トランポリン用の実行時スペースを確保する C の式。この式の値は、トランポリンのスペースへのメモリ参照を表す RTX とすべきである。

このマクロが定義されていない場合は、デフォルトでトランポリンはスタックスロットとして確保される。ほとんどの機種ではこのデフォルトが正しい。例外となる機種は、スタック領域にある命令を実行することが不可能な機種である。そのような機種では、別のスタックを独立に実装しなければならない可能性がある。その場合は、このマクロを FUNCTION_PROLOGUEFUNCTION_EPILOGUE を一緒に使って行なう。

fp は、あるデータ構造、struct function を指す。この構造体は、トランポリンが必要になる関数を含む関数(包含関数)のコンパイル状況を記述する。普通(ALLOCATE_TRAMPOLINE が定義されてないとき)、トランポリン用のスタックスロットはこの包含関数のスタックフレーム内にある。その他の割当戦略を取った場合も、この情報に類似したものを行なわなければならない。

多くの機種ではトランポリンを実装するのは困難である。命令とデータで別々のキャッシュを持っているからである。スタック位置へ書き込んでも命令キャッシュにあるメモリ内容をクリアしないので、プログラムがその位置にジャンプしたとき、古い内容を実行してしまう。

二つの解決方法がある。一つは、トランポリンが設定されたら常に命令キャッシュの関係する部分をクリアすることである。もう一つは、全てのトランポリンを、ある標準のサブルーチンにジャンプさせることにより、同じものにしてしまうことである。前者の方法はトランポリンの実行が速くなり、後者は初期化が速くなる。

トランポリンが初期化されるとき命令キャッシュをクリアするには、キャッシュの形状を記述する以下のマクロを定義する。

INSN_CACHE_SIZE
キャッシュの合計サイズをバイト単位で表す。
INSN_CACHE_LINE_WIDTH
キャッシュの各ラインの長さをバイト数で表す。キャッシュは分離したスロットである複数のキャッシュ・ラインからなる。各キャッシュ・ラインは、メモリから取り出した、ある連続なデータの塊を保持する。データがキャッシュに持ち込まれる度に、一本のライン全体が一度に読み込まれる。あるキャッシュ・ラインにロードされたデータは、常に、ラインの大きさに等しい境界に整列する。
INSN_CACHE_DEPTH
任意の特定のメモリ位置を保持できる別のキャッシュラインの数。

あるいは、命令キャッシュを直接クリアするシステムコールまたは命令がある機種では、以下のマクロを定義することができる。

CLEAR_INSN_CACHE (BEG, END)
一個の C の式。定義されていれば、この式は、指定された間隔で命令キャッシュをクリアする。このマクロが定義されておらず、マクロ INSN_CACHE_SIZE が定義されていると、ある汎用のコードが生成され、キャッシュをクリアする。このマクロの定義は普通、一連の asm 文となるだろう。BEGEND はどちらもポインタ式である。

標準のサブルーチンを使うには、以下のマクロを定義する。さらに、トランポリンの中の命令が、あるキャッシュライン全体を全く同一の命令で埋め尽くすこと、あるいはトランポリンコードの先頭が常にそのキャッシュラインの同じ場所に整列することを保証しなければならない。m68k.h を指針として読んで欲しい。

TRANSFER_FROM_TRAMPOLINE
トランポリンがその仕事を行なうために特別なサブルーチンを必要とする時はこのマクロを定義する。このマクロは、GNU CC によりコンパイルされるasm 文の連なりに展開される必要がある。展開されると、ライブラリ関数 __transfer_from_trampoline に入る。

あるコンパイル済みの C の関数の通常のプロローグコードを、そのサブルーチンにジャンプするときには、実行するのを避ける必要がある場合は、アセンブラコードの中に特別なラベルを置くことで行なうことができる。asm 文を一個使ってアセンブララベルを生成し、もう一個の asm 文でそのラベルをグローバルにする。そうしておくと、トランポリンがそのラベルを使って、その特別なアセンブラコードに直接ジャンプすることができる。


Node:Library Calls, Next:, Previous:Trampolines, Up:Target Macros

暗黙のライブラリルーチン呼び出し

この節では、ライブラリルーチンの暗黙的な呼び出しについて説明する。

MULSI3_LIBCALL
符号付きのワード同士の乗算の際に呼び出すべき関数名を与える C の文字列定数。このマクロを定義しない場合は、デフォルトの名前、__mulsi3 が使われる。__mulsi3libgcc.a で定義される。
DIVSI3_LIBCALL
符号付きのワード同士の除算の際に呼び出すべき関数名を与える C の文字列定数。このマクロを定義しない場合は、デフォルトの名前、__divsi3 が使われる。__divsi3libgcc.a で定義される。
UDIVSI3_LIBCALL
符号なしのワード同士の除算の際に呼び出すべき関数名を与える C の文字列定数。このマクロを定義しない場合は、デフォルトの名前、__udivsi3 が使われる。__udivsi3libgcc.a で定義される。
MODSI3_LIBCALL
C の文字列定数。これは、符号付きの全ワードをもう一つの符号付き全ワードで割った余りを求めるために呼び出す関数名を与える。このマクロを定義しないと、デフォルトの名前が使われる。これは、__modsi3 であり、libgcc.a で定義されている関数である。
UMODSI3_LIBCALL
C の文字列定数。これは、符号なしの全ワードをもう一つの符号なし全ワードで割った余りを求めるために呼び出す関数名を与える。このマクロを定義しないと、デフォルトの名前が使われる。これは、__umodsi3 であり、libgcc.a で定義されている関数である。
MULDI3_LIBCALL
C の文字列定数。これは、符号付きの2ワードともう一つの符号付き2ワードの積を求めるために呼び出す関数名を与える。このマクロを定義しないと、デフォルトの名前が使われる。これは、__muldi3 であり、libgcc.a で定義されている関数である。
DIVDI3_LIBCALL
C の文字列定数。これは、符号付きのダブルワード同士の商を求めるために呼び出す関数名を与える。このマクロを定義しないと、デフォルトの名前が使われる。これは、__divdi3 であり、libgcc.a で定義されている関数である。
UDIVDI3_LIBCALL
C の文字列定数。これは、符号なしのダブルワード同士の商を求めるために呼び出す関数名を与える。このマクロを定義しないと、デフォルトの名前が使われる。これは、__udivdi3 であり、libgcc.a で定義されている関数である。
MODDI3_LIBCALL
C の文字列定数。これは、符号付きのダブルワード同士の剰余を求めるために呼び出す関数名を与える。このマクロを定義しないと、デフォルトの名前が使われる。これは、__moddi3 であり、libgcc.a で定義されている関数である。
UMODDI3_LIBCALL
C の文字列定数。これは、符号なしの(ダブル?)ワード同士の剰余を求めるために呼び出す関数名を与える。このマクロを定義しないと、デフォルトの名前が使われる。これは、__umoddi3 であり、libgcc.a で定義されている関数である。
INIT_TARGET_OPTABS
一個の C の文。この文は、ライブラリルーチンの宣言を追加して、既存のものの名前を付け替える。init_optabs は、全ての通常ライブラリルーチンを初期化した後、このマクロを呼び出す。
TARGET_EDOM
ターゲット機種の EDOM の値を、C の整数定数式として表したもの。このマクロを定義しない場合は、GNU CC は EDOM の値を errno に直接置こうとはしない。/usr/include/errno.h を見て、読者のシステムでの EDOM の値を探すこと。

TARGET_EDOM を定義しないと、コンパイルされたコードが、そのライブラリ関数を呼び出し、エラーを報告させることで、ドメインエラーを報告する。読者のシステムの数学関数がエラーがあるときに matherr を使うなら、TARGET_EDOMO を未定義とし、通常通り matherr が使われるようにすべきである。

GEN_ERRNO_RTX
グローバル「変数」 errno を参照する RTL 式を作る C の式としてこのマクロを定義する。(システムによっては、errno は実際には変数ではない可能性がある。) このマクロを定義しない場合は、適切なデフォルトが使われる。
TARGET_MEM_FUNCTIONS
GNU CC が、BSD の関数 bcopybzero ではなく、System V(と ANSI C) の関数 memcpymemset の呼び出しを生成すべきなら、このマクロを定義する。
LIBGCC_NEEDS_DOUBLE
float 型の引数だけがライブラリ関数に渡せない(そのためdouble に変換しなければならない)場合は、このマクロを定義する。このマクロは、ライブラリ呼び出しがどのように生成されるのかとlibgcc1.c の中のライブラリルーチンがどのように引数を受け取るのかの両方に影響する。i860 のように、浮動小数点引数と固定小数点引数では渡し方が異なる場合には役に立つマクロである。
FLOAT_ARG_TYPE
ライブラリルーチンが float 型の引数を取り出す時に使われる型を変えたい場合はこのマクロで定義する。(デフォルトでは、floatint の共用体型を使う。)

float にすれば良いように思うだろうが、旧来の C コンパイラではうまく行かない。float として宣言されている全ての引数がdouble として渡されることを想定しているからである。この float から double の変換を避けるために、ライブラリルーチンは、その値を何か他の型として要求し、その後でfloat として扱う。

システムによっては、このために使える他の型がない場合もある。そういうシステムでは、LIBGCC_NEEDS_DOUBLE を代わりに使って、その値を渡される前に double に強制的に変換するようにしなければならない。

FLOATIFY (passed-value)
ライブラリルーチンが float 型の引数を渡された型の代わりに float として再度指示する方法を変えたい場合はこのマクロを定義する。型を変えたい場合はこのマクロで定義する。デフォルトでは、前出の共用体の float フィールドを取る式である。
FLOAT_VALUE_TYPE
ライブラリルーチンが、float 型を持つべき値を返すのに使われる型を変えるには、このマクロを定義する。(デフォルトでは int になる。)

float にすれば良いように思うだろうが、旧来の C コンパイラではうまく行かない。float として宣言された値を不必要に double に変換するからである。

INTIFY (float-value)
float 型を返すライブラリルーチンの値を、それを返すためにはどのようにパッケージするべきか、その方法を変更したいときはこのマクロを定義する。これらの関数は実際に FLOAT_VALUE_TYPE(普通int になる)型を返すように宣言される。

これらの値は float 型として返すことはできない。なぜなら、旧来の C コンパイラは常にの値を double に変換してしまうからである。

intify という名前の局所変数が、マクロ INTIFY を使うときはいつでも利用可能である。これは、float 型のフィールド fFLOAT_VALUE_TTYPE 型か int 型のフィールド i とからなる共用体である。

このマクロを定義しない場合の、デフォルトの定義の動作は、この値をその共用体を通してコピーする。

nongcc_SI_type
このマクロは、システムの C コンパイラで SImode に対応するデータ型名を定義する。

その型が通常の long int なら、このマクロを定義する必要はない。

nongcc_word_type
このマクロは、システムの C コンパイラで word_mode に対応するデータ型名を定義する。

その型が通常の long int なら、このマクロを定義する必要はない。

perform_...
これらのマクロは、libgcc1.c 中のライブラリルーチン群にある、float 型と double 型についての様々な算術演算を実行する C の文を明示的に提供するように定義する。これらのマクロとその引数の完全なリストについては libgcc1.c を見ること。

ほとんどの機種では、これらのマクロはどれも定義する必要がない。何故なら、システム付属の C コンパイラが面倒を見るからである。

NEXT_OBJC_RUNTIME
このマクロは、NeXT システムの呼び出し規約を使って Objective C のメッセージを送信するためのコードを生成するように定義する。この呼び出し規約には、オブジェクト、セレクタ、メソッド引数を全て一度にメソッド検索ライブラリ関数に渡すことが含まれる。

デフォルトの呼び出し規約は、オブジェクトと検索関数のセレクタを渡すだけである。検索関数はメソッドへのポインタを返す。


Node:Addressing Modes, Next:, Previous:Library Calls, Up:Target Macros

アドレッシングモード

この節では、アドレッシングモードについて説明する。

HAVE_POST_INCREMENT
マシンがポストインクリメントのアドレッシングをサポートしている場合は、ゼロでない値を取る C の式である。
HAVE_PRE_INCREMENT
HAVE_POST_DECREMENT
HAVE_PRE_DECREMENT
HAVE_POST_INCREMENT に同様である。
CONSTANT_ADDRESS_P (x)
RTX x がアドレスとして有効な定数であれば、1 となる C の式を定義する。多くのマシンでは、CONSTANT_P (x) として定義すれば良いが、幾つかのマシンではアドレスとして使える定数に制限がある。

CONSTANT_P は、明示的には未知である値を持つ、整数値の式を受け付ける。そのような式としては、例えば、symbol_reflabel_refhigh といった式、const 算術式、const_intconst_double 式がある。

MAX_REGS_PER_ADDRESS
有効なメモリアドレスに現れることができるレジスタ数の最大値を表す数である。 GO_IF_LEGITIMATE_ADDRESS が受け付ける最大数に等しい値を指定するかどうかは読者の責任であることに注意。
GO_IF_LEGITIMATE_ADDRESS (mode, x, label)
条件付きの goto label; を含む一個の C の複文。この goto は、x(ある RTX) がターゲット機種で、モード mode のメモリオペランドとして正しいメモリアドレスである場合に実行される。

普通は、幾つかの単純なマクロを定義して、このマクロのサブルーチンとする。そうしないと、大変複雑になりがちで理解するのが難しくなるからである。

このマクロは二種類なければならない。厳密な版と厳密でない版である。厳密な版は再ロード・パスで使われる。これは、ハードレジスタが割り当てられていない疑似レジスタはすべてメモリ参照であると考えられるように定義しなければならない。なにかの種類のレジスタを必要とする文脈では、ハードレジスタが割り当てられていない疑似レジスタは拒絶しなければならない。

厳密でない版は他のパスで使われる。こちらは、なにかの種類のレジスタが必要とされる、あらゆる文脈で全ての疑似レジスタを受け付けるように定義しなければならない。

GNU CC のソースファイルで、このマクロの厳密版を使いたいところでは、マクロを REG_OK_STRICT を定義する。条件文 #ifdef REG_OK_STRICT を使って、厳密版を使いたいところでは厳密版を定義し、それ以外のところでは厳密でない版を定義するべきである。

色々な目的(ベースレジスタ向けや、インデックスレジスタ向けなど)に受付可能なレジスタを検査するサブルーチン群は、普通はGO_IF_LEGITIMAITE_ADDRESS を定義するのに使われるサブルーチン群の中にある。これらのサブルーチンマクロだけが二つの変種を必要とする。高レベルのマクロは厳密であってもなくても同じで良い。

通常、symbol_ref と整数の和である定数アドレスは、const RTX の内側に格納され、定数であるという印が付けられる。このため、このような和を正当なアドレスとして特別に認識する必要はない。普通は、単に const は全て正当であるとして認識すれば良い。

通常、PRINT_OPERAND_ADDRESS は、const が付いていない定数和を扱う準備はしていない。単体の plus があると、インデックスすることを想定している。もしそうなら、そのような単体の定数和は不正なアドレスとして拒絶して、PRINT_OPERAND_ADDRESS に渡らないようにしなければならない。

機種によっては、シンボリックなアドレスが正当かどうかはそのアドレスが参照しているセクションに依存する。そういう機種では、マクロ ENCODE_SECTION_INFO を定義して、その情報を symbol_ref に格納し、そこで検査を行なうようにする。const があった場合は、その中を見て symbol_ref を探し、セクションを決定する必要がある。See Assembler Format

名前の文字列を修正する最善の方法は、文字列の前にテキストを追加し、さらに適当な区切り文字を付けて、曖昧さをなくすことである。ASM_OUTPUT_LABELREF を修正して、追加テキストを消去してデコードし、かつ、その名前を適切に出力し、さらに STRIP_NAME_ENCODING を定義して、元の名前の文字列を参照するようにする必要がある。

ここで symbol_ref に貯えた情報を、マクロ GO_IF_LEGITIMATE_ADDRESSPRINT_OPERAND_ADDRESS の定義の中で検査することができる。

REG_OK_FOR_BASE_P (x)
一個の C の式。この式は、x (reg RTX と仮定される) がベースレジスタとして使うのに適していれば、ゼロでない値となる。ハードレジスタの場合には、常に、ハードウェアが許すものは受け付けて、それ以外は拒絶すべきである。このマクロが疑似レジスタを受け付けるか拒絶するかは、上記のREG_OK_STRICT により制御されなければならない。普通、これには二種類の定義が必要になる。REG_OK_STRICT が実際に使われるものを選ぶ。
REG_MODE_OK_FOR_BASE_P (x, mode)
一個の C の式。REG_OK_FOR_BASE_P にほとんど同じであるが、その式が mode のメモリ参照のモードを調べるという点が異なる。そのメモリ参照のモードが、あるレジスタがベースレジスタとして使えるかどうかに影響するなら、このマクロを定義すべきである。このマクロを定義すると、GNU CC は REG_OK_FOR_BASE_P の代わりにこちらを使う。
REG_OK_FOR_INDEX_P (x)
一個の C の式で、その値は、x (reg RTX と仮定される)がインデックスレジスタとして使うのが有効なら、ゼロでない値となる。

インデックスレジスタとベースレジスタの違いは、インデックスレジスタはスケーリングされることである。あるアドレスが二つのレジスタの和を含んでいて、そのどちらもスケーリングされないのであれば、どちらか一つが「ベース」となり、他方は「インデックス」というラベルが貼られる。だが、どちらのラベル付が使われても、レジスタがそれぞれの役割を果たす、その機種の制約に収まらなければならない。コンパイラは両方のラベル付を試して、有効なものを一つ見つけ出し、どちらのラベル付も動作しない場合にのみ、一方のレジスタ、あるいは両方のレジスタを再ロードする。

LEGITIMIZE_ADDRESS (x, oldx, mode, win)
一個の C の複文。この文は、x をモード mode のオペランドの有効なメモリアドレスで置き換えることを試みる。win は、コード中のどこか別のところにある 一個の C のラベルである。このマクロ定義は、
GO_IF_LEGITIMATE_ADDRESS (mode, x, win);

を使って、アドレスが正当なものになっている場合には、それ以上の処理を避ける。

x は、常に break_out_memory_refs の呼び出しの結果であり、oldx は、その関数に与えられて x を生成したオペランドである。

このマクロにより生成されたコードは x の下位構造を変えてはならない。このコードがx をより正しい形に変換するなら、x(これは常に、ある C の変数になる)に新しい値を割り当てるべきである。

このマクロが正しいアドレスを提示する必要はない。コンパイラには全ての場合に正しいアドレスにする標準的な方法がいくつかある。だが、機種依存の戦略を取ると生成されるコードが良くなることも多い。

LEGITIMIZE_RELOAD_ADDRESS (x, mode, opnum, type, ind_levels, win)
C の複文。この複文は、再ロードを必要とするアドレスである x を、モード mode のオペランドに対する有効なメモリ参照で置き換えることを試みる。win はコードのどこか別の場所にある、C の文ラベルになる。このマクロを定義するのは必須ではないが、実行速度の点から有用である。

例えば、i386 では、二つの疑似レジスタの和を一個のレジスタに再ロードすることにより、二つの再ロードレジスタの代わりに一つの再ロードレジスタを使用することが可能なことがときどきある。一方、多くの RISC プロセッサのオフセットは限られているので、スタックスロットをアドレスために中間のアドレスを生成する必要があることが多い。LEGITIMIZE_RELOAD_ADDRESS を適切に定義すると、近くにまとまっている幾つかのスタックスロット用に生成される中間アドレスを同じものにする事ができるので、共有が可能にある。

注意。このマクロを使うには注意が必要である。これを効率良く使うためには再ロードの仕組みをいくらか知っている必要がある。そして、再ロードの内部についての知識をたくさん詰め込んだマクロを生成するのはきわめて簡単である。

注意。このマクロは、前回のこのマクロの呼出しにより作られたアドレスを再ロードできなければならない。そういうアドレスの取扱いに失敗すると、GCC は正しくないコードを生成したり、異常終了したりする。

このマクロの定義では、push_reload を使って、再ロードが必要な部分を示す必要がある。numtypeind_ldevels は普通は変更無しで push_reload に渡すのに適している。

このマクロが生成したコードは、x の下位構造を変更してはならない。これが x をさらに正統な形に変換するなら、x (これは常に C の変数である)に新しい値を割り当てる必要がある。これは、push_reload を呼び出すことで間接的に変更した部分にも適用される。

このマクロは、strict_memory_address_p を使って、アドレスが正統になるかどうかを検査しても良い。

x の一部だけ変更したいときの標準的な方法の一つは、copy_rtx を使うことである。ただし、共有しないのは RTL の一つのレベルだけである。つまり、変更される部分がトップのレベルにないときは、まずトップレベルを置き換える必要がある。このマクロが正統なアドレスを出す必要はない。だが、機種依存の戦略がより良いコードを生成可能な事が多い。

GO_IF_MODE_DEPENDENT_ADDRESS (addr, label)
一個の C の文か複文であり、条件付きの goto label; を含む。この goto は、メモリアドレス x (一個の RTX)がそれに使われるメモリ参照のマシンモードによって意味が違ったり、そのアドレスがあるモードでは有効だがその他のモードでは有効ではないという場合に実行される。

自動インクリメントと自動デクリメントのアドレスには、普通モードに依存した効果がある。なぜなら、インクリメントとデクリメントの量は対象のオペランドの大きさだからである。機種によっては、その他にモード依存のアドレスを持つものもある。多くの RISC 機種にはモード依存のアドレスがない。

addr がその機種の有効なアドレスであると仮定して良い。

LEGITIMATE_CONSTANT_P (x)
一個の C の式。この式は、x がターゲット機種の即値オペランドとして正しい定数ならゼロでない値となる。xCONSTANT_P を満たすと仮定して良いので、その検査は必要ない。実際、 CONSTANT_P が有効な機種では、1 がこのマクロの適切な定義になる。


Node:Condition Code, Next:, Previous:Addressing Modes, Up:Target Macros

条件コードステータス

条件コードステータスについて説明する。

ファイル conditions.h で、変数 cc_status を定義している。これは、条件コードがどのように計算されるかを記述している(条件コードを設定した命令によって条件コードの解釈が異なる場合)。この変数は、条件コードが現在元にしている RTL 式と、色々な標準のフラグを含んでいる。

場合によっては、機種固有のフラグをマシン記述ヘッダファイルで追加で定義しなければならないこともある。また、機種固有の情報を CC_STATUS_MDEP を定義することで追加することができる。

CC_STATUS_MDEP
cc_statusmdep 成分を宣言するのに使われるデータ型についての C のコード。デフォルトは int になる。

このマクロは、cc0 を使用しない機種では使われない。

CC_STATUS_MDEP_INIT
mdep フィールドを「空」に初期化する C の式。デフォルトの定義は何もしない。何故なら、ほとんどの機種ではこのフィールドは使わないからである。このフィールドを使う場合には、恐らくこのマクロを定義して初期化をすべきであろう。

このマクロは、cc0 を使用しない機種では使われない。

NOTICE_UPDATE_CC (exp, insn)
本体が exp である insn insn に対してcc_status の成分を適切に設定する、C の複文。このマクロは、条件コードを設定する insn を認識する責任を負う。これには、明示的に (cc0) を設定するものだけでなく、他の処理の副産物として条件コードを設定するものも含まれる。

このマクロは、cc0 を使用しない機種では使われない。

条件コードは設定しないが他のマシンレジスタをいじる命令があるなら、このマクロで、条件コードがそれを反映するように記録されている式をそれらの命令が無効にするかどうかを検査しなければならない。例えば、68000 では、アドレスレジスタにストアする命令は条件コードを設定しない。これは普通 NOTICE_UPDATE_CC がそういう命令に対して cc_status を変えないままにしておくことが可能であるということを意味する。だが、直前の命令が a4@(102) という位置に基づいて条件コードを設定し、現在の命令が新しい値を a4 にストアするとしよう。条件コードはこれにより変更されないものの、それが a4@(102) の内容を反映しているというのはもはや真ではない。このため、NOTICE_UPDATE_CC は、この場合 cc_status を変更することにより、条件コード値については何もわからないということを言わなければならない。

NOTICE_UPDATE_CC は、覗き穴最適化の結果を扱う準備をするように定義しなければならない。覗き穴最適化の結果とは、そのパターンが様々な、regmem、あるいは単なるオペランドである定数を含む parallel RTX であるような insn 群である。これらの insn の RTL 構造は、その insn が実際に何をするのかを表すのには充分ではない。NOTICE_UPDATE_CC が、こういう insn に対してなすべきことは、単に CC_STATUS_INIT を実行することである。

NOTICE_UPDATE_CC の可能な定義の一つは、例えば cc という名前の属性(see Insn Attributes)を見る関数を呼び出すことである。これにより、パターンについての詳細な情報を二箇所、すなわちmd ファイルと NOTICE_UPDATE_CC に置くのを避けることができる。

EXTRA_CC_MODES
レジスタにある条件コード値の追加のモードに使われる名前のリストである。このリストの名前は、enum machine_mode に追加され、その全てがクラス MODE_CC を持つ。規約により、これらの名前は CC で始まり、mode で終わるようにする。

このマクロを定義するのは、cc0 を使わない機種で、しかも追加のモードが必要な場合に限ること。

EXTRA_CC_NAMES
EXTRA_CC_MODES に列挙したモードの名前を与える C の文字列のリスト。例えば、SPARC では、このマクロと EXTRA_CC_MODES を以下のように定義している。
#define EXTRA_CC_MODES CC_NOOVmode, CCFPmode, CCFPEmode
#define EXTRA_CC_NAMES "CC_NOOV", "CCFP", "CCFPE"

このマクロは、EXTRA_CC_MODES が定義されていなければ必要とされない。

SELECT_CC_MODE (op, x, y)
クラス MODE_CC のあるモードで、比較演算コード op をRTX xy に適用したときに使われるものを返す。例えば、SPARC では、SELECT_CC_MODE は、以下のように定義されている(see Jump Patterns でこの定義の理由を説明している)。
#define SELECT_CC_MODE(OP,X,Y) \
  (GET_MODE_CLASS (GET_MODE (X)) == MODE_FLOAT          \
   ? ((OP == EQ || OP == NE) ? CCFPmode : CCFPEmode)    \
   : ((GET_CODE (X) == PLUS || GET_CODE (X) == MINUS    \
       || GET_CODE (X) == NEG) \
      ? CC_NOOVmode : CCmode))

このマクロは、EXTRA_CC_MODES が定義されていなければ、定義する必要はない。

CANONICALIZE_COMPARISON (code, op0, op1)
機種によっては、可能な比較が全ては定義されていないものがあるが、無効な比較を有効なものに変換することができる。例えば、Alpha には GT の比較がないが、代わりに LT の比較を使って、オペランドの順番を入れ替えることができる。

そういう機種では、このマクロを一個の C の文として定義し、必要な変換を行なうようにする。code は、最初の比較コードであり、op0op1 はそれぞれ比較の左オペランドと右オペランドである。必要に応じて、codeop0op1 を更新すべきである。

GNU CC は、このマクロから生じる比較が有効であるとは仮定しないが、結果の insn が md ファイルにあるパターンにマッチするかどうかは分かる。

比較のコードやオペランドを変更することが全くないのなら、このマクロを定義する必要はない。

REVERSIBLE_CC_MODE (mode)
モードが mode の比較を反転することが常に安全に行なえるのなら、値が 1 となる C の式である。SELECT_CC_MODE が浮動小数点の不等性の比較に対して、常に mode を返すことができるなら、REVERSIBLE_CC_MODE (mode) はゼロでなければならない。

このマクロが常にゼロを返すか浮動小数点形式が IEEE_FLOAT_FORMAT 以外なら、このマクロを定義する必要はない。例えば、以下に Sparc で使われている定義を示す。浮動小数点数の不等性の比較は常に CCFPEmode で与えられる。

#define REVERSIBLE_CC_MODE(MODE)  ((MODE) != CCFPEmode)


Node:Costs, Next:, Previous:Condition Code, Up:Target Macros

操作の相対的コストの記述

以下のマクロ群を使って、ターゲットマシンの色々な操作の相対的な速度を記述する。

CONST_COSTS (x, code, outer_code)
C の switch 文の一部を定義する。この switch 文の断片では、定数 RTL 式の相対的なコストを記述する。式コード const_intconstsymbol_reflabel_refconst_double にそれぞれ対応する case ラベルが含まれていなければならない。各ケースでは、最終的には return 文に達して、その種類の定数値を式の中で使うことの相対的なコストを返さなくてはならない。コストは、定数の具体的な値に依存する可能性がある。この定数はx を調べるのに使うことができる。そして、それを含む式の RTX コードはouter_code に入っている。

code は式コードである。これは冗長である。というのは、GET_CODE (x) で求めることができるからである。

RTX_COSTS (x, code, outer_code)
CONST_COSTS とほぼ同じだが、違いは非定数 RTL 式に適用されることである。これを使って、例えば、乗算命令のコストがどれぐらいかを示すことができる。このマクロを書くときは、定数COSTS_N_INSNS (n) を使って、n 個の高速な命令に等しいコストを指定することができる。outer_code は、x が含まれている式のコードである。

このマクロはオプションであり、デフォルトのコストの想定がターゲット機種に適しているなら定義しないこと。

DEFAULT_RTX_COSTS (x, code, outer_code)
このマクロが定義されていると、RTX_COSTSCONST_COSTS マクロで取り扱われない場合に呼び出される。これにより、case のラベルをマクロにいれる必要がなくなるが、そのコード、あるいはそれを呼び出す関数は、x 中の RTL は既に取り扱われたことの内どんな型にでもなりうることを保証しなければならない。引数は RTX_COSTS のものと同じである。そしてこのマクロは、取扱いが可能な任意の RTL 式のコストを与える return 文を実行する必要がある。このマクロが値を返さない RTL に対しては、デフォルトのコスト計算が使われる。

このマクロはオプションである。デフォルトのコスト想定がターゲット機種にてきせつであるなら定義しないこと。

ADDRESS_COST (address)
address を含むアドレッシングモードのコストを与える式である。定義されていないと、コストは address 式と CONST_COSTS の値から計算される。

ほとんどの CISC マシンでは、デフォルトのコストが、そのアドレッシングモードの実際のコストの良い近似になっている。だが、RISC マシンでは、普通、全ての命令が同じ命令長と実行時間になる。このため、全てのアドレスのコストが等しくなる。

アドレス形式が複数ある場合には、コストが最小の形式が使われる。複数の形式が同じ最小のコストになる場合には、最も複雑なものが使われる。

例えば、あるレジスタとある定数の和に等しいアドレスが同じ基本ブロック内で二回使われたとしよう。このマクロが定義されていないときは、このアドレスはあるレジスタで計算され、メモリ参照はそのレジスタを通した間接参照になる。この和を含むアドレッシングモードのコストが、単純な間接参照のコストより高くない機種では、これにより、命令が一個追加され、恐らく追加のレジスタも一個必要になるだろう。このマクロで適切に指定すると、こういう機種でのオーバーヘッドを消去する。

このマクロは、ループの強度削減においても似たような使い方をされる。

address はアドレスとして有効である必要はない。その場合、コストは関係ないのでどんな値にもなりうる。無効なアドレスに別のコストを割り当てる必要はない。

レジスタ一個よりも多くのものを含むアドレスの計算コストがレジスタを一個しか含まないアドレスのコストと同じである機種では、ADDRESS_COST を定義してそのことを反映させると、ADDRESS_COST がそのように定義されていなければ一つしか生存できないようなあるコードの範囲で、二つのレジスタが生存できるようになる。この効果はこのマクロを定義するときに考慮に入れる必要がある。コストが等しくなるのは、おそらく、たくさんレジスタのある機種上で、異なる数のレジスタを含むアドレスの場合だけになるはずである。

このマクロは普通は、定義しないか、定数として定義されるかのどちらかである。

REGISTER_MOVE_COST (from, to)
クラス from のレジスタから、クラス to のレジスタへデータを移動するコストを表す式。クラスは、GENERAL_REGS のような列挙値で表される。2 という値がデフォルトである。その他の値は、2 に相対的な値として解釈される。

fromto と同じである場合、コストが常に 2 である必要はない。機種によっては、汎用レジスタでないレジスタ間での移動が高くつくものがある。

再ロードパスで二つのハードレジスタを使った一個の set からなる insn を見つけると、それらのレジスタのクラスに REGISTER_MOVE_COST を適用すると 2 という値を返すなら、再ロードパスはその insn の制約が満たされることを保証するための検査を行なわない。レジスタ移動のコストを 2 以外にすると再ロードパスは制約が満たされることを検証する。movm というパターンの制約がこのようなコピーを許さないのであれば、コストを 2 以外にすべきである。

MEMORY_MOVE_COST (mode, class, in)
モード mode のデータをクラス class のレジスタとメモリの間で移動するコストを表す式。in は、値がメモリに書き込まれるべきものならゼロであり、読み出すべきものならゼロでない値となる。このコストは、REGISTER_MOVE_COST のコストに相対的な値である。レジスタとメモリの間の移動が、二つのレジスタ間のものより高く付くなら、このマクロが相対的なコストを表すように定義すべきである。

このマクロを定義しない場合、GCC はデフォルトのコスト 4 に、もしそれが必要であれば、第二の再ロードレジスタを経由してコピーするコストを足したものを使う。メモリと class のレジスタの間でコピーをするのに第二の再ロードレジスタを必要とするが、再ロードの機構が中間を経由してコピーするより複雑な場合は、このマクロを定義して、そういう移動の実際のコストを反映させるようにする。

GCC は、第二の再ロードレジスタが必要な場合、memory_move_secondary_cost という関数を定義する。これは、第二の再ロードレジスタ経由のコピーによるコストを計算する。読者の機種では、メモリから第二のレジスタを使って伝統的な方法でコピーを行うが、しかしデフォルトのベース値の 4 では合わないという場合は、このマクロを定義して、この関数の結果に何か他の値を加えるようにする。この関数への引数は、このマクロへの引数と同じである。

BRANCH_COST
分岐命令のコストを表す C の式。1 という値がデフォルトである。その他の値は 1 に対しての相対値として解釈される。

以下に示すマクロは、正確な相対的コストは指定せず、ある動作が GNU CC が普通期待するよりも高くつくということだけを示す。

SLOW_BYTE_ACCESS
大きさがワードより小さなメモリをアクセスするのが、ワードをアクセスするより速くないなら、すなわち、二個以上の命令を必要とするか、バイトのロードと(整合されている)ワードのロードの間でコストに差がないなら、0 でない値を持つ C の式をこのマクロに定義する。

このマクロが定義されていない場合は、コンパイラはフィールドをアクセスするのに、それを含む最小のオブジェクトを探すことで行なう。定義されていれば、アラインメントが許せば、全ワードのロードが使われる。バイト単位のアクセスがワード単位のアクセスよりも高速でないかぎり、ワード単位のアクセスが望ましい。というのは、後続のメモリアクセスが、その構造体の同じワード内の異なるバイトにある他のフィールドをアクセスする場合は、そのメモリ参照を消去できるからである。

SLOW_ZERO_EXTEND
char または shortint へのゼロ拡張が、デスティネーションがゼロであることがわかっているレジスタの場合には高速に行なわれるなら、このマクロを定義する。

このマクロを定義する場合は、以下のような構造の RTL を認識する命令パターンを持っていなければ成らない。

(set (strict_low_part (subreg:QI (reg:SI ...) 0)) ...)

HImode についても同様である。

SLOW_UNALIGNED_ACCESS
整合の取れていないアクセスのコストが整合しているアクセスのコストよりも何倍も高い場合、例えばトラップハンドラでエミュレートされているような場合は、このマクロを値 1 に定義すること。

このマクロがゼロでない場合は、GNU CC は、ブロック移動用のコードを生成するとき STRICT_ALIGNMENT がゼロでないかの用に動作する。これにより、非常にたくさんの命令が生成される可能性がある。このため、整合の取れていないアクセスが、1 サイクルか 2 サイクル程度しかメモリアクセスの時間に加わらない場合は、このマクロをゼロでない値に定義しないこと。

このマクロの値が常にゼロなら、定義する必要はない。

DONT_REDUCE_ADDR
このマクロを定義すると、メモリアドレスの強度削減が禁止される。機種によっては、そういう強度削減は百害あって一利なしである。
MOVE_RATIO
スカラのメモリ-メモリ移動 insn の数の敷居値である。この値より小さい と、ある insn 列を、文字列移動命令やライブラリ呼出しの代わりに生成する必要がある。。この値を大きくすると必ずコードが速くなるが、いつかはコードサイズが増大することによるコストが高くなる。

メモリ-メモリ移動命令がない機種では、このマクロは対応する、メモリ-メモリ 命令列 の数を表す。

これを定義しない場合は、適切なデフォルトが使われる。

MOVE_BY_PIECES_P (size, alignment)
一個の C の式。この式は、メモリの塊を一つコピーするのに move_by_pieces が使われるかどうか、あるいは何か他のブロック移動のための機構が使われるかどうかを決定するのに使われる。move_by_pieces_ninsnsMOVE_RATIO より小さい値を返すなら、デフォルトは 1 になる。
MOVE_MAX_PIECES
一個の C の式。move_by_pieces で、メモリをコピーするのに使われるロードあるいはストアの最大単位を決定するのに使われる。デフォルトは MOVE_MAX になる。
USE_LOAD_POST_INCREMENT (mode)
一個の C の式。ロード・ポストインクリメントを、指定したモードに使うのが良いかどうかを決めるのに使われる。デフォルトは HAVE_POST_INCREMENT の値になる。
USE_LOAD_POST_DECREMENT (mode)
一個の C の式。ロード・ポストデクリメントを、指定したモードに使うのが良いかどうかを決めるのに使われる。デフォルトは HAVE_POST_DECREMENT の値になる。
USE_LOAD_PRE_INCREMENT (mode)
一個の C の式。ロード・プリインクリメントを、指定したモードに使うのが良いかどうかを決めるのに使われる。デフォルトは HAVE_PRE_INCREMENT の値になる。
USE_LOAD_PRE_DECREMENT (mode)
一個の C の式。ロード・プリインクリメントを、指定したモードに使うのが良いかどうかを決めるのに使われる。デフォルトは HAVE_PRE_INCREMENT の値になる。
USE_STORE_POST_INCREMENT (mode)
一個の C の式。ストア・ポストインクリメントを、指定したモードに使うのが良いかどうかを決めるのに使われる。デフォルトは HAVE_POST_INCREMENT の値になる。
USE_STORE_POST_DECREMENT (mode)
一個の C の式。ストア・ポストデクリメントを、指定したモードに使うのが良いかどうかを決めるのに使われる。デフォルトは HAVE_POST_DECREMENT の値になる。
USE_STORE_PRE_INCREMENT (mode)
一個の C の式。ストア・プリインクリメントを、指定したモードに使うのが良いかどうかを決めるのに使われる。デフォルトは HAVE_PRE_INCREMENT の値になる。
USE_STORE_PRE_DECREMENT (mode)
一個の C の式。ストア・プリデクリメントを、指定したモードに使うのが良いかどうかを決めるのに使われる。デフォルトは HAVE_PRE_DECREMENT の値になる。
NO_FUNCTION_CSE
定数の関数アドレスを呼び出すほうが、レジスタに保持されたアドレスを呼び出すよりも効率が良いか同等なら、このマクロを定義する。
NO_RECURSIVE_FUNCTION_CSE
関数が自分自身を呼び出すのに、明示的なアドレスを使ったほうが、レジスタに保持されているアドレスを呼び出すより効率が良いか同等なら、このマクロを定義する。
ADJUST_COST (insn, link, dep_insn, cost)
一個の C の文(セミコロンなし)。この文は、整数変数 cost を、insn との関係に基づいて更新する。insn は、依存関係 link を通じて dep_insn に依存する。デフォルトでは、cost の調整はなんら行なわれない。これは、例えば、スケジューラに対し、出力依存や逆依存はデータ依存と同じコストは被らないことを指示するのに使うことができる。
ADJUST_PRIORITY (insn)
一個の C の文(セミコロンなし)。この文は整数のスケジューリング優先度INSN_PRIORITY(insn) を更新する。insn を早めに実行するには優先度を下げ、遅めに実行するには優先度を上げる。insn のスケジューリング優先度を調整する必要がなければこのマクロは定義しないこと。


Node:Sections, Next:, Previous:Costs, Up:Target Macros

出力をセクション(text, data, ...)に分割する

あるオブジェクトファイルは、異なる型のデータを含む幾つかのセクションに分けられる。最も共通のケースとして、三つのセクションがある。テキスト・セクションは、機械命令と読みだし専用のデータを含む。データ・セクションは、初期された書き込み可能なデータを含む。BSS セクション は、非初期化データを含む。システムによっては、他の種類のセクションを持つ。

コンパイラはアセンブラに対していつセクションを切り替えるかの指示を出さなくてはならない。以下のマクロ群は、アセンブラに対してこの切替えを指示するコマンドの制御を行なう。

TEXT_SECTION_ASM_OP
機械命令と読みだし専用データの直前に現れる必要があるアセンブラ命令を表す文字列を値として持つ C の式である。普通は ".text" となる。
DATA_SECTION_ASM_OP
後続のデータが初期化済の書き込み可能なデータであることを指示するアセンブラ命令を表す文字列を値として持つ C の式である。普通は ".data" となる。
SHARED_SECTION_ASM_OP
定義されている場合は、後続のデータが共有データであることを特定するアセンブラ命令を表す文字列を値として持つ C の式である。定義されていない場合は、DATA_SECTION_ASM_OP が使われる。
BSS_SECTION_ASM_OP
定義されている場合は、後続のデータが非初期化データであることを指示するアセンブラ命令を表す文字列を値として持つ C の式である。これが定義されておらず、かつ ASM_OUTPUT_BSSASM_OUTPUT_ALIGNED_BSS も定義されていない場合は、非初期化グローバルデータは -fno-common が指定されている場合は、データセクションに出力され、それ以外の場合は ASM_OUTPUT_COMMON が使われる。
SHARED_BSS_SECTION_ASM_OP
定義されている場合は、後続のデータが非初期化共有データであることを指示するアセンブラ命令を表す文字列を値として持つ C の式である。これが定義されておらず、かつ BSS_SECTION_ASM_OP が定義されている場合は、BSS_SECTION_ASM_OP が使われる。
INIT_SECTION_ASM_OP
定義されている場合は、後続のデータが初期化コードであることを指示するアセンブラ命令を表す文字列を値として持つ C の式である。定義されていない場合は、GNU CC はこのようなセクションは存在しないと仮定する。
EXTRA_SECTIONS
標準の二つのセクション、in_textin_data 以外の他のセクションの名前のリストである。(GCC が使わなければならない)他のセクションが存在しないシステムでは、このマクロを定義する必要はない。
EXTRA_SECTION_FUNCTIONS
varasm.c で定義されるべき関数を 1 個以上ならべたもの。ここで指定した関数の仕事は、関数 text_sectiondata_section が行なう作業と同様な作業を追加のセクションに対して行なうことである。EXTRA_SECTIONS を定義しない場合には、このマクロは定義しないこと。
READONLY_DATA_SECTION
多くのマシンでは、読みだし専用変数、定数、ジャンプ表はテキストセクションに置かれる。これにあてはまらないマシンの場合は、このマクロには、読みだし専用のデータに使われるセクションへの切替えを行なう関数名(data_sectionEXTRA_SECTIONS で定義されている関数のどれか)を定義する必要がある。

読みだし専用のデータがテキストセクションに置かれるべきものなら、このマクロは定義するべきでない。

SELECT_SECTION (exp, reloc)
exp を出力するのに適したセクションへの切替えを行なう C の一個の文か複数の文。expVAR_DECL ノードか、ある種類の定数と仮定して良い。reloc は、exp の初期値がリンク時に再配置を必要とするかどうかを指示する。text_section か、他のセクション向けの関数を呼び出すことでセクションを選択するようにする。

全ての読みだし専用変数と定数を読みだし専用セクション(普通はテキストセクション)に置く場合は、このマクロを定義しないこと。

SELECT_RTX_SECTION (mode, rtx)
rtx をモード mode で出力するのに適したセクションへの切替えを行なう C の一個の文か複数の文。rtx は、RTL 中のある種類の定数と仮定して良い。引数 mode は、const_int rtx の場合は冗長である。text_section か、他のセクション向けの関数を呼び出すことでセクションを選択するようにする。

定数は全て、読みだし専用データセクションにおくなら、このマクロを定義しないこと。

JUMP_TABLES_IN_TEXT_SECTION
ジャンプ表(insn tablejump 向け)は、アセンブラ命令と一緒にテキストセクションに置くべきなら、このマクロをゼロでない値を持つ式として定義する。それ以外の場合は、読みだし専用データセクションが使われる。

このマクロは、独立した読みだし専用データセクションがない場合には関係してこない。

ENCODE_SECTION_INFO (decl)
シンボルへの参照を、そのシンボルにより指定される変数や関数についての何かの情報に依存して、取扱を変えなくてはならない場合に、このマクロを定義する。例えば、そのシンボルがどのセクションに属するかといった情報である。

このマクロは、定義されていれば、decl についての rtl が生成され、DECL_RTL (decl) に格納された直後に実行される。この rtl の値は、アドレスが symbol_ref である mem になる。

このマクロで通常行なうべきことは、SYMBOL_REF_FLAG のような、symbol_ref 内のフラグを記録したり、(1ビットでは表せない情報であれば) symbol_ref 内の修正された名前の文字列を格納することである。

STRIP_NAME_ENCODING (var, sym_name)
セクション情報をエンコードする文字群なしで、sym_name をデコードし、var の実際の名前の部分を格納する。ENCODE_SECTION_INFO がシンボル名文字列を書き換える場合はこのマクロを定義する。
UNIQUE_SECTION_P (decl)
ターゲット固有の理由により、decl がある一意的なセクションに置かれるべきであるなら、評価すると真になるような C の式。このマクロを定義しない場合のデフォルトは、0 である。-ffunction-sections オプションを指定することでも、関数を一意的なセクションに置かれる事に注意。
UNIQUE_SECTION (decl, reloc)
一意的なセクション名を組み立てる C の式で、STRING_CST ノードとして表され、DECL_SECTION_NAME (decl) に代入される。reloc で、exp の初期値がリンク時の再配置を必要とするかどうかを指定する。このマクロを定義しない場合は、GNU CC はシンボル名の前に . を付けたものをセクション名として使う。


Node:PIC, Next:, Previous:Sections, Up:Target Macros

位置独立コード

このセクションでは、位置独立コード(Position Independent Code, PIC)の生成を実装する手助けをするマクロを説明する。以下のマクロを単に定義するだけでは、正しい PIC を生成するには十分ではない。マクロ、GO_IF_LEGITIMATE_ADDRESSPRINT_OPERAND_ADDRESSLEGITIMIZE_ADDRESS についてもサポートを追加しなければならない。movsi の入力オペランドがシンボルで表されたアドレスを含んでいる時に適切な処理を行なうように、movsi の定義を修正しなければならない。また、switch 文の扱いを、相対アドレスを使うように書き換える必要もある。

PIC_OFFSET_TABLE_REGNUM
メモリ中の静的なデータアドレスのテーブルを参照するのに使うレジスタの番号である。場合によっては、このレジスタはプロセッサの「アプリケーションバイナリインターフェース」(ABI) で定義されることもある。このマクロが定義されていると、このレジスタの RTL は一回だけ生成される。これは、スタックポインタやフレームポインタレジスタの場合と同じである。このマクロが定義されていない場合は、必要に応じてこのようなレジスタを割り当てるのは機種依存ファイルの責任である。
PIC_OFFSET_TABLE_REG_CALL_CLOBBERED
PIC_OFFSET_TABLE_REGNUM で定義されるレジスタが、関数呼び出しにより破壊されるならこのマクロを定義する。PIC_OFFSET_TABLE_REGNUM が定義されていない場合は、このマクロは定義しないこと。
FINALIZE_PIC
位置独立コードを生成することにより、二つの異なったプログラム(AとB)が共通のライブラリ(libC.a) を共有するとき、ライブラリのテキスト部分は、そのライブラリがどちらのプログラムでも同じアドレスにリンクされるかどうかによらず、共有することができる。環境によっては、位置独立コードは、異なるアドレッシングモードを必要とするだけでなく、そのアドレッシングモードを機能させるために特別なコードを必要とすることがある。

マクロ FINALIZE_PIC は、一旦関数がアセンブリコードにコンパイルされれば、これらの特別なコードを生成するフックとして働く。だが、コンパイルされる前はそうでない。(コンパイルされる前に行なわれないのは、インライン関数をコンパイルする場合、インライン関数を使っている関数で PIC のプロローグが複数取り込まれてしまうことになり、その後にアセンブリ言語にコンパイルされるからである。)

LEGITIMATE_PIC_OPERAND_P (x)
一個の C の式。この式は、x が、ターゲット機種で位置独立コードを生成するときに正しい即値オペランドであるなら、ゼロでない値となる。xCONSTANT_P を満たしていると仮定して良いので、そのための検査は必要ない。また flag_pic が真であることも仮定して良いので、こちらも検査する必要はない。(SYMBOL_REF を含む)全ての定数が、位置独立コードを生成するときに即値オペランドになりうるのであれば、このマクロを定義する必要はない。


Node:Assembler Format, Next:, Previous:PIC, Up:Target Macros

出力アセンブリ言語の定義

この節では、主な目的がアセンブラ言語での命令の書き方を記述することにあるマクロを紹介する。命令が何をするかは説明しない。


Node:File Framework, Next:, Previous:Assembler Format, Up:Assembler Format

アセンブラファイルの全体的枠組

この節では、アセンブラファイルについての全体的な枠組を説明する。

ASM_FILE_START (stream)
アセンブラファイルの先頭に書き出すべきテキストを、標準入出力ストリーム stream へ出力するC の式を定義する。

普通は、このマクロは #NO_APP を含む行を一行出力するように定義される。#NO_APP はコメントであり、多くのアセンブラには何の効果ももたらさないが、GNU アセンブラに対しては、ある種のアセンブラ構文に関する検査を省くことにより、時間を節約することを指示する。

SDB を使用するシステムでは、ある一定のコマンドを出力する必要がある。attasm.h を参照のこと。

ASM_FILE_END (stream)
アセンブラファイルの末尾に追加される何か適切なテキストを、標準入出力ストリーム stream に出力する C の式。

このマクロが定義されていない場合は、デフォルトはファイルの最後に何も特別なものは出力されない。多くのシステムでは何も定義を必要としない。

SDB を使っているシステムでは、特定のコマンドを出力する必要がある。attasm.h を参照のこと。

ASM_IDENTIFY_GCC (file)
オブジェクトファイルが GNU CC(あるいは別の GNU コンパイラ)でコンパイルされたことを特定するアセンブラコマンドを出力するC の式。

このマクロを定義しない場合は、gcc-compiled.: という文字列が出力される。この文字列は、BSD システムでは何か他の理由で定義されることが決してないようなシンボルを定義するように選ばれている。GDB は、実行形式ファイルからシンボルテーブルを読み込むときにこのシンボルが存在するかどうかを検査する。

非BSDシステムでは、GDB とのやり取りは何か別の形式で調整しなければならない。GDB が使われていないシステムでは、このマクロの本体を空に定義することができる。

ASM_COMMENT_START
ターゲットのアセンブラ言語において、コメントを開始する方法を記述するC の文字列定数。コンパイラは、コメントは行末で終了すると仮定する。
ASM_APP_ON
個々の asm 文、あるいは連続した一塊のasm 文の直前に出力すべきテキストを表す C の文字列定数。通常は "#APP" になる。これは、ほとんどのアセンブラには何の効果もないが、GNU アセンブラに対しては、後続の行が全て正しいアセンブラ構文をなしているかどうかを検査しなければならないことを指示する。
ASM_APP_OFF
個々の asm 文、あるいは連続した一塊のasm 文の直後に出力すべきテキストを表す C の文字列定数。通常は "#NO_APP" になる。これは、GNU アセンブラに対しては、通常のコンパイラの出力について成り立つ時間を節約する仮定を復活させることを指示する。
ASM_OUTPUT_SOURCE_FILENAME (stream, name)
一個の C の文。この文では、現在のソースファイル名が name であることを知らせる、COFF 形式の情報または DWARF 形式のデバッグ情報を、標準入出力ストリーム stream に出力する。

使われているファイル形式の標準的な出力形式が適切なものであるなら、このマクロを定義する必要はない。

OUTPUT_QUOTED_STRING (stream, string)
一個の C の文。この文は、文字列 string を標準入出力ストリームstream に出力する。コンフィギュレーションファイルで関数output_quoted_string を呼び出さない場合は、GNU CC はこの関数をアセンブラソースにファイル名を出力するためにしか呼び出さない。このため、この関数をこのマクロと組み合わせて使うことで、ファイル名の形式を正規化することができる。
ASM_OUTPUT_SOURCE_LINE (stream, line)
一個の C の文。この文は、現在のソースファイルの行番号 line に対するコードの前に DBX または SDB 形式のデバッグ情報を出力する。出力先は標準入出力ストリーム stream である。

使われているデバッガ用の標準的なデバッグ情報形式が適切なものであるなら、このマクロを定義する必要はない。

ASM_OUTPUT_IDENT (stream, string)
一個の C の文。この文は、string というテキストを含む #ident 制御子を処理するものをアセンブラファイルに出力する。このマクロが定義されていないと、#ident 制御子に対しては何も出力されない。
ASM_OUTPUT_SECTION_NAME (stream, decl, name, reloc)
一個の C の文。この文は、FUNCTION_DECL か、VAR_DECL か、NULL_TREE であるオブジェクト decl に対して、セクションを name に切り替えるためのものをアセンブラファイルに出力する。reloc は、decl の初期値がリンク時の再配置を必要とするかどうかを指示する。ターゲットのフォーマットによっては、任意のセクションをサポートしていないものもあるので、そういう場合はこのマクロを定義しないこと。

現時点では、このマクロはセクションの属性をサポートするために使われているだけである。このマクロが定義されていないと、セクションの属性は無効になる。

OBJC_PROLOGUE
一個の C の文。この文は、任意の Objective C のオブジェクト定義やメッセージの送出に先行することが要求されるアセンブラ文を出力する。この文は、Objective C プログラムをコンパイルするときにだけ実行される。


Node:Data Output, Next:, Previous:File Framework, Up:Assembler Format

データの出力

この節ではデータの出力について説明する。

ASM_OUTPUT_LONG_DOUBLE (stream, value)
ASM_OUTPUT_DOUBLE (stream, value)
ASM_OUTPUT_FLOAT (stream, value)
ASM_OUTPUT_THREE_QUARTER_FLOAT (stream, value)
ASM_OUTPUT_SHORT_FLOAT (stream, value)
ASM_OUTPUT_BYTE_FLOAT (stream, value)
標準入出力ストリーム stream に、あるアセンブラ命令を出力する C の文である。このアセンブラ命令は、それぞれ TFmodeDFmodeSFmodeTQFmodeHFmodeQFmode の、値がvalue である浮動小数点定数をアセンブルする。value は、REAL_VALUE_TYPE 型の C の式である。REAL_VALUE_TO_TARGET_DOUBLE のようなマクロを使うと、これらの定義を書く助けとなる。
ASM_OUTPUT_QUADRUPLE_INT (stream, exp)
ASM_OUTPUT_DOUBLE_INT (stream, exp)
ASM_OUTPUT_INT (stream, exp)
ASM_OUTPUT_SHORT (stream, exp)
ASM_OUTPUT_CHAR (stream, exp)
標準入出力ストリーム stream に、あるアセンブラ命令を出力する C の文である。このアセンブラ命令は、それぞれ 16、8、4、2、1 バイトの、値が value である整数をアセンブルする。exp は、定数値を表す RTL 式である。output_addr_const (stream, exp) を使って、この値を一個のアセンブラ式として出力する。

UNITS_PER_WORD より大きなサイズについては、マクロの動作が、各ワードについて一回づつ、UNITS_PER_WORD の大きさに対応するマクロを繰り返し呼び出すのと同じであるなら、このマクロを定義する必要はない。

ASM_OUTPUT_BYTE (stream, value)
値が value である一バイトをアセンブルするアセンブラ命令を標準入出力ストリーム stream に出力するための C の文を定義する。
ASM_BYTE_OP
一バイトの定数列に使われる疑似命令を与える C の文字列定数。このマクロが定義されていない場合、デフォルトは "byte" になる。
ASM_OUTPUT_ASCII (stream, ptr, len)
長さ len バイトの ptr で示される文字列定数をアセンブルするアセンブラ命令を、標準入出力ストリーム stream に出力するための C の文を定義する。ptr は、char * 型の C の式で、len は、int 型のC の式である。

アセンブラが、Berkeley Unix のアセンブラにあるような .ascii 疑似命令を備えているなら、このマクロは定義しないこと。

CONSTANT_POOL_BEFORE_FUNCTION
このマクロは一個の C の式として定義する。この式は、GNU CC が、ある関数のコードの前にその関数の定数領域を出力すべきであるなら ゼロでない値とすべきである。定数領域を関数の後に出力すべきなら、ゼロにする。このマクロを定義しない場合は、GNU CC は定数領域を関数の前に出力する。これが普通である。
ASM_OUTPUT_POOL_PROLOGUE (file, funname, fundecl, size)
関数の定数領域の開始を定義するアセンブラ命令を出力するためのC の文を定義する。funname は、関数名を与える文字列である。その関数の戻り値型が必須であり、その型は funcdecl から取得することができる。size は、このマクロで定義される命令が呼び出された直後に書き出される定数領域の大きさを、バイト単位であらわしたものである。

定数領域の開始を知らせる必要がない普通の場合は、このマクロは定義する必要はない。

ASM_OUTPUT_SPECIAL_POOL_ENTRY (file, x, mode, align, labelno, jumpto)
特別な取扱いが必要なら、定数プールに一個の定数を出力するC の文。セミコロンは付けても付けなくても良い。(このマクロは、通常どおり出力可能なRTL 式については、何もする必要はない。)

引数 file は、アセンブラコードの出力先の標準入出力ストリームである。mode はマシンモード(この場合 x は、const_intである) である。align は、値 x に必要とされるアラインメントである。これだけのアラインメントを強制するアセンブラ命令を出力すべきである。

引数 labelno は、このプールエントリのアドレスを表す内部ラベルで使われる番号である。このマクロの定義は、適切な場所にラベル定義を出力する責任がある。以下にその方法を示す。

ASM_OUTPUT_INTERNAL_LABEL (file, "LC", labelno);

プールエントリを特別な方法で出力する場合は、ラベル jumpto への goto で終えるべきである。こうすることで、同じプールのエントリが、通常の方法で二回出力されることを防ぐ。

することがなければ、このマクロを定義する必要はない。

CONSTANT_AFTER_FUNCTION_P (exp)
一個の C の式を定義するマクロ。この式は、tree 型の定数 exp を、関数のコードの後に出力すべきなら、ゼロでない値となる。コンパイラは通常は全ての定数を関数の前に出力する。それで良ければこのマクロを定義する必要はない。
ASM_OUTPUT_POOL_EPILOGUE (file, funname, fundecl, size)
一個の C の文であり、関数の定数プールの終りに置くアセンブラコマンドを出力する。funname は、関数名を与える文字列である。関数の戻り値型が必要なら、fundecl から得ることができる。size は、GNU CC がこの呼び出しの直前に書き出す定数プールの大きさをバイト単位で表したものである。

定数プールにエピローグが必要なければ、このマクロを定義する必要はない。普通は定義する必要がない。

IS_ASM_LOGICAL_LINE_SEPARATOR (C)
一個の C の式を定義するマクロ。この式は、C が、アセンブラにより論理的な行区切りとして使われる場合には、ゼロでない値となる。

このマクロを定義しない場合は、デフォルトでは、文字 ; だけが論理的な行区切りとして扱われる。

ASM_OPEN_PAREN
ASM_CLOSE_PAREN
これらのマクロは C の文字列定数として定義され、算術式をグループ化するためのアセンブラの構文を記述する。ほとんどのアセンブラでは以下の定義で正しい。
#define ASM_OPEN_PAREN "("
#define ASM_CLOSE_PAREN ")"

以下のマクロは real.h で定義されており、ASM_OUTPUT_DOUBLE やその仲間の定義を書くのに使われる。

REAL_VALUE_TO_TARGET_SINGLE (x, l)
REAL_VALUE_TO_TARGET_DOUBLE (x, l)
REAL_VALUE_TO_TARGET_LONG_DOUBLE (x, l)
REAL_VALUE_TYPE 型の x を、ターゲットの浮動小数点表現に変換し、そのビットパターンをアドレスが l にある、long int 型の配列に格納する。出力される配列の用素数は、対象のターゲット浮動小数点データ型の大きさにより決まる。ビットパターンの 32 ビットずつが、long int 型の配列の各要素に入る。各要素は、たとえ long int がホストマシンの 32 ビットより広くても、変換結果のうちの 32 ビットを保持する。

配列の要素値は、fprintf を使って、ターゲット機種のメモリに現れる順序で出力できるようになっている。

REAL_VALUE_TO_DECIMAL (x, format, string)
このマクロは、REAL_VALUE_TYPE 型の x を、10進数に変換し、それを文字列として string に格納する。string としては、結果を保持するのに充分長いスペースのメモリブロックのアドレスを渡さなければならない。

引数 format は、出力文字列をどのように整形するかを知らせるprintf と同じ指定である。


Node:Uninitialized Data, Next:, Previous:Data Output, Up:Assembler Format

非初期化変数の出力

この節で説明するマクロはそれぞれ、一個の非初期化変数を出力する作業を全部行なう。

ASM_OUTPUT_COMMON (stream, name, size, rounded)
C の文(セミコロンなし)であり、標準入出力ストリーム streamname という名前でサイズが size バイトのコモンラベルのアセンブラ定義を出力する。変数 rounded は、呼びだし側が要求するアライメントまで切り上げた大きさである。

名前自身を出力するには、assemble_name (stream, name) という式を使う。その前後で、その名前を定義するために追加で必要なアセンブラ構文を出力し、最後に改行を出力する。

このマクロは、非初期化コモングローバル変数のアセンブラ定義がどのように出力されるかを制御する。

ASM_OUTPUT_ALIGNED_COMMON (stream, name, size, alignment)
ASM_OUTPUT_COMMON とほぼ同じだが、違いは必要となるアラインメントを、独立した明示的な引数として取ることである。このマクロを定義すると、ASM_OUTPUT_COMMON の代わりに使われ、変数に要求されるアラインメントをより柔軟に扱えるようになる。アラインメントはビット数で指定する。
ASM_OUTPUT_ALIGNED_DECL_COMMON (stream, decl, name, size, alignment)
ASM_OUTPUT_ALIGNED_COMMON とほぼ同じだが、違いは、出力すべき変数がひとつあれば、その宣言 decl を指定する点にある。対応する変数がなければ decl には NULL_TREE を指定する。このマクロを定義すると、GNU CC は ASM_OUTPUT_COMMONASM_OUTPUT_ALIGNED_COMMON の両方の代わりに使う。何を出力するかを選択するために変数の宣言が見える必要があるときはこのマクロを定義すること。
ASM_OUTPUT_SHARED_COMMON (stream, name, size, rounded)
定義されていれば、ASM_OUTPUT_COMMON とほぼ同じだが、違いは name が共有されるときに使われる点にある。定義されていないと、ASM_OUTPUT_COMMON が使われる。
ASM_OUTPUT_BSS (stream, decl, name, size, rounded)
一個のC の文(セミコロンなし)。標準入出力ストリーム stream に、name という名前で、サイズが size バイトの非初期化グローバル decl のアセンブラ定義を出力する。変数 rounded は、呼び出し側が要求するアラインメントがなんであれ、そのアラインメントに切り上げられたサイズである。

このマクロを定義するときは varasm.c に定義されている関数 asm_output_bss を使うようにして欲しい。それが不可能な場合は、assemble_name (stream, name) という式を使ってその名前自身を出力する。その前後で、その名前を定義するアセンブラ構文を追加し、次に改行を出力する。

このマクロは、非初期化グローバル変数のアセンブラ定義がどのように出力されるかを制御する。このマクロは、c++ のように common データを持たない言語を適切にサポートするためにある。だが、このマクロは現時点では全てのターゲットで定義されているわけではない。このマクロと ASM_OUTPUT_ALIGNED_BSS が定義されていない場合は、ASM_OUTPUT_COMMONASM_OUTPUT_ALIGNED_COMMONASM_OUTPUT_ALIGNED_DECL_COMMON が使われる。

ASM_OUTPUT_ALIGNED_BSS (stream, decl, name, size, alignment)
ASM_OUTPUT_BSS に似ているが、違いは、必要なアラインメントを別個の明示的な引数として取ることである。このマクロを定義すると、ASM_OUTPUT_BSS の代わりに使われ、変数で必要とされるアラインメントをより柔軟に扱えるようになる。アライメントはビット数で指定する。

このマクロを定義するときは varasm.c で定義されている関数 asm_output_aligned_bss を使うようにして欲しい。

ASM_OUTPUT_SHARED_BSS (stream, decl, name, size, rounded)
定義されていれば、ASM_OUTPUT_BSS とほぼ同様だが、違いは name が共有されるときに使われることである。定義されていない場合は、ASM_OUTPUT_BSS が使われる。
ASM_OUTPUT_LOCAL (stream, name, size, rounded)
一個の C の文(セミコロン無し)。標準入出力ストリーム stream にサイズが size バイトで、name という名前のローカル・コモン・ラベルのアセンブラ定義を出力する。変数 rounded は、呼び出し側が要求するアラインメントに切り上げられるサイズである。

という式を使ってその名前自身を出力する。その前後で、その名前を定義するアセンブラ構文を追加し、次に改行を出力する。

このマクロは、非初期化静的変数のアセンブラ定義をどのように出力するかを制御する。

ASM_OUTPUT_ALIGNED_LOCAL (stream, name, size, alignment)
ASM_OUTPUT_LOCAL とほぼ同じだが、違いは、必要なアラインメントを別個の明示的な引数として取ることである。このマクロを定義すると、ASM_OUTPUT_LOCAL の代わりに使われ、変数で必要とされるアラインメントをより柔軟に扱えるようになる。アライメントはビット数で指定する。
ASM_OUTPUT_ALIGNED_DECL_LOCAL (stream, decl, name, size, alignment)
ASM_OUTPUT_ALIGNED_DECL とほぼ同じだが、違いは、出力すべき変数がひとつあれば、その宣言 decl を指定する点にある。対応する変数がなければ decl には NULL_TREE を指定する。このマクロを定義すると、GNU CC は ASM_OUTPUT_DECLASM_OUTPUT_ALIGNED_DECL の両方の代わりに使う。何を出力するかを選択するために変数の宣言が見える必要があるときはこのマクロを定義すること。
ASM_OUTPUT_SHARED_LOCAL (stream, name, size, rounded)
定義されていれば、ASM_OUTPUT_LOCAL とほぼ同様だが、違いは name が共有されるときに使われることである。定義されていない場合は、ASM_OUTPUT_LOCAL が使われる。


Node:Label Output, Next:, Previous:Uninitialized Data, Up:Assembler Format

ラベルの出力と生成

ラベルの出力について説明する。

ASM_OUTPUT_LABEL (stream, name)
一個のC の文(セミコロンなし)。標準入出力ストリーム stream に、name という名前のラベルを出力する。名前自身を出力するには、assemble_name (stream, name) を使うこと。この前後で、名前の定義するアセンブラ構文と改行を追加で出力する。
ASM_DECLARE_FUNCTION_NAME (stream, name, decl)
一個のC の文(セミコロンなし)。標準入出力ストリーム stream に、定義しようとしている関数名 name を宣言するのに必要なテキストを出力する。このマクロはラベル定義を出力する責任がある(おそらく ASM_OUTPUT_LABEL をつかうことになるだろう)。引数 decl は、その関数を表現するFUNCTION_DECL ツリーノードである。

このマクロが定義されていないと、関数名は普通の方法で、あるラベルとして定義される(ASM_OUTPUT_LABEL が使われる)。

ASM_DECLARE_FUNCTION_SIZE (stream, name, decl)
一個のC の文(セミコロンなし)。標準入出力ストリーム stream に、定義しようとしている関数のサイズを宣言するのに必要なテキストを出力する。引数 name は関数名である。引数 decl は、その関数を表現するFUNCTION_DECL ツリーノードである。

このマクロが定義されていないと、関数のサイズは定義されない。

ASM_DECLARE_OBJECT_NAME (stream, name, decl)
一個のC の文(セミコロンなし)。標準入出力ストリーム stream に、定義しようとしている初期化変数の名前 name を宣言するのに必要なテキストを出力する。このマクロはラベル定義を出力しなければならない(おそらくASM_OUTPUT_LABEL を使うことになるだろう)。引数 decl は、その変数を表現する VAR_DECL ツリーノードである。

このマクロが定義されていないと、変数名は普通の方法で、あるラベルとして定義される(ASM_OUTPUT_LABEL が使われる)。

ASM_FINISH_DECLARE_OBJECT (stream, decl, toplevel, atend)
一個の C の文(セミコロンなし)。この文は、変数名の宣言を終了させる。これは、コンパイラが一旦その初期化子を完全に処理し、その初期化子で制御される場合は配列の大きさを決定する機会があった場合に行なわれる。これは、オブジェクトの大きさについて何か宣言する必要があるシステムで使われる。

このマクロを定義しないのは、何もしないコードに定義するのと同じである。

ASM_GLOBALIZE_LABEL (stream, name)
一個のC の文(セミコロンなし)。標準入出力ストリーム stream に、ラベル name をグローバルにするためのコマンドを出力する。グローバルにするとは、他のファイルから参照可能にすることである。式 assemble_name (stream, name) を使って、名前自体は出力する。その前後で、その名前をグローバルにするアセンブラ構文を追加し、その後に改行を続ける。
ASM_WEAKEN_LABEL
一個のC の文(セミコロンなし)。標準入出力ストリーム stream に、ラベル name をウィークにするためのコマンドを出力する。ウィークにするとは、他のファイルから参照可能であるが、それ以外の定義が利用可能でない場合にだけ使われるようにすることである。式 assemble_name (stream, name) を使って、名前自体は出力する。その前後で、その名前をウィークにするアセンブラ構文を追加し、その後に改行を続ける。

このマクロを定義しないと、GNU CC はウィークシンボルをサポートしないので、マクロ SUPPORTS_WEAK を定義してはいけない。

SUPPORTS_WEAK
ターゲットがウィークシンボルをサポートしているなら、真と評価される C の式である。

このマクロを定義しない場合は defaults.h がデフォルトの定義を提供する。ASM_WEAKEN_LABEL が定義されているとデフォルトの定義は1 で、定義されていないと 0 である。ウィークシンボルのサポートを -melf のようなコンパイラフラグで制御したい場合はこのマクロを定義する。

MAKE_DECL_ONE_ONLY
一個の C の文(セミコロン無し)。この文は、decl を、複数の翻訳単位にある余分なコピーはリンカが捨てさるようなパブリックなシンボルとして生成するように、印を付ける。オブジェクトファイル形式がこの仕組みをサポートしている場合、例えば Microsoft Windows の PE/COFF 形式のセクションフラグ COMDAT のような場合で、このサポートにより、例えば別のセクションの置くような、decl に対する変更を必要とする場合は、このマクロを定義する。
SUPPORTS_ONE_ONLY
一個の C の式。ターゲットが「宣言は一つだけ」(one-only)という考え方をサポートしている場合は、この式を評価すると真になる。

このマクロを定義しない場合は、varasm.c がデフォルトの定義を提供する。MAKE_DECL_ONE_ONLY が定義されていると、デフォルトの定義は 1 になり、定義されていない場合は 0 になる。「一つだけ」式のシンボルサポートをコンパイラフラグで制御したい場合や、宣言を「ひとつだけ」として生成するように印をつけるには、DECL_ONE_ONLY フラグを設定すれば充分な場合は、このマクロを定義する。

ASM_OUTPUT_EXTERNAL (stream, decl, name)
一個の C の文(セミコロン無し)。標準入出力ストリーム stream に、name という名前の外部シンボルで、このコンパイル単位では参照しているが、定義はされていないものの名前を宣言するために必要なテキストを出力する。decl の値はその宣言のツリーノードである。

何も出力する必要がなければ、このマクロは定義しなくて良い。GNU アセンブラと大部分の Unix のアセンブラはなにも必要としない。

ASM_OUTPUT_EXTERNAL_LIBCALL (stream, symref)
一個の C の文(セミコロン無し)。stream に、ライブラリ関数名を外部名として宣言するためのアセンブラ疑似命令を出力する。このライブラリ関数名は symref で与えられる。symref は、rtx 型であり、symbol_ref である。

何も出力する必要がなければ、このマクロは定義しなくて良い。GNU アセンブラと大部分の Unix のアセンブラはなにも必要としない。

ASM_OUTPUT_LABELREF (stream, name)
一個の C の文(セミコロン無し)。標準入出力ストリーム stream に、name という名前に対する参照をアセンブラの構文で出力する。このマクロでは、ほとんどの Berkeley Unix システムの場合のように、対象となるオペレーティングシステムでの習慣であるなら、名前の前に _ を付加しなければならない。このマクロは、assemble_name で使われる。
ASM_OUTPUT_INTERNAL_LABEL (stream, prefix, num)
一個の C の文。この文は、標準入出力ストリーム stream に、文字列 prefix と番号 num から作られるラベルを出力する。

こうして作られるラベルが、ユーザレベルの関数や変数用に使われるラベルとは明確に区別できるということが、本当に本質的なことである。そうなっていないと、ある種のプログラムでは内部ラベルとの名前の衝突が発生してしまう。

内部ラベルは、オブジェクトファイル中のシンボルテーブルからは除外することが望ましい。多くのアセンブラには、除外すべきラベルについての名前付の規則がある。多くのシステムでは、ラベルの先頭に文字 L が付いていると除外対象になる。読者のシステムではどういう規則になっているかを調べ、それに従うこと。

このマクロの普通の定義は以下の通りである。

fprintf (stream, "L%s%d:\n", prefix, num)

ASM_GENERATE_INTERNAL_LABEL (string, prefix, num)
一個の C の文。この文は、文字列 string に、文字列 prefix と番号 num から作られる名前のラベルを格納する。

この文字列は、後で assemble_name によって出力されたときに、同じ prefixnum を与えたときにASM_OUTPUT_INTERNAL_LABEL が生成するのと同じものを、生成するようにしなければならない。

この文字列が、* で始まっていると、assemble_name は文字列の残りの部分をそのまま出力する。ASM_GENERATE_INTERNAL_LABEL* をそのように使うと便利なことが多い。文字列が * で始まっていないと、ASM_OUTPUT_LABELREF がこの文字列の出力を行ない、変更を行なう可能性がある。(もちろん、ASM_OUTPUT_LABELREF も、マシン記述の一部であるので、対象となる機種でそれが何をしているかを知っておきべきだ。)

ASM_FORMAT_PRIVATE_NAME (outvar, name, number)
一個の C の式。この式は、outvar (これは char * 型の変数)に、文字列 namenumber から作られ、何か適切な区切り文字を加えた、新たに確保した文字列を代入する。この文字列用のスペースは、alloca で割り当てること。

この文字列は、ASM_OUTPUT_LABELREF の引数として使われ、名前が name である、内部的な静的変数用のアセンブララベルを作り出す。このため、文字列はアセンブラコードとして有効なものにならなければならない。引数 number は、マクロが実行される度に異なる。これにより、異なるスコープにある、似たような名前の内部的な静的変数同士の名前の衝突を防ぐ。

理想的には、この文字列は C の識別子としては有効でないようにして、ユーザ定義のシンボルとの衝突を防ぐようにすべきである。多くのアセンブラはアセンブラシンボルの中に、ピリオドやパーセント記号を入れるのを許している。少なくともそのどちらか一つを、名前と番号の間に入れれば充分であろう。

ASM_OUTPUT_DEF (stream, name, value)
一個の C の文。標準入出力ストリーム stream に、シンボル name の値が value になるように定義する(同じであると見なす)アセンブラコードを出力する。

SET_ASM_OP が定義されていれば、ほとんどのシステムで正しい、デフォルトの定義が提供される。

ASM_OUTPUT_DEFINE_LABEL_DIFFERENCE_SYMBOL (stream, symbol, high, low)
一個の C の文。標準入出力ストリーム stream に、シンボル symbol の値が、二つのシンボル highlow の差、すなわち high - low に等しくなるように定義する(同じであると見なす)アセンブラコードを出力する。GNU CC はシンボル highlow を既にアセンブラが知っていることを保証するので、この差は一つの定数に解決される。

SET_ASM_OP が定義されていると、デフォルトの定義が提供され、ほとんどのシステムで正しいものになっている。

ASM_OUTPUT_WEAK_ALIAS (stream, name, value)
一個の C の文。標準入出力ストリーム stream に、ウィークシンボル name の値が、value に等しくなるように定義する(同じであると見なす)アセンブラコードを出力する。

このマクロはターゲットがウィークエイリアスしかサポートしていないときに定義すること。可能なら、代わりに ASM_OUTPUT_DEF を定義すること。

OBJC_GEN_METHOD_LABEL (buf, is_inst, class_name, cat_name, sel_name)
このマクロを定義すると、Objectvie C のメソッドのデフォルトのアセンブラでの名前を上書きする。

デフォルトの名前は、一意的なメソッド番号の後にクラス名が続いたもの(例えば、_1_Foo)になる。カテゴリ中のメソッドについては、カテゴリ名もアセンブラでの名前に含まれる(例えば、_1_Foo_Bar)。

これらの名前はほとんどのシステムで安全だが、デバッグが困難になる。メソッドのセレクタが名前に入っていないからである。このため、幾つかの特定のシステムでは名前を生成する別の方法を定義している。

bufchar * 型の式であり、名前を格納すべきバッファを指定する。このバッファの長さは、class_namecat_namesel_name を足した長さに、さらに 50 文字文の余裕を見込んだものである。

引数 is_inst は、メソッドがインスタンスメソッドかクラスメソッドかを指定する。class_name は、クラス名である。cat_name はカテゴリ名である(メソッドがあるカテゴリに入っていないなら NULLである)。sel_name はセレクタ名である。

アセンブラがクォートした名前を扱えるシステムでは、このマクロを使うことで読みやすい名前を提供することができる。


Node:Initialization, Next:, Previous:Label Output, Up:Assembler Format

初期化関数の扱われ方

ある種の言語では、コンパイルされたコードには コンストラクタ が含まれる。コンストラクタは、初期化ルーチンとも呼ばれることもあり、プログラムの起動時にそのプログラムのデータを初期化する関数である。この関数は、プログラムが「開始」するまえに呼ばれる必要がある。つまり、main の前に呼ばれる必要がある。

いくつかの言語では、コンパイルを行なうと、終了ルーチンとも呼ばれる デストラクタを生成する。デストラクタは、プログラムが終了するときに呼び出されなくてはならない。

初期化と終了関数を動作させるためには、コンパイラがアセンブラコードに何らかの出力を行なって、これらの関数が適切な時期に呼び出されるようにしなければならない。

GCC 現在サポートしている、初期化関数と終了関数の実行方法には大きく分けて二つの方法がある。どちらの方法も、それぞれさらに二種類に分けられる。構成方法のほとんどは、この4つの方法全部に共通している。

リンカは、これらの関数のリストを二つ構築しなければならない。一つは、初期化関数のリストであり、__CTOR_LIST__ と呼ばれる。もう一つは、終了関数のリストであり、__DTOR_LIST__ と呼ばれる。

どちらのリストも無視される関数ポインタが先頭に置かれる。(この関数ポインタには、環境によって、0、1、あるいは後ろに置かれる関数ポインタの数のどれかの値が置かれる。) この後に、0個以上のコンストラクタ(あるいはデストラクタ)への関数ポインタの並びが続く。最後に、値が 0 の関数ポインタが置かれる。

オペレーティング・システムや実行形式ファイル形式に依存して、crtstuff.clibgcc2.c のどちらかが、起動時と終了時にこれらのリストを走査する。コンストラクタは、リスト中の順番とは逆の順序で呼び出される。デストラクタは、リストの順番で呼び出される。

静的なコンストラクタを扱う最適な方法は、セクションに任意の名前を付けることができるオブジェクトファイル形式でしか使えない。あるセクションがコンストラクタのリストのために取られる。そして、もう一つ別のセクションがデストラクタのために取られる。伝統的に、この二つのセクションは、.ctors.dtors と呼ばれる。初期化関数を定義しているオブジェクトファイルは、その関数を指すワードをコンストラクタセクションに置く。リンカがこれらのワードをまとめ上げ、一つの連続した .ctors セクションを作る。終了関数も同様に扱われる。

この方法を使うには、マクロ ASM_OUTPUT_CONSTRUCTORASM_OUTPUT_DESTRUCTOR に適切な定義を与える必要がある。それには、普通は svr4.h をインクルードすれば良い。

任意のセクションを使えるなら、さらに crtstuff.c 中のコードの呼ばれ方により、二つの変種がある。プログラムの起動時に実行される 初期化 セクションをサポートしているシステムでは、crtstuff.c の中身がコンパイルされて、そのセクションの中に入る。プログラムは、gcc ドライバにより以下のようにリンクされる。

ld -o output_file crtbegin.o ... crtend.o -lgcc

ある関数(__do_global_ctors) の先頭が、crtbegin.o の初期化セクションに現れる。この関数の残りの部分は crtend.o の初期化セクションに現れる。リンカは、初期化セクションのこの二つの部分を合わせて、関数全体を作る。この中間にリンクされるユーザのオブジェクトファイルがどれもコードに寄与するなら、そのコードは __do_global_ctors の本体の一部として実行される。

この方法を使うには、マクロ INIT_SECTION_ASM_OP を適切に定義しなくてはならない。

初期化セクションが使えないときは、INIT_SECTION_ASM_OP は定義しないこと。そうすると、__do_global_ctors は他の全ての関数と同様、テキストセクションの中に作られ、libgcc.a に置かれる。GCC が main という名前の関数をコンパイルするときは、その関数のプロローグコードの直後の最初の実行可能なコードとして、__main を呼び出す手続きを挿入する。関数 __main は、libgcc2.c で定義されており、単に __do_global_ctors を呼び出す。

ファイル形式が任意個数のセクションをサポートしていない場合は、また二つの変種がある。一番簡単な方法の場合は、GNU リンカ(GNU ld) と a.out 形式を使わなければならない。この場合、ASM_OUTPUT_CONSTRUCTOR を定義して、N_SETT 型の .stabs エントリを一個作るようにする。この N_SETT 型のエントリは、__CTOR_LIST__ という名前を参照しており、初期化コードを含む void 型の関数のアドレスを、その値として持っている。GNU リンカはこれを、その値をある「集合」に追加する要求として認識する。この値は累積され、最終的には上記の形式のベクトルとして実行形式ファイルに置かれる。このベクトルの前には個数(無視される)が置かれ、ベクトルの最後の要素はゼロとなる。ASM_OUTPUT_DESTRUCTOR も同様に扱われる。初期化セクションが使えないので、INIT_SECTION_ASM_OP がないと、main は上記のように __main を呼び出すようにコンパイルされ、初期化処理を開始する。

最後の変種では、任意個数のセクションも GNU リンカも使わない。ダイナミックリンクを行ないたい場合と ECOFF のように、GNU リンカがサポートしていないファイル形式を使うときには、これが好ましい方法である。この場合、ASM_OUTPUT_CONSTRUCTORN_SETT を作り出さない。初期化関数と終了関数は単にその名前により認識される。このため、リンクの段階で、collect2 という余分のプログラムを必要とする。このプログラムは、GNU CC と合わせて使うときは、リンカのふりをする。collect2 は、通常のリンカを実行させることで自分の仕事を行なう。ただし、初期化関数と終了関数のベクトルを含むよう調整も行なう。これらの関数は上記のように __main を経由して呼び出される。

これらのコンフィギュレーションの選択肢から選び出す作業は、オペレーティングシステム依存のファイルを config サブディレクトリに置くことで簡素化される。ここに置くファイルで関係するパラメータを全て定義する。普通は、そのうちの一個のファイルを読者の固有の機種依存のコンフィギュレーションファイルに含めれば充分である。オペレーティング依存のファイルには以下のものがある。

aoutos.h
`a.out' 形式を使用するオペレーティングシステム向けのファイル。
next.h
`MachO' 形式を使用するオペレーティングシステム向けのファイル。
svr3.h
System V Release 3、それに `COFF' 形式を使用する類似のシステム向けのファイル。
svr4.h
System V Release 4、それに `ELF 形式を使用する類似のシステム向けのファイル。
vms.h
VMS システム向けのファイル。


Node:Macros for Initialization, Next:, Previous:Initialization, Up:Assembler Format

初期化ルーチンを制御するマクロ

以下のマクロは、コンパイラが初期化関数と終了関数をどのように扱うかを制御する。

INIT_SECTION_ASM_OP
一個の C の文字列定数。定義されていれば、続くデータを初期化コードとして特定するアセンブラ命令を表す。定義されていないと、GNU CC はそのようなセクションは存在しないと仮定する。初期化関数と終了関数用に特別なセクションを使っているときは、このマクロは crtstuff.clibgcc2.c がどのように初期化関数を編成して実行するかをも制御する。
HAS_INIT_SECTION
これが定義されていると、main で上述の __main を呼び出さないようにする。このマクロは、初期化セクションの内容をシンボル一つ毎に制御するシステム、例えば OSF/1 では定義すべきである。そして、INIT_SECTION_ASM_OP をサポートしているシステムでは明示的には定義すべきでない。
LD_INIT_SWITCH
一個の C の文字列定数。定義されていれば、リンカに対して続くシンボルが初期化ルーチンであることを知らせるスイッチである。
LD_FINI_SWITCH
一個の C の文字列定数。定義されていれば、リンカに対して続くシンボルが終了ルーチンであることを知らせるスイッチである。
INVOKE__main
このマクロが定義されていると、INIT_SECTION_ASM_OP の有無に関わらず main から __main を呼び出す。初期化セクションが自動的には実行されないが、コンストラクタとデストラクタのリストを集めるのに使えるシステムでは、このマクロを定義すべきである。
ASM_OUTPUT_CONSTRUCTOR (stream, name)
このマクロには一個の C の文を定義する。この文は、stream にアセンブラコードを出力する。このアセンブラコードは、初期化時に name という名前の関数を呼び出すように調整を行なう。

name は、コンパイラにより自動的に生成された C の関数名であると仮定する。この関数には引数はない。関数 assemble_name を使えば、name という名前を出力できる。この関数は、アンダースコアを追加するといった、システム固有の文法的変換を行なう。

このマクロを定義しない場合は、その関数を呼び出すように調整するための特別な出力は行なわれない。これは、その関数が何か他の手段で呼び出されるなら正しい動作である。その手段としては、例えば、collect2 プログラムによるものがある。collect2 は、シンボルテーブルを見て名前から該当する関数を見つけ出す。

ASM_OUTPUT_DESTRUCTOR (stream, name)
これは、初期化関数ではなくて終了関数に対して使われることを除けば ASM_OUTPUT_CONSTRUCTOR と同じである。

ASM_OUTPUT_CONSTRUCTORASM_OUTPUT_DESTRUCTOR が定義されている場合、生成されたオブジェクトファイル用に生成される初期化ルーチンは静的なリンケージを持つ。

システムがコンストラクタを処理する手段として collect2 を使っているなら、collect2 は通常 nm を使って、呼び出すべきコンストラクタ関数を探すためにオブジェクトファイルを走査する。そういうシステムでは、ASM_OUTPUT_CONSTRUCTORASM_OUTPUT_DESTRUCTOR を、グローバルスコープを持たなければならない、オブジェクトフィアルの初期化ルーチンとして定義してはならない。

ある一定のシステムでは、以下のマクロ群を定義することで、collect2 の動作をより速くすることができる。(そして、ある場合には、なにはともあれ動作するようにはなる。)

OBJECT_FORMAT_COFF
COFF(Common Object File Format) のオブジェクトファイルを使っているなら、このマクロを定義する。そうすると、collect2 がこのフォーマットを前提として、動的なコンストラクタ/デストラクタ関数を探すのに、直接オブジェクトファイルを走査することができるようになる。
OBJECT_FORMAT_ROSE
ROSE 形式のオブジェクトファイルを使っているなら、このマクロを定義する。そうすると、collect2 がこのフォーマットを前提として、動的なコンストラクタ/デストラクタ関数を探すのに、直接オブジェクトファイルを走査することができるようになる。

これらのマクロはネイティブコンパイラの場合にのみ有効である。クロスコンパイラの場合は、collect2 は常にターゲット機種用のnm を使う。

REAL_NM_FILE_NAME
nm を実行するのに使用するファイル名を表す C の文字列定数を定義する。デフォルトは、nm をパスから検索する。

システムが共有ライブラリをサポートしており、指定したライブラリや実行形式の動的な依存関係を表示するプログラムがあるなら、以下のマクロ群を定義することで、共有ライブラリ内の初期化関数と終了関数の実行をサポートするようにできる。

LDD_SUFFIX
ダイナミックリンクにおける依存関係を出力するプログラム、例えば SunOS 4 の場合だと "ldd" のようなプログラムの名前を C の文字列定数として定義する。
PARSE_LDD_OUTPUT (PTR)
LDD_SUFFIX で指定されるプログラムの出力からファイル名を取り出す C のコードを定義する。PTR は、char * 型の変数で、LDD_SUFFIX の出力のある行の先頭を指す。その行が動的な依存関係を示しているなら、そのコードはその行の上でファイル名の先頭まで PTR を進めなければならない。動的な依存関係でなければ、PTRNULL に設定しなければならない。


Node:Instruction Output, Next:, Previous:Macros for Initialization, Up:Assembler Format

アセンブラ命令の出力

この節では、アセンブラ命令の出力について解説する。

REGISTER_NAMES
C の初期化子で、マシンレジスタのアセンブラでの名前をそれぞれC の文字列定数で表したものである。これを使ってコンパイラはレジスタ番号を変換してアセンブラ言語に入れる。
ADDITIONAL_REGISTER_NAMES
定義されていれば、レジスタ名とレジスタ番号からなる構造体の配列に対する、C の初期化子である。このマクロはハードレジスタの名前を追加で定義し、asm 文の宣言で、レジスタを参照するのに別名を使えるようにする。
ASM_OUTPUT_OPCODE (stream, ptr)
機械命令に対して、異なる名前を必要とする、変わったアセンブラを使うときはこのマクロを定義する。

このマクロの定義は、C の、一個の文か複数個の文となり、アセンブラ命令のオペコードを標準入出力ストリーム stream に出力する。マクロのオペランド ptrchar * 型の変数であり、オペコード名の「内部」形式を指す。この内部形式は、マシン記述に書かれているものである。この定義では、必要となる変換を行ないつつ、オペコード名を stream に出力し、変数 ptr を、オペコードの最後を指すようにインクリメントして、二回出力されないようにする。

実際は、このマクロ定義でオペコード名全体は処理しなくても良いし、オペコード名以外のものも含めて処理しても良い。だが、オペランドの代入を行なう %列を含むテキストを処理する場合は、その代入を自分で行なわなければならない。ptr をインクリメントして、普通に出力されるべきでないテキスト部分を越えるようにすること。

オペランドの値を見る必要があるなら、recog_operand の要素として入っている。

このマクロの定義が何もしないものなら、命令は普通の方法で出力される。

FINAL_PRESCAN_INSN (insn, opvec, noperands)
一個の C の文。この文は定義されていれば、insn 用のアセンブラコードを出力する直前に実行され、抽出されたオペランドを異なる出力となるように修正する。

ここで引数 opvecinsn から抽出したオペランドを保持するベクトルであり、noperands はこの insn にとって意味のあるデータを保持するベクトルの要素数である。このベクトルの内容は、この isn のテンプレートをアセンブラコードに変換するのに使われるものなので、このベクトルの内容を変えることでアセンブラ出力を変更することができる。

このマクロは、色々なアセンブラの記法で一個の命令パターンファイルを共有している場合に役に立つ。このマクロの定義を異なるものにすることにより、命令の大部分を異なる出力(例えばオペランドの配置替え)になるようにすることができる。個々の命令パターンに影響する、アセンブラ記法の差異は、そのパターンの出力ルーチンで条件で切り分けて書くことで取り扱うようにするのが自然である。

このマクロが定義されていなければ、ヌル文に等価である。

FINAL_PRESCAN_LABEL
これが定義されていると、FINAL_PRESCAN_INSN が各 CODE_LABEL について呼び出される。その場合、opvec はヌルポインタに、noperands はゼロになる。
PRINT_OPERAND (stream, x, code)
一個の C の複文。標準入出力ストリーム stream に命令オペランド x 用のアセンブラ構文を出力する。x は RTL 式である。

code は、オペランドを出力する幾つかの方法の一つを指定するのに使われる値である。これは、同じオペランドを文脈によって異なる出力をしなければならない場合に使われる。code は、オペランドの出力を要求するのに使われる % 指定から来る。% 指定が単に %digit なら code は 0 である。%ltrdigit なら code は、ltr の ASCII コードである。

x がレジスタなら、このマクロはそのレジスタ名を出力すべきである。レジスタ名は、char *[] 型の配列 reg_names に入っている。reg_names は、REGISTER_NAMES で初期化される。

マシン記述に %punct 指定(% の後に区切り文字一文字が続く)があれば、このマクロは x がヌルポインタで、区切り文字がcode である場合に呼び出される。

PRINT_OPERAND_PUNCT_VALID_P (code)
一個の C の式。codePRINT_OPERAND マクロで使うのに有効な区切り文字である場合にこの式を評価すると真になる。PRINT_OPERAND_PUNCT_VALID_P が定義されていないと、このように使われる区切り文字がないということを意味する(標準の % を除く)。
PRINT_OPERAND_ADDRESS (stream, x)
一個の C の複文。標準入出力ストリーム stream に、ある命令の、アドレスが x のメモリ参照であるオペランド用のアセンブラ構文を出力する。x は RTL 式である。

機種によっては、シンボリックなアドレス用の構文は、そのアドレスが指しているセクションに依存する。そういう機種では、マクロ ENCODE_SECTION_INFO を定義して、その情報を symbol_ref に格納し、このマクロでそれを検査すること。

DBR_OUTPUT_SEQEND(file)
一個の C の文。全てのスロットの埋め草命令が出力された後に実行すべき文である。必要なら dbr_sequence_length を呼び出して、あるシーケンスで埋められるスロット数(現在、シーケンスを出力中でないならゼロになる)を決定し、NOP命令を幾つ出力するかを決める。

何もすべきことがないならこのマクロは定義しないこと。ただし、遅延シーケンスの範囲が明らかになっている(例えば、空白によって) のなら、アセンブリ出力を読むときに役に立つであろう。

遅延スロットを持つ命令を出力するルーチンは、シーケンスの一部として出力されないように(すなわち、スケジューリングパスが実行されないとき、あるいはスロットを埋める命令が見つからない場合) 準備されていなければならない。変数 final_sequence はシーケンスの処理中でないときはヌルになり、処理中の場合は出力される sequence RTX が入っている。

REGISTER_PREFIX
LOCAL_LABEL_PREFIX
USER_LABEL_PREFIX
IMMEDIATE_PREFIX
それぞれ、C の文字列式である。定義されていれば、asm_fprintf (final.c 参照)のオプション %R%L%U%I で使われる。一個の md ファイルで複数のアセンブラ形式をサポートしなければならないときに使う。その場合、色々な tm.h でこれらのマクロを別々に定義する。
ASSEMBLER_DIALECT
ターゲットのアセンブラ言語に複数の方言がある(オペコードが異なる等)場合は、このマクロを一個の C の式として定義する。この式は、使うべきアセンブラ言語の方言のインデックス番号を指定する。この番号は 0 から始まる。

このマクロが定義されていると、{option0|option1|option2...} という形の構文を、パターンの出力テンプレート(see Output Template) や asm_fprintf の第一引数で使うことができる。この構文は、ASSEMBLER_DIALECT の値が 0、1、2等になるのに応じて、option0option1option2 等を出力する。ここで指定する文字列内の任意の特殊文字は、その通常の意味が保たれる。

このマクロを定義しない場合は、{|} の各文字は、テンプレートや asm_fprintf のオペランドで使われたときに特別な意味を持たない。

色々な種類のアセンブラ言語構文をこの方法を使って表すことができるなら、REGISTER_PREFIXLOCAL_LABEL_PREFIXUSER_LABEL_PREFIXIMMEDIATE_PREFIX といったマクロを定義すること。構文の差異が大きくて、オペコードやオペランドの順番が異なるような場合は、ASSEMBLER_DIALECT を定義して、{option0|option1} という構文を使うこと。

ASM_OUTPUT_REG_PUSH (stream, regno)
一個の C の式。stream にハードレジスタ番号 regno をスタックにプッシュするアセンブラコードを出力する。このコードは最適化する必要はない。このマクロが使われるのは、プロファイリングの時だけなので。
ASM_OUTPUT_REG_POP (stream, regno)
一個の C の式。stream にハードレジスタ番号 regno をスタックからポップするアセンブラコードを出力する。このコードは最適化する必要はない。このマクロが使われるのは、プロファイリングの時だけなので。


Node:Dispatch Tables, Next:, Previous:Instruction Output, Up:Assembler Format

ディスパッチテーブルの出力

この節ではディスパッチテーブルについて説明する。

ASM_OUTPUT_ADDR_DIFF_ELT (stream, body, value, rel)
この定義は一個の C の文とし、標準入出力ストリーム stream に、二つのラベルの差を生成するアセンブラの疑似命令を出力するようにする。valuerel は二つの内部ラベルの数である。これらのラベルの定義は、ASM_OUTPUT_INTERNAL_LABEL を使って出力され、それらはここで同じように出力されなければならない。例えば、以下のようにする。
fprintf (stream, "\t.word L%d-L%d\n",
         value, rel)

ディスパッチテーブル中のアドレスが、テーブル自身のアドレスに対して相対的な機種では、このマクロを提供しなければならない。これが定義されている、GNU CC は PIC を生成する時にも、全ての機種でこのマクロを使用する。bodyADDR_DIFF_VEC 本体である。モードとフラグが読めるように提供されている。

ASM_OUTPUT_ADDR_VEC_ELT (stream, value)
ディスパッチテーブル中のアドレスが絶対アドレスである機種ではこのマクロを提供すべきである。

この定義は一個の C の文とし、標準入出力ストリーム stream にラベルに対する参照を生成するアセンブラの疑似命令を出力するようにする。value は、内部ラベルの数であり、内部ラベルの定義は ASM_OUTPUT_INTERNAL_LABEL で出力される。例えば、以下のようになる。

fprintf (stream, "\t.word L%d\n", value)

ASM_OUTPUT_CASE_LABEL (stream, prefix, num, table)
ジャンプテーブルの前のラベルを特別な方法で出力する必要がある場合はこれを定義する。引数のうち最初の三つは ASM_OUTPUT_INTERNAL_LABEL のものと同じである。四番目の引数は、ラベルに続くジャンプテーブル(addr_vecaddr_diff_vec を含む jump_insn)である。

この機能は、System V で、このテーブルについての swbeg 文を出力するのに使われている。

このマクロが定義されていない場合は、これらのラベルはASM_OUTPUT_INTERNAL_LABEL で出力される。

ASM_OUTPUT_CASE_END (stream, num, table)
ジャンプテーブルの最後に何か特別なものを出力しなければならない時はこれを定義する。この定義は一個の C の文とし、テーブル用のアセンブラコードが書かれた後に実行されるようにすべきである。適切なコードを標準入出力ストリーム stream に書き出すべきである。引数 table は、ジャンプテーブルの insn であり、num は先行ラベルのラベル番号である。

このマクロが定義されていない場合は、ジャンプテーブルの最後には何も特別なものは出力されない。


Node:Exception Region Output, Next:, Previous:Dispatch Tables, Up:Assembler Format

例外領域用のアセンブラコマンド

この節では、例外領域の開始地点、終了地点をマークするコマンドについて説明する。

ASM_OUTPUT_EH_REGION_BEG ()
例外領域の開始地点をマークするテキストを出力する C の式である。

多くのプラットフォームではこのマクロは定義する必要がない。

ASM_OUTPUT_EH_REGION_END ()
例外領域の終了地点をマークするテキストを出力する C の式である。

多くのプラットフォームではこのマクロは定義する必要がない。

EXCEPTION_SECTION ()
一個の C の式。この式は、主となる例外テーブルを置くべきセクション(see Sections)への切替えを行なう。デフォルトは、ASM_OUTPUT_SECTION_NAME により名前付可能なセクションをサポートしている機種では、.gcc_except_table という名前のセクションになる。サポートしていない機種では、-fpic-fPIC が有効な場合は data_section、有効でなければ readonly_data_section になる。
EH_FRAME_SECTION_ASM_OP
一個の C の文字列定数。これが定義されていれば、例外処理フレームの巻き戻し情報用のセクションに切り替えるアセンブラの命令を表す。定義されていないと、ターゲットが名前付きセクションをサポートしていればGNU CC がデフォルトの定義を提供する。crtstuff.c では、このマクロを使って適切なセクションへの切替えを行なっている。

ターゲットが DWARF 2 のフレームの巻き戻し情報をサポートしていて、かつ、デフォルトの定義では正しく動作しない場合は、このシンボルを定義しなければならない。

OMIT_EH_TABLE ()
一個の C の式。この式は、通常の例外テーブル出力を省くべきならゼロでない値となる。

ほとんどのプラットフォームでは、このマクロを定義する必要はない。

EH_TABLE_LOOKUP ()
実行時の例外の検索と対応するハンドラを探す実行時サポートの、デフォルトの方法がうまく行かない場合の別の選択肢である。

ほとんどのプラットフォームでは、このマクロを定義する必要はない。

DOESNT_NEED_UNWINDER
一個の C の式。この式は、現在の関数が、それ用に生成された関数の巻き戻しを必要とするかどうかを決定する。いつ、どのようにこれを定義したら良いか、詳細についてはexcept.c を参照すること。
MASK_RETURN_ADDR
RETURN_ADDR_RTX を経由して見つかった戻りアドレスをマスクするのに使われる RTX である。このため、なんら余分なビットは立っていない。
DWARF2_UNWIND_INFO
ターゲットが DWARF 2 のフレーム巻き戻し情報をサポートしているが、例外処理と一緒には動作していない場合には、このマクロを 0 に定義する。それ以外の場合、ターゲットがこの情報をサポートしていれば(INCOMING_RETURN_ADDR_RTXUNALIGNED_INT_ASM_OPOBJECT_FORMAT_ELF のどちらかを定義している場合)、GCC はデフォルトの定義 1 を提供する。

このマクロが 1 に定義されていれば、DWARF 2 の巻き戻しは、デフォルトの例外処理機構になる。それ以外の場合は、setjmp/longjmp がデフォルトで使われる。

このマクロが何かに定義されていれば、DWARF 2 の巻き戻しが、インライン巻き戻しと非 setjmp の場合の __unwind_function の代わりに使われる。


Node:Alignment Output, Previous:Exception Region Output, Up:Assembler Format

アラインメント用アセンブラコマンド

この節ではアラインメントに関するコマンドを説明する。

LABEL_ALIGN_AFTER_BARRIER (label)
label の前に置くアラインメント(2を底とする対数)。BARRIER に続くものである。

このマクロは、その様な場合になんら特別な整列をしないのであれば、定義する必要はない。現在、ほとんどのマシン記述でこのマクロを定義していない。

LOOP_ALIGN (label)
label の前に置くアラインメント(2を底とする対数)。NOTE_INSN_LOOP_REG に続くものである。

このマクロは、その様な場合になんら特別な整列をしないのであれば、定義する必要はない。現在、ほとんどのマシン記述でこのマクロを定義していない。

LABEL_ALIGN (label)
label の前に置くアラインメント(2を底とする対数)。LABEL_ALIGN_AFTER_BARRIER / LOOP_ALIGN が異なるアラインメントを指定している場合、指定された複数の値のうち最大のものが使われる。
ASM_OUTPUT_SKIP (stream, nbytes)
C の文で、標準入出力ストリーム stream に、位置カウンタを nbytes バイト進めるアセンブラ命令を出力する。飛ばされたバイトはロード時にゼロとならなければならない。nbytes は、int 型の式である。
ASM_NO_SKIP_IN_TEXT
このマクロは、ASM_OUTPUT_SKIP は、飛ばしたバイト群にゼロを埋めるの失敗するので、テキストセクションでは使うべきでないなら、定義する。これは多くの Unix システムでは真になる。そういうシステムでは、バイト群を飛ばす疑似命令をテキストセクションで使うと、ゼロではなく NOP 命令を生成するのである。
ASM_OUTPUT_ALIGN (stream, power)
一個の C の文。標準入出力ストリーム stream に、位置カウンタを2 の power 乗バイトの倍数進めるアセンブラ命令を出力する。power は、int 型の C の式である。
ASM_OUTPUT_MAX_SKIP_ALIGN (stream, power, max_skip)
一個の C の文。標準入出力ストリーム stream に、位置カウンタを2 の power 乗バイトの倍数進めるアセンブラ命令を出力する。ただし、要求したアラインメントを満たすのに必要なバイト数がmax_skip 以下の場合に限られる。powermax_skip は、int 型の C の式である。


Node:Debugging Info, Next:, Previous:Assembler Format, Up:Target Macros

デバッグ情報形式の制御

本節ではデバッグ情報の指定方法を説明する。


Node:All Debuggers, Next:, Previous:Debugging Info, Up:Debugging Info

全てのデバッグ上方形式に関係するマクロ

以下のマクロは、全てのデバッグ情報形式に関係する。

DBX_REGISTER_NUMBER (regno)
コンパイラが使用するレジスタ番号 regno に対応する、DBX のレジスタ番号を返す C の式。単純な場合は、この式の値は regno そのものになる。だが、コンパイラは知っているが DBX は知らないレジスタがあったり、その逆もある。そういう場合は、あるレジスタはコンパイラとDBX で別の番号を必要とする。

ある二つのレジスタが GNU CC 内部で連続する番号になっており、それらをペアとして使って複数ワードの値を保持する事ができるのであれば、DBX_REGISTER_NUMBER で番号を付け替えた後でも連続する番号になっていなければならない。そうなってないと、デバッガがそのレジスタのペアをアクセスできなくなってしまう。デバッガは、レジスタのペアは、デバッガ自身の番号付けの仕組みで連続になっていることを想定しているからである。

DEBX_REGISTER_NUMBER を、レジスタのペアを保存しないようなやりかたで定義したことがわかったら、代わりにしなければならないことは実際のレジスタ番号付の仕組みの方を再定義することである。

DEBUGGER_AUTO_OFFSET (x)
アドレスが x(RTL式)である自動変数の整数オフセット値を返す C の式。デフォルトの計算方法では、x はフレームポインタをベースにしており、フレームポインタからのオフセットを与えると仮定している。このことは、DBX 向けのデバッグ情報出力や SDB 向けの COFF形式デバッグ情報出力を生成し、かつ、-g オプションを指定したときにフレームポインタの消去を許すターゲットでは必要とされる。
DEBUGGER_ARG_OFFSET (offset, x)
アドレスが x(RTL 式) である引数の整数のオフセット値を返す C の式。名目上のオフセットは offset である。
PREFERRED_DEBUGGING_TYPE
単に -g オプションを指定した場合に GNU CC が生成すべきデバッグ情報形式を返す C の式である。GNU CC がデバッグ情報出力の形式を複数サポートするにはこのマクロを定義する。現在、指定可能な値は、DBX_DEBUGSDB_DEBUGDWARF_DEBUGDWARF2_DEBUG である。

ユーザが -ggdb を指定したとき、GNU CC は通常このマクロの値を基にデバッグ情報の出力形式を選択する。しかし、例外が二つある。DWARF2_DEBUGGING_INFO は定義されているが LINKER_DOES_NOT_WORK_WITH_DWARF2 が定義されていない場合は、GNU CC は DWARF2_DEBUG という値を使う。そうではなくて、DBX_DEBUGGING_INFO が定義されている場合は、GNU CC は DBX_DEBUG を使う。

このマクロの値が影響するのはデフォルトのデバッグ出力だけである。ユーザはいつでも、-gstabs-gcoff-gdwarf-1-gdwarf-2-gxcoff を使って特定の出力形式を選ぶことができる。


Node:DBX Options, Next:, Previous:All Debuggers, Up:Debugging Info

DBX 形式の出力に固有のオプション

以下は、DBX 形式の出力を行なう場合に固有のオプションである。

DBX_DEBUGGING_INFO
-g オプションを指定した場合に、DBX 向けのデバッグ出力を生成する必要があるなら、このマクロを定義する。
XCOFF_DEBUGGING_INFO
-g オプションを指定した場合に、XCOFF 形式のデバッグ出力を生成する必要があるなら、このマクロを定義する。これは、DBX 形式の一変種である。
DEFAULT_GDB_EXTENSIONS
デフォルトで DBX デバッグ情報の GDB 拡張版を生成すべきかどうかを制御するマクロである。定義しない場合は、デフォルトで 1 になる。これは、どんな場合でも常に拡張版の情報を生成する。
DEBUG_SYMS_TEXT
.stabs コマンドは全てテキストセクションに出力すべきなら、このマクロを定義する。
ASM_STABS_OP
.stabs の代わりに通常のデバッグシンボルを定義する、アセンブラ疑似命令を指定する C の文字列定数である。このマクロを定義しなければ、.stabs が代わりに使われる。このマクロは、DBX 形式のデバッグ情報にのみ適用される。
ASM_STABD_OP
.stabd の代わりに、その値が現在位置であるデバッグシンボルを定義するアセンブラ疑似命令を指定する C の文字列定数である。このマクロを定義しなければ、.stabd が代わりに使われる。このマクロは、DBX 形式のデバッグ情報にのみ適用される。
ASM_STABN_OP
.stabn の代わりに、名前を持たないデバッグシンボルを定義するアセンブラ疑似命令を指定する C の文字列定数である。このマクロを定義しなければ、.stabn が代わりに使われる。このマクロは、DBX 形式のデバッグ情報にのみ適用される。
DBX_NO_XREFS
DBX が xstagname という構文をサポートしていないシステムでは、このマクロを定義する。あるシステムでは、この構文を使って、tagname という名前の構造体の前方参照を記述する。他のシステムでは、この構文は全くサポートされていない。
DBX_CONTIN_LENGTH
DBX 形式のデバッグ情報のシンボル名は、その長さがある一定の長さ(デフォルトでは 80 文字)を越えると、通常、二つの .stabs 制御子に分割され、継続して置かれる。DBX がこの分割を必要とするオペレーティングシステムもあれば、分割を行なってはならないものもある。分割を禁止するには、このマクロの値をゼロとして定義すれば良い。デフォルトの分割の長さは、このマクロを望みの長さを表す式として定義することで変更できる。
DBX_CONTIN_CHAR
普通継続を表すには、継続行が続く場合には .stabs 文字列の最後に文字 \ を追加する。この代わりに別の文字を使うには、このマクロを使用したい文字の文字定数として定義する。自分のシステムではバックスラッシュが正しいのなら、このマクロは定義しないこと。
DBX_STATIC_STAB_DATA_SECTION
非グローバル静的変数用の .stabs 疑似命令を出力する前に、データセクションへの切替えを必要とする場合はこのマクロを定義する。
DBX_TYPE_DECL_STABS_CODE
typedef 向けの .stabs 疑似命令の "code" フィールドに使う値。デフォルトは N_LSYM である。
DBX_STATIC_CONST_VAR_CODE
テキストセクション中の静的変数向けの .stabs 疑似命令の "code" フィールドに使う値。DBX 形式は、このための「正しい」方法というのを提供していない。デフォルトは N_FUN である。
DBX_REGPARM_STABS_CODE
レジスタ渡しされる仮引数向けの .stabs 疑似命令の "code" フィールドに使う値。DBX 形式は、このための「正しい」方法というのを提供していない。デフォルトは N_RSYM である。
DBX_REGPARM_STABS_LETTER
DBX のシンボルデータで、シンボルをレジスタ渡しされるパラメータとして特定するのに使われる文字。DBX の形式には、レジスタ渡しされるパラメータを表す、広く使われている方法がない。デフォルトは 'P' である。
DBX_MEMPARM_STABS_LETTER
DBX のシンボルデータで、シンボルをスタックパラメータとして特定するのに使われる文字。デフォルトは 'p' である。
DBX_FUNCTION_FIRST
ある関数とその引数についての DBX の情報を、その関数のアセンブラコードの前に置くべき場合は、このマクロを定義する。DBX 形式では、普通、デバッグ情報は完全にアセンブラコードの後ろに置かれる。
DBX_LBRAC_FIRST
あるブロックについての N_LBRAC シンボルを、そのブロックで定義されている変数と関数に関するデバッグ情報の前に置くべきである場合は、このマクロを定義する。DBX 形式では、普通、N_LBRAC シンボルが最初に来る。
DBX_BLOCKS_FUNCTION_RELATIVE
ブロックのスコープを記述するシンボル(N_LBRAC または N_RBRAC) の値が、そのブロックを含む関数の開始位置からの相対的な値とすべき場合は、このマクロを定義する。GNU C は普通は絶対アドレスを使う。
DBX_USE_BINCL
Sun システムの場合のように、インクルードされたヘッダファイルに対してはN_BINCLN_EINCL のスタブ(stabs)を生成すべき場合には、このマクロを定義する。また、このマクロを定義すると、GNU C は、型番号を、ファイル番号とファイル内での型番号の対として出力する。GNU C は普通は、N_BINCLN_EINCL スタブは生成せず、型番号として一個の番号を出力する。


Node:DBX Hooks, Next:, Previous:DBX Options, Up:Debugging Info

DBX 形式用の制限のないフック

以下は、DBX 形式向けのフックである。

DBX_OUTPUT_LBRAC (stream, name)
変数名についてのスコープレベルの開始を表すデバッグ情報を stream に出力する方法を指定するマクロ。引数 name は、スコープの開始位置アドレスを値として持つアセンブラシンボル名(assemble_name で使う)である。
DBX_OUTPUT_RBRAC (stream, name)
DBX_OUTPUT_LBRAC と同様だが、スコープレベルの終了点を表す。
DBX_OUTPUT_ENUM (stream, type)
ターゲットマシンが列挙型を出力するのに特別な扱いを必要とする場合は、このマクロを定義する。この定義は C の文(セミコロンなし)とし、型 type についての適切な情報を stream に出力するようにする。
DBX_OUTPUT_FUNCTION_END (stream, function)
ターゲット機種で、ある関数のデバッグ情報の最後に特別な出力を必要とする場合は、このマクロを定義する。この定義は一個の C の文(セミコロンなし)として、適切な情報を stream に出力する必要がある。function はその関数に対する FUNCTION_DECL ノードである。
DBX_OUTPUT_STANDARD_TYPES (syms)
コンパイルの開始時に標準的なデータ型の出力順序を制御する必要があるときはこのマクロを定義する。引数 syms は、ある tree であり、これは、全ての定義済みグローバルシンボルの連鎖である。このグローバルシンボルにはデータ型名も含まれる。

通常、DBX の出力は、整数型と文字型の定義で始まり、特定の言語の他の全ての定義済み型がその後に特に決まった順序なしに続く。

機種によっては、異なる特定の型を最初に出力する必要のあるものがある。それを行なうためには、DBX_OUTPUT_STANDARD_TYPES を定義して、それらのシンボルを必要な順序で出力するようにする。定義済みの型で明示的に出力しないものはどれも、後で特に順不同で出力される。

このマクロは、C 言語の場合しか動作しないようには定義しないように注意すること。組み込み型のほとんどをアクセスするためのグローバル変数はない。別の言語は別の型のセットを持っている可能性があるからである。特定の型を出力する方法は、syms を眺めて、それが見つかるかどうかを調べることである。以下に例を示す。

{
  tree decl;

  for (decl = syms; decl; decl = TREE_CHAIN (decl))
    if (!strcmp (IDENTIFIER_POINTER (DECL_NAME (decl)),
                 "long int"))
      dbxout_symbol (decl);
  ...
}

これは、期待する型が存在しない場合には何もしない。

C の全ての組み込み型で使われる名前を見つけるには、c-decl.c の関数 init_decl_processing を参照すること。

以下は、特定の型を見つけるもう一つの方法である。

{
  tree decl;
  for (decl = syms; decl; decl = TREE_CHAIN (decl))
    if (TREE_CODE (decl) == TYPE_DECL
        && (TREE_CODE (TREE_TYPE (decl))
            == INTEGER_CST)
        && TYPE_PRECISION (TREE_TYPE (decl)) == 16
        && TYPE_UNSIGNED (TREE_TYPE (decl)))
      /* This must be unsigned short.  */
      dbxout_symbol (decl);
  ...
}

NO_DBX_FUNCTION_END
スタブを包み込む形式の中には(特に ECOFF)、.stabs "",N_FUN,,0,0,Lscope-function-1 という GDB の DBX に対する拡張構文を取り扱えないものがある。そういう機種ではこのマクロを定義してこの機能を外し、他の GDB の拡張に影響しないようにする。


Node:File Names and DBX, Next:, Previous:DBX Hooks, Up:Debugging Info

DBX 形式のファイル名

DBX 形式でのファイル名の扱いについて説明する。

DBX_WORKING_DIRECTORY
カレントディレクトリを各オブジェクトファイル中に記録することをDBX が必要とするなら、このマクロを定義する。

GDB の拡張が有効になっている場合は、常にカレントディレクトリが記録されることに注意。

DBX_OUTPUT_MAIN_SOURCE_FILENAME (stream, name)
ファイル name が主ソースファイル--コンパイルの入力ファイルとして指定されたファイルであることを知らせる DBX デバッグ情報を標準入出力ストリーム stream に出力する C の文。このマクロは、一回だけ、コンパイル開始時に呼び出される。

DBX デバッグ情報出力の標準形が適切なら、このマクロを定義する必要はない。

DBX_OUTPUT_MAIN_SOURCE_DIRECTORY (stream, name)
コンパイルの行なわれている間のカレントディレクトリ名が name であることを知らせる DBX デバッグ情報を標準入出力ストリーム stream に出力する C の文。

DBX デバッグ情報出力の標準形が適切なら、このマクロを定義する必要はない。

DBX_OUTPUT_MAIN_SOURCE_FILE_END (stream, name)
主ソースファイル name のコンパイルの終了点でのデバッグ情報を出力する C の文。

このマクロを定義しなければ、コンパイルの終了点で何も特別な出力は行なわれない。これは多くの機種で正しい処理である。

DBX_OUTPUT_SOURCE_FILENAME (stream, name)
ファイル name が現在のソースファイルであることを知らせる、DBX デバッグ情報を標準入出力ストリーム stream に出力する C の文。この出力は、#include、あるいはインクルードファイルの最後、#line コマンドの結果として入力が異なるソースファイルに移る度に生成される。

DBX デバッグ情報出力の標準形が適切なら、このマクロを定義する必要はない。


Node:SDB and DWARF, Previous:File Names and DBX, Up:Debugging Info

SDB と DWARF 用出力向けのマクロ

以下に SDB と DWARF の出力向けのマクロを示す。

SDB_DEBUGGING_INFO
GNU CC に-g オプションを指定した場合に、SDB 向けに COFF 形式のデバッグ情報を出力すべきであるなら、このマクロを定義する。
DWARF_DEBUGGING_INFO
GNU CC に -g オプションを指定した場合に、dwarf 形式のデバッグ情報を出力すべきなら、このマクロを定義する。
DWARF2_DEBUGGING_INFO
GNU CC に -g オプションを指定した場合に、dwarf バージョン2形式のデバッグ情報を出力すべきなら、このマクロを定義する。

オプションの呼び出しフレームデバッグ情報をサポートするには、INCOMIMG_RETURN_ADDR_RTX も定義しなければならず、かつ、RTL をプロローグにたいして使うのならプロローグ isnsn にRTX_FRAME_RELATED_P を設定するか、プロローグに対して使うのでなければ、FUNCTION_PROLOGUE から dwarf2out_def_cfadwarf2out_reg_save を適切に呼び出すかの、どちらかをしなければならない。

DWARF2_FRAME_INFO
GNU CC が常に Dwarf 2 のフレーム情報を出力すべきであるなら、このマクロをゼロでない値に定義する。DWARF2_UNWIND_INFO (see Exception Region Output) がゼロでなければ、GNU CC はこの情報を、DWARF2_FRAME_INFO をどう定義するかに関わらずに、出力する。
LINKER_DOES_NOT_WORK_WITH_DWARF2
リンカが Dwarf バージョン 2 を正しく扱えない場合はこのマクロを定義する。通常、ユーザが -ggdb だけを指定した場合には、GNU CC は、利用可能なら Dwarf バージョン 2 を使う。詳細については、マクロ PREFERRED_DEBUGGING_TYPE の説明を参照のこと。
PUT_SDB_...
これらのマクロは、特別な SDB 向けアセンブラ制御子のアセンブラ文法を上書きするのに使う。マクロとその引数の一覧については、sdbout.c を参照のこと。標準の文法を使うなら、自分で定義する必要はない。
SDB_DELIM
アセンブラの中にはセミコロンを区切り記号として認識しないものがある。中には SDB 向け疑似命令同士の区切りとしても使えないものがある。そういう場合は、使える区切り記号(普通は \n)をこのマクロに定義する。必要な変更点がこれだけなら、PUT_SDB_op というマクロ群を新たに定義する必要はない。
SDB_GENERATE_FAKE
無名の構造体や共用体の型名向けのダミー名を構成する方法を、通常のものと違うものを使いたいときはこのマクロで定義する。詳細は、sdbout.c を参照のこと。
SDB_ALLOW_UNKNOWN_REFERENCES
未定義の構造体、共用体、列挙型のタグに対する参照を生成することを許すなら、このマクロを定義する。標準の COFF は、未定義タグへの参照を扱うことを許していないが、MIPS ECOFF はサポートしている。
SDB_ALLOW_FORWARD_REFERENCES
まだ処理していない構造体、共用体、列挙型のタグへの参照を許すなら、このマクロを定義する。


Node:Cross-compilation, Next:, Previous:Debugging Info, Up:Target Macros

クロスコンパイルと浮動小数点

最近の計算機は整数については、全て 2 の補数表現を使っているが、浮動小数点数の表現の方には色々な種類がある。このため、クロスコンパイラの場合は、コンパイルしたプログラムの浮動小数点数表現と、コンパイルを実行したマシンの浮動小数点数表現とでは異なっていることがある。

表現の仕組みが違うと、表現できる数の範囲と精度も違ってくる可能性があるので、クロスコンパイラがホストマシンの浮動小数点演算に頼ることはできない。このため、浮動小数点定数はターゲットマシンの形式で表現しなければならない。このことは、クロスコンパイラは、浮動小数点定数をパースするのに atof を使えないということを意味する。代わりの専用のルーチンを用意して、それを使う必要がある。さらに、定数の畳み込みも、ターゲットマシンの演算をエミュレートする必要がある(あるいは、全く何もしないかである)。

以下の表に示すマクロは、異なる浮動小数点形式の間でクロスコンパイルを行なう場合にだけ定義すること。

その他の場合には、定義しないこと。そうすると、デフォルトの定義が設定され、データ型として double を使う、等しいかどうかのテストには == を使う、等々。

これらのマクロはどれも、そのオペランドを何度使ってもかまわない。副作用があるオペランドをコンパイラが使うことはないので。

REAL_VALUE_TYPE
ターゲットマシンの形式で浮動小数点値を保持するのに使われる C のデータ型を表すマクロである。普通は、int の配列を含む struct になる。
REAL_VALUES_EQUAL (x, y)
REAL_VALUE_TYPE 型の二つの値 xy の等価性を比較する C の式を表すマクロである。
REAL_VALUES_LESS (x, y)
xy より小さいかどうかをテストする C の式を表すマクロである。どちらの値も REAL_VALUE_TYPE であり、ターゲットマシンの表現での浮動小数点数と解釈される。
REAL_VALUE_LDEXP (x, scale)
標準ライブラリ関数 ldexp を実行する C の式を定義するマクロである。ただし、ターゲット機種の浮動小数点表現を使う。x とこの式の値はどちらも REAL_VALUE_TYPE 型である。二番目の引数 scale は整数である。
REAL_VALUE_FIX (x)
ターゲット機種の浮動小数点値 x を符号付き整数に変換する C の式を定義するマクロである。x の型は REAL_VALUE_TYPE である。
REAL_VALUE_UNSIGNED_FIX (x)
ターゲット機種の浮動小数点値 x を符号なし整数に変換する C の式を定義するマクロである。x の型は REAL_VALUE_TYPE である。
REAL_VALUE_RNDZINT (x)
ターゲット機種の浮動小数点値 x を 0 に向かっての整数値への丸めを行なう C の式を定義するマクロである。ただし、値は以前として浮動小数数である。x とこの値の型は、REAL_VALUE_TYPE である。
REAL_VALUE_UNSIGNED_RNDZINT (x)
ターゲット機種の浮動小数点値 x を 0 に向かっての符号なし整数値への丸めを行なう C の式を定義するマクロである。ただし、値は以前として浮動小数数である。x とこの値の型は、REAL_VALUE_TYPE である。
REAL_VALUE_ATOF (string, mode)
char * 型の式である string を、モード mode のターゲット機種の浮動小数点数に変換する C の式を定義するマクロである。この値の型は REAL_VALUE_TYPE である。
REAL_INFINITY
無限大が浮動小数点値として許されており、従って 0 による割り算が正当なものである場合にこのマクロを定義する。
REAL_VALUE_ISINF (x)
浮動小数点値 x が、無限大かどうかを決定するC の式を定義する。このマクロの値は int 型である。デフォルトでは、isinf の呼び出しとして定義される。
REAL_VALUE_ISNAN (x)
浮動小数点値 x が、非数 (nan, not-a-number) かどうかを決定するC の式を定義する。このマクロの値は int 型である。デフォルトでは、isnan の呼び出しとして定義される。

クロスコンパイル時に浮動小数点定数の畳み込みを動作させたいなら、以下のマクロを定義する。これらのマクロを定義しない場合は、クロスコンパイルは可能だが、浮動小数点値については定数畳み込みが行なわれない。

REAL_ARITHMETIC (output, code, x, y)
このマクロは一個の C の文を定義する。その文では、二つの浮動小数点値 xy の算術演算を行なう。どちらの型もターゲット機種の表現でのREAL_VALUE_TYPE である。結果も同じ型と同じ表現になり、output に格納され、後で利用可能になる。

実行されるべき演算は code で指定される。これは木コードで常に次のどれか一つである。PLUS_EXPRMINUS_EXPRMULT_EXPRRDIV_EXPRMAX_EXPRMIN_EXPR

このマクロを展開したものは、オーバーフローを検査する責任がある。オーバーフローが発生下場合は、マクロの展開したものはreturn 0; という文を実行して、要求された算術演算を実行することが出来ないことを知らせるべきである。

REAL_VALUE_NEGATE (x)
浮動小数点値 x の符号反転値を返す C の式を表すマクロである。x とこの式の値はどちらも REAL_VALUE_TYPE 型で、ターゲット機種の浮動小数点表現である。

このマクロではオーバーフローを知らせる方法はない。符号反転演算ではオーバーフローは起きないからである。

REAL_VALUE_TRUNCATE (mode, x)
浮動小数点数値 x をモード mode に変換する C の式を定義するマクロである。

x とこの式の値はどちらも、ターゲット機種の浮動小数点表現であり、REAL_VALUE_TYPE 型である。ただし、その値は、モード mode の精度を持つ浮動小数点定数として正しく出力されるビットパターンになっている必要がある。

このマクロは、オーバーフローを報告する機能を持たない。

REAL_VALUE_TO_INT (low, high, x)
浮動小数点数値 x を倍精度整数に変換し、二つの int 型の変数、lowhigh に格納する C の式を定義するマクロである。
REAL_VALUE_FROM_INT (x, low, high, mode)
二つの int 型変数 lowhigh に格納されている倍精度整数を浮動小数点数値に変換し、x に格納する C の式を定義するマクロである。


Node:Misc, Previous:Cross-compilation, Up:Target Macros

種々雑多なパラメータ

以下に、種々雑多なパラメータを示す。

PREDICATE_CODES
ファイル machine.c で特殊な目的の述語を定義した場合は、これを定義する。このマクロは、ある構造体の配列の初期化子内で呼び出される。この構造体の先頭のフィールドは述語名で、第二のフィールドはRTL コードの配列である。各述語について、式中でその述語にマッチする可能性のある全ての RTL コードのリストを第二のフィールドの値とする。このリストには最後にコンマを付ける。典型的な RISC マシン向けの、二つのエントリを持つリストの例を以下に示す。
#define PREDICATE_CODES \
  {"gen_reg_rtx_operand", {SUBREG, REG}},  \
  {"reg_or_short_cint_operand", {SUBREG, REG, CONST_INT}},

このマクロを定義しても生成されるコードには影響を与えない。(ただし、間違った定義により、その述語にマッチする可能性のある RTL コードが排除されると、コンパイラは誤動作を起こす。) そのかわり、genrecog により作られるテーブルがよりコンパクトで効率の良いものになり、コンパイラの速度を速める。このマクロで定義されるリストに含めるべき述語で一番重要なものは、ほとんどの insn パターンで使われる述語である。

CASE_VECTOR_MODE
あるマシンモード名の別名である。これは、ジャンプテーブルの要素が持つべきマシンモードである。
CASE_VECTOR_SHORTEN_MODE (min_offset, max_offset, body)
オプションのマクロである。最小オフセットと最大オフセットが既知の場合、addr_diff_vec に適したモードを返す。これが定義されていると、分岐短縮の追加のコードを有効にし、addr_diff_vec を取り扱う。これを動作させるためには、INSN_ALIGN を定義し、addr_diff_vec のアラインメントを明確にする必要もある。引数 body は、offset_unsigned とスケールフラグが更新可能なように提供されている。
CASE_VECTOR_PC_RELATIVE
このマクロは、ジャンプテーブルが相対アドレスを保持すべき場合を表す C の式に定義する。ジャンプテーブルが相対アドレスを保持することがなければ、このマクロを定義する必要はない。
CASE_DROPS_THROUGH
これは、インデックス値が範囲外にあるときに、プログラムの制御がcase insn を通り抜けるときに定義する。これは、指定されたdefault ラベルが、case insn 自体により実際に無視されるということを意味する。
CASE_VALUES_THRESHOLD
条件分岐のツリーではなく、ジャンプ表を使うのが最適であるような、異なる値の最小値を定義する。デフォルトは、casesi 命令のある機種では 4 で、それ以外の場合は 5 である。ほとんどの機種でこれが最適である。
WORD_REGISTER_OPERATIONS
レジスタとワードより小さな整数モード間の演算が常にそのレジスタ全体を使って行なわれるなら、このマクロを定義する。
LOAD_EXTEND_OP (mode)
一個の C の式。この式は、insn が、ワードより狭い整数モードであるmode でメモリを読み出すとき、mode の外側のビットを、読み出したデータを符号拡張したものに設定するか、ゼロ拡張したものに設定するかを指定する。その insn が符号拡張する mode の値にはSIGN_EXTEND を、ゼロ拡張する場合には ZERO_EXTEND を、それ以外のモードには NIL を返す。

このマクロは、mode が非整数だったり、幅が BITS_PER_WORD 以上だと呼び出されないので、そういう場合は任意の値を返して良い。常に NIL を返すようなら、このマクロは定義しないこと。このマクロを定義する機種では、普通は定数 SIGN_EXTENDZERO_EXTEND をそのまま定義することになるだろう。

SHORT_IMMEDIATES_SIGN_EXTEND
short の即値をレジスタにロードすると符号拡張されるならこのマクロを定義する。
IMPLICIT_FIX_EXPR
浮動小数点値を固定小数点値への変換でデフォルトで使われるべき木コードの別名。通常は、FIX_ROUND_EXPR が使われる。
FIXUNS_TRUNC_LIKE_FIX_TRUNC
浮動小数点数を符号付き固定少数点数に変換するのと同じ命令が、符号なしの固定少数点数にも正しく変換出来るなら、このマクロを定義する。
EASY_DIV_EXPR
一般の場合向けにコードをコンパイルするのに一番簡単な種類の割り算を表す木コードの別名。TRUNC_DIV_EXPRFLOOR_DIV_EXPRCEIL_DIV_EXPRROUND_DIV_EXPR のどれかになる。これら4つの割り算は、結果の整数へ丸め方に違いがある。EASY_DIV_EXPR は、どの種類の割り算を使っても構わない場合で、効率が良いものを選択するときに使われる。
MOVE_MAX
ある一つの命令で、メモリとレジスタ間またはメモリとメモリ間で高速に移動できる最大のバイト数。
MAX_MOVE_MAX
ある一つの命令で、メモリとレジスタ間またはメモリとメモリ間で高速に移動できる最大のバイト数。これが定義されていない場合、デフォルトは MOVE_MAX になる。定義されている場合には、MOVE_MAX が実行時に取りうる値のうち、最大値を値とする定数値になる。
SHIFT_COUNT_TRUNCATED
一個の C の式。この式は、対象機種でのシフト演算のシフト数に実際に使われるビット数が、シフト対象のオブジェクトの大きさを表現するのに必要なビット数と同じであるなら、ゼロでない値となる。このマクロがゼロでないと、コンパイラは、符号拡張やゼロ拡張や、あるいはシフト演算のシフト数を切り詰めるための何らかのビット毎の and 命令を省略しても問題ないと想定する。bit test 命令も含む、可変位置のビットフィールドに作用する命令を持つ機種では、SHIFT_COUNT_TRUNCATED がゼロでないと、ビットフィールド命令への引数として振る舞う値の切り詰めを削除することを有効にする。

どちらのタイプの命令もシフト数と位置(ビットフィールド演算用)を切り詰めるか、あるいは可変位置のビットフィールド命令が存在しない場合は、このマクロを定義すべきである。

しかし、80386 や 680x0 のように、機種によっては、シフト演算に対してだけ切り詰めが行なわれ、(本物であれ見かけだけのものであれ)ビットフィールド演算には適用されないものがある。そういう機種ではSHIFT_COUNT_TRUNCATED をゼロに定義すること。そして、代わりに、mdファイルに、シフト命令の暗黙の切り詰めを含むパターンを追加する。

このマクロは、常に値がゼロになるようなら定義する必要はない。

TRULY_NOOP_TRUNCATION (outprec, inprec)
一個の C の式。この機種で、inprec ビットの整数を outprec ビットの整数に、単にその inprec ビットの整数が outprec ビットしかないかのように操作することで「変換」しても大丈夫なら、この式はゼロでない値となる。ここで、outprecinprec よりも小さいとする。

多くの機種では、この式は 1 になる。

TRULY_NOOP_TRUNCATION が、MODES_TIEABLE_P が 0 になるモードに対するサイズの対については 1 を返すときは、結果のコードは最適とは言えない。これが問題になる場合は、こういうケースでTRULY_NOOP_TRUNCATION が 0 を返すようにすると改善される。

STORE_FLAG_VALUE
C の式である。この式は、条件が真のときに、整数モードの比較演算で返され、フラグ格納命令(scond)で格納される値を記述する。この記述は、全ての scond パターンと結果がMODE_INT モードになる全ての比較演算に適用されなければならない。

この値が 1 か -1 の場合は、比較演算を実現している命令が比較が真の場合厳密に 1 または -1 を返し、偽の場合は 0 を返すということを意味する。それ以外の値の場合は、その値は、比較が真になるときに、その結果のうち、1 になることが保証されているビットを表す。この値は、比較演算のモードで解釈される。このモードは、scond パターンの先頭のオペランドのモードで与えられる。STORE_FLAG_VALUEの下位ビットか符号ビットのどちらかが立つ。現時点では、この二つのビットしか使われていない。

STORE_FLAG_VALUE が 1 でも -1 でもない場合は、コンパイラは指定されたビットにのみ依存するコードを生成する。また、それは比較演算を等価な演算に置き換えることも、等価な演算が必要なビットを設定するのであれば、その他のビットが未定義状態になったとしても、可能である。例えば、比較演算が SImode の値を返し、STORE_FLAG_VALUE0x80000000 と定義されている機種では、符号ビットのみが関係するので、

(ne:SI (and:SI x (const_int power-of-2)) (const_int 0))

という式は、次のように変換することができる。

(ashift:SI x (const_int n))

ここで n は、テスト対象のビットを符号ビットの位置に移動するために適切なシフト数である。

真の値に対し常に下位のビットを設定するが、他のどのビットの値も保証しないという機種を記述する方法は存在しない。だが、そういう命令を持つ機種を一つも知らない。GNU CC をそういう機種に移植する場合には、比較演算子用パターンに、その結果と 1 の論理積を実行する命令を含めるようにしてほしい。そして、我々に知らせて欲しい。(see How to Report Bugs).

ある機種が、比較演算の結果(あるいは条件コード)から値を得る命令には複数あることが良くある。以下に、STORE_FLAG_VALUE の値、すなわち使われる命令を選択する指針を示す。

多くの機種では、STORE_FLAG_VALUE として選ばれた値とその否定を同じ命令数で生成することができる。そういう機種では、その場合用のパターンも定義すべきである。例えば、以下にマッチするパターンである。

(set A (neg:m (ne:m B C)))

機種によっては、条件コード値に対する andplus 演算が、対応する scond 命令に andplus が続いたものより、少ない命令数で実行することもできる。そういう機種では、適切なパターンを定義すること。条件コード値に対する plusminus 演算を実行するパターンには、それぞれ incsccdecscc という名前を使うこと。例としては rs6000.md を参照ほしい。GNU Superoptimizer を使うと、それ以外の機種でこのような命令列を見つけることができる。

ストアフラグ命令のない機種では STORE_FLAG_VALUE を定義する必要はない。

FLOAT_STORE_FLAG_VALUE
C の式で、浮動小数点の比較演算結果が真の場合に返されるゼロでない浮動小数点値を与える。比較演算が浮動小数点値を返す機種ではこのマクロを定義すること。そういう演算がこの場合は、このマクロは定義しないこと。
Pmode
ポインタ向けのマシンモードの別名である。ほとんどのマシンでは、ハードウェアポインタの幅に対応する整数モードに定義する。32ビットマシンなら SImode だし、64ビットマシンなら DImode になる。マシンによっては、PSImode のような、部分整数モードの一つに定義しなければならない。

Pmode の幅は、少なくとも POINTER_SIZE の値と同じでなければならない。同じでない場合は、マクロPOINTERS_EXTEND_UNSIGNED を定義して、ポインタが Pmode にどのように拡張されるかを指定しなければならない。

FUNCTION_MODE
call RTL 式の中で、呼びだし中の関数をメモリ参照するのに使われるマシンモードの別名である。ほとんどのマシンではこれは QImode とすべきである。
INTEGRATE_THRESHOLD (decl)
最大の命令数を表す C の式。この数を越えたら、関数 decl をインライン展開すべきでない。decl は、ある FUNCTION_DECL ノードである。

このマクロの定義のデフォルトは、64 に、関数が受け付ける引数の数を8倍したものを足したものになる。RISC マシンではもっと大きな敷居値を使うべきであると考えている人もいる。

SCCS_DIRECTIVE
プリプロセッサに、#sccs という制御子を無視させ、エラーメッセージを出力させない場合はこれを定義する。
NO_IMPLICIT_EXTERN_C
システムのヘッダファイルが、C だけでなく C++ もサポートしている場合は、このマクロを定義する。このマクロを定義すると、C++ でシステムヘッダファイルを使う場合に良く行なわれる方法である、ファイルの中身を extern "C" {...} で囲むという処理を行なわない。
HANDLE_PRAGMA (getc, ungetc, name)
なんらかの pragma を実装する場合はこのマクロを定義する。定義するなら、その #pragma がマクロにより処理されるなら、値が 1 となり、そうでなければ 0 となる C の式とする。引数 getc は、int (*)(void) 型の関数であり、入力ストリームの次の文字か、あるいは文字が残っていなければ EOF を返す。引数 ungetc は、void (*)(int) 型の関数であり、文字を入力ストリームに戻す。name は、入力ストリームで #pragma に続く単語である。入力ストリームポインタは、この単語の直後を指すことになる。入力ストリームは、この式がゼロを返すなら何もいじらないままにしておくべきだし、ゼロでない値を返すなら、pragma の最後の次の文字を指しているべきである。pragma の行に残っているその他の文字は無視される。

一般に、#pragma の新しい使い方を実装しようとするのは良くない。このマクロを定義すべきただ一つの理由は、他のコンパイラのサポートしている#pragma を既に使ってしまっているユーザプログラムのために互換性を提供することにある。

プラグマが属性により実装可能なら、マクロ INSERT_ATTRIBUTES が定義するのに役に立つものになるだろう。

注意: このマクロの古いバージョンには引数が二つしか無かった。streamtoken である。このマクロは、gcc を構築するときにcpp ライブラリがあってもなくても動作するようにするために変更された。

HANDLE_SYSV_PRAGMA
System V 形式のプラグマ #pragma pack(<n>)#pragma weak <name> [=<value>] を GCC でサポートしたい場合はこのマクロを値が 1 になるように定義する。

pack プラグマは構造体内のフィールドの最大アラインメントをバイト数で指定する。__aligned____packed__attribute__ と同じである。pack の値としてゼロを指定すると、デフォルトの動作に戻る。

weak プラグマは SUPPORTS_WEAKASM_WEAKEN_LABEL が定義されている場合にのみ動作する。これが有効になっていると、具体的に指定されたウィーク・ラベルを作ることができるようになる。このラベルには値を持たせることもできる。

HANDLE_PRAGMA_PACK_PUSH_POP
Win32 形式のプラグマ #pragma pack(push,<n>)#pragma pack(pop) をサポートする場合は、このマクロを値が 1 になるように定義する。pack(push,<n>) プラグマは、構造体内のフィールドの最大アラインメントをバイト数で指定する。__aligned____packed__attribute__ と同じである。pack の値としてゼロを指定すると、デフォルトの動作に戻る。このプラグマを連続して呼び出すと、直前の値がスタック状に積まれる。このため、#pragma pack(pop) を呼び出すと、直前の値が返ってくる。
VALID_MACHINE_DECL_ATTRIBUTE (decl, attributes, identifier, args)
定義されているなら、一個の C の式である。その値は、引数が args である identifier が、decl についての有効な機種固有の属性なら、ゼロでない値となる。attributes に指定される属性は、事前に decl に割り当てられている。
VALID_MACHINE_TYPE_ATTRIBUTE (type, attributes, identifier, args)
定義されているなら、一個の C の式である。その値は、引数が args である identifiertype についての有効な機種固有の属性なら、ゼロでないとなる。attributes に指定される属性は、事前に type に割り当てられている。
COMP_TYPE_ATTRIBUTES (type1, type2)
定義されているなら、一個の C の式である。その値は、type1type2 の属性に互換性がなければゼロであり、互換性があるなら 1 であり、ほぼ互換(警告が出る)なら 2 になる。
SET_DEFAULT_TYPE_ATTRIBUTES (type)
定義されるなら、デフォルトの属性を新規に定義された type に割り当てる C の文とする。
MERGE_MACHINE_TYPE_ATTRIBUTES (type1, type2)
type 属性をマージするのに特別な取扱いが必要な場合はこのマクロを定義する。定義されていれば、type1type2TYPE_ATTRIBUTES の組合せのリストになる。comptypes が既に呼び出されており、1 を返していることを想定している。
MERGE_MACHINE_DECL_ATTRIBUTES (olddecl, newdecl)
decl 属性をマージするのに特別な取扱いが必要な場合はこのマクロを定義する。定義されていれば、olddeclnewdeclDECL_MACHINE_ATTRIBUTES の組合せのリストになる。newdeclolddecl の重複した宣言である。これが必要になる例は、一つの属性がもう一つ別の属性を上書きする場合や、属性が後続の定義により無効化される場合である。
INSERT_ATTRIBUTES (node, attr_ptr, prefix_ptr)
decl が作られるときに属性を追加するのを可能にしたい場合は、このマクロを定義する。これは、普通はバックエンドがプラグマを実装するときに、そのプラグマの効果に対応する属性を使って行うときに役に立つ。引数 node は、作られようとしている decl である。引数 attr_ptr は、この decl 用の属性リストへのポインタである。prefix_ptr は、宣言の指定子や修飾子の後、しかし宣言自体の前に現れる属性のリストへのポインタである。
SET_DEFAULT_DECL_ATTRIBUTES (decl, attributes)
定義されていれば、一個の C の文。新しく定義された decl にデフォルトの属性を割り当てる。
DOLLARS_IN_IDENTIFIERS
このマクロを定義することで、識別子名中での文字 $ の使用方法を制御する。定義する値は 0 か 1 か 2 でなければならない。0 に定義すると、デフォルトでは $ を使うことは許されない。1 に定義すると、デフォルトでは -traditional が指定された場合に$ を使うことができる。2 に定義すると、デフォルトでは -ansi が指定されない場合に$ を使うことができる。このマクロのデフォルト値は 1 である。デフォルト値で良いなら、このマクロを定義する必要はない。このマクロはコンパイラ本体を制御し、プリプロセッサには影響がない。
NO_DOLLAR_IN_LABEL
アセンブラがラベル名として文字 $ を受け付けない場合にこのマクロを定義する。デフォルトでは、G++ が生成するコンストラクタ名とデストラクタ名の識別子で $ が使われる。このマクロを定義すると、代わりに . を使う。
NO_DOT_IN_LABEL
アセンブラがラベル名として文字 . を受け付けない場合にこのマクロを定義する。デフォルトでは、G++ が生成するコンストラクタ名とデストラクタ名で . が使われる。このマクロを定義すると、. を使わないように名前を書き換える。
DEFAULT_MAIN_RETURN
ターゲットシステムが、全てのプログラムは、main 関数は、デフォルトで、つまり明示的な戻り値がない場合は、標準的な「成功」値を返すと想定しているなら、このマクロを定義する。

この定義は C の文(セミコロンなし)とし、適切な rtl 命令を生成するようにする。これは、main 関数の終端をコンパイルするときだけ使われる。

HAVE_ATEXIT
ターゲットシステムが ANSI C 規格の atexit 関数をサポートしている場合はこのマクロを定義する。これが定義されておらず、かつ、INIT_SECTION_ASM_OP も定義されていない場合は、デフォルトのexit 関数が C++ をサポートするために提供される。
EXIT_BODY
exit 関数が、_exit で終了する前に、外部関数_cleanup を呼び出す以外に何か処理を必要とするなら、このマクロを定義する。マクロ EXIT_BODY を定義する必要があるのは、HAVE_ATEXITINIT_SECTION_ASM_OP も定義されていないときだけである。
INSN_SETS_ARE_DELAYED (insn)
このマクロは、一個の C の式として定義する。この式は、たとえ insn 内で設定されたり破壊されるリソースを使っているようにみえても、遅延スロットスケジューラが insn の遅延スロットに命令を置くのが安全であるなら、ゼロでない値となる。insn は常に、一個の jump_insninsn である。insnjump_insn が実際には関数呼び出しであり、そのために、このように動作するのであれば、このマクロを定義すべきである。

これが常にゼロを返すようなら、このマクロを定義する必要はない。

INSN_REFERENCES_ARE_DELAYED (insn)
このマクロは、一個の C の式として定義する。この式は、たとえ insn で参照されているリソースを設定したり破壊したりするように見えたとしても、遅延スロットスケジューラが insn の遅延スロットに命令を置くのが安全であるなら、ゼロでない値となる。insn は常に、一個の jump_insninsn である。insnjump_insn が実際には関数呼び出しであり、そのオペランドが呼び出されるサブルーチンで実際に使われるレジスタとなる機種では、このマクロを定義すべきである。こうすることで、遅延スロットスケジューラが、引数レジスタに引数をコピーする命令を、 insn の遅延スロットに移動できるようになる。

これが常にゼロを返すようなら、このマクロを定義する必要はない。

MACHINE_DEPENDENT_REORG (insn)
非常にまれだが、コード生成を正しく行なおうとすると、二回目のジャンプ最適化パスと遅延分岐スケジューリングの間で、機種依存の処理が必要になることがある。そういう機種では、このマクロを insn で開始するコードに作用する C の文として定義する。
MULTIPLE_SYMBOL_SPACES
一つのコンパイル単位で定義されているグローバルシンボルを他のコンパイル単位にある未定義シンボルに結び付けるのにユーザの介在が必要な場合は、このマクロを定義する。例えば、Microsoft Windows では、シンボルは共有ライブラリ(DLL)から明示的にインポートしなければならない。
ISSUE_RATE
一個の C の式で、スーパスカラ機種の場合、幾つの命令を同時に発行できるかを返す。これは Haifa スケジューラでのみ使われており、旧来のスケジューラでは使われていない。
MD_SCHED_INIT (file, verbose)
-fsched-verbose-n. 一個の C の文。これは、スケジュールされる各命令ブロックの先頭でHaifa スケジューラにより実行される。file はヌルポインタか、あるいはデバッグ出力の書きだし先の標準入出力ストリームである。verbose は、-fsched-verbose-n で指定される詳細度レベルである。
MD_SCHED_REORDER (file, verbose, ready, n_ready)
一個の C の文であり、Haifa スケジューラがレディ・リストをスケジューリングした後に実行される。これにより、マシン記述で、並べ変えを行うことが可能になる。(例えば、VLIW マシンで二つの小さい命令を組み合わせる)。file はヌルポインタか、デバッグ出力の書きだし先標準入出力ストリームである。verbose は、-fsched-verbose-n で指定される饒舌度レベルである。ready は、スケジュールされる準備の整っている命令のレディ・リストである。n_ready はレディ・リストにある要素数である。スケジューラはレディ・リストを逆順に読む。ready[n_ready-1] から始めてready[0] に向かうのである。
MD_SCHED_VARIABLE_ISSUE (file, verbose, insn, more)
一個の C の文であり、Haifa スケジューラがレディ・リストのある一個の insn をスケジューリングした後に実行される。file はヌルポインタか、デバッグ出力の書きだし先標準入出力ストリームである。verbose は、-fsched-verbose-n で指定される饒舌度レベルである。insn は、スケジュールされた命令である。more は現在のサイクルで発行可能な命令数である。マクロ MD_SCHED_VARIABLE_ISSUE に、more の値を更新する(普通は more- とする)責任がある。
MAX_INTEGER_COMPUTATION_MODE
ロード、ストア、コピー演算以外の演算に使用可能な整数マシンモードのうち最大のものに定義する。

このマクロを定義する必要があるのは、ターゲットが word_mode より大きな値を汎用レジスタに保持できる場合である。ほとんどのターゲットではこのマクロを定義すべきではない。

MATH_LIBRARY
C の文字列定数を定義する。これは、システムの数学ライブラリをリンクするためのリンカへの引数を表す。ターゲットに独立した数学ライブラリがない場合は、"" とする。

このマクロを定義する必要があるのは、デフォルトの "-lm" ではまずい場合だけである。


Node:Config, Next:, Previous:Target Macros, Up:Top

コンフィギュレーションファイル

コンフィギュレーションファイル xm-machine.h では、GCC が動作するマシンとシステムを記述するマクロを定義する。これは、GCC の生成コードが目的とするマシンを記述するmachine.h の定義と異なる点である。xm-machine.h で定義される値のほとんどは、実際には GCC が動作する全てのマシンで同じになる。このため、全てのコンフィギュレーションファイルの多くの部分は同一である。しかし、幾つかのマクロは異なっており、それを以下に示す。

USG
ホストが System V なら、このマクロを定義する。
VMS
ホストが VMS なら、このマクロを定義する。
FATAL_EXIT_CODE
コンパイラが重大なエラーの後で終了するときに返すべきステータスコードを表す式。
SUCCESS_EXIT_CODE
コンパイラが重大なエラーなしに終了した場合に返すべきステータスコードを表す式。
HOST_WORDS_BIG_ENDIAN
ホストマシンが複数ワードからなる値を構成するワードを、ビッグエンディアンで格納するなら、このマクロを定義する。(GCC は、ホストの、一個のワードの中のバイト順には依存しない。)
HOST_FLOAT_WORDS_BIG_ENDIAN
ホストマシンが、DFmodeXFmodeTFmode の浮動小数点数をメモリに格納するのに、符号ビットを含むワードを最下位アドレスに置くなら、このマクロを 1 に定義する。それ以外なら、ゼロに定義する。

このマクロは、バイト順が複数ワードの整数と同じなら、定義する必要はない。

HOST_FLOAT_FORMAT
ホスト機種の浮動小数点形式を区別する数値コード。このコードの選択肢とデフォルトについては、Storage LayoutTARGET_FLOAT_FORMAT を参照のこと。
HOST_BITS_PER_CHAR
ホストマシンの char のビット数を表す C の式。
HOST_BITS_PER_SHORT
ホストマシンの short のビット数を表す C の式。
HOST_BITS_PER_INT
ホストマシンの int のビット数を表す C の式。
HOST_BITS_PER_LONG
ホストマシンの long のビット数を表す C の式。
ONLY_INT_FIELDS
ホストのコンパイラが、ビットフィールドの型として int しかサポートしていない場合は、このマクロを定義する。ほとんどの C コンパイラでは、enum を含む他の整数型も使える。
OBSTACK_CHUNK_SIZE
通常の obstack のメモリ塊の大きさを表す C の式である。これを定義しない場合は、普通の適切なデフォルトが使われる。
OBSTACK_CHUNK_ALLOC
obstack のメモリ塊を確保するのに使われる関数である。これを定義しない場合は、xmalloc が使われる
OBSTACK_CHUNK_FREE
obstack のメモリ塊を開放するのに使われる関数である。これを定義しない場合は、free が使われる
USE_C_ALLOCA
このマクロを定義すると、C で実装された alloca を使ってGNU C を実行することを表す。alloca の C 版は、alloca.c にある。これを使うには、Makefile の変数 ALLOCA も修正する必要がある。(これは、我々がこの処置が必要であることを知っているシステムでは自動的に行なわれる。)

このマクロを定義するなら、おそらく以下のようにする必要がある。

#ifndef __GNUC__
#define USE_C_ALLOCA
#else
#define alloca __builtin_alloca
#endif

こうしておくと、GCC が GCC でコンパイルされた場合は、もっと効率の良い組み込み alloca 関数を使うようになる。

FUNCTION_CONVERSION_BUG
ホストコンパイラが、式の中で使った場合に、関数値を関数へのポインタに正しく変換できない場合はこのマクロを定義する。
HAVE_VPRINTF
ライブラリ関数 vprintf があればこれを定義する。
MULTIBYTE_CHARS
GCC への入力としてマルチバイト文字をサポートすることを有効にするなら、このマクロを定義する。このためには、ホストシステムがマルチバイト文字を幅広文字に変換するための ANSI C ライブラリ関数群をサポートしている必要がある。
HAVE_PUTENV
ライブラリ関数 putenv がある場合は、これを定義する。
POSIX
システムが POSIX.1 準拠であればこれを定義する。
NO_SYS_SIGLIST
変数 sys_siglist を提供していないシステムではこのマクロを定義する。

システムによっては、この変数を提供はしているが、_sys_siglist のように別の名前になっている場合もある。そういう場合は、sys_siglist をマクロとして定義し、実際に提供される名前に展開されるようにすることが出来る。

autoconf は、普通、システムヘッダファイルの中に sys_siglist の宣言を見つけたなら、SYS_SIGLIST_DECLARES を定義する。しかし、sys_siglist を別の名前に定義した場合には、autoconf が自動的に SYS_SIGLIST_DECLARED を定義することはない。つまり、sys_siglist を定義したなら、 % SYS_SIGLIST_DECLARE も合わせて定義すべきである。

USE_PROTOTYPES
ホストのコンパイラがプロトタイプをサポートしている場合は、たとえ __STDC__ を定義していない場合でも、このマクロを1 に定義する。あるいは、GCC をコンパイルする際にはプロトタイプを使いたくないのであれば、このマクロを 0 に定義する。USE_PROTOTYPES が定義されていない場合は、ホストのコンパイラがプロトタイプをサポートしているかどうかは、 __STDC__ が定義されているかを検査することにより、自動的に決定される。
NO_MD_PROTOTYPES
マシン記述ファイルからプロトタイプが生成されるのは抑止したいが、GCC 内の他のプロトタイプは使いたいという場合は、これを定義する。USE_PROTOTYPES が 0 に定義されているか、ホストコンパイラがプロトタイプをサポートしていない場合は、このマクロを定義しても何の効果もない。
MD_CALL_PROTOTYPES
マシン記述ファイルから生成される関数 gen_callgen_call_value のプロトタイプを生成したい場合はこのマクロを定義する。USE_PROTOTYPES が 0 に定義されているか、ホストコンパイラがプロトタイプをサポートしていない場合、あるいは、NO_MD_PROTOTYPES が定義されている場合は、このマクロは何の効果もない。全てのマシン記述ファイルを、適切な数の引数を持つようにする修正が終わったら、このマクロは削除される予定である。
PATH_SEPARATOR
パスの成分の区切り文字を表す C の文字定数を定義する。デフォルト値はコロンである。
DIR_SEPARATOR
ファイル名指定の中のディレクトリを区切るのにスラッシュ以外の文字を使っているシステムでは、このマクロで、その文字を指定する C の文字定数を定義する。GCC がファイル名を表示するとき、指定した文字が使われる。GCC は、ファイル名をパースするときにスラッシュと指定した文字の両方を調べる。
OBJECT_SUFFIX
移植しようとしている機種でのオブジェクトファイルの拡張子を表すC の文字列を定義するマクロである。このマクロを定義しない場合は、GCC はオブジェクトファイルの拡張子として.o を使う。
EXECUTABLE_SUFFIX
移植しようとしている機種での実行形式ファイルの拡張子を表すC の文字列を定義するマクロである。このマクロを定義しない場合は、GCC は実行形式ファイルの拡張子としてヌル文字列を使う。
COLLECT_EXPORT_LIST
このマクロが定義されていると、collect2 は、コマンド行に指定された個々のオブジェクトファイルを調べ、リンカ向けにエクスポートリストを作る。AIX のように、リンカが main 関数から参照されていないオブジェクトファイルは捨て去り、エクスポートリストを使うようなシステムではこのマクロを定義する。

さらに、System V 向けのコンフィギュレーションファイルでは、bcopybzerobcmp を別名として定義している。いくつかのファイルでは、GCC でコンパイルされる場合にはalloca をマクロとして定義するようになっており、GCC の組み込みの alloca の利点をいかすようになっている。


Node:Fragments, Next:, Previous:Config, Up:Top

Makefile 断片

configure スクリプトを使って GCC のコンフィギュレーションを行なうと、テンプレートファイル Makefile.in からファイル Makefile を作成する。その際に、config ディレクトリから、t-targetx-host という名前の makefile の断片ファイルを取り込む。これらのファイルが存在しない場合は、そのターゲットやホスト向けに何も追加する必要がないということを意味する。


Node:Target Fragment, Next:, Previous:Fragments, Up:Fragments

ターゲットの Makefile 断片

ターゲットの makefile 断片、t-target は、Makefile で使われる、特別なターゲット依存の変数と特別な make のターゲットを定義する。

LIBGCC1
libgcc1.a を構築するルール。ターゲットが libgcc1.a の中の関数を必要としないのであれば、空に設定すること。See Interface.
CROSS_LIBGCC1
クロスコンパイラを作成するときに、libgcc1.a を構築するのに使う規則である。ターゲットが libgcc1.a にある関数を使う必要がない場合は、このマクロは空にする。See Cross Runtime.
LIBGCC2_CFLAGS
libgcc2.c をコンパイルするときに使うコンパイラのフラグである。
LIB2FUNCS_EXTRA
libgcc.a に、コンパイルまたはアセンブルして入れるべきファイルのソースファイル名のリストである。
CRTSTUFF_T_CFLAGS
crtsfuff.c をコンパイルするときに使われる特別なフラグである。See Initialization.
CRTSTUFF_T_CFLAGS_S
共有リンク用に crtstuff.c をコンパイルするときに使われる特別なフラグである。EXTRA-PARTScrtbeginS.ocrtendS.o を使っている場合にはこのフラグが使われる。See Initialization.
MULTILIB_OPTIONS
ターゲットによっては、GCC を異なる起動の仕方をすると、一緒にリンクできないオブジェクトが生成されることがある。例えば、幾つかのターゲットでは、GCC がビッグエンディアンとリトルエンディアン両方のコードを生成する。こういうターゲットには、非互換なオプションの組合せに一つずつの、複数のバージョンの libgcc.a をコンパイルするように設定しなければならない。GCC がリンカを起動するとき、使われたコマンド行オプションに応じて、正しいバージョンの libgcc.a をリンクするように調整する。

マクロ MULTILIB_OPTIONS には、libgcc.a の特別なバージョンを構築しなければならない場合向けのオプションの組を列挙する。互いに互換性のないオプションは、スラッシュで区切って並べて書く。一緒に組み合わせて使うことも出来るオプションはスペースで区切って書く。構築手順により、互換性のあるオプションの全ての組合せが構築される。

例えば、MULTILIB_OPTIONSm68000/m68020 msoft-float と設定したとすると、Makefile は、libgcc.a の特別なバージョンを、-m68000-m68020-msoft-float-m68000 -msoft-float-m68020 -msoft-float というオプションの組合せの分だけ作る。

MULTILIB_DIRNAMES
MULTILIB_OPTIONS を使う場合、この変数で様々なライブラリを置くのに使うべきディレクトリ名を指定する。MULTILIB_OPTIONS の要素毎に MULTILIB_DIRNAMES に一つ要素を書くこと。MULTILIB_DIRNAMES を使わない場合、デフォルト値はMULTILIB_OPTIONS のスラッシュを全て空白として扱ったものになる。

例えば、MULTILIB_OPTIONSm68000/m68020 msoft-float 設定されている場合は、MULTILIB_DIRNAMES のデフォルト値はm68000 m68020 msoft-float となる。ディレクトリ名として別の組合わせにしたい場合は別の値を指定すれば良い。

MULTILIB_MATCHES
同じオプションを二つの別の書き方をすることもある。あるオプションが MULTILIB_OPTIONS に列挙されている場合、GCC はその別名について知る必要がある。その場合、MULTILIB_MATCHES に、option=option という形式の項目のリストを設定し、全ての関係する別名を記述するようにする。例えば、m68000=mc68000 m68020=mc68020 とする。
MULTILIB_EXCEPTIONS
複数の組の MULTILIB_OPTIONS が指定されている場合、その中に構築すべきでない組合せが出てくる場合もある。そういう場合は、MULTILIB_EXCEPTIONS を設定して、構築すべきでないオプションの例外を全て、シェルの case 文の構文で指定する。

例えば、PowerPC の組み込み ABI サポートでは、-mcall-aixdesc オプションと、 -mrelocatable-mlittle オプションのどちらかを同時に指定してコンパイルしたライブラリは構築しないのが望ましい。このため、MULTILIB_EXCEPTIONS*mrelocatable/*mcall-aixdesc* *mlittle/*mcall-aixdesc* と設定する。

MULTILIB_EXTRA_OPTS
複数のバージョンの libgcc.a を構築する時、ある決まったオプション群を常に GCC にわたすべきであるという場合が時々ある。その場合は、MULTILIB_EXTRA_OPTS に、構築するときに必ず使われるオプションのリストを設定する。


Node:Host Fragment, Previous:Target Fragment, Up:Fragments

ホストの Makefile 断片

ホスト向けの Makefile の断片である、x-host では、Makefile で使用される、ホスト依存の特別な変数と make のターゲットを定義している。

CC
第一ステージのコンパイルに使うコンパイラ。
CLIB
そのホストで必要となるライブラリ。
OLDCC
ネイティブのコンパイルで、libgcc1.a を作る際に使うコンパイラ。
OLDAR
ネイティブのコンパイルで、libgcc1.a を作るのに使う ar コマンド。
INSTALL
使用すべきインストールコマンド。


Node:Funding, Next:, Previous:Fragments, Up:Top

フリーソフトウェアへの資金提供

読者が今から数年のうちにもっとたくさんのフリーソフトウェアが欲しいと思うなら、その開発資金を提供するよう人々に奨励することは読者にとって意味のあることである。知られているうち、最も有効な方法は、商用再配布業者に寄付を行うよう要請することである。

フリーソフトウェアシステムのユーザは、有料の配布業者に、売価の一部をフリーソフトウェアの開発者--Free Software Foundation やその他の人々-- に寄付するように奨励することで、開発のペースを速めることができる。

配布業者にこれらのことを行うよう納得させるには、要求し、かつ期待することである。そういうわけで、配布業者を比較するときは、フリーソフトウェアの開発にどれだけ寄付を行っているかで判断の一部にして欲しい。配布業者に、最も寄付を行う業者になるためには競争しなければならないことを示すのである。

この方法をうまく機能させるためには、比較の出来る数字を要求しなければならない。例えば、「我々は、ディスクが一枚売れる毎に Frobnitz プロジェクトに10 ドル寄付します。」という具合にである。曖昧な約束で満足してはいけない。例えば、「利益の一部は寄付されます。」では、比較に規準にならない。

「このディスクの利益の」ある正確な比率としてもあまり意味がない。独創的な経理や無関係なビジネス上の決定により、販売価格のどれぐらいの割合を利益として計上するかが大きく変わりうるからである。読者が支払った価格が 50 ドルだと、利益の 10 パーセントはおそらく一ドルに満たない。数セントかもしれないし、全然ないかもしれないのである。

再配布業者の中には、自分達で開発を行っているところもある。これもまた有益なことである。ただし、誰もが正直で居続けるためには、彼らがどんな種類の開発を、どれぐらいやっているのかを問い合わせる必要がある。開発の種類によっては、それ以外のものとくらべて、長期に渡る差が出てくる。例えば、あるプログラムの独立したバージョンを保守するのはほとんど貢献しない。コミュニティ全体向けの標準バージョンのプログラムを保守するのは、非常に貢献する。簡単な新規の移植はあまり貢献しない。誰か他の人が間違いなくやるはずだからである。難しい移植、例えば GNU コンパイラ集に新しい CPU を追加するようなものは、もっと貢献する。重要な新しい機能や新しいパッケージを開発するのが最も貢献度が大きいと言える。

さらなる開発をサポートするのは、フリーソフトウェアを有料で配布するときに「適切なことを行う」ことであるという考え方を確立することによって、さらにフリーソフトウェアを作るのに安定したリソースの提供しつづけることが保証できる。

Copyright (C) 1994 Free Software Foundation, Inc.
Verbatim copying and redistribution of this section is permitted
without royalty; alteration is not permitted.


Node:GNU/Linux, Next:, Previous:Funding, Up:Top

Linux と GNU プロジェクト

多くのコンピュータユーザは、GNU システムの修正版を毎日、それと知ることなく使っている。変な成り行きで、現在広く使われている GNU のバージョンは "Linux" として知られていることの方が多い。多くのユーザは、それが GNU プロジェクトにどれぐらい関係しているのかに気が付いていない。

実際に Linux は存在する。それはカーネルであり、上記の人々が使っているものである。だが、カーネルというものはそれだけで使うことはできないものである。カーネルは、システム全体の一部としてのみ役に立つのである。Linux が良く使われているシステムは、GNU システムの修正版である。言い換えれば、Linux ベースの GNU システムなのである。

多くのユーザは、カーネル-これは Linux である-とシステム全体- こちらも "Linux"と呼ばれている-と間の区別にあまり気が付いていない。名前を曖昧に使うのは、理解の助けにならない。

プログラマは、大体 Linux がカーネルであることを知っている。だが、かれらはシステム全体が Linux と呼ばれているのも同様に聞いており、そのため、その名前にあった歴史をしばしば勝手に作り出してしまう。例えば、多くの人が信じていることに、Linus Torvalds がカーネルを書き上げ、彼の友人達が他のフリーソフトウェアを捜し回ったとき、Unix ライクなシステムを作るのに必要なほとんど全てのものが既に利用可能であったことに、特に理由はないというのがある。

彼らが見つけたものは偶然ではない。それは GNU システムだったのである。利用可能なフリーソフトウェアを合わせた結果、完全なシステムになったのは、GNU プロジェクトが 1984 年以来をそれを作るために作業をしてきたからである。GNU 宣言は、GNU と呼ばれる、フリーなUnix ライクシステムを開発することを目標に明示した。Linux が書かれたときには、システムはほとんど完成していたのである。

ほとんどのフリーソフトウェアのプロジェクトは、特定の仕事を行う特定のプログラムを開発することを目標にしている。例えば、Linus Torvalds は、Unix ライクなカーネル(Linux) を書くことを目指した。Donald Knuth はテキスト・フォーマッタ(TeX) を書くことを目指した。Bob Scheifler は、ウィンドウシステム(X Window System) を開発することを目指した。この種類のプロジェクトの貢献度を、そのプロジェクトから出てきた特定のプログラムで測ることは自然なことである。

この方法で GNU プロジェクトの貢献度を測ったらどうなるだろうか? ある CD-ROM ベンダは、自社の Linux ディストリビューションで、GNU ソフトウェアは、一個の構成要素としては最大であり、ソースコード全体の 28% 程度を占め、これには、それなしにはシステムとして成り立たないような本質的で主要な要素が含まれている。Linux 自体は 3% 程度を占めるに過ぎない。そういうことで、このシステムの名前を選ぶのに、システムにあるプログラムを誰が書いたかを規準にするなら、最も適切なものを一つ選ぶとしたら GNU になるだろう。

しかし、我々はこれが問題を考えるのに正しい方法だとは考えない。GNU プロジェクトは、特定のソフトウェアパッケージを開発するプロジェクトではなかったし、現在でもそうである。既に達成しているが、C コンパイラを開発するプロジェクトではなかった。これも既に開発済みであるが、テキストエディタを開発するプロジェクトではなかった。GNU プロジェクトの目標は、完全なフリーの Unix 風システム を開発することであった。

多くの人が、このシステムにあるフリーソフトウェアに重要な貢献をしており、彼らは全て栄誉に値する。だが、これが システム であり、単に便利なプログラムの集まりではないことの理由は、GNU プロジェクトがこれらを一つにすることを目指していたからである。我々は、完全なフリーのシステムを作るのに必要なプログラムを書いた。本質的ではあるが、わくわくするようなものではない主要な要素、例えばアセンブラやリンカを書いた。これらがないとシステムとして成り立たないからである。完全なシステムにはプログラミングツール以上のものが必要である。そのため、我々はその他の要素も同様に書いた。例えば、Bourne Again SHell や PostScript インタプリタ Ghostscript やGNU C ライブラリ等である。

90年代初めには、カーネルを除けば全システムを組み立てていた(カーネルについても我々は作業をしていた。GNU Hurd がそれであり、これは Mach 上で動くものであった)。このカーネルを開発するのは、我々が思っていた以上に非常に困難であり、現在も完成させるべく作業をしている。

幸運にも、GNU Hurd の完成を待つ必要はない。今では、Linux が動作するからである。Linus Torvalds が Linux を書いたとき、かれは最後の大きな隙間を埋めたのである。人々は、Linx を GNU システムと組み合わせて完全なフリーのシステムを作ることが可能になった。それが Linux ベースの GNU システムである(略して、GNU/Linux システムと言っても良い)。

これらを組み合わせるというと簡単なことのように聞こえるかもしれないが、これは単純な作業ではない。GNU C ライブラリ(省略して glibc と呼ばれる)は相当の変更が必要であった。完全なシステムを、箱から取り出してすぐ動作するようなディストリビューションとして統合するのは、やはり大仕事である。それにはシステムをインストールする方法とブートする方法という問題を解決する必要がある。我々が取り組んだことのない問題である。なぜなら、我々はその地点まで到達していなかったのである。色々なシステムのディストリビューションを開発した人は相当な貢献をしているのである。

GNU プロジェクトは GNU システム同様 GNU/Linux システムもサポートしている。資金提供も行っている。我々は、GNU C ライブラリに対する Linux に関連する部分の拡張の書き直しに資金を提供しているので、現在ではうまく統合され、最新の GNU/Linux システムは現在のライブラリのリリースを変更無しで使っている。我々は、Debian GNU/Linux の開発の初期段階にも資金を提供した。

我々は、現在では、我々自身の作業のほとんどに Linux ベースの GNU システムを使っている。読者も使ってくれることを望んでいる。ただし、"Linux" という名前を曖昧に使って、人々を混乱させないようにして欲しい。Linux はカーネルであり、システムの本質的で重要な要素の一つである。全体としてのシステムは多かれ少なかれ GNU システムなのである。


Node:Copying, Next:, Previous:GNU/Linux, Up:Top

GNU GENERAL PUBLIC LICENSE

Version 2, June 1991

Copyright © 1989, 1991 Free Software Foundation, Inc.
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA

Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.

Preamble

The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) You can apply it to your programs, too.

When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things.

To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it.

For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights.

We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software.

Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations.

Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all.

The precise terms and conditions for copying, distribution and modification follow.

  1. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you".

    Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does.

  2. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program.

    You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee.

  3. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions:
    1. You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change.
    2. You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License.
    3. If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.)

    These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it.

    Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program.

    In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License.

  4. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following:
    1. Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or,
    2. Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or,
    3. Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.)

    The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable.

    If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code.

  5. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance.
  6. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it.
  7. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License.
  8. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program.

    If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances.

    It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice.

    This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License.

  9. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License.
  10. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns.

    Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation.

  11. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally.
  12. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
  13. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.

How to Apply These Terms to Your New Programs

If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms.

To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found.

one line to give the program's name and a brief idea of what it does.
Copyright (C) yyyy  name of author

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.

Also add information on how to contact you by electronic and paper mail.

If the program is interactive, make it output a short notice like this when it starts in an interactive mode:

Gnomovision version 69, Copyright (C) yyyy name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details
type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.

The hypothetical commands show w and show c should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than show w and show c; they could even be mouse-clicks or menu items--whatever suits your program.

You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names:

Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.

signature of Ty Coon, 1 April 1989
Ty Coon, President of Vice

This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Library General Public License instead of this License.


Node:Contributors, Next:, Previous:Copying, Up:Top

GCC に貢献した人々

Richard Stallman に加えて、たくさんの人々が GCC のコードを書いている。


Node:Index, Previous:Contributors, Up:Top

Index

Table of Contents


Footnotes

  1. Fortran ではこの機能を割り当て形 goto と呼んでいるが、この呼び方は C では適当でないように思える。C では、単にラベル変数にラベルのアドレスを格納すること以上の事が可能だからである。

  2. ファイルのベース名とは、前にある全てのパス情報と .h.C.cc のようなサフィックスを取り除いた名前である。